180 lines
7.7 KiB
Python
180 lines
7.7 KiB
Python
"""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'})
|