Files
AutonetSellCar/backend/app/api/verification.py
AutonetSellCar Deploy 1f0dcb1ddb Initial commit: AutonetSellCar platform with deployment system
- Frontend: Next.js 14 with TypeScript
- Backend: FastAPI with SQLAlchemy
- Agent: Carmodoo sync agent
- Deployment: Docker Compose based staging/production setup
- Scripts: Automated deployment with rollback support

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 13:24:39 +09:00

232 lines
6.7 KiB
Python

"""
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)