Igen
This commit is contained in:
@@ -1,39 +1,151 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
"""
|
||||
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
|
||||
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
|
||||
from app.schemas import UserCreate, UserOut, Token
|
||||
|
||||
router = APIRouter(prefix="/auth", tags=["auth"])
|
||||
|
||||
|
||||
@router.post("/register", response_model=UserOut, status_code=201)
|
||||
def register(data: UserCreate, db: Session = Depends(get_db)):
|
||||
# ── 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-mailen er allerede i brug")
|
||||
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()
|
||||
db.refresh(user)
|
||||
return user
|
||||
|
||||
# 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).first()
|
||||
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(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Forkert brugernavn eller kodeord",
|
||||
)
|
||||
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 {"access_token": token}
|
||||
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."}
|
||||
|
||||
Reference in New Issue
Block a user