from flask import Blueprint, render_template, request, jsonify, make_response, flash from io import BytesIO # <-- Deze regel lost de NameError op from xhtml2pdf import pisa from datetime import datetime from services.smartschool_api import SmartschoolService from config import Config from database import execute_query from tenancy import per_school from blueprints.auth import login_required from rechten import recht_vereist smartschool_bp = Blueprint("/ss",__name__) # Eén Smartschool-client per school (met het webservice-wachtwoord van die school) ss_service = per_school(lambda: SmartschoolService( platform=Config.SS_API_PLATFORM, webservice_pwd=Config.SS_API_PW )) @smartschool_bp.route('/smartschool', methods=['GET', 'POST']) @login_required @recht_vereist('smartschool') def smartschool(): results = [] query = (request.form.get('query') or '').strip() if request.method == 'POST' and query: # 1) Exact internnummer of gebruikersnaam: rechtstreeks bij Smartschool try: user_data = ss_service.get_student_details(query) except Exception as e: user_data = None flash(f"Smartschool is niet bereikbaar of nog niet ingesteld voor deze school ({e}).", "error") if user_data: results = [user_data] else: # 2) Deel van een naam, voornaam of gebruikersnaam: zoeken in de leerlingen van PIVOT results = zoek_leerlingen_lokaal(query) return render_template('smartschool_beheer.html', results=results, query=query) MAX_RESULTATEN = 25 def zoek_leerlingen_lokaal(query): """Leerlingen uit de tabel Leerlingen (gevuld door de Informat-sync) die op de zoekterm lijken. Geeft dicts met dezelfde sleutels als Smartschool (internnummer, voornaam, naam, gebruikersnaam).""" zoek = f"%{query}%" rows = execute_query( "SELECT Internnummer, Voornaam, Naam, Gebruikersnaam FROM Leerlingen " "WHERE Internnummer = %s OR Gebruikersnaam LIKE %s OR Voornaam LIKE %s OR Naam LIKE %s " " OR CONCAT_WS(' ', Voornaam, Naam) LIKE %s OR CONCAT_WS(' ', Naam, Voornaam) LIKE %s " "ORDER BY Naam, Voornaam LIMIT %s", (query, zoek, zoek, zoek, zoek, zoek, MAX_RESULTATEN)) return [{'internnummer': r['Internnummer'], 'voornaam': r['Voornaam'] or '', 'naam': r['Naam'] or '', 'gebruikersnaam': r['Gebruikersnaam'] or ''} for r in rows] @smartschool_bp.route('/smartschool/reset', methods=['POST']) @login_required @recht_vereist('smartschool') def smartschool_reset(): identifier = request.form.get('username') new_pass = request.form.get('new_password') acc_type = int(request.form.get('account_type', 0)) generate_pdf = request.form.get('generate_pdf') == 'true' display_name = request.form.get('display_name') # Ontvang de naam uit de browser result = ss_service.reset_password(identifier, new_pass, acc_type) if result == "0": if generate_pdf: # We gebruiken de display_name die we van de frontend hebben gekregen # Voor de e-mail label kunnen we nog steeds student details ophalen indien nodig student_data = ss_service.get_student_details(identifier) email_label = student_data.get('gebruikersnaam') if acc_type == 0 else f"Co-account van {student_data['voornaam']}" rendered_html = render_template( 'pdf_template_leerling.html', naam=display_name, datum=datetime.now().strftime("%d/%m/%Y"), email=email_label, wachtwoord=new_pass ) pdf_out = BytesIO() pisa_status = pisa.CreatePDF(rendered_html, dest=pdf_out) if pisa_status.err: return jsonify({"status": "error", "message": "PDF generatie mislukt"}) pdf_out.seek(0) response = make_response(pdf_out.read()) response.headers['Content-Type'] = 'application/pdf' response.headers['Content-Disposition'] = f'attachment; filename=Account_{identifier}.pdf' return response return jsonify({"status": "success"}) return jsonify({"status": "error", "message": f"Code {result}"}) @smartschool_bp.route('/smartschool/coaccounts', methods=['POST']) @login_required @recht_vereist('smartschool') def smartschool_coaccounts(): username = request.form.get('username') # Gebruik de nieuwe parser functie co_accounts = ss_service.get_co_accounts_from_details(username) return jsonify({"status": "success", "accounts": co_accounts})