diff --git a/api/v1/auth.py b/api/v1/auth.py index c812523..d1d58ce 100644 --- a/api/v1/auth.py +++ b/api/v1/auth.py @@ -1,7 +1,7 @@ from datetime import datetime, timedelta from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText -from fastapi import APIRouter, Depends, Form, HTTPException, status, Body +from fastapi import APIRouter, HTTPException, status, Body from fastapi.responses import JSONResponse from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from sqlalchemy import update, select @@ -10,7 +10,6 @@ from models.schemas import Token, UserCreate, UserResponse from config.database import get_db from models.db import users_table from config.settings import settings -from sqlalchemy.ext.asyncio import AsyncSession from jose import jwt, JWTError from smtplib import SMTP from services.user_service import UserService @@ -21,32 +20,33 @@ router = APIRouter() oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/token") @router.post("/signup", status_code=201, summary="User Signup") -async def signup(user: UserCreate, db=Depends(get_db)): - existing_user = await AuthService.get_user_by_email(user.email, db) - if existing_user: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="Email already registered." - ) - return await UserService.create_user(user, db) +async def signup(user: UserCreate): + async with get_db() as db: + existing_user = await AuthService.get_user_by_email(user.email, db) + if existing_user: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="Email already registered." + ) + return await UserService.create_user(user, db) @router.post("/token", response_model=Token, summary="Login and get access token") -async def login_for_access_token( form_data: OAuth2PasswordRequestForm = Depends(), db=Depends(get_db)): - user = await AuthService.authenticate_user(form_data.username, form_data.password, db) - logger.info(f"User {form_data.username} logged in") - if not user: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Incorrect email or password", - headers={"WWW-Authenticate": "Bearer"}, - ) - access_token = AuthService.create_access_token(data={"sub": user["email"]}) - return {"access_token": access_token, "token_type": "bearer"} +async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Body(...)): + async with get_db() as db: + user = await AuthService.authenticate_user(form_data.username, form_data.password, db) + logger.info(f"User {form_data.username} logged in") + if not user: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Incorrect email or password", + headers={"WWW-Authenticate": "Bearer"}, + ) + access_token = AuthService.create_access_token(data={"sub": user["email"]}) + return {"access_token": access_token, "token_type": "bearer"} @router.post("/isvalid-token", summary="Verify token validity") async def verify_token(token: str = Body(...)): try: - # Décoder le token pour vérifier sa validité payload = jwt.decode(token, settings.secret_key, algorithms=[settings.algorithm]) return {"valid": True, "message": "Token is valid", "payload": payload} except jwt.ExpiredSignatureError: @@ -61,88 +61,86 @@ async def verify_token(token: str = Body(...)): ) @router.get("/me", summary="Get current user") -async def read_users_me(token:str = Depends(oauth2_scheme) , db=Depends(get_db)): - return await AuthService.get_current_user(token, db) +async def read_users_me(token: str = Body(...)): + async with get_db() as db: + return await AuthService.get_current_user(token, db) @router.post("/reset-password") -async def reset_password(token: str = Body(...), new_password: str = Body(...), db: AsyncSession = Depends(get_db)): - try: - payload = jwt.decode(token, settings.secret_key, algorithms=[settings.algorithm]) - email = payload.get("sub") - if email is None: - raise HTTPException(status_code=400, detail="Invalid token") - except JWTError: - raise HTTPException(status_code=400, detail="Invalid or expired token") +async def reset_password(token: str = Body(...), new_password: str = Body(...)): + async with get_db() as db: + try: + payload = jwt.decode(token, settings.secret_key, algorithms=[settings.algorithm]) + email = payload.get("sub") + if email is None: + raise HTTPException(status_code=400, detail="Invalid token") + except JWTError: + raise HTTPException(status_code=400, detail="Invalid or expired token") - # Hash the new password - hashed_password = pwd_context.hash(new_password) + hashed_password = pwd_context.hash(new_password) - # Update the user's password - query = ( - update(users_table) - .where(users_table.c.email == email) - .values(hashed_password=hashed_password) - .execution_options(synchronize_session="fetch") - ) - await db.execute(query) - await db.commit() + query = ( + update(users_table) + .where(users_table.c.email == email) + .values(hashed_password=hashed_password) + .execution_options(synchronize_session="fetch") + ) + await db.execute(query) - return JSONResponse(content={"message": "Password updated successfully."}) + return JSONResponse(content={"message": "Password updated successfully."}) @router.post("/password-reset-request") -async def password_reset_request(email: str, db: AsyncSession = Depends(get_db)): - query = select(users_table).where(users_table.c.email == email) - result = await db.execute(query) - user = result.fetchone() - if not user: - raise HTTPException(status_code=404, detail="User not found") +async def password_reset_request(email: str = Body(...)): + async with get_db() as db: + query = select(users_table).where(users_table.c.email == email) + result = await db.execute(query) + user = result.fetchone() + if not user: + raise HTTPException(status_code=404, detail="User not found") - # Générer un token JWT - reset_token = jwt.encode( - {"sub": email, "exp": datetime.utcnow() + timedelta(hours=1)}, - settings.secret_key, - algorithm=settings.algorithm, - ) + reset_token = jwt.encode( + {"sub": email, "exp": datetime.utcnow() + timedelta(hours=1)}, + settings.secret_key, + algorithm=settings.algorithm, + ) - reset_link = f"{settings.resetpass_url}/?token={reset_token}" + reset_link = f"{settings.resetpass_url}/?token={reset_token}" - # Envoyer le lien par email - try: - subject = "mot de passe perdu" - sender_email = settings.email_username - receiver_email = email - logger.info(f"sender {settings.email_username} receiver {email}") + try: + subject = "mot de passe perdu" + sender_email = settings.email_username + receiver_email = email + logger.info(f"sender {settings.email_username} receiver {email}") - message = MIMEMultipart("alternative") - message["Subject"] = subject - message["From"] = sender_email - message["To"] = receiver_email + message = MIMEMultipart("alternative") + message["Subject"] = subject + message["From"] = sender_email + message["To"] = receiver_email - text = f"You requested a password reset. Click the link below to reset your password:\n{reset_link}" - html = f""" - - -

