diff --git a/shvatka/api/routes/game.py b/shvatka/api/routes/game.py index 3d5d113c..646ffe9d 100644 --- a/shvatka/api/routes/game.py +++ b/shvatka/api/routes/game.py @@ -1,10 +1,14 @@ +from typing import BinaryIO + from fastapi import APIRouter from fastapi.params import Depends, Path from shvatka.api.dependencies import dao_provider, player_provider, active_game_provider from shvatka.api.models import responses +from shvatka.core.interfaces.clients.file_storage import FileGateway from shvatka.core.models import dto -from shvatka.core.services.game import get_authors_games, get_completed_games, get_full_game +from shvatka.core.services.game import get_authors_games, get_completed_games, get_full_game, get_game +from shvatka.core.services.scenario.files import get_file_content from shvatka.infrastructure.db.dao.holder import HolderDao @@ -37,10 +41,22 @@ async def get_game_card( return responses.FullGame.from_core(game) +async def get_game_file( + dao: HolderDao = Depends(dao_provider), # type: ignore[assignment] + player: dto.Player = Depends(player_provider), # type: ignore[assignment] + id_: int = Path(alias="id"), # type: ignore[assignment] + guid: str = Path(alias="guid"), # type: ignore[assignment] + file_gateway: FileGateway = Depends(), +) -> BinaryIO: + game = await get_game(id_, dao=dao.game) + return await get_file_content(guid, file_gateway, player, game, dao.file_info) + + def setup() -> APIRouter: router = APIRouter(prefix="/games") router.add_api_route("", get_all_games, methods=["GET"]) router.add_api_route("/my", get_my_games_list, methods=["GET"]) router.add_api_route("/active", get_active_game, methods=["GET"]) router.add_api_route("/{id}", get_game_card, methods=["GET"]) + router.add_api_route("/{id}/files/{guid}", get_game_card, methods=["GET"]) return router diff --git a/shvatka/core/interfaces/dal/complex.py b/shvatka/core/interfaces/dal/complex.py index 78f72c5b..5cdd1d4f 100644 --- a/shvatka/core/interfaces/dal/complex.py +++ b/shvatka/core/interfaces/dal/complex.py @@ -1,6 +1,7 @@ from typing import Protocol from shvatka.core.interfaces.dal.base import Committer +from shvatka.core.interfaces.dal.file_info import FileInfoGetter from shvatka.core.interfaces.dal.game import ( MaxGameNumberGetter, GameNumberUpdater, @@ -44,9 +45,6 @@ class GameCompleter( pass -class GamePackager(GameKeyGetter, LevelTimesGetter, GameWaiversGetter, Protocol): +class GamePackager(GameKeyGetter, LevelTimesGetter, GameWaiversGetter, FileInfoGetter, Protocol): async def get_full(self, id_: int) -> dto.FullGame: raise NotImplementedError - - async def get_by_guid(self, guid: str) -> scn.VerifiableFileMeta: - raise NotImplementedError diff --git a/shvatka/core/interfaces/dal/file_info.py b/shvatka/core/interfaces/dal/file_info.py index 1bbf1980..f32d625b 100644 --- a/shvatka/core/interfaces/dal/file_info.py +++ b/shvatka/core/interfaces/dal/file_info.py @@ -1,8 +1,14 @@ from typing import Protocol from shvatka.core.models import dto +from shvatka.core.models.dto import scn class FileInfoMerger(Protocol): async def replace_file_info(self, primary: dto.Player, secondary: dto.Player) -> None: raise NotImplementedError + + +class FileInfoGetter(Protocol): + async def get_by_guid(self, guid: str) -> scn.VerifiableFileMeta: + raise NotImplementedError diff --git a/shvatka/core/services/scenario/files.py b/shvatka/core/services/scenario/files.py index 48de87b1..0b360674 100644 --- a/shvatka/core/services/scenario/files.py +++ b/shvatka/core/services/scenario/files.py @@ -1,7 +1,7 @@ from typing import BinaryIO, Sequence from shvatka.core.interfaces.clients.file_storage import FileGateway -from shvatka.core.interfaces.dal.complex import GamePackager +from shvatka.core.interfaces.dal.file_info import FileInfoGetter from shvatka.core.interfaces.dal.game import GameUpserter from shvatka.core.models import dto from shvatka.core.models.dto import scn @@ -24,7 +24,7 @@ async def upsert_files( async def get_file_metas( - game: dto.FullGame, author: dto.Player, dao: GamePackager + game: dto.FullGame, author: dto.Player, dao: FileInfoGetter ) -> Sequence[scn.FileMeta]: file_metas: list[scn.FileMeta] = [] for guid in game.get_guids(): @@ -44,6 +44,14 @@ async def get_file_contents( return contents +async def get_file_content( + guid: str, file_gateway: FileGateway, author: dto.Player, game: dto.Game, dao: FileInfoGetter +) -> BinaryIO: + meta = await dao.get_by_guid(guid) + check_file_meta_can_read(author, meta, game) + return await file_gateway.get(meta) + + def check_file_meta_can_read( author: dto.Player, file_meta: scn.VerifiableFileMeta, game: dto.Game ):