feat: v4.0.1 — onboarding, landing page, smart redirect, register GET, 404 stylé, API unifiée

- Landing page / pour visiteurs non-auth (template landing.html)
- Redirection / intelligente: non-auth → landing, auth sans Gitea → local workspace, auth+Gitea → dashboard
- GET /auth/register — page d'inscription dédiée (tab register actif)
- 404 handler stylisé thème Notion sombre (JSON pour /api/*, HTML pour le reste)
- Alias /api/pages GET/POST → /board/api/pages (307 redirect)
- 133 tests passent
This commit is contained in:
2026-07-20 07:55:09 -04:00
parent 47b0f80dfe
commit 0a675a94f7
4 changed files with 311 additions and 7 deletions
+59 -1
View File
@@ -4,7 +4,7 @@ from __future__ import annotations
import logging
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from fastapi.middleware.cors import CORSMiddleware
from starlette.middleware.sessions import SessionMiddleware
@@ -84,3 +84,61 @@ async def pwa_manifest():
"theme_color": "#191919",
"icons": [{"src": "/static/icon-192.png", "sizes": "192x192", "type": "image/png"}],
}
# ═══════════ API aliases (v4.0.1) ═══════════
@app.get("/api/pages")
async def api_pages_alias(request: Request):
"""Alias /api/pages → /board/api/pages for API path consistency."""
from fastapi.responses import RedirectResponse
qs = str(request.url.query)
target = f"/board/api/pages{'?' + qs if qs else ''}"
return RedirectResponse(url=target, status_code=307)
@app.post("/api/pages")
async def api_pages_post_alias(request: Request):
"""Alias POST /api/pages → /board/api/pages for API path consistency."""
from fastapi.responses import RedirectResponse
return RedirectResponse(url="/board/api/pages", status_code=307)
# ═══════════ Styled 404 handler ═══════════
NOT_FOUND_HTML = """<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>404 — FlowDeck</title>
<style>
:root{--bg:#191919;--text:#e0e0e0;--text-dim:#999;--accent:#2383E2}
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);display:flex;align-items:center;justify-content:center;min-height:100vh;text-align:center}
.box h1{font-size:6rem;font-weight:800;opacity:.08;line-height:1}
.box p{font-size:18px;color:var(--text-dim);margin:8px 0 24px}
.box a{color:var(--accent);text-decoration:none;font-size:14px}
.box a:hover{text-decoration:underline}
</style>
</head>
<body>
<div class="box">
<h1>404</h1>
<p>This page doesn't exist or has been moved.</p>
<a href="/">← Back to FlowDeck</a>
</div>
</body>
</html>"""
@app.exception_handler(404)
async def not_found_handler(request: Request, exc):
"""Styled 404 page matching the FlowDeck dark theme."""
from fastapi.responses import HTMLResponse
# API routes should get JSON, not HTML
if request.url.path.startswith("/api/") or request.url.path.startswith("/board/api/"):
from fastapi.responses import JSONResponse
return JSONResponse({"detail": "Not found"}, status_code=404)
return HTMLResponse(NOT_FOUND_HTML, status_code=404)