""" Verification API Endpoints Handles email and phone verification for users """ from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session from pydantic import BaseModel, EmailStr from typing import Optional from ..database import get_db from ..models import User from ..services import verification_service from .auth import get_current_user, get_current_user_optional router = APIRouter(prefix="/verification", tags=["verification"]) # Request/Response schemas class SendEmailCodeRequest(BaseModel): email: EmailStr language: str = "en" class SendPhoneCodeRequest(BaseModel): phone: str language: str = "en" class VerifyCodeRequest(BaseModel): code: str email: Optional[str] = None phone: Optional[str] = None class VerificationResponse(BaseModel): success: bool message: str class VerificationStatusResponse(BaseModel): email_verified: bool phone_verified: bool email: Optional[str] = None phone: Optional[str] = None # Email Verification Endpoints @router.post("/email/send", response_model=VerificationResponse) async def send_email_code( request: SendEmailCodeRequest, db: Session = Depends(get_db), current_user: User = Depends(get_current_user_optional) ): """Send email verification code""" user_id = current_user.id if current_user else None # If user is logged in, only allow sending to their email if current_user and current_user.email != request.email: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="You can only verify your own email address" ) success, message = await verification_service.send_email_verification( db=db, email=request.email, user_id=user_id, language=request.language ) if not success: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=message) return VerificationResponse(success=True, message=message) @router.post("/email/verify", response_model=VerificationResponse) async def verify_email_code( request: VerifyCodeRequest, db: Session = Depends(get_db), current_user: User = Depends(get_current_user_optional) ): """Verify email code""" email = request.email if current_user: email = current_user.email if not email: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Email is required" ) success, message = verification_service.verify_code( db=db, code=request.code, code_type="email", email=email ) if not success: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=message) # If user is logged in, mark their email as verified if current_user: verification_service.mark_email_verified(db, current_user) return VerificationResponse(success=True, message=message) # Phone Verification Endpoints @router.post("/phone/send", response_model=VerificationResponse) async def send_phone_code( request: SendPhoneCodeRequest, db: Session = Depends(get_db), current_user: User = Depends(get_current_user) # Requires login ): """Send phone verification code (requires login)""" success, message = await verification_service.send_sms_verification( db=db, phone=request.phone, user_id=current_user.id, language=request.language ) if not success: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=message) return VerificationResponse(success=True, message=message) @router.post("/phone/verify", response_model=VerificationResponse) async def verify_phone_code( request: VerifyCodeRequest, db: Session = Depends(get_db), current_user: User = Depends(get_current_user) # Requires login ): """Verify phone code (requires login)""" if not request.phone: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Phone number is required" ) # Normalize phone number phone = request.phone.strip().replace(" ", "").replace("-", "") if not phone.startswith("+"): if phone.startswith("9") and len(phone) == 8: phone = "+976" + phone success, message = verification_service.verify_code( db=db, code=request.code, code_type="phone", phone=phone ) if not success: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=message) # Mark phone as verified verification_service.mark_phone_verified(db, current_user, phone) return VerificationResponse(success=True, message=message) # Status Endpoint @router.get("/status", response_model=VerificationStatusResponse) async def get_verification_status( current_user: User = Depends(get_current_user), ): """Get current user's verification status""" return VerificationStatusResponse( email_verified=current_user.email_verified or False, phone_verified=current_user.phone_verified or False, email=current_user.email, phone=current_user.phone ) # Pre-registration email verification (for signup flow) @router.post("/email/send-preregister", response_model=VerificationResponse) async def send_preregister_email_code( request: SendEmailCodeRequest, db: Session = Depends(get_db) ): """Send email verification code for new registration (no login required)""" # Check if email is already registered existing = db.query(User).filter(User.email == request.email).first() if existing: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="This email is already registered" ) success, message = await verification_service.send_email_verification( db=db, email=request.email, user_id=None, language=request.language ) if not success: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=message) return VerificationResponse(success=True, message=message) @router.post("/email/verify-preregister", response_model=VerificationResponse) async def verify_preregister_email_code( request: VerifyCodeRequest, db: Session = Depends(get_db) ): """Verify email code for new registration (no login required)""" if not request.email: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Email is required" ) success, message = verification_service.verify_code( db=db, code=request.code, code_type="email", email=request.email ) if not success: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=message) return VerificationResponse(success=True, message=message)