From 4de3e2406a68b0c72a28ac73c223e66dee1a537d Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 29 Apr 2026 13:31:15 +0100 Subject: [PATCH] Add hosted legal pages --- src/repixelizer/gui.py | 17 ++++ src/repixelizer/gui_static/landing.html | 3 + src/repixelizer/gui_static/privacy.html | 113 ++++++++++++++++++++++ src/repixelizer/gui_static/terms.html | 119 ++++++++++++++++++++++++ tests/test_gui.py | 32 +++++++ 5 files changed, 284 insertions(+) create mode 100644 src/repixelizer/gui_static/privacy.html create mode 100644 src/repixelizer/gui_static/terms.html diff --git a/src/repixelizer/gui.py b/src/repixelizer/gui.py index b89e928..5d9cc1c 100644 --- a/src/repixelizer/gui.py +++ b/src/repixelizer/gui.py @@ -923,6 +923,13 @@ def _landing_page_html( ) +def _static_html_page(static_dir: Path, filename: str) -> str: + styles_path = static_dir / "styles.css" + styles_version = int(styles_path.stat().st_mtime_ns) if styles_path.exists() else 0 + template = (static_dir / filename).read_text(encoding="utf-8") + return template.replace("{{STYLES_VERSION}}", str(styles_version)) + + def create_app(): deps = _require_gui_dependencies() FastAPI = deps["FastAPI"] @@ -1238,6 +1245,16 @@ def create_app(): ) ) return RedirectResponse(url="/app/") + + @app.api_route("/privacy", methods=["GET", "HEAD"]) + @app.api_route("/privacy/", methods=["GET", "HEAD"]) + def privacy_policy(): + return HTMLResponse(_static_html_page(static_dir, "privacy.html")) + + @app.api_route("/terms", methods=["GET", "HEAD"]) + @app.api_route("/terms/", methods=["GET", "HEAD"]) + def terms_of_service(): + return HTMLResponse(_static_html_page(static_dir, "terms.html")) else: # pragma: no cover - only relevant before frontend assets exist @app.get("/") def root_missing(): diff --git a/src/repixelizer/gui_static/landing.html b/src/repixelizer/gui_static/landing.html index f5b57e7..74ddc34 100644 --- a/src/repixelizer/gui_static/landing.html +++ b/src/repixelizer/gui_static/landing.html @@ -229,6 +229,9 @@

Self-hosters can still go straight to the app. Hosted mode just gets a front door instead of making everyone trip over raw controls immediately.

+

+ Privacy Policy ยท Terms of Service +