# /opt/docker/dev/service_finder/backend/app/api/v1/endpoints/auth.py from fastapi import APIRouter, Depends, HTTPException, status, Request, Form, Response from fastapi.security import OAuth2PasswordRequestForm from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select from app.db.session import get_db from app.services.auth_service import AuthService from app.core.security import create_tokens, DEFAULT_RANK_MAP from app.core.config import settings from app.services.config_service import config from app.schemas.auth import UserLiteRegister, Token, UserKYCComplete from app.api.deps import get_current_user from app.models.identity import User # JAVÍTVA: Új központi modell from app.core.translation_helper import t # Translation helper from pydantic import BaseModel, Field, EmailStr router = APIRouter() @router.post("/register", status_code=status.HTTP_201_CREATED) async def register(user_in: UserLiteRegister, db: AsyncSession = Depends(get_db)): """ Regisztráció (Lite fázis) - új felhasználó létrehozása. """ user = await AuthService.register_lite(db, user_in) return { "status": "success", "message": t("AUTH.REGISTRATION_SUCCESS"), "user_id": user.id, "email": user.email } @router.post("/login", response_model=Token) async def login( response: Response, db: AsyncSession = Depends(get_db), form_data: OAuth2PasswordRequestForm = Depends(), remember_me: bool = Form(False) ): """ Bejelentkezés remember_me opcióval. A remember_me paramétert explicit Form mezőként kell elküldeni, mivel az OAuth2PasswordRequestForm nem támogatja alapból. """ user = await AuthService.authenticate(db, form_data.username, form_data.password) if not user: raise HTTPException(status_code=401, detail=t("AUTH.INVALID_CREDENTIALS")) ranks = await settings.get_db_setting(db, "rbac_rank_matrix", default=DEFAULT_RANK_MAP) role_name = user.role.value if hasattr(user.role, 'value') else str(user.role) role_key = role_name.upper() # A DEFAULT_RANK_MAP nagybetűs kulcsokat vár token_data = { "sub": str(user.id), "role": role_name, "rank": ranks.get(role_key, 10), "scope_level": user.scope_level or "individual", "scope_id": str(user.scope_id) if user.scope_id else str(user.id) } access, refresh = create_tokens(data=token_data, remember_me=remember_me) # Kinyerjük a beállításokból, hogy meddig él a refresh token (itt is, vagy a create_tokens is ezt csinálja) # A SSoT szerint auth_remember_me_days = 30 if remember_me: max_age_days = await config.get_setting(db, "auth_remember_me_days", default=30) else: max_age_days = await config.get_setting(db, "auth_refresh_default_days", default=1) max_age_sec = int(max_age_days) * 24 * 60 * 60 response.set_cookie( key="refresh_token", value=refresh, httponly=True, secure=True, # Use Secure samesite="lax", max_age=max_age_sec ) return {"access_token": access, "refresh_token": refresh, "token_type": "bearer", "is_active": user.is_active} class VerifyEmailRequest(BaseModel): token: str = Field(..., description="Email verification token (UUID)") @router.post("/verify-email") async def verify_email(request: VerifyEmailRequest, db: AsyncSession = Depends(get_db)): """ Email megerősítés token alapján. """ success = await AuthService.verify_email(db, request.token) if not success: raise HTTPException(status_code=400, detail=t("AUTH.INVALID_OR_EXPIRED_TOKEN")) return {"status": "success", "message": t("AUTH.EMAIL_VERIFICATION_SUCCESS")} class ForgotPasswordRequest(BaseModel): email: EmailStr = Field(..., description="Email cím a jelszó visszaállításhoz") @router.post("/forgot-password") async def forgot_password(request: ForgotPasswordRequest, db: AsyncSession = Depends(get_db)): """ Elfelejtett jelszó folyamat indítása. Mindig sikeres választ ad, hogy megelőzzük az email enumerációt. """ result = await AuthService.initiate_password_reset(db, request.email) # Mindig ugyanazt a választ adjuk, függetlenül attól, hogy létezik-e a felhasználó return { "status": "success", "message": "Ha ez az email cím regisztrálva van, akkor elküldtünk egy jelszó-visszaállítási linket." } class ResetPasswordRequest(BaseModel): email: EmailStr = Field(..., description="Email cím") token: str = Field(..., description="Jelszó visszaállítási token") new_password: str = Field(..., description="Új jelszó") @router.post("/reset-password") async def reset_password(request: ResetPasswordRequest, db: AsyncSession = Depends(get_db)): """ Jelszó visszaállítása token alapján. """ success = await AuthService.reset_password(db, request.email, request.token, request.new_password) if not success: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Érvénytelen token, lejárt token vagy nem létező felhasználó." ) return {"status": "success", "message": "Jelszó sikeresen megváltoztatva."} @router.post("/complete-kyc") async def complete_kyc(kyc_in: UserKYCComplete, db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user)): user = await AuthService.complete_kyc(db, current_user.id, kyc_in) if not user: raise HTTPException(status_code=404, detail="User nem található.") return {"status": "success", "message": "Fiók aktiválva."} @router.get("/me") async def get_current_user_profile(current_user: User = Depends(get_current_user)): """ Return current user profile (alias for /users/me). """ from app.schemas.user import UserResponse return UserResponse.model_validate(current_user)