From eef85f36a9139168431ef924f4b8325c1bbea603 Mon Sep 17 00:00:00 2001 From: mwiegand Date: Mon, 11 May 2026 21:55:34 +0200 Subject: [PATCH] profile: GET /profile page with change-password form Adds the page reachable from the username link in the header. Renders the form skeleton; the POST handler lands in the next commit. Co-Authored-By: Claude Opus 4.7 (1M context) --- l4d2web/app.py | 2 ++ l4d2web/routes/profile_routes.py | 27 +++++++++++++++ l4d2web/templates/base.html | 2 +- l4d2web/templates/profile.html | 33 ++++++++++++++++++ l4d2web/tests/test_profile.py | 58 ++++++++++++++++++++++++++++++++ 5 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 l4d2web/routes/profile_routes.py create mode 100644 l4d2web/templates/profile.html create mode 100644 l4d2web/tests/test_profile.py diff --git a/l4d2web/app.py b/l4d2web/app.py index 68b11f0..670b25d 100644 --- a/l4d2web/app.py +++ b/l4d2web/app.py @@ -16,6 +16,7 @@ from l4d2web.routes.job_routes import bp as job_bp from l4d2web.routes.log_routes import bp as log_bp from l4d2web.routes.overlay_routes import bp as overlay_bp from l4d2web.routes.page_routes import bp as page_bp +from l4d2web.routes.profile_routes import bp as profile_bp from l4d2web.routes.server_routes import bp as server_bp from l4d2web.routes.workshop_routes import bp as workshop_bp from l4d2web.services.job_worker import ( @@ -82,6 +83,7 @@ def create_app(test_config: dict[str, object] | None = None) -> Flask: app.register_blueprint(job_bp) app.register_blueprint(log_bp) app.register_blueprint(page_bp) + app.register_blueprint(profile_bp) register_cli(app) if app.config.get("TESTING"): reset_login_rate_limits() diff --git a/l4d2web/routes/profile_routes.py b/l4d2web/routes/profile_routes.py new file mode 100644 index 0000000..5f464e1 --- /dev/null +++ b/l4d2web/routes/profile_routes.py @@ -0,0 +1,27 @@ +from flask import Blueprint, render_template, request + +from l4d2web.auth import require_login + + +bp = Blueprint("profile", __name__) + + +_ERROR_MESSAGES = { + "fields_required": "Fill in all three fields.", + "mismatch": "New password and confirmation do not match.", + "too_short": "New password must be at least 8 characters.", + "empty": "New password must not be empty.", + "wrong_current": "Current password is incorrect.", +} + + +@bp.get("/profile") +@require_login +def profile_page() -> str: + error_key = request.args.get("error", "") + success = request.args.get("success") == "1" + return render_template( + "profile.html", + error_message=_ERROR_MESSAGES.get(error_key, ""), + success=success, + ) diff --git a/l4d2web/templates/base.html b/l4d2web/templates/base.html index 49e438f..18cc7b4 100644 --- a/l4d2web/templates/base.html +++ b/l4d2web/templates/base.html @@ -24,7 +24,7 @@ {% if g.user %}