correction and minor changes

main
Anaz 2025-01-15 20:37:39 +04:00
parent 59df9bc409
commit 0e041336a4
10 changed files with 205 additions and 109 deletions

View File

@ -1,4 +1,5 @@
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from services.need_request_service import NeedRequestService
from models.schemas import NeedRequestCreate, NeedRequestUpdate
from config.database import get_db
@ -6,17 +7,22 @@ from services.auth_service import AuthService
router = APIRouter()
# Configuration pour OAuth2
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)
@router.get("/", status_code=status.HTTP_200_OK)
async def get_all_reports(db=Depends(get_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_by_id(need_id, 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
@ -26,16 +32,16 @@ async def get_need(need_id: int, db=Depends(get_db)):
async def update_need(
need_id: int,
need_update: NeedRequestUpdate,
token: str = Depends(oauth2_scheme),
db=Depends(get_db),
current_user=Depends(AuthService.get_current_user),
):
need = await NeedRequestService.get_need_by_id(need_id, 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")
# V<>rifie si l'utilisateur est l'auteur ou un administrateur
if need.requester_email != current_user.email and not await AuthService.admin_required(db=db):
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",
@ -47,16 +53,17 @@ async def update_need(
@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),
current_user=Depends(AuthService.get_current_user),
):
need = await NeedRequestService.get_need_by_id(need_id, 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")
# V<>rifie si l'utilisateur est l'auteur ou un administrateur
if need.requester_email != current_user.email and not await AuthService.admin_required(db=db):
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",

View File

@ -1,8 +1,9 @@
from fastapi import APIRouter, Depends, HTTPException
from services.person_report_service import PersonReportService
from models.schemas import PersonReportCreate, PersonReportUpdate, PersonReportResponse
from models.schemas import PersonReportCreate, PersonReportUpdate, PersonReportResponse, UserResponse
from config.database import get_db
from typing import Optional
from services.auth_service import AuthService
router = APIRouter()
@ -20,4 +21,8 @@ async def get_report(report_id: int, db=Depends(get_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)
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)

View File

@ -1 +1,30 @@
from fastapi import APIRouter, Depends, HTTPException, status from services.report_service import ReportService from models.schemas import UserReport, UserReportUpdate from config.database import get_db from services.auth_service import AuthService admin_required = AuthService.admin_required 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) @router.get("/{report_id}", status_code=status.HTTP_200_OK) async def get_report(report_id: int, db=Depends(get_db), current_user=Depends(admin_required)): return await ReportService.get_report_by_id(report_id, db) @router.get("/", status_code=status.HTTP_200_OK) async def get_all_reports(db=Depends(get_db), current_user=Depends(admin_required)): return await ReportService.get_all_reports(db) @router.put("/{report_id}", status_code=status.HTTP_200_OK) async def update_report(report_id: int, report_update: UserReportUpdate, db=Depends(get_db), current_user=Depends(admin_required)): return await ReportService.update_report(report_id, report_update, db) @router.delete("/{report_id}", status_code=status.HTTP_200_OK) async def delete_report(report_id: int, db=Depends(get_db), current_user=Depends(admin_required)): return await ReportService.delete_report(report_id, db)
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from services.report_service import ReportService
from models.schemas import UserReport, UserReportUpdate
from config.database import get_db
from services.auth_service import AuthService
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)
@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)
@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)
@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)
@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)

View File

@ -11,11 +11,11 @@ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/token")
@router.post("/", status_code=201)
async def create_role(name: str, permissions: List[str], db: AsyncSession = Depends(get_db), token: str = Depends(oauth2_scheme)):
async def create_role(name: str, db: AsyncSession = Depends(get_db), 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, permissions, db, token)
return await RoleService.create_role(name, db, token)
@router.get("/{role_id}", response_model=Role)

View File

@ -2,14 +2,20 @@ from pydantic import BaseModel, EmailStr, model_validator
from datetime import datetime
from typing import List, Optional
class RoleBase(BaseModel):
name: str
class RoleCreate(RoleBase):
permissions: List[str]
class RoleResponse(RoleBase):
class Role(BaseModel):
id: int
name: str
permissions: List[str]
class Config:
orm_mode = True
class UserUpdateRole(BaseModel):
email: EmailStr
new_role: str
class RoleResponse(BaseModel):
name: str
permissions: List[str]
class Config:
@ -24,7 +30,15 @@ class UserBase(BaseModel):
class UserCreate(UserBase):
password: str
role: str
role: Role
# Validation au niveau du modèle
@model_validator(mode="before")
def convert_role_to_dict(cls, values):
role = values.get("role")
if isinstance(role, str):
values["role"] = {"id": 0, "name": role, "permissions": []}
return values
class UserResponse(BaseModel):
email: EmailStr
@ -52,18 +66,6 @@ class Permission(BaseModel):
id: int
name: str
class Role(BaseModel):
id: int
name: str
permissions: List[str]
class Config:
orm_mode = True
class UserUpdateRole(BaseModel):
email: EmailStr
new_role: str
class UserBlockBan(BaseModel):
email: EmailStr
@ -112,7 +114,7 @@ class UserReport(BaseModel):
status: Optional[str] = "pending"
class UserReportUpdate(BaseModel):
reason: Optional[str] = None
#reason: Optional[str] = None
status: Optional[str] = None # Exemples : "pending", "resolved"
class TechnicalIssue(BaseModel):

