diff --git a/app/auth.py b/app/auth.py index 1e637e3..f451fdd 100644 --- a/app/auth.py +++ b/app/auth.py @@ -3,7 +3,7 @@ JWT validation compatibile con GEPAFIN-BE. Il BE Spring emette token HS512 con payload: sub: "email:userId:hubId" userId: int - auth: "ROLE_SUPER_ADMIN" | "ROLE_BENEFICIARY" | ... + auth: "ROLE_SUPER_ADMIN" | "ROLE_BENEFICIARY" | "ROLE_CONFIDI" | ... exp: unix timestamp loginAttemptId: int """ @@ -29,6 +29,15 @@ class AuthUser: def is_beneficiary(self) -> bool: return self.role == "ROLE_BENEFICIARY" + def is_confidi(self) -> bool: + return self.role == "ROLE_CONFIDI" + + def is_owner_role(self) -> bool: + """Ruoli che possono essere proprietari di una pratica (user_id match): + BENEFICIARY (azienda diretta) o CONFIDI (delegato per conto azienda). + Pattern allineato al BE Gepafin (DashboardDao, CompanyDocumentDao).""" + return self.role in ("ROLE_BENEFICIARY", "ROLE_CONFIDI") + def get_current_user( credentials: HTTPAuthorizationCredentials = Depends(bearer_scheme), diff --git a/app/routers/custom_checks.py b/app/routers/custom_checks.py index 4d04d1c..8b05de6 100644 --- a/app/routers/custom_checks.py +++ b/app/routers/custom_checks.py @@ -36,16 +36,16 @@ def _get_practice(db: Session, practice_id: UUID, user: AuthUser) -> RemissionPr if not p: raise HTTPException(status_code=404, detail=f"Pratica {practice_id} non trovata") # Autorizzazione base: beneficiario owner o istruttore - if user.is_beneficiary() and p.user_id != user.user_id: + if user.is_owner_role() and p.user_id != user.user_id: raise HTTPException(status_code=403, detail="Accesso negato") - if not user.is_beneficiary() and not _is_instructor(user): + if not user.is_owner_role() and not _is_instructor(user): raise HTTPException(status_code=403, detail="Ruolo non autorizzato") return p def _can_declare(user: AuthUser, practice: RemissionPractice) -> bool: """Solo beneficiario owner e solo su DRAFT | AWAITING_AMENDMENT.""" - if not user.is_beneficiary(): + if not user.is_owner_role(): return False if practice.user_id != user.user_id: return False diff --git a/app/routers/files.py b/app/routers/files.py index e90de84..3bd3842 100644 --- a/app/routers/files.py +++ b/app/routers/files.py @@ -38,7 +38,7 @@ def _can_upload(user: AuthUser, practice: RemissionPractice) -> bool: """Beneficiario proprietario in DRAFT/AWAITING_AMENDMENT oppure istruttore.""" if _is_instructor(user): return True - if user.is_beneficiary() and practice.user_id == user.user_id: + if user.is_owner_role() and practice.user_id == user.user_id: return practice.status in ("DRAFT", "AWAITING_AMENDMENT") return False @@ -46,14 +46,14 @@ def _can_upload(user: AuthUser, practice: RemissionPractice) -> bool: def _can_download(user: AuthUser, practice: RemissionPractice) -> bool: if _is_instructor(user): return True - if user.is_beneficiary() and practice.user_id == user.user_id: + if user.is_owner_role() and practice.user_id == user.user_id: return True return False def _can_delete(user: AuthUser, practice: RemissionPractice) -> bool: """Solo beneficiario su pratica modificabile. Istruttore non elimina file.""" - if user.is_beneficiary() and practice.user_id == user.user_id: + if user.is_owner_role() and practice.user_id == user.user_id: return practice.status in ("DRAFT", "AWAITING_AMENDMENT") if user.is_superadmin(): return True diff --git a/app/routers/instructor.py b/app/routers/instructor.py index fc1b1c9..22e2afd 100644 --- a/app/routers/instructor.py +++ b/app/routers/instructor.py @@ -446,7 +446,7 @@ def respond_amendment_beneficiary(practice_id: UUID, amendment_id: UUID, user: AuthUser = Depends(get_current_user)): """Beneficiario risponde al soccorso istruttorio (stato AWAITING -> RESPONSE_RECEIVED).""" p = _get_practice_or_404(db, practice_id) - if user.is_beneficiary() and p.user_id != user.user_id: + if user.is_owner_role() and p.user_id != user.user_id: raise HTTPException(status_code=403, detail="Non sei il proprietario della pratica") ar = _amendment_or_404(db, practice_id, amendment_id) @@ -620,7 +620,7 @@ async def upload_response_document(practice_id: UUID, amendment_id: UUID, """Beneficiario allega un documento come supporto alla sua risposta al soccorso. Consentito su amendment in stato AWAITING, solo dal proprietario pratica.""" p = _get_practice_or_404(db, practice_id) - if user.is_beneficiary() and p.user_id != user.user_id: + if user.is_owner_role() and p.user_id != user.user_id: raise HTTPException(status_code=403, detail="Non sei il proprietario della pratica") ar = _amendment_or_404(db, practice_id, amendment_id) diff --git a/app/routers/practices.py b/app/routers/practices.py index 6dd845f..42ed63d 100644 --- a/app/routers/practices.py +++ b/app/routers/practices.py @@ -39,7 +39,7 @@ def _get_practice_or_404(db: Session, practice_id: UUID, user: AuthUser) -> Remi raise HTTPException(status_code=404, detail=f"Pratica {practice_id} non trovata") # Solo il beneficiario owner o un superadmin può accedere - if user.is_beneficiary() and practice.user_id != user.user_id: + if user.is_owner_role() and practice.user_id != user.user_id: raise HTTPException(status_code=403, detail="Accesso negato a questa pratica") return practice @@ -438,7 +438,7 @@ def start_practice(body: PracticeStartRequest, db: Session = Depends(get_db), if app_row["status"] != "CONTRACT_SIGNED": raise HTTPException(status_code=409, detail=f"Application in stato {app_row['status']}, richiesto CONTRACT_SIGNED") - if user.is_beneficiary() and app_row["user_id"] != user.user_id: + if user.is_owner_role() and app_row["user_id"] != user.user_id: raise HTTPException(status_code=403, detail="Application non di tua proprieta") # Schema del bando @@ -446,7 +446,7 @@ def start_practice(body: PracticeStartRequest, db: Session = Depends(get_db), if not schema: raise HTTPException(status_code=409, detail="Nessuno schema di rendicontazione configurato per questo bando.") - if schema.status != "PUBLISHED" and user.is_beneficiary(): + if schema.status != "PUBLISHED" and user.is_owner_role(): raise HTTPException(status_code=409, detail="Lo schema di rendicontazione non e ancora stato pubblicato.")