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
+21
View File
@@ -85,6 +85,27 @@ async function handleLogin(e){e.preventDefault();const email=document.getElement
</html>"""
@router.get("/register")
async def register_page(request: Request):
"""Show the registration page (local login page with register tab active)."""
return HTMLResponse(LOCAL_LOGIN_HTML.replace(
'class="tab active" onclick="switchTab(\'login\')"',
'class="tab" onclick="switchTab(\'login\')"'
).replace(
'class="tab" onclick="switchTab(\'register\')"',
'class="tab active" onclick="switchTab(\'register\')"'
).replace(
'let mode=\'login\';',
'let mode=\'register\';'
).replace(
'id="name-group" style="display:none"',
'id="name-group" style="display:block"'
).replace(
'id="submit-btn">Login<',
'id="submit-btn">Register<'
), status_code=200)
@router.get("/login")
async def login(request: Request, provider: str = Query("gitea")):
"""Redirect to OAuth2 authorize page or show local login page."""
+27 -6
View File
@@ -404,11 +404,29 @@ async def dashboard(
search: str = Query(default=""),
show_archived: bool = Query(default=False),
):
auth = _get_user_or_redirect(request)
if isinstance(auth, RedirectResponse):
return auth
# Check if user has Gitea connected — if not, show local workspace
user_id = auth.get("id") if isinstance(auth, dict) else 1
"""Smart root route: landing for visitors, local workspace for new users, dashboard for Gitea users."""
user = SessionManager.decode_session(request.cookies.get("flowdeck_session", ""))
# ── Not authenticated → show landing page ──
if not user:
# Allow through if DB is empty (fresh install)
try:
with get_conn() as conn:
count = conn.execute("SELECT COUNT(*) FROM users").fetchone()[0]
if count == 0:
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader("app/templates"))
template = env.get_template("landing.html")
return template.render()
except Exception:
pass
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader("app/templates"))
template = env.get_template("landing.html")
return template.render()
# ── Authenticated ──
user_id = user.get("id", 1)
has_gitea = False
try:
with get_conn() as conn:
@@ -419,8 +437,9 @@ async def dashboard(
has_gitea = bool(tok)
except Exception:
pass
if not has_gitea:
# Check if user has any workspace — if not, send to workspaces
# Check if user has any workspace
try:
with get_conn() as conn:
ws_count = conn.execute(
@@ -431,6 +450,8 @@ async def dashboard(
except Exception:
pass
return RedirectResponse("/local-workspace", status_code=302)
# ── Gitea user → full dashboard ──
try:
repos = await gitea.get_user_repos(page=1, limit=50)
if search: