from fastapi import APIRouter, Depends, Form, HTTPException, Request, status from fastapi.responses import HTMLResponse, RedirectResponse, Response from sqlalchemy.ext.asyncio import AsyncSession from app.core.config import settings from app.core.database import get_db from app.crud import user as user_crud from app.deps import get_current_web_user from app.models.user import User from app.services import ldap as ldap_service from app.services.auth import issue_token_pair from app.web.templates import templates router = APIRouter(include_in_schema=False) def _set_auth_cookie(response: Response, access_token: str) -> None: response.set_cookie( key=settings.cookie_name, value=access_token, httponly=True, secure=settings.cookie_secure, samesite="lax", max_age=settings.access_token_expire_minutes * 60, path="/", ) @router.get("/", response_class=HTMLResponse) async def dashboard( request: Request, user: User = Depends(get_current_web_user), ): return templates.TemplateResponse(request, "dashboard.html", {"user": user}) @router.get("/login", response_class=HTMLResponse) async def login_page(request: Request): return templates.TemplateResponse( request, "login.html", {"ldap_enabled": settings.ldap_enabled} ) @router.post("/login") async def login_submit( request: Request, email: str = Form(...), password: str = Form(...), db: AsyncSession = Depends(get_db), ): user = await user_crud.authenticate(db, email, password) if user is None: # Re-render the form with an error (HTMX swaps the form partial). return templates.TemplateResponse( request, "login.html", { "error": "Incorrect email or password", "email": email, "ldap_enabled": settings.ldap_enabled, }, status_code=status.HTTP_401_UNAUTHORIZED, ) access, _ = await issue_token_pair(db, user) response = RedirectResponse(url="/", status_code=status.HTTP_303_SEE_OTHER) _set_auth_cookie(response, access) return response @router.post("/login/ldap") async def login_ldap_submit( request: Request, username: str = Form(...), password: str = Form(...), db: AsyncSession = Depends(get_db), ): if not settings.ldap_enabled: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) user = await ldap_service.login(db, username, password) if user is None: return templates.TemplateResponse( request, "login.html", { "error": "LDAP sign-in failed", "username": username, "ldap_enabled": True, }, status_code=status.HTTP_401_UNAUTHORIZED, ) access, _ = await issue_token_pair(db, user) response = RedirectResponse(url="/", status_code=status.HTTP_303_SEE_OTHER) _set_auth_cookie(response, access) return response @router.post("/logout") async def logout(request: Request): response = RedirectResponse(url="/login", status_code=status.HTTP_303_SEE_OTHER) response.delete_cookie(settings.cookie_name, path="/") return response