CP_EHRENAMT/app/routes/profil.py
2026-06-25 18:58:44 +02:00

110 lines
3.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Profil: Anzeigename, Profilbild und optionale freiwillige Angaben.
Nichts außer dem (ohnehin vorhandenen) Anzeigenamen ist Pflicht. Die freiwilligen
Felder sind über die Liste FREIWILLIGE_FELDER definiert und werden als JSON in
user.freiwillige_angaben abgelegt ein neues Feld ist damit eine Zeile mehr in
der Liste, ohne DB-Migration. Läuft in beiden Shells (shell_base je Rolle).
"""
import json
import os
import uuid
from flask import (
Blueprint,
abort,
current_app,
flash,
redirect,
render_template,
request,
send_from_directory,
url_for,
)
from .. import db
from ..auth import current_user, login_required
from ..models import User
from ..team_scope import team_query
bp = Blueprint("profil", __name__, url_prefix="/profil")
# Erlaubte Bildtypen fürs Profilbild (serverseitig geprüft).
BILD_ENDUNGEN = {"png", "jpg", "jpeg", "gif", "webp"}
# Optionale freiwillige Angaben. Neues Feld = ein Eintrag mehr; "mehrzeilig" für
# Textarea. Werte landen als JSON-Objekt in user.freiwillige_angaben.
FREIWILLIGE_FELDER = [
{"key": "pronomen", "label": "Pronomen", "placeholder": "z. B. sie/ihr, er/ihm"},
{"key": "ueber_mich", "label": "Über mich", "placeholder": "Ein, zwei Sätze ganz freiwillig", "mehrzeilig": True},
]
_GUELTIGE_KEYS = {f["key"] for f in FREIWILLIGE_FELDER}
def _endung(dateiname):
if not dateiname or "." not in dateiname:
return ""
return dateiname.rsplit(".", 1)[1].lower()
def _angaben_lesen(user):
"""freiwillige_angaben als Dict (robust gegen leer/kaputt)."""
if not user.freiwillige_angaben:
return {}
try:
daten = json.loads(user.freiwillige_angaben)
return daten if isinstance(daten, dict) else {}
except (ValueError, TypeError):
return {}
@bp.route("/", methods=("GET", "POST"))
@login_required
def index():
user = current_user()
if request.method == "POST":
anzeigename = (request.form.get("anzeigename") or "").strip()
if not anzeigename:
flash("Bitte einen Anzeigenamen angeben.")
return redirect(url_for("profil.index"))
user.anzeigename = anzeigename
# Freiwillige Felder: nur bekannte Keys, leere Werte fallen raus.
angaben = {}
for feld in FREIWILLIGE_FELDER:
wert = (request.form.get(feld["key"]) or "").strip()
if wert:
angaben[feld["key"]] = wert
user.freiwillige_angaben = json.dumps(angaben, ensure_ascii=False) if angaben else None
# Profilbild optional. Nur bei tatsächlichem Upload anfassen.
datei = request.files.get("profilbild")
if datei and datei.filename:
endung = _endung(datei.filename)
if endung not in BILD_ENDUNGEN:
flash("Dieses Bildformat ist nicht erlaubt. Erlaubt: PNG, JPG, GIF, WebP.")
return redirect(url_for("profil.index"))
name = f"profil_{uuid.uuid4().hex}.{endung}"
datei.save(os.path.join(current_app.config["UPLOAD_FOLDER"], name))
user.profilbild_pfad = name
db.session.commit()
flash("Profil gespeichert.")
return redirect(url_for("profil.index"))
return render_template(
"profil.html",
felder=FREIWILLIGE_FELDER,
angaben=_angaben_lesen(user),
)
@bp.route("/bild/<int:user_id>")
@login_required
def bild(user_id):
"""Profilbild eines Team-Mitglieds ausliefern (team-gescoped)."""
user = team_query(User).filter_by(id=user_id).first()
if user is None or not user.profilbild_pfad:
abort(404)
return send_from_directory(current_app.config["UPLOAD_FOLDER"], user.profilbild_pfad)