107 lines
4.1 KiB
Python
107 lines
4.1 KiB
Python
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
from uuid import uuid4
|
|
|
|
from flask import Blueprint, current_app, flash, jsonify, redirect, render_template, request, url_for
|
|
from flask_login import current_user, login_required
|
|
from werkzeug.utils import secure_filename
|
|
|
|
from ..extensions import csrf, db
|
|
from ..forms import SettingsProfileForm
|
|
from ..models import BadgeDefinition, PushSubscription
|
|
from ..services.notifications import push_enabled
|
|
|
|
|
|
bp = Blueprint("settings", __name__, url_prefix="/settings")
|
|
|
|
|
|
def _save_avatar(file_storage) -> str:
|
|
filename = secure_filename(file_storage.filename or "")
|
|
ext = Path(filename).suffix.lower() or ".png"
|
|
relative_path = Path("avatars") / f"{uuid4().hex}{ext}"
|
|
absolute_path = Path(current_app.config["UPLOAD_FOLDER"]) / relative_path
|
|
absolute_path.parent.mkdir(parents=True, exist_ok=True)
|
|
file_storage.save(absolute_path)
|
|
return relative_path.as_posix()
|
|
|
|
|
|
@bp.route("", methods=["GET", "POST"])
|
|
@login_required
|
|
def index():
|
|
form = SettingsProfileForm(original_email=current_user.email, obj=current_user)
|
|
if form.validate_on_submit():
|
|
current_user.name = form.name.data.strip()
|
|
current_user.email = form.email.data.lower().strip()
|
|
current_user.notification_task_due_enabled = form.notification_task_due_enabled.data
|
|
current_user.notification_monthly_winner_enabled = form.notification_monthly_winner_enabled.data
|
|
if form.password.data:
|
|
current_user.set_password(form.password.data)
|
|
if form.avatar.data:
|
|
current_user.avatar_path = _save_avatar(form.avatar.data)
|
|
db.session.commit()
|
|
flash("Deine Einstellungen wurden gespeichert.", "success")
|
|
return redirect(url_for("settings.index"))
|
|
|
|
badges = BadgeDefinition.query.order_by(BadgeDefinition.name.asc()).all()
|
|
subscriptions = PushSubscription.query.filter_by(user_id=current_user.id).all()
|
|
return render_template(
|
|
"settings/index.html",
|
|
form=form,
|
|
badges=badges,
|
|
push_ready=push_enabled(),
|
|
vapid_public_key=current_app.config["VAPID_PUBLIC_KEY"],
|
|
has_subscription=bool(subscriptions),
|
|
)
|
|
|
|
|
|
@bp.route("/badges/<int:badge_id>", methods=["POST"])
|
|
@login_required
|
|
def update_badge(badge_id: int):
|
|
badge = BadgeDefinition.query.get_or_404(badge_id)
|
|
badge.threshold = max(1, request.form.get("threshold", type=int, default=badge.threshold))
|
|
badge.bonus_points = max(0, request.form.get("bonus_points", type=int, default=badge.bonus_points))
|
|
badge.active = request.form.get("active") == "on"
|
|
db.session.commit()
|
|
flash(f"Badge „{badge.name}“ wurde aktualisiert.", "success")
|
|
return redirect(url_for("settings.index"))
|
|
|
|
|
|
@bp.route("/push/subscribe", methods=["POST"])
|
|
@login_required
|
|
@csrf.exempt
|
|
def push_subscribe():
|
|
if not push_enabled():
|
|
return jsonify({"ok": False, "message": "VAPID ist nicht konfiguriert."}), 400
|
|
|
|
data = request.get_json(silent=True) or {}
|
|
endpoint = data.get("endpoint")
|
|
keys = data.get("keys", {})
|
|
if not endpoint or not keys.get("p256dh") or not keys.get("auth"):
|
|
return jsonify({"ok": False, "message": "Subscription unvollständig."}), 400
|
|
|
|
subscription = PushSubscription.query.filter_by(endpoint=endpoint).first()
|
|
if not subscription:
|
|
subscription = PushSubscription(user_id=current_user.id, endpoint=endpoint, p256dh=keys["p256dh"], auth=keys["auth"])
|
|
db.session.add(subscription)
|
|
else:
|
|
subscription.user_id = current_user.id
|
|
subscription.p256dh = keys["p256dh"]
|
|
subscription.auth = keys["auth"]
|
|
db.session.commit()
|
|
return jsonify({"ok": True})
|
|
|
|
|
|
@bp.route("/push/unsubscribe", methods=["POST"])
|
|
@login_required
|
|
@csrf.exempt
|
|
def push_unsubscribe():
|
|
data = request.get_json(silent=True) or {}
|
|
endpoint = data.get("endpoint")
|
|
if endpoint:
|
|
subscription = PushSubscription.query.filter_by(endpoint=endpoint, user_id=current_user.id).first()
|
|
if subscription:
|
|
db.session.delete(subscription)
|
|
db.session.commit()
|
|
return jsonify({"ok": True})
|