Files
LinedanceAfspiller/linedance-api/app/routers/auth.py
2026-04-12 11:34:09 +02:00

152 lines
4.9 KiB
Python

"""
auth.py — Register, verify, login, profil.
"""
from datetime import datetime, timezone
from fastapi import APIRouter, Depends, HTTPException, BackgroundTasks
from fastapi.security import OAuth2PasswordRequestForm
from fastapi.responses import HTMLResponse
from sqlalchemy.orm import Session
from pydantic import BaseModel, EmailStr
from app.core.database import get_db
from app.core.security import hash_password, verify_password, create_access_token, get_current_user
from app.core.mail import generate_verify_token, send_verification_email
from app.models import User
router = APIRouter(prefix="/auth", tags=["auth"])
# ── Schemas ───────────────────────────────────────────────────────────────────
class UserCreate(BaseModel):
username: str
email: EmailStr
full_name: str = ""
password: str
class UserOut(BaseModel):
id: str
username: str
email: str
full_name: str
is_verified: bool
created_at: datetime
class Config:
from_attributes = True
class Token(BaseModel):
access_token: str
token_type: str = "bearer"
user: UserOut
# ── Endpoints ─────────────────────────────────────────────────────────────────
@router.post("/register", response_model=dict, status_code=201)
async def register(
data: UserCreate,
background_tasks: BackgroundTasks,
db: Session = Depends(get_db)
):
# Tjek om brugernavn eller email allerede er i brug
if db.query(User).filter(User.username == data.username).first():
raise HTTPException(400, "Brugernavnet er allerede i brug")
if db.query(User).filter(User.email == data.email).first():
raise HTTPException(400, "E-mailadressen er allerede registreret")
token = generate_verify_token()
user = User(
username=data.username,
email=data.email,
full_name=data.full_name,
password_hash=hash_password(data.password),
is_verified=False,
verify_token=token,
)
db.add(user)
db.commit()
# Send verificerings-mail i baggrunden
background_tasks.add_task(
send_verification_email, data.email, data.username, token
)
return {
"message": f"Konto oprettet. Tjek din e-mail ({data.email}) for at bekræfte.",
"email": data.email,
}
@router.get("/verify/{token}", response_class=HTMLResponse)
def verify_email(token: str, db: Session = Depends(get_db)):
user = db.query(User).filter(User.verify_token == token).first()
if not user:
return HTMLResponse("""
<html><body style="font-family:sans-serif;text-align:center;padding:60px">
<h2>❌ Ugyldigt eller udløbet link</h2>
<p>Prøv at registrere dig igen.</p>
</body></html>
""", status_code=400)
user.is_verified = True
user.verify_token = None
db.commit()
return HTMLResponse("""
<html><body style="font-family:sans-serif;text-align:center;padding:60px;
background:#1a1d23;color:#e0e4f0">
<h2 style="color:#e8a020">✓ E-mail bekræftet!</h2>
<p>Din konto er nu aktiv. Du kan logge ind i LineDance Player.</p>
<p style="color:#5a6070;font-size:14px">Du kan lukke dette vindue.</p>
</body></html>
""")
@router.post("/login", response_model=Token)
def login(
form: OAuth2PasswordRequestForm = Depends(),
db: Session = Depends(get_db)
):
user = db.query(User).filter(
(User.username == form.username) | (User.email == form.username)
).first()
if not user or not verify_password(form.password, user.password_hash):
raise HTTPException(401, "Forkert brugernavn eller kodeord")
if not user.is_verified:
raise HTTPException(403, "E-mailadressen er ikke bekræftet endnu. Tjek din indbakke.")
token = create_access_token({"sub": user.id})
return Token(
access_token=token,
user=UserOut.model_validate(user)
)
@router.get("/me", response_model=UserOut)
def me(current_user: User = Depends(get_current_user)):
return current_user
@router.post("/resend-verification")
async def resend_verification(
email: str,
background_tasks: BackgroundTasks,
db: Session = Depends(get_db)
):
user = db.query(User).filter(User.email == email).first()
if not user or user.is_verified:
# Svar altid OK — afslør ikke om email eksisterer
return {"message": "Hvis e-mailen er registreret, sendes et nyt link."}
token = generate_verify_token()
user.verify_token = token
db.commit()
background_tasks.add_task(
send_verification_email, user.email, user.username, token
)
return {"message": "Nyt verificerings-link er sendt."}