Skip to content

Commit

Permalink
Levels count (#86)
Browse files Browse the repository at this point in the history
* #79 added levels count for game scn

* added levels count

* added test

* fixed liner

* added more attentionable info about no levels

* added level count preview for dialogs preview

---------

Co-authored-by: ychebyshev <[email protected]>
  • Loading branch information
bomzheg and ychebyshev authored Jun 6, 2024
1 parent 1dd9b90 commit fdae4f2
Show file tree
Hide file tree
Showing 11 changed files with 75 additions and 9 deletions.
5 changes: 5 additions & 0 deletions shvatka/core/interfaces/dal/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ async def get_all_by_author(self, author: dto.Player) -> list[dto.Game]:
raise NotImplementedError


class PreviewGameByIdGetter(Protocol):
async def get_preview(self, id_: int, author: dto.Player | None = None) -> dto.PreviewGame:
raise NotImplementedError


class GameByIdGetter(Protocol):
async def get_by_id(self, id_: int, author: dto.Player | None = None) -> dto.Game:
raise NotImplementedError
Expand Down
2 changes: 1 addition & 1 deletion shvatka/core/models/dto/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from .common import DateRange
from .forum_team import ForumTeam
from .forum_user import ForumUser
from .game import Game, FullGame, GameResults
from .game import Game, PreviewGame, FullGame, GameResults
from .level import Level
from .level_testing import (
LevelTestSuite,
Expand Down
19 changes: 19 additions & 0 deletions shvatka/core/models/dto/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,25 @@ def to_full_game(self, levels: list[Level]) -> FullGame:
)


@dataclass
class PreviewGame(Game):
levels_count: int

@classmethod
def from_game(cls, self: Game, levels_count: int) -> PreviewGame:
return cls(
id=self.id,
author=self.author,
name=self.name,
status=self.status,
start_at=self.start_at,
results=self.results,
manage_token=self.manage_token,
number=self.number,
levels_count=levels_count,
)


@dataclass
class FullGame(Game):
levels: list[Level] = field(default_factory=list)
Expand Down
7 changes: 7 additions & 0 deletions shvatka/core/services/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
GameNameChecker,
GameRenamer,
CompletedGameFinder,
PreviewGameByIdGetter,
)
from shvatka.core.interfaces.dal.level import LevelLinker
from shvatka.core.interfaces.scheduler import Scheduler
Expand Down Expand Up @@ -104,6 +105,12 @@ async def get_game(id_: int, *, author: dto.Player | None = None, dao: GameByIdG
return await dao.get_by_id(id_=id_, author=author)


async def get_preview_game(
id_: int, *, author: dto.Player | None = None, dao: PreviewGameByIdGetter
) -> dto.PreviewGame:
return await dao.get_preview(id_=id_, author=author)


async def get_full_game(id_: int, author: dto.Player, dao: GameByIdGetter) -> dto.FullGame:
game = await dao.get_full(id_=id_)
check_can_read(game, author)
Expand Down
7 changes: 7 additions & 0 deletions shvatka/infrastructure/db/dao/rdb/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ async def get_by_id(self, id_: int, author: dto.Player | None = None) -> dto.Gam
raise GameHasAnotherAuthor(game_id=game.id, player=author)
return game.to_dto(author)

async def get_preview(self, id_: int, author: dto.Player | None = None) -> dto.PreviewGame:
game = await self.get_by_id(id_, author)
levels: ScalarResult[int] = await self.session.scalars(
select(models.Level.id).where(models.Level.game_id == id_)
)
return dto.PreviewGame.from_game(game, levels_count=len(levels.all()))

async def get_all_by_author(self, author: dto.Player) -> list[dto.Game]:
result: ScalarResult[models.Game] = await self.session.scalars(
select(models.Game).where(
Expand Down
15 changes: 10 additions & 5 deletions shvatka/infrastructure/db/models/level.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import typing
from typing import Any

from dataclass_factory import Factory
Expand All @@ -9,6 +10,10 @@
from shvatka.core.models.dto.scn.level import LevelScenario
from shvatka.infrastructure.db.models import Base

if typing.TYPE_CHECKING:
from .game import Game
from .player import Player


class ScenarioField(TypeDecorator):
impl = JSON
Expand All @@ -33,15 +38,15 @@ class Level(Base):
__tablename__ = "levels"
__mapper_args__ = {"eager_defaults": True}
id = mapped_column(Integer, primary_key=True)
name_id = mapped_column(Text, nullable=False)
game_id = mapped_column(ForeignKey("games.id"), nullable=True)
game = relationship(
name_id: Mapped[str] = mapped_column(Text, nullable=False)
game_id: Mapped[int] = mapped_column(ForeignKey("games.id"), nullable=True)
game: Mapped["Game"] = relationship(
"Game",
foreign_keys=game_id,
back_populates="levels",
)
author_id = mapped_column(ForeignKey("players.id"), nullable=False)
author = relationship(
author_id: Mapped[int] = mapped_column(ForeignKey("players.id"), nullable=False)
author: Mapped["Player"] = relationship(
"Player",
foreign_keys=author_id,
back_populates="my_levels",
Expand Down
5 changes: 5 additions & 0 deletions shvatka/tgbot/dialogs/game_manage/dialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,11 @@
Jinja(
"Выбрана игра: <b>{{game.name}}</b> с ID {{game.id}}\n"
"Текущий статус: <b>{{game.status}}</b>\n"
"{% if game.levels_count %}"
"Количество уровней: <b>{{game.levels_count}}</b>\n"
"{% else %}"
"\n\n❗️<b><u>В игре ещё нет ни одного уровня!</u></b>❗️\n\n"
"{% endif %}"
"Дата и время начала: {% if game.start_at %} "
"{{ game.start_at|user_timezone }} "
"{% else %} "
Expand Down
2 changes: 1 addition & 1 deletion shvatka/tgbot/dialogs/game_manage/getters.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ async def get_game(dao: HolderDao, player: dto.Player, dialog_manager: DialogMan
or dialog_manager.start_data["my_game_id"]
)
return {
"game": await game.get_game(
"game": await game.get_preview_game(
id_=game_id,
author=player,
dao=dao.game,
Expand Down
2 changes: 1 addition & 1 deletion shvatka/tgbot/dialogs/game_scn/dialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@

game_editor = Dialog(
Window(
Jinja("Игра <b>{{game.name}}</b>\n\n"),
Jinja("Игра <b>{{game.name}}</b> содержит {{ levels | length }} уровней.\n\n"),
Const("<b>Уровни игры</b>"),
SwitchTo(
Const("📑Добавить уровень"),
Expand Down
3 changes: 2 additions & 1 deletion shvatka/tgbot/dialogs/preview_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
is_dummy=False,
)

PREVIEW_GAME = dto.Game(
PREVIEW_GAME = dto.PreviewGame(
id=1,
author=PREVIEW_AUTHOR,
name="Схватка это чудо",
Expand All @@ -31,6 +31,7 @@
keys_url=None,
),
number=1,
levels_count=13,
)
TIMES_PRESET = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60]
RENDERED_HINTS_PREVIEW = "0: 📃🪪\n10: 📃\n10: 📃\n15: 📃\n20: 📃\n25: 🪪\n30: 📡\n45: 📃"
17 changes: 17 additions & 0 deletions tests/integration/test_game.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,23 @@ async def test_game_get_full(
assert game_expected == game_actual


@pytest.mark.asyncio
async def test_game_get_preview(
author: dto.Player,
simple_scn: RawGameScenario,
dao: HolderDao,
dcf: Factory,
file_gateway: FileGateway,
):
game_expected = await upsert_game(simple_scn, author, dao.game_upserter, dcf, file_gateway)
game_actual = await dao.game.get_preview(game_expected.id)
assert len(game_expected.levels) == game_actual.levels_count
assert game_expected.id == game_actual.id
assert game_expected.name == game_actual.name
assert game_expected.status == game_actual.status
assert game_expected.author == game_actual.author


@pytest.mark.asyncio
async def test_cant_change_finished(finished_game: dto.FullGame, dao: HolderDao):
level = finished_game.levels[0]
Expand Down

0 comments on commit fdae4f2

Please sign in to comment.