Initial commit

This commit is contained in:
Kristof committed 2026-10-14 12:29:29 +02:00
commit 536ff43ce4
158 files changed
+30355

No files matched your search

+179
View File
@@ -0,0 +1,179 @@
"""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/<code>/<sleutel>.<ext>', 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'})