View File

@ -165,7 +165,7 @@ class AuthService:
query = users_table.select().where(users_table.c.email == token_data.email)
result = await db.execute(query)
user = result.fetchone()
user = result.mappings().first()
if user is None:
raise credentials_exception
@ -199,7 +199,7 @@ class AuthService:
query = select(users_table).where(users_table.c.email == token_data.email)
result = await db.execute(query)
current_user = result.fetchone()
current_user = result.mappings().first()
if current_user is None:
raise credentials_exception
@ -235,7 +235,7 @@ class AuthService:
# Récupérer les informations mises à jour
updated_user_query = select(users_table).where(users_table.c.id == user_id)
result = await db.execute(updated_user_query)
updated_user = result.fetchone()
updated_user = result.mappings().first()
return UserResponse(**updated_user)
@ -243,4 +243,4 @@ class AuthService:
async def get_user_by_email(email: str, db: AsyncSession):
query = select(users_table).where(users_table.c.email == email)
result = await db.execute(query)
return result.fetchone()
return result.mappings().first()

View File

@ -3,7 +3,7 @@ from models.schemas import NeedRequestCreate
from config.database import get_db
from models.db import need_requests_table, users_table
from models.schemas import TokenData
from fastapi import HTTPException, Depends, status
from fastapi import HTTPException, Depends, logger, status
from fastapi.security import OAuth2PasswordBearer
from config.settings import settings
from jose import jwt, JWTError
@ -29,7 +29,7 @@ class NeedRequestService:
result = await db.execute(query)
await db.commit()
need_id = result.inserted_primary_key[0]
return {"id": need_id, **need.dict()}
return {"id": need_id, **need.model_dump()}
except Exception as e:
await db.rollback()
raise HTTPException(status_code=500, detail=f"Could not create need request: {str(e)}")
@ -38,7 +38,7 @@ class NeedRequestService:
async def get_need(need_id: int, db):
query = select(need_requests_table).where(need_requests_table.c.id == need_id)
result = await db.execute(query)
need = result.fetchone()
need = result.mappings().fetchone()
if need is None:
raise HTTPException(status_code=404, detail="Need request not found")
return dict(need)
@ -47,7 +47,7 @@ class NeedRequestService:
async def get_all_needs(db):
query = select(need_requests_table).where(need_requests_table.c.deleted == None)
result = await db.execute(query)
needs = result.fetchall()
needs = result.mappings().all()
return [dict(need) for need in needs]
@staticmethod
@ -78,7 +78,7 @@ class NeedRequestService:
query = (
update(need_requests_table)
.where(need_requests_table.c.id == need_id)
.values(deleted=datetime.utcnow())
.values(deleted=datetime.now(datetime.timezone.utc()))
)
try:
result = await db.execute(query)
@ -108,20 +108,22 @@ class NeedRequestService:
# R<>cup<75>re l'utilisateur depuis la base de donn<6E>es
user_query = select(users_table).where(users_table.c.email == token_data.email)
result = await db.execute(user_query)
user = result.fetchone()
user = result.mappings().fetchone()
logger.info("user loooooooooooooooooooo: " +user)
if user is None:
raise credentials_exception
# R<>cup<75>re la demande de besoin
need_query = select(need_requests_table).where(need_requests_table.c.id == need_id)
result = await db.execute(need_query)
need = result.fetchone()
need = result.mappings().fetchone()
if need is None:
raise HTTPException(status_code=404, detail="Need request not found")
# V<>rifie si l'utilisateur est l'auteur ou un administrateur
if need["requester_email"] != user["email"] and user["role"] != "admin":
raise credentials_exception
return False
return user
return True

View File

