diff --git a/api/v1/person_reports.py b/api/v1/person_reports.py index 9ecbf05..5d27ee9 100644 --- a/api/v1/person_reports.py +++ b/api/v1/person_reports.py @@ -1,4 +1,4 @@ -from fastapi import APIRouter, Depends, File, HTTPException, UploadFile +from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile from fastapi.security import OAuth2PasswordBearer from pydantic import ValidationError from services.person_report_service import PersonReportService @@ -6,26 +6,23 @@ from models.schemas import PersonReportCreate, PersonReportUpdate, PersonReportR from config.database import get_db from typing import Optional from services.auth_service import AuthService +from utils.logging import logger router = APIRouter() oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/token") @router.post("/", status_code=201) async def create_report( - report: str, # Le champ report est reçu sous forme de chaîne JSON - image_file: Optional[UploadFile] = File(None), # L'image est facultative + 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(), token: str = Depends(oauth2_scheme) ): - try: - # Valider et convertir la chaîne JSON en objet PersonReportCreate - report_data = PersonReportCreate.model_validate_json(report) - except ValidationError as e: - raise HTTPException(status_code=422, detail=f"Invalid report data: {e}") + logger.info(f"Creating report: {file.filename if file else None} - {report}") # Appeler le service pour traiter le rapport try: - created_report = await PersonReportService.create_report(report_data, db, image_file, token) + 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)}") @@ -44,5 +41,5 @@ async def list_reports(status: Optional[str] = None, db=Depends(get_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), current_user: UserResponse = Depends(AuthService.get_current_user)): - return await PersonReportService.delete_report(report_id, db, current_user) \ No newline at end of file +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 diff --git a/models/schemas.py b/models/schemas.py index 5126750..f1f3fa7 100644 --- a/models/schemas.py +++ b/models/schemas.py @@ -1,6 +1,8 @@ +import json +from fastapi import Form, UploadFile from pydantic import BaseModel, EmailStr, model_validator from datetime import datetime -from typing import List, Optional +from typing import Any, List, Optional class Role(BaseModel): id: int @@ -131,11 +133,19 @@ class PersonReportBase(BaseModel): reporter_email: str class PersonReportCreate(BaseModel): - full_name: str - date_of_birth: datetime - status: str - location: Optional[str] = None - gps_coordinates: Optional[str] = None + full_name: Optional[str] = Form(None) + date_of_birth: Optional[datetime] = Form(None) + status: Optional[str] = Form(None) + location: Optional[str] = Form(None) + gps_coordinates: Optional[str] = Form(None) + @model_validator(mode='before') + @classmethod + def validate_to_json(cls, value: Any) -> Any: + print(value) + if isinstance(value, str): + return cls(**json.loads(value)) + return value + class PersonReportUpdate(BaseModel): status: Optional[str] = None diff --git a/services/person_report_service.py b/services/person_report_service.py index df8e0e2..0adddb9 100644 --- a/services/person_report_service.py +++ b/services/person_report_service.py @@ -1,5 +1,5 @@ from sqlalchemy import delete, select, update -from fastapi import HTTPException +from fastapi import HTTPException, UploadFile from models.schemas import PersonReportCreate, PersonReportUpdate, PersonReportResponse from config.database import get_db from models.db import person_reports_table @@ -8,20 +8,24 @@ from fastapi import Depends from fastapi.security import OAuth2PasswordBearer from services.auth_service import AuthService -from services.s3_service import UploadService +from services.upload_service import UploadService oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/token") class PersonReportService: @staticmethod - async def create_report(report: PersonReportCreate, db, image_file, token): - user = await AuthService.get_current_user(token, db) - image_url = await UploadService.upload_image_to_s3(image_file, user.email) if image_file else None - - query = person_reports_table.insert().values(**report.model_dump(), - photo_url=image_url, - reporter_email=user["email"]) + async def create_report(report: PersonReportCreate, db, token, file: Optional[UploadFile] = None ): + user = await AuthService.get_current_user(token, db)if file else None + image_url = await UploadService.upload_image_to_s3( file, user["id"]) + #image_url = file.filename if file else None + query = person_reports_table.insert().values(full_name=report.full_name, + date_of_birth=report.date_of_birth, + status=report.status, + location=report.location, + gps_coordinates=report.gps_coordinates, + photo_url=image_url["path_with_name"] if image_url else None, + reporter_email=user["email"]) try: result = await db.execute(query) await db.commit() @@ -50,7 +54,7 @@ class PersonReportService: async def get_report(report_id: int, db): query = select(person_reports_table).where(person_reports_table.c.id == report_id) result = await db.execute(query) - report = result.fetchone() + report = result.mappings().first() if not report: raise HTTPException(status_code=404, detail="Report not found") return PersonReportResponse(**report) @@ -65,10 +69,9 @@ class PersonReportService: return [PersonReportResponse(**report) for report in reports] @staticmethod - async def delete_report(report_id: int, db, current_user): + async def delete_report(report_id: int, db, token): # Vérifier les droits de l'utilisateur - if not current_user.role.permissions or "delete_reports" not in current_user.role.permissions: - raise HTTPException(status_code=403, detail="Permission denied") + await AuthService.check_permissions( token , db, ["admin","collectivité","état"]) query = delete(person_reports_table).where(person_reports_table.c.id == report_id) try: diff --git a/services/s3_service.py b/services/s3_service.py deleted file mode 100644 index 658ce20..0000000 --- a/services/s3_service.py +++ /dev/null @@ -1,22 +0,0 @@ -from fastapi import UploadFile, HTTPException -import boto3 -from botocore.exceptions import NoCredentialsError -from config.settings import settings - -s3_client = boto3.client( - 's3', - aws_access_key_id=settings.aws_access_key_id, - aws_secret_access_key=settings.aws_secret_access_key -) - -class UploadService: - @staticmethod - async def upload_file(file: UploadFile): - try: - s3_client.upload_fileobj(file.file, settings.aws_bucket_name, file.filename) - file_url = f"https://{settings.aws_bucket_name}.s3.amazonaws.com/{file.filename}" - return {"file_url": file_url} - except NoCredentialsError: - raise HTTPException(status_code=500, detail="AWS credentials not available") - except Exception as e: - raise HTTPException(status_code=500, detail=f"Could not upload file: {str(e)}") \ No newline at end of file diff --git a/services/upload_service.py b/services/upload_service.py index 460433d..0b622ad 100644 --- a/services/upload_service.py +++ b/services/upload_service.py @@ -25,6 +25,7 @@ class UploadService: } S3_CONFIG = { + "url": "https://api.mayotte-urgence.com/cdn-storage", "bucket": "sywmtnsg", "endpoint_url": "https://ht2-storage.n0c.com:5443", "region_name": "ht2-storage", @@ -71,7 +72,7 @@ class UploadService: return { "success": True, - "path_with_name": full_path.replace("public", ""), + "path_with_name": S3_CONFIG["url"]+full_path.replace("public", ""), "filename": new_filename, "original_filename": file.filename, "filetype": extension,