"""API REST de partage de cartes.""" from __future__ import annotations from fastapi import APIRouter, Response, status from app.api.deps import ( DbSession, ManagementToken, RateLimitCreate, RateLimitRead, RateLimitWrite, SharingEnabled, ) from app.schemas.share import ( ShareCreatedOut, ShareCreateIn, ShareExpiryIn, ShareOwnerOut, SharePublicOut, ShareUpdatedOut, ) from app.services import shares as share_service router = APIRouter(prefix="/shares", tags=["shares"]) def _share_path(share_token: str) -> str: return f"/s/{share_token}" @router.post( "", response_model=ShareCreatedOut, status_code=status.HTTP_201_CREATED, summary="Publier un snapshot de carte et obtenir un lien non repertorie", ) def create_share( payload: ShareCreateIn, session: DbSession, _sharing: SharingEnabled, _rate: RateLimitCreate, ) -> ShareCreatedOut: # `permanent` distingue "aucune preference" (defaut de l'instance) de # "explicitement sans expiration", que le JSON seul ne permet pas de separer. explicit = payload.permanent or payload.expires_in_days is not None share, management_token = share_service.create_share( session, title=payload.title, document=payload.map, expires_in_days=None if payload.permanent else payload.expires_in_days, expiry_explicit=explicit, ) return ShareCreatedOut( share_token=share.share_token, management_token=management_token, share_path=_share_path(share.share_token), title=share.title, created_at=share.created_at, updated_at=share.updated_at, expires_at=share.expires_at, ) @router.get( "/{share_token}", response_model=SharePublicOut, summary="Lire une carte partagee (public, lecture seule)", ) def read_share( share_token: str, session: DbSession, _sharing: SharingEnabled, _rate: RateLimitRead, ) -> SharePublicOut: share = share_service.get_share(session, share_token) return SharePublicOut( share_token=share.share_token, title=share.title, map_version=share.map_version, map=share_service.load_map_data(share), created_at=share.created_at, updated_at=share.updated_at, expires_at=share.expires_at, ) @router.put( "/{share_token}", response_model=ShareUpdatedOut, summary="Mettre a jour le snapshot partage (necessite le jeton de gestion)", ) def update_share( share_token: str, payload: ShareCreateIn, session: DbSession, management_token: ManagementToken, _sharing: SharingEnabled, _rate: RateLimitWrite, ) -> ShareUpdatedOut: share = share_service.update_share( session, share_token, management_token=management_token, title=payload.title, document=payload.map, ) return ShareUpdatedOut( share_token=share.share_token, share_path=_share_path(share.share_token), title=share.title, updated_at=share.updated_at, expires_at=share.expires_at, ) @router.patch( "/{share_token}", response_model=ShareOwnerOut, summary="Modifier l'expiration du partage (necessite le jeton de gestion)", ) def update_expiry( share_token: str, payload: ShareExpiryIn, session: DbSession, management_token: ManagementToken, _sharing: SharingEnabled, _rate: RateLimitWrite, ) -> ShareOwnerOut: share = share_service.set_expiry( session, share_token, management_token=management_token, expires_in_days=None if payload.permanent else payload.expires_in_days, ) return ShareOwnerOut( share_token=share.share_token, title=share.title, created_at=share.created_at, updated_at=share.updated_at, expires_at=share.expires_at, ) @router.post( "/{share_token}/verify", response_model=ShareOwnerOut, summary="Verifier qu'une cle de gestion correspond a ce partage", ) def verify_share( share_token: str, session: DbSession, management_token: ManagementToken, _sharing: SharingEnabled, _rate: RateLimitWrite, ) -> ShareOwnerOut: """Permet de reimporter une cle de gestion depuis un autre navigateur. Ne renvoie aucune donnee de carte : seulement de quoi reconstituer la fiche de partage locale. """ share = share_service.verify_management_token( session, share_token, management_token=management_token ) return ShareOwnerOut( share_token=share.share_token, title=share.title, created_at=share.created_at, updated_at=share.updated_at, expires_at=share.expires_at, ) @router.delete( "/{share_token}", status_code=status.HTTP_204_NO_CONTENT, response_class=Response, summary="Supprimer le partage (necessite le jeton de gestion)", ) def delete_share( share_token: str, session: DbSession, management_token: ManagementToken, _sharing: SharingEnabled, _rate: RateLimitWrite, ) -> Response: share_service.delete_share(session, share_token, management_token=management_token) return Response(status_code=status.HTTP_204_NO_CONTENT)