@ -1,4 +1,4 @@
from sqlalchemy import select, update
from sqlalchemy import delete, select, update
from fastapi import HTTPException
from models.schemas import PersonReportCreate, PersonReportUpdate, PersonReportResponse
from config.database import get_db
@ -13,7 +13,7 @@ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/token")
class PersonReportService:
@staticmethod
async def create_report(report: PersonReportCreate, db):
query = person_reports_table.insert().values(**report.dict())
query = person_reports_table.insert().values(**report.model_dump())
try:
result = await db.execute(query)
await db.commit()
@ -28,7 +28,7 @@ class PersonReportService:
query = (
person_reports_table.update()
.where(person_reports_table.c.id == report_id)
.values(**report.dict(exclude_unset=True))
.values(**report.model_dump(exclude_unset=True))
)
try:
await db.execute(query)
@ -54,4 +54,21 @@ class PersonReportService:
query = query.where(person_reports_table.c.status == status)
result = await db.execute(query)
reports = result.fetchall()
return [PersonReportResponse(**report) for report in reports]
return [PersonReportResponse(**report) for report in reports]
@staticmethod
async def delete_report(report_id: int, db, current_user):
# 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")
query = delete(person_reports_table).where(person_reports_table.c.id == report_id)
try:
result = await db.execute(query)
if result.rowcount == 0:
raise HTTPException(status_code=404, detail="Report not found")
await db.commit()
return {"detail": "Report deleted successfully"}
except Exception as e:
await db.rollback()
raise HTTPException(status_code=500, detail=f"Could not delete report: {str(e)}")

View File

