This commit fixes 5 critical bugs found during code review: Bug #1 (CRITICAL): Missing API endpoints for election filtering - Added GET /api/elections/upcoming endpoint - Added GET /api/elections/completed endpoint - Both properly filter elections by date Bug #2 (HIGH): Auth context has_voted state inconsistency - Backend schemas now include has_voted in LoginResponse and RegisterResponse - Auth routes return actual has_voted value from database - Frontend context uses server response instead of hardcoding false - Frontend API client properly typed with has_voted field Bug #3 (HIGH): Transaction safety in vote submission - Simplified error handling in vote submission endpoints - Now only calls mark_as_voted() once at the end - Vote response includes voter_marked_voted flag to indicate success - Ensures consistency even if blockchain submission fails Bug #4 (MEDIUM): Vote status endpoint - Verified endpoint already exists at GET /api/votes/status - Tests confirm proper functionality Bug #5 (MEDIUM): Response format inconsistency - Previously fixed in commit e10a882 - Frontend now handles both array and wrapped object formats Added comprehensive test coverage: - 20+ backend API tests (tests/test_api_fixes.py) - 6+ auth context tests (frontend/__tests__/auth-context.test.tsx) - 8+ elections API tests (frontend/__tests__/elections-api.test.ts) - 10+ vote submission tests (frontend/__tests__/vote-submission.test.ts) All fixes ensure frontend and backend communicate consistently. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
87 lines
2.6 KiB
Python
87 lines
2.6 KiB
Python
"""
|
|
Routes pour l'authentification et les électeurs.
|
|
"""
|
|
|
|
from fastapi import APIRouter, HTTPException, status, Depends
|
|
from sqlalchemy.orm import Session
|
|
from .. import schemas, services
|
|
from ..auth import create_access_token
|
|
from ..dependencies import get_db, get_current_voter
|
|
from ..models import Voter
|
|
from datetime import timedelta
|
|
|
|
router = APIRouter(prefix="/api/auth", tags=["auth"])
|
|
|
|
|
|
@router.post("/register", response_model=schemas.RegisterResponse)
|
|
def register(voter_data: schemas.VoterRegister, db: Session = Depends(get_db)):
|
|
"""Enregistrer un nouvel électeur"""
|
|
|
|
# Vérifier que l'email n'existe pas déjà
|
|
existing_voter = services.VoterService.get_voter_by_email(db, voter_data.email)
|
|
if existing_voter:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="Email already registered"
|
|
)
|
|
|
|
# Créer le nouvel électeur
|
|
voter = services.VoterService.create_voter(db, voter_data)
|
|
|
|
# Créer le token JWT
|
|
access_token_expires = timedelta(minutes=30)
|
|
access_token = create_access_token(
|
|
data={"voter_id": voter.id},
|
|
expires_delta=access_token_expires
|
|
)
|
|
|
|
return schemas.RegisterResponse(
|
|
access_token=access_token,
|
|
expires_in=30 * 60,
|
|
id=voter.id,
|
|
email=voter.email,
|
|
first_name=voter.first_name,
|
|
last_name=voter.last_name,
|
|
has_voted=voter.has_voted
|
|
)
|
|
|
|
|
|
@router.post("/login", response_model=schemas.LoginResponse)
|
|
def login(credentials: schemas.VoterLogin, db: Session = Depends(get_db)):
|
|
"""Authentifier un électeur et retourner un token"""
|
|
|
|
voter = services.VoterService.verify_voter_credentials(
|
|
db,
|
|
credentials.email,
|
|
credentials.password
|
|
)
|
|
|
|
if not voter:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
detail="Invalid email or password"
|
|
)
|
|
|
|
# Créer le token JWT
|
|
access_token_expires = timedelta(minutes=30)
|
|
access_token = create_access_token(
|
|
data={"voter_id": voter.id},
|
|
expires_delta=access_token_expires
|
|
)
|
|
|
|
return schemas.LoginResponse(
|
|
access_token=access_token,
|
|
expires_in=30 * 60,
|
|
id=voter.id,
|
|
email=voter.email,
|
|
first_name=voter.first_name,
|
|
last_name=voter.last_name,
|
|
has_voted=voter.has_voted
|
|
)
|
|
|
|
|
|
@router.get("/profile", response_model=schemas.VoterProfile)
|
|
def get_profile(current_voter: Voter = Depends(get_current_voter)):
|
|
"""Récupérer le profil de l'électeur actuel"""
|
|
return current_voter
|