from dataclasses import dataclass, asdict from typing import Literal, Annotated from litestar import Controller, get, Litestar, put, Request, Response, MediaType from litestar.params import Parameter from pydantic import UUID4 from secretsanta.domain import Group from secretsanta.repo import S3Repo from secretsanta.service import ( GetGroupParticipantsService, CreateGroupService, GetPairService, ) from secretsanta.settings import get_config @dataclass class CreateGroup: participants: list[str] @dataclass class PairResponse: pair: str class GroupController(Controller): path = "api/v1/groups" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.repo = S3Repo() self.get_participants_service = GetGroupParticipantsService(self.repo) self.create_group_service = CreateGroupService(self.repo) self.get_pair_service = GetPairService(self.repo) @staticmethod def _group2urls(participants: list[str], url: str) -> list[str]: return [f"{url}/pair/{participant_name}" for participant_name in participants] @get("/{group_uuid:uuid}") async def get_participants(self, request: Request, group_uuid: UUID4) -> list[str]: participants = await self.get_participants_service.run(group_uuid) return self._group2urls(participants, request.url) @put("/{group_uuid:uuid}") async def create_group( self, request: Request, group_uuid: UUID4, data: CreateGroup ) -> list[str]: group = await self.create_group_service.run( Group(uuid=group_uuid, **asdict(data)) ) return self._group2urls(group.participants, request.url) @get("/{group_uuid:uuid}/pair/{participant_name:str}") async def get_pair( self, group_uuid: UUID4, participant_name: str, response_type: Annotated[ Literal["json", "plain"], Parameter(query="type") ] = "plain", ) -> Response[str] | PairResponse: pair = await self.get_pair_service.run( group_uuid=group_uuid, participant=participant_name ) if response_type == "json": return PairResponse(pair=pair) return Response(content=pair, media_type=MediaType.TEXT) config = get_config() app = Litestar(route_handlers=[GroupController], debug=config.environment == "local")