@ -1 +1,87 @@
from sqlalchemy import insert, update, select, delete from models.schemas import UserReport, UserReportUpdate from config.database import get_db from models.db import user_reports_table from fastapi import HTTPException, status class ReportService: @staticmethod async def create_report(report: UserReport, db): query = insert(user_reports_table).values( reporter_id=report.reporter_id, reported_user_id=report.reported_user_id, reason=report.reason, status="pending" # Par défaut, le statut est "pending" ) try: result = await db.execute(query) await db.commit() report_id = result.inserted_primary_key[0] return {"id": report_id, **report.dict()} except Exception as e: await db.rollback() raise HTTPException(status_code=500, detail=f"Could not create user report: {str(e)}") @staticmethod async def get_report_by_id(report_id: int, db): query = select(user_reports_table).where(user_reports_table.c.id == report_id) result = await db.execute(query) report = result.fetchone() if not report: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Report not found") return dict(report) @staticmethod async def get_all_reports(db): query = select(user_reports_table) result = await db.execute(query) reports = result.fetchall() return [dict(report) for report in reports] @staticmethod async def update_report(report_id: int, report_update: UserReportUpdate, db): query = ( update(user_reports_table) .where(user_reports_table.c.id == report_id) .values(**report_update.dict(exclude_unset=True)) .returning(user_reports_table.c.id) ) try: result = await db.execute(query) await db.commit() updated_id = result.fetchone() if not updated_id: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Report not found") return {"id": updated_id[0], **report_update.dict()} except Exception as e: await db.rollback() raise HTTPException(status_code=500, detail=f"Could not update report: {str(e)}") @staticmethod async def delete_report(report_id: int, db): query = delete(user_reports_table).where(user_reports_table.c.id == report_id) try: result = await db.execute(query) await db.commit() if result.rowcount == 0: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Report not found") return {"detail": "Report deleted successfully"} except Exception as e: await db.rollback() raise HTTPException(status_code=500, detail=f"Could not delete report: {str(e)}")
from fastapi.security import OAuth2PasswordBearer
from sqlalchemy import insert, update, select, delete
from models.schemas import UserReport, UserReportUpdate
from config.database import get_db
from models.db import user_reports_table
from fastapi import Depends, HTTPException, status
from services.auth_service import AuthService
# Configuration pour OAuth2
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/token")
class ReportService:
@staticmethod
async def create_report(report: UserReport, db):
query = insert(user_reports_table).values(
reporter_id=report.reporter_id,
reported_user_id=report.reported_user_id,
reason=report.reason,
status="pending" # Par défaut, le statut est "pending"
)
try:
result = await db.execute(query)
await db.commit()
report_id = result.inserted_primary_key[0]
return {"id": report_id, **report.model_dump()}
except Exception as e:
await db.rollback()
raise HTTPException(status_code=500, detail=f"Could not create user report: {str(e)}")
@staticmethod
async def get_report_by_id(report_id: int, db, token: str = Depends(oauth2_scheme)):
await AuthService.admin_required(token, db)
query = select(user_reports_table).where(user_reports_table.c.id == report_id)
result = await db.execute(query)
report = result.mappings().fetchone()
if not report:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Report not found")
return dict(report)
@staticmethod
async def get_all_reports(db, token: str = Depends(oauth2_scheme)):
await AuthService.admin_required(token, db)
query = select(user_reports_table)
result = await db.execute(query)
reports = result.mappings().all()
return [dict(report) for report in reports]
@staticmethod
async def update_report(report_id: int, report_update: UserReportUpdate, db, token: str = Depends(oauth2_scheme)):
await AuthService.admin_required(token, db)
query = (
update(user_reports_table)
.where(user_reports_table.c.id == report_id)
.values(**report_update.model_dump(exclude_unset=True))
)
try:
await db.execute(query)
await db.commit()
# Récupérer le rapport mis à jour
select_query = select(user_reports_table).where(user_reports_table.c.id == report_id)
result = await db.execute(select_query)
updated_report = result.mappings().fetchone()
if not updated_report:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Report not found")
return dict(updated_report)
except Exception as e:
await db.rollback()
raise HTTPException(status_code=500, detail=f"Could not update report: {str(e)}")
@staticmethod
async def delete_report(report_id: int, db, token: str):
await AuthService.admin_required(token, db)
query = delete(user_reports_table).where(user_reports_table.c.id == report_id)
try:
result = await db.execute(query)
await db.commit()
if result.rowcount == 0:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Report not found")
return {"detail": "Report deleted successfully"}
except Exception as e:
await db.rollback()
raise HTTPException(status_code=500, detail=f"Could not delete report: {str(e)}")

View File

@ -7,6 +7,7 @@ from config.database import get_db
from config.settings import settings
from jose import jwt, JWTError
from sqlalchemy.ext.asyncio import AsyncSession
from services.auth_service import AuthService
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/token")
@ -36,39 +37,18 @@ class RoleService:
return roles_with_permissions
@staticmethod
async def create_role(name: str, permissions: list, db, token: str):
async def create_role(name: str, db, token: str):
"""
Crée un nouveau rôle avec les permissions spécifiées (réservé aux administrateurs).
"""
await RoleService.admin_required(token, db)
# Vérifier que les permissions sont valides
valid_permissions = settings.available_permissions
filtered_permissions = [p for p in permissions if p in valid_permissions]
if not filtered_permissions:
raise HTTPException(status_code=400, detail="No valid permissions provided.")
await AuthService.admin_required(token, db)
# Insérer le rôle
query = insert(roles_table).values(name=name)
try:
result = await db.execute(query)
await db.commit()
role_id = result.inserted_primary_key[0]
# Associer les permissions valides au rôle
for permission in filtered_permissions:
permission_query = select(permissions_table).where(permissions_table.c.name == permission)
permission_result = await db.execute(permission_query)
permission_record = permission_result.mappings().fetchone()
if permission_record:
insert_query = insert(role_permissions_table).values(
role_id=role_id, permission_id=permission_record['id']
)
await db.execute(insert_query)
await db.commit()
return {"id": role_id, "name": name, "permissions": filtered_permissions}
return {"id": role_id, "name": name}
except Exception as e:
await db.rollback()
raise HTTPException(status_code=500, detail=f"Could not create role: {str(e)}")
@ -78,7 +58,7 @@ class RoleService:
"""
Met à jour un rôle par son ID (réservé aux administrateurs).
"""
await RoleService.admin_required(token, db)
await AuthService.admin_required(token, db)
if "permissions" in data:
# Supprimer les anciennes permissions
delete_query = delete(role_permissions_table).where(role_permissions_table.c.role_id == role_id)
@ -123,7 +103,7 @@ class RoleService:
"""
Supprime un rôle par son ID (réservé aux administrateurs).
"""
await RoleService.admin_required(token, db)
await AuthService.admin_required(token, db)
query = delete(roles_table).where(roles_table.c.id == role_id)
try:
result = await db.execute(query)
@ -135,38 +115,6 @@ class RoleService:
await db.rollback()
raise HTTPException(status_code=500, detail=f"Could not delete role: {str(e)}")
@staticmethod
async def admin_required(token: str = Depends(oauth2_scheme), db: AsyncSession = Depends(get_db)):
"""
Vérifie si l'utilisateur actuel est un administrateur.
"""
credentials_exception = HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="You do not have permission to perform this action.",
)
try:
# Décodage du token JWT
payload = jwt.decode(token, settings.secret_key, algorithms=[settings.algorithm])
email: str = payload.get("sub")
if email is None:
raise credentials_exception
token_data = TokenData(email=email)
except JWTError:
raise credentials_exception
# Récupère l'utilisateur depuis la base de données
user_query = select(users_table).where(users_table.c.email == token_data.email)
result = await db.execute(user_query)
user = result.fetchone()
if user is None:
raise credentials_exception
# Vérifie si l'utilisateur a le rôle d'administrateur
if user["role"] != "admin":
raise credentials_exception
return user
@staticmethod
async def get_all_permissions(db: AsyncSession):
"""