"""Gmail › Handtekeningen: sjabloon, logo, OU's, functie/telefoon (Google) en toepassen in Gmail.""" import time from flask import Blueprint, render_template, request, redirect, url_for, flash, session, jsonify, Response, abort from blueprints.auth import login_required from rechten import recht_vereist, log from services import handtekening_service as hs from tenancy import huidige_school, school_op_code, in_school handtekeningen_bp = Blueprint('handtekeningen', __name__) handtekening_logo_bp = Blueprint('handtekening_logo', __name__) # publiek (Gmail haalt het logo op) CACHE_SECONDEN = 5 * 60 def _door(): return session.get('naam') or session.get('user') def _gebruikers(inst, vernieuw=False): school = huidige_school() sleutel = ('handtekening_gebruikers', tuple(inst['ous']), bool(inst.get('Met_sub_ous'))) bewaard = school.cache.get('handtekening_gebruikers') if bewaard and not vernieuw and bewaard[0] == sleutel and time.time() - bewaard[1] < CACHE_SECONDEN: return bewaard[2] lijst = hs.gebruikers(inst['ous'], bool(inst.get('Met_sub_ous'))) school.cache['handtekening_gebruikers'] = (sleutel, time.time(), lijst) return lijst @handtekeningen_bp.route('/', methods=['GET']) @login_required @recht_vereist('gmail_handtekeningen') def overzicht(): inst = hs.instellingen() fout_ou = fout_gebruikers = None try: ous = hs.ou_lijst() except hs.HandtekeningFout as e: ous, fout_ou = inst['ous'], str(e) gebruikers = [] if inst['ous']: try: gebruikers = _gebruikers(inst, vernieuw=bool(request.args.get('vernieuw'))) except Exception as e: fout_gebruikers = str(e) if request.args.get('vernieuw'): return redirect(url_for('handtekeningen.overzicht')) logboek = hs.logboek() return render_template('handtekeningen.html', inst=inst, ous=ous, fout_ou=fout_ou, gebruikers=gebruikers, fout_gebruikers=fout_gebruikers, logboek=logboek, velden=hs.VELDEN, standaard_sjabloon=hs.STANDAARD_SJABLOON, max_tekens=hs.MAX_TEKENS, publiek_voorstel=request.host_url.rstrip('/'), status=hs.Toepasser().status, school_gegevens=hs.gegevens({})) @handtekeningen_bp.route('/sjabloon', methods=['POST']) @login_required @recht_vereist('gmail_handtekeningen') def sjabloon(): hs.ensure_tables() try: hs.bewaar(request.form.get('sjabloon'), request.form.getlist('ou'), request.form.get('met_sub') == '1', request.form.get('logo_url'), request.form.get('logo_breedte') or 120, request.form.get('publiek_adres'), _door()) bestand = request.files.get('logo') if bestand and bestand.filename: hs.bewaar_logo(bestand.read(), bestand.mimetype) elif request.form.get('logo_wissen') == '1': hs.verwijder_logo() huidige_school().cache.pop('handtekening_gebruikers', None) log("Gmail-handtekening: sjabloon en instellingen bewaard") flash("Handtekening en instellingen bewaard. Klik op ▶ Toepassen om ze in Gmail te zetten.", "success") except hs.HandtekeningFout as e: flash(str(e), "error") except Exception as e: flash(f"Bewaren mislukt: {e}", "error") return redirect(url_for('handtekeningen.overzicht')) @handtekeningen_bp.route('/voorbeeld', methods=['POST']) @login_required @recht_vereist('gmail_handtekeningen') def voorbeeld(): """Live voorbeeld met het (nog niet bewaarde) sjabloon uit de editor en de gegevens van één gebruiker.""" d = request.get_json(silent=True) or {} inst = hs.instellingen() if d.get('logo_url') is not None: inst['Logo_url'] = (d.get('logo_url') or '').strip() or None if d.get('publiek_adres') is not None: inst['Publiek_adres'] = (d.get('publiek_adres') or '').strip().rstrip('/') or None try: inst['Logo_breedte'] = int(d.get('logo_breedte') or inst.get('Logo_breedte') or 120) except ValueError: pass inst['logo_link'] = hs.logo_link(inst) # In het voorbeeld het geüploade logo via de eigen (ingelogde) sessie tonen, ook als het publiek adres nog niet klopt if not inst.get('Logo_url') and inst.get('heeft_logo') and inst.get('Logo_sleutel'): inst['logo_link'] = url_for('handtekening_logo.logo', code=huidige_school().code, sleutel=inst['Logo_sleutel'], ext=hs.LOGO_TYPES.get(inst.get('Logo_type'), 'png')) g = d.get('gebruiker') or {} tekst = hs.vul_in(d.get('sjabloon') if d.get('sjabloon') is not None else inst.get('Sjabloon'), hs.gegevens(g), inst) return jsonify(ok=True, html=tekst, tekens=len(tekst)) @handtekeningen_bp.route('/gebruiker', methods=['POST']) @login_required @recht_vereist('gmail_handtekeningen') def gebruiker(): """Functie en telefoon van één gebruiker in Google bewaren.""" d = request.get_json(silent=True) or {} email = (d.get('email') or '').strip().lower() functie, telefoon = (d.get('functie') or '').strip()[:100], (d.get('telefoon') or '').strip()[:40] if not email: return jsonify(ok=False, fout="Geen gebruiker."), 400 try: hs.bewaar_in_google(email, functie, telefoon) except hs.HandtekeningFout as e: return jsonify(ok=False, fout=str(e)), 400 bewaard = huidige_school().cache.get('handtekening_gebruikers') if bewaard: for u in bewaard[2]: if u['email'] == email: u.update(functie=functie, telefoon=telefoon) log(f"Gmail-handtekening: functie/telefoon van {email} aangepast in Google") return jsonify(ok=True) @handtekeningen_bp.route('/toepassen', methods=['POST']) @login_required @recht_vereist('gmail_handtekeningen') def toepassen(): d = request.get_json(silent=True) or {} emails = None if d.get('alle') else [e for e in (d.get('emails') or []) if isinstance(e, str)] if emails is not None and not emails: return jsonify(ok=False, fout="Niemand geselecteerd."), 400 if not hs.Toepasser().start(emails, _door()): return jsonify(ok=False, fout="Er loopt al een opdracht."), 409 log(f"Gmail-handtekening toepassen ({'iedereen' if emails is None else len(emails)})") return jsonify(ok=True) @handtekeningen_bp.route('/status.json', methods=['GET']) @login_required @recht_vereist('gmail_handtekeningen') def status(): s = dict(hs.Toepasser().status) if not s['bezig']: s['logboek'] = {k: {'ok': bool(v['Ok']), 'melding': v['Melding'] or '', 'op': v['Toegepast'].strftime('%d-%m-%Y %H:%M')} for k, v in hs.logboek().items()} return jsonify(s) @handtekeningen_bp.route('/nachtelijk', methods=['POST']) @login_required @recht_vereist('gmail_handtekeningen') def nachtelijk(): aan = request.form.get('aan') == '1' hs.zet_nacht(aan, _door()) log(f"Gmail-handtekening: nachtelijk opnieuw toepassen {'aan' if aan else 'uit'}") flash("Elke nacht wordt de handtekening opnieuw gezet bij wie ze gewijzigd heeft." if aan else "Het nachtelijk opnieuw toepassen staat uit.", "success") return redirect(url_for('handtekeningen.overzicht')) # --------------------------------------------------------------------- # Publiek: het logo (Gmail haalt het op via een link; geen aanmelding) # --------------------------------------------------------------------- @handtekening_logo_bp.route('/handtekening-logo//.', methods=['GET']) def logo(code, sleutel, ext): school = school_op_code(code) if not school or not sleutel.isalnum(): abort(404) with in_school(school): data, soort = hs.logo_bestand(sleutel) if not data: abort(404) return Response(bytes(data), mimetype=soort, headers={'Cache-Control': 'public, max-age=86400'})