Files
gepafin-rendicontazione-api/app/routers/schemas.py

163 lines
6.1 KiB
Python

"""
Endpoint gestione schema rendicontazione per bando.
"""
import copy
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from sqlalchemy.exc import IntegrityError
from ..db import get_db
from ..auth import AuthUser, get_current_user, require_superadmin
from ..models import CallRemissionSchema
from ..schemas import RemissionSchemaOut, RemissionSchemaCreate, RemissionSchemaUpdate, ApiResponse
from ..templates import RESTART_TEMPLATE
router = APIRouter(prefix="/api/rendicontazione-schemas", tags=["rendicontazione-schemas"])
@router.get("/{call_id}", response_model=ApiResponse)
def get_schema(call_id: int, db: Session = Depends(get_db), user: AuthUser = Depends(get_current_user)):
"""Legge lo schema di rendicontazione per un bando. 404 se non esiste."""
schema = db.query(CallRemissionSchema).filter(CallRemissionSchema.call_id == call_id).first()
if not schema:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Nessuno schema di rendicontazione per call_id={call_id}. Usa POST per crearlo.",
)
return ApiResponse(data=RemissionSchemaOut.model_validate(schema).model_dump(mode="json"))
@router.post("/{call_id}", response_model=ApiResponse)
def create_schema(
call_id: int,
body: RemissionSchemaCreate,
db: Session = Depends(get_db),
user: AuthUser = Depends(require_superadmin),
):
"""Crea uno schema di rendicontazione per un bando. Fallisce se esiste già."""
existing = db.query(CallRemissionSchema).filter(CallRemissionSchema.call_id == call_id).first()
if existing:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail=f"Schema già esistente per call_id={call_id}. Usa PUT per aggiornarlo.",
)
schema = CallRemissionSchema(
call_id=call_id,
schema_json=body.schema_json,
status="DRAFT",
created_by=user.user_id,
)
db.add(schema)
db.commit()
db.refresh(schema)
return ApiResponse(
message=f"Schema creato per call_id={call_id}",
data=RemissionSchemaOut.model_validate(schema).model_dump(mode="json"),
)
@router.put("/{call_id}", response_model=ApiResponse)
def update_schema(
call_id: int,
body: RemissionSchemaUpdate,
db: Session = Depends(get_db),
user: AuthUser = Depends(require_superadmin),
):
"""Aggiorna schema esistente. Blocca modifiche se già PUBLISHED."""
schema = db.query(CallRemissionSchema).filter(CallRemissionSchema.call_id == call_id).first()
if not schema:
raise HTTPException(status_code=404, detail=f"Schema non trovato per call_id={call_id}")
if schema.status == "PUBLISHED":
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="Schema PUBLISHED non modificabile. Crea una nuova versione.",
)
if body.schema_json is not None:
schema.schema_json = body.schema_json
db.commit()
db.refresh(schema)
return ApiResponse(
message=f"Schema aggiornato per call_id={call_id}",
data=RemissionSchemaOut.model_validate(schema).model_dump(mode="json"),
)
@router.post("/{call_id}/initialize-restart", response_model=ApiResponse)
def initialize_restart(
call_id: int,
db: Session = Depends(get_db),
user: AuthUser = Depends(require_superadmin),
):
"""Inizializza schema per un bando usando il template RE-START. Fallisce se esiste già."""
existing = db.query(CallRemissionSchema).filter(CallRemissionSchema.call_id == call_id).first()
if existing:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail=f"Schema già esistente per call_id={call_id}. Usa PUT per modificarlo.",
)
schema = CallRemissionSchema(
call_id=call_id,
schema_json=copy.deepcopy(RESTART_TEMPLATE),
status="DRAFT",
created_by=user.user_id,
)
db.add(schema)
db.commit()
db.refresh(schema)
return ApiResponse(
message=f"Schema RE-START inizializzato per call_id={call_id}",
data=RemissionSchemaOut.model_validate(schema).model_dump(mode="json"),
)
@router.post("/{call_id}/publish", response_model=ApiResponse)
def publish_schema(
call_id: int,
db: Session = Depends(get_db),
user: AuthUser = Depends(require_superadmin),
):
"""Pubblica lo schema (status DRAFT -> PUBLISHED). Una volta pubblicato, non è più editabile."""
from datetime import datetime, timezone
schema = db.query(CallRemissionSchema).filter(CallRemissionSchema.call_id == call_id).first()
if not schema:
raise HTTPException(status_code=404, detail=f"Schema non trovato per call_id={call_id}")
if schema.status == "PUBLISHED":
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="Schema già pubblicato.",
)
schema.status = "PUBLISHED"
schema.published_at = datetime.now(timezone.utc)
schema.published_by = user.user_id
db.commit()
db.refresh(schema)
return ApiResponse(
message=f"Schema pubblicato per call_id={call_id}",
data=RemissionSchemaOut.model_validate(schema).model_dump(mode="json"),
)
@router.delete("/{call_id}", response_model=ApiResponse)
def delete_schema(
call_id: int,
db: Session = Depends(get_db),
user: AuthUser = Depends(require_superadmin),
):
"""Cancella schema. Consentito solo in DRAFT."""
schema = db.query(CallRemissionSchema).filter(CallRemissionSchema.call_id == call_id).first()
if not schema:
raise HTTPException(status_code=404, detail=f"Schema non trovato per call_id={call_id}")
if schema.status == "PUBLISHED":
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="Schema PUBLISHED non cancellabile.",
)
db.delete(schema)
db.commit()
return ApiResponse(message=f"Schema cancellato per call_id={call_id}")
@router.get("/templates/restart", response_model=ApiResponse)
def get_restart_template(user: AuthUser = Depends(require_superadmin)):
"""Restituisce il template RE-START senza persisterlo. Utile per preview."""
return ApiResponse(data=RESTART_TEMPLATE)