You requested a password reset.
- Click the link below to reset your password:
- Redefinir mon mot de passe -

- - - """ + text = f"You requested a password reset. Click the link below to reset your password:\n{reset_link}" + html = f""" + + +

You requested a password reset.
+ Click the link below to reset your password:
+ Redefinir mon mot de passe +

+ + + """ - part1 = MIMEText(text, "plain") - part2 = MIMEText(html, "html") - message.attach(part1) - message.attach(part2) + part1 = MIMEText(text, "plain") + part2 = MIMEText(html, "html") + message.attach(part1) + message.attach(part2) - with SMTP(settings.email_host, settings.email_port) as server: - server.starttls() - server.login(settings.email_username, settings.email_password) - server.sendmail(sender_email, receiver_email, message.as_string()) + with SMTP(settings.email_host, settings.email_port) as server: + server.starttls() + server.login(settings.email_username, settings.email_password) + server.sendmail(sender_email, receiver_email, message.as_string()) - logger.info(f"Password reset email sent to {email}") - return JSONResponse(content={"message": "Password reset link sent via email."}) + logger.info(f"Password reset email sent to {email}") + return JSONResponse(content={"message": "Password reset link sent via email."}) - except Exception as e: - logger.error(f"Failed to send password reset email to {email}: {str(e)}") - raise HTTPException(status_code=500, detail=f"Failed to send password reset email. sender {sender_email} receiver {receiver_email}") + except Exception as e: + logger.error(f"Failed to send password reset email to {email}: {str(e)}") + raise HTTPException(status_code=500, detail=f"Failed to send password reset email. sender {sender_email} receiver {receiver_email}") \ No newline at end of file diff --git a/api/v1/messages.py b/api/v1/messages.py index 269c5de..03572d7 100644 --- a/api/v1/messages.py +++ b/api/v1/messages.py @@ -6,5 +6,6 @@ from config.database import get_db router = APIRouter() @router.post("/", status_code=201) -async def report_issue(issue: TechnicalIssue, db=Depends(get_db)): - return await MessageService.create_issue(issue, db) \ No newline at end of file +async def report_issue(issue: TechnicalIssue): + async with get_db() as db: + return await MessageService.create_issue(issue, db) \ No newline at end of file diff --git a/api/v1/need_requests.py b/api/v1/need_requests.py index fffc1a1..72e2476 100644 --- a/api/v1/need_requests.py +++ b/api/v1/need_requests.py @@ -11,62 +11,58 @@ router = APIRouter() oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/token") @router.post("/", status_code=status.HTTP_201_CREATED) -async def request_need(need: NeedRequestCreate, db=Depends(get_db)): - - return await NeedRequestService.create_need(need, db) +async def request_need(need: NeedRequestCreate): + async with get_db() as db: + return await NeedRequestService.create_need(need, db) @router.get("/", status_code=status.HTTP_200_OK) -async def get_all_reports(db=Depends(get_db)): - return await NeedRequestService.get_all_needs(db) +async def get_all_reports(): + async with get_db() as db: + return await NeedRequestService.get_all_needs(db) @router.get("/{need_id}", status_code=status.HTTP_200_OK) -async def get_need(need_id: int, db=Depends(get_db)): - - need = await NeedRequestService.get_need(need_id, db) - if not need: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Need request not found") - return need - +async def get_need(need_id: int): + async with get_db() as db: + need = await NeedRequestService.get_need(need_id, db) + if not need: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Need request not found") + return need @router.put("/{need_id}", status_code=status.HTTP_200_OK) async def update_need( need_id: int, need_update: NeedRequestUpdate, - token: str = Depends(oauth2_scheme), - db=Depends(get_db), + token: str = Depends(oauth2_scheme) ): + async with get_db() as db: + need = await NeedRequestService.get_need(need_id, db) + if not need: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Need request not found") - need = await NeedRequestService.get_need(need_id, db) - if not need: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Need request not found") - - # V�rifie si l'utilisateur est l'auteur ou un administrateur - if NeedRequestService.verify_requester_or_admin(need_id, token, db): - raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, - detail="You do not have permission to update this need request", - ) - - return await NeedRequestService.update_need(need_id, need_update, db) + # Vérifie si l'utilisateur est l'auteur ou un administrateur + if NeedRequestService.verify_requester_or_admin(need_id, token, db): + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="You do not have permission to update this need request", + ) + return await NeedRequestService.update_need(need_id, need_update, db) @router.delete("/{need_id}", status_code=status.HTTP_200_OK) async def delete_need( need_id: int, - token: str = Depends(oauth2_scheme), - db=Depends(get_db), - + token: str = Depends(oauth2_scheme) ): + async with get_db() as db: + need = await NeedRequestService.get_need(need_id, db) + if not need: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Need request not found") - need = await NeedRequestService.get_need(need_id, db) - if not need: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Need request not found") + # Vérifie si l'utilisateur est l'auteur ou un administrateur + if NeedRequestService.verify_requester_or_admin(need_id, token, db): + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="You do not have permission to delete this need request", + ) - # V�rifie si l'utilisateur est l'auteur ou un administrateur - if NeedRequestService.verify_requester_or_admin(need_id, token, db): - raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, - detail="You do not have permission to delete this need request", - ) - - return await NeedRequestService.delete_need(need_id, db) + return await NeedRequestService.delete_need(need_id, db) \ No newline at end of file diff --git a/api/v1/person_reports.py b/api/v1/person_reports.py index ac17513..bd9dc7a 100644 --- a/api/v1/person_reports.py +++ b/api/v1/person_reports.py @@ -13,31 +13,34 @@ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/token") @router.post("/", status_code=201) async def create_report( - file: Optional[UploadFile] = File(None), # Le champ photo est reçu sous forme de fichier - report: PersonReportCreate = Form(...), # Le champ report est reçu sous forme de chaîne JSON - db: get_db = Depends(), + file: Optional[UploadFile] = File(None), + report: PersonReportCreate = Form(...), token: str = Depends(oauth2_scheme) ): - # Appeler le service pour traiter le rapport - try: - created_report = await PersonReportService.create_report(report, db, token, file) - except Exception as e: - raise HTTPException(status_code=500, detail=f"An error occurred while creating the report: {str(e)}") - + async with get_db() as db: + try: + created_report = await PersonReportService.create_report(report, db, token, file) + except Exception as e: + raise HTTPException(status_code=500, detail=f"An error occurred while creating the report: {str(e)}") + return created_report @router.put("/{report_id}") -async def update_report(report_id: int, report: PersonReportUpdate, db=Depends(get_db)): - return await PersonReportService.update_report(report_id, report, db) +async def update_report(report_id: int, report: PersonReportUpdate): + async with get_db() as db: + return await PersonReportService.update_report(report_id, report, db) @router.get("/{report_id}") -async def get_report(report_id: int, db=Depends(get_db)): - return await PersonReportService.get_report(report_id, db) +async def get_report(report_id: int): + async with get_db() as db: + return await PersonReportService.get_report(report_id, db) @router.get("/", response_model=list[PersonReportResponse]) -async def list_reports(status: Optional[str] = None, db=Depends(get_db)): - return await PersonReportService.list_reports(status, db) +async def list_reports(status: Optional[str] = None): + async with get_db() as db: + return await PersonReportService.list_reports(status, db) @router.delete("/{report_id}", status_code=204) -async def delete_report(report_id: int, db=Depends(get_db), token: str = Depends(oauth2_scheme)): - return await PersonReportService.delete_report(report_id, db, token) \ No newline at end of file +async def delete_report(report_id: int, token: str = Depends(oauth2_scheme)): + async with get_db() as db: + return await PersonReportService.delete_report(report_id, db, token) \ No newline at end of file diff --git a/api/v1/points_of_interest.py b/api/v1/points_of_interest.py index f24672f..001f1d5 100644 --- a/api/v1/points_of_interest.py +++ b/api/v1/points_of_interest.py @@ -8,25 +8,26 @@ router = APIRouter() oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/token") @router.post("/", status_code=201) -async def create_point(point: CreatePointOfInterest, db=Depends(get_db), token: str = Depends(oauth2_scheme)): - return await PointsOfInterestService.create_point_of_interest(point, db, token) - +async def create_point(point: CreatePointOfInterest, token: str = Depends(oauth2_scheme)): + async with get_db() as db: + return await PointsOfInterestService.create_point_of_interest(point, db, token) @router.get("/{point_id}") -async def get_point(point_id: int, db=Depends(get_db)): - return await PointsOfInterestService.get_point_of_interest(point_id, db) - +async def get_point(point_id: int): + async with get_db() as db: + return await PointsOfInterestService.get_point_of_interest(point_id, db) @router.get("/") -async def get_all_points(db=Depends(get_db)): - return await PointsOfInterestService.get_all_points_of_interest(db) - +async def get_all_points(): + async with get_db() as db: + return await PointsOfInterestService.get_all_points_of_interest(db) @router.put("/{point_id}") -async def update_point(point_id: int, point: UpdatePointOfInterest, db=Depends(get_db), token: str = Depends(oauth2_scheme)): - return await PointsOfInterestService.update_point_of_interest(point_id, point, db, token) - +async def update_point(point_id: int, point: UpdatePointOfInterest, token: str = Depends(oauth2_scheme)): + async with get_db() as db: + return await PointsOfInterestService.update_point_of_interest(point_id, point, db, token) @router.delete("/{point_id}") -async def delete_point(point_id: int, db=Depends(get_db), token: str = Depends(oauth2_scheme)): - return await PointsOfInterestService.delete_point_of_interest(point_id, db, token) +async def delete_point(point_id: int, token: str = Depends(oauth2_scheme)): + async with get_db() as db: + return await PointsOfInterestService.delete_point_of_interest(point_id, db, token) \ No newline at end of file diff --git a/api/v1/reports.py b/api/v1/reports.py index eb5b7c3..17d22ec 100644 --- a/api/v1/reports.py +++ b/api/v1/reports.py @@ -10,21 +10,26 @@ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/token") router = APIRouter() @router.post("/", status_code=status.HTTP_201_CREATED) -async def report_user(report: UserReport, db=Depends(get_db)): - return await ReportService.create_report(report, db) +async def report_user(report: UserReport): + async with get_db() as db: + return await ReportService.create_report(report, db) @router.get("/{report_id}", status_code=status.HTTP_200_OK) -async def get_report(report_id: int, db=Depends(get_db), token: str = Depends(oauth2_scheme)): - return await ReportService.get_report_by_id(report_id, db, token) +async def get_report(report_id: int, token: str = Depends(oauth2_scheme)): + async with get_db() as db: + return await ReportService.get_report_by_id(report_id, db, token) @router.get("/", status_code=status.HTTP_200_OK) -async def get_all_reports(db=Depends(get_db), token: str = Depends(oauth2_scheme)): - return await ReportService.get_all_reports(db, token) +async def get_all_reports(token: str = Depends(oauth2_scheme)): + async with get_db() as db: + return await ReportService.get_all_reports(db, token) @router.put("/{report_id}", status_code=status.HTTP_200_OK) -async def update_report(report_id: int, report_update: UserReportUpdate, db=Depends(get_db), token: str = Depends(oauth2_scheme)): - return await ReportService.update_report(report_id, report_update, db, token) +async def update_report(report_id: int, report_update: UserReportUpdate, token: str = Depends(oauth2_scheme)): + async with get_db() as db: + return await ReportService.update_report(report_id, report_update, db, token) @router.delete("/{report_id}", status_code=status.HTTP_200_OK) -async def delete_report(report_id: int, db=Depends(get_db), token: str = Depends(oauth2_scheme)): - return await ReportService.delete_report(report_id, db, token) +async def delete_report(report_id: int, token: str = Depends(oauth2_scheme)): + async with get_db() as db: + return await ReportService.delete_report(report_id, db, token) \ No newline at end of file diff --git a/api/v1/roles.py b/api/v1/roles.py index aa08ce0..0016edd 100644 --- a/api/v1/roles.py +++ b/api/v1/roles.py @@ -9,50 +9,50 @@ from typing import List router = APIRouter() oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/token") - @router.post("/", status_code=201) -async def create_role(name: str, db: AsyncSession = Depends(get_db), token: str = Depends(oauth2_scheme)): +async def create_role(name: str, token: str = Depends(oauth2_scheme)): """ Créer un nouveau rôle avec des permissions associées (réservé aux administrateurs). """ - return await RoleService.create_role(name, db, token) - + async with get_db() as db: + return await RoleService.create_role(name, db, token) @router.get("/{role_id}", response_model=Role) -async def get_role(role_id: int, db: AsyncSession = Depends(get_db)): +async def get_role(role_id: int): """ Récupérer les détails d'un rôle spécifique. """ - return await RoleService.get_role(role_id, db) - + async with get_db() as db: + return await RoleService.get_role(role_id, db) @router.get("/", response_model=List[Role]) -async def get_all_roles(db: AsyncSession = Depends(get_db)): +async def get_all_roles(): """ Récupérer tous les rôles avec leurs permissions associées. """ - return await RoleService.get_all_roles(db) - + async with get_db() as db: + return await RoleService.get_all_roles(db) @router.put("/{role_id}") -async def update_role(role_id: int, role: Role, db: AsyncSession = Depends(get_db), token: str = Depends(oauth2_scheme)): +async def update_role(role_id: int, role: Role, token: str = Depends(oauth2_scheme)): """ Mettre à jour un rôle existant (réservé aux administrateurs). """ - return await RoleService.update_role(role_id, role.dict(), db, token) - + async with get_db() as db: + return await RoleService.update_role(role_id, role.dict(), db, token) @router.delete("/{role_id}") -async def delete_role(role_id: int, db: AsyncSession = Depends(get_db), token: str = Depends(oauth2_scheme)): +async def delete_role(role_id: int, token: str = Depends(oauth2_scheme)): """ Supprimer un rôle (réservé aux administrateurs). """ - return await RoleService.delete_role(role_id, db, token) - + async with get_db() as db: + return await RoleService.delete_role(role_id, db, token) @router.get("/roles/permissions", response_model=List[Permission]) -async def get_all_permissions(db: AsyncSession = Depends(get_db)): +async def get_all_permissions(): """ Récupérer toutes les permissions disponibles. """ - return await RoleService.get_all_permissions(db) + async with get_db() as db: + return await RoleService.get_all_permissions(db) \ No newline at end of file diff --git a/api/v1/shelters.py b/api/v1/shelters.py index fea9436..f32a684 100644 --- a/api/v1/shelters.py +++ b/api/v1/shelters.py @@ -8,25 +8,26 @@ router = APIRouter() oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/token") @router.post("/", status_code=201) -async def create_shelter(shelter: CreateShelter, db=Depends(get_db), token: str = Depends(oauth2_scheme)): - return await ShelterService.create_shelter(shelter, db, token) - +async def create_shelter(shelter: CreateShelter, token: str = Depends(oauth2_scheme)): + async with get_db() as db: + return await ShelterService.create_shelter(shelter, db, token) @router.get("/{shelter_id}") -async def get_shelter(shelter_id: int, db=Depends(get_db)): - return await ShelterService.get_shelter(shelter_id, db) - +async def get_shelter(shelter_id: int): + async with get_db() as db: + return await ShelterService.get_shelter(shelter_id, db) @router.get("/") -async def get_all_shelters(db=Depends(get_db)): - return await ShelterService.get_all_shelters(db) - +async def get_all_shelters(): + async with get_db() as db: + return await ShelterService.get_all_shelters(db) @router.put("/{shelter_id}") -async def update_shelter(shelter_id: int, shelter: UpdateShelter, db=Depends(get_db), token: str = Depends(oauth2_scheme)): - return await ShelterService.update_shelter(shelter_id, shelter, db, token) - +async def update_shelter(shelter_id: int, shelter: UpdateShelter, token: str = Depends(oauth2_scheme)): + async with get_db() as db: + return await ShelterService.update_shelter(shelter_id, shelter, db, token) @router.delete("/{shelter_id}") -async def delete_shelter(shelter_id: int, db=Depends(get_db), token: str = Depends(oauth2_scheme)): - return await ShelterService.delete_shelter(shelter_id, db, token) +async def delete_shelter(shelter_id: int, token: str = Depends(oauth2_scheme)): + async with get_db() as db: + return await ShelterService.delete_shelter(shelter_id, db, token) \ No newline at end of file diff --git a/api/v1/technical_issues.py b/api/v1/technical_issues.py index 9d1417b..c0bc2fa 100644 --- a/api/v1/technical_issues.py +++ b/api/v1/technical_issues.py @@ -9,21 +9,26 @@ router = APIRouter() oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/token") @router.post("/", status_code=201) -async def create_issue(issue: CreateTechnicalIssue, db=Depends(get_db), token: str = Depends(oauth2_scheme)): - return await TechnicalIssueService.create_issue(issue, db, token) +async def create_issue(issue: CreateTechnicalIssue, token: str = Depends(oauth2_scheme)): + async with get_db() as db: + return await TechnicalIssueService.create_issue(issue, db, token) @router.get("/{issue_id}") -async def get_issue(issue_id: int, db=Depends(get_db), token: str = Depends(oauth2_scheme)): - return await TechnicalIssueService.get_issue(issue_id, db, token) +async def get_issue(issue_id: int, token: str = Depends(oauth2_scheme)): + async with get_db() as db: + return await TechnicalIssueService.get_issue(issue_id, db, token) @router.get("/") -async def get_all_issues(db=Depends(get_db), token: str = Depends(oauth2_scheme)): - return await TechnicalIssueService.get_all_issues(db, token) +async def get_all_issues(token: str = Depends(oauth2_scheme)): + async with get_db() as db: + return await TechnicalIssueService.get_all_issues(db, token) @router.put("/{issue_id}") -async def update_issue(issue_id: int, issue_data: UpdateTechnicalIssue, db=Depends(get_db), token: str = Depends(oauth2_scheme)): - return await TechnicalIssueService.update_issue(issue_id, issue_data, db, token) +async def update_issue(issue_id: int, issue_data: UpdateTechnicalIssue, token: str = Depends(oauth2_scheme)): + async with get_db() as db: + return await TechnicalIssueService.update_issue(issue_id, issue_data, db, token) @router.delete("/{issue_id}") -async def delete_issue(issue_id: int, db=Depends(get_db), token: str = Depends(oauth2_scheme)): - return await TechnicalIssueService.delete_issue(issue_id, db, token) +async def delete_issue(issue_id: int, token: str = Depends(oauth2_scheme)): + async with get_db() as db: + return await TechnicalIssueService.delete_issue(issue_id, db, token) \ No newline at end of file diff --git a/api/v1/uploads.py b/api/v1/uploads.py index 2a53b43..db95b2f 100644 --- a/api/v1/uploads.py +++ b/api/v1/uploads.py @@ -10,7 +10,8 @@ router = APIRouter() oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/token") @router.post("/") -async def upload_file(file: UploadFile, db=Depends(get_db), token: str = Depends(oauth2_scheme)): - user = await AuthService.get_current_user(token, db) - logger.info(f"User {user} is uploading a file") - return await UploadService.upload_image_to_s3(file, user["id"]) \ No newline at end of file +async def upload_file(file: UploadFile, token: str = Depends(oauth2_scheme)): + async with get_db() as db: + user = await AuthService.get_current_user(token, db) + logger.info(f"User {user} is uploading a file") + return await UploadService.upload_image_to_s3(file, user["id"]) \ No newline at end of file diff --git a/api/v1/users.py b/api/v1/users.py index bc3ef10..9eab785 100644 --- a/api/v1/users.py +++ b/api/v1/users.py @@ -1,6 +1,5 @@ from fastapi import APIRouter, Depends, HTTPException from fastapi.security import OAuth2PasswordBearer -from sqlalchemy.ext.asyncio import AsyncSession from services.user_service import UserService from models.schemas import UserUpdateRole, UserBlockBan, UserResponse from config.database import get_db @@ -11,29 +10,36 @@ router = APIRouter() oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/token") @router.get("/", response_model=list[UserResponse]) -async def list_users(status: Optional[str] = None, db=Depends(get_db), token: str = Depends(oauth2_scheme)): - return await UserService.list_users(token, status, db) +async def list_users(status: Optional[str] = None, token: str = Depends(oauth2_scheme)): + async with get_db() as db: + return await UserService.list_users(token, status, db) @router.patch("/role", status_code=200) -async def change_role(user_update: UserUpdateRole, db: AsyncSession = Depends(get_db), token: str = Depends(oauth2_scheme)): - return await UserService.change_user_role(user_update, db, token) +async def change_role(user_update: UserUpdateRole, token: str = Depends(oauth2_scheme)): + async with get_db() as db: + return await UserService.change_user_role(user_update, db, token) @router.post("/block", status_code=200) -async def block_user(user_action: UserBlockBan, db: AsyncSession = Depends(get_db), token: str = Depends(oauth2_scheme)): - return await UserService.block_user(user_action, db, token) +async def block_user(user_action: UserBlockBan, token: str = Depends(oauth2_scheme)): + async with get_db() as db: + return await UserService.block_user(user_action, db, token) @router.post("/ban", status_code=200) -async def ban_user(user_action: UserBlockBan, db: AsyncSession = Depends(get_db), token: str = Depends(oauth2_scheme)): - return await UserService.ban_user(user_action, db, token) +async def ban_user(user_action: UserBlockBan, token: str = Depends(oauth2_scheme)): + async with get_db() as db: + return await UserService.ban_user(user_action, db, token) @router.post("/unblock", status_code=200) -async def unblock_user(user_action: UserBlockBan, db: AsyncSession = Depends(get_db), token: str = Depends(oauth2_scheme)): - return await UserService.unblock_user(user_action, db, token) +async def unblock_user(user_action: UserBlockBan, token: str = Depends(oauth2_scheme)): + async with get_db() as db: + return await UserService.unblock_user(user_action, db, token) @router.post("/unban", status_code=200) -async def unban_user(user_action: UserBlockBan, db: AsyncSession = Depends(get_db), token: str = Depends(oauth2_scheme)): - return await UserService.unban_user(user_action, db, token) +async def unban_user(user_action: UserBlockBan, token: str = Depends(oauth2_scheme)): + async with get_db() as db: + return await UserService.unban_user(user_action, db, token) @router.get("/getuserbymail", response_model=UserResponse) -async def get_user_by_email(email: str, db=Depends(get_db), token: str = Depends(oauth2_scheme)): - return await UserService.get_user_by_email(email, db, token) \ No newline at end of file +async def get_user_by_email(email: str, token: str = Depends(oauth2_scheme)): + async with get_db() as db: + return await UserService.get_user_by_email(email, db, token) \ No newline at end of file diff --git a/config/database.py b/config/database.py index f8a6db4..e60b995 100644 --- a/config/database.py +++ b/config/database.py @@ -1,14 +1,46 @@ from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.orm import sessionmaker +from sqlalchemy.exc import SQLAlchemyError from config.settings import settings import logging +from contextlib import asynccontextmanager logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) DATABASE_URL = settings.database_url -engine = create_async_engine(DATABASE_URL, echo=True) -AsyncSessionLocal = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False) + +# Configuration optimisée du moteur +engine = create_async_engine( + DATABASE_URL, + echo=True, + pool_size=5, + max_overflow=10, + pool_timeout=30, + pool_recycle=1800, + pool_pre_ping=True +) + +AsyncSessionLocal = sessionmaker( + engine, + class_=AsyncSession, + expire_on_commit=False, + autocommit=False, + autoflush=False +) + +@asynccontextmanager +async def get_db(): + session = AsyncSessionLocal() + try: + yield session + await session.commit() + except SQLAlchemyError as e: + await session.rollback() + logger.error(f"Database error: {str(e)}") + raise + finally: + await session.close() async def init_db(): from models.db import metadata @@ -18,8 +50,4 @@ async def init_db(): logger.info("Database tables created successfully.") except Exception as e: logger.error(f"Error creating database tables: {str(e)}") - raise - -async def get_db(): - async with AsyncSessionLocal() as session: - yield session + raise \ No newline at end of file diff --git a/config/database.txt b/config/database.txt new file mode 100644 index 0000000..f8a6db4 --- /dev/null +++ b/config/database.txt @@ -0,0 +1,25 @@ +from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession +from sqlalchemy.orm import sessionmaker +from config.settings import settings +import logging + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +DATABASE_URL = settings.database_url +engine = create_async_engine(DATABASE_URL, echo=True) +AsyncSessionLocal = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False) + +async def init_db(): + from models.db import metadata + try: + async with engine.begin() as conn: + await conn.run_sync(metadata.create_all) + logger.info("Database tables created successfully.") + except Exception as e: + logger.error(f"Error creating database tables: {str(e)}") + raise + +async def get_db(): + async with AsyncSessionLocal() as session: + yield session