77 lines
2.6 KiB
Python

from datetime import datetime, timezone
from fastapi import APIRouter, Request, Form, HTTPException
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.templating import Jinja2Templates
from sqlalchemy import select
from app.models.base import async_session
from app.models.user import User
from app.auth import hash_password, verify_password, create_session
router = APIRouter()
templates = Jinja2Templates(directory="app/templates")
@router.get("/login", response_class=HTMLResponse)
async def login_page(request: Request):
return templates.TemplateResponse(request, "login.html")
@router.post("/login")
async def login(request: Request, username: str = Form(), password: str = Form()):
async with async_session() as session:
result = await session.execute(select(User).where(User.username == username))
user = result.scalar_one_or_none()
if not user or not verify_password(password, user.password_hash):
return templates.TemplateResponse(
request, "login.html",
{"error": "Invalid username or password"},
)
token = await create_session(user.id)
resp = RedirectResponse(url="/dashboard", status_code=303)
resp.set_cookie(key="session_token", value=token, httponly=True, max_age=86400 * 30)
return resp
@router.get("/register", response_class=HTMLResponse)
async def register_page(request: Request):
return templates.TemplateResponse(request, "register.html")
@router.post("/register")
async def register(
request: Request,
username: str = Form(),
password: str = Form(),
display_name: str = Form(default=""),
):
async with async_session() as session:
result = await session.execute(select(User).where(User.username == username))
if result.scalar_one_or_none():
return templates.TemplateResponse(
request, "register.html",
{"error": "Username already taken"},
)
user = User(
username=username,
password_hash=hash_password(password),
display_name=display_name or username,
created_at=datetime.now(timezone.utc).isoformat(),
)
session.add(user)
await session.commit()
await session.refresh(user)
token = await create_session(user.id)
resp = RedirectResponse(url="/dashboard", status_code=303)
resp.set_cookie(key="session_token", value=token, httponly=True, max_age=86400 * 30)
return resp
@router.get("/logout")
async def logout():
resp = RedirectResponse(url="/login", status_code=303)
resp.delete_cookie("session_token")
return resp