Skip to content

Commit

Permalink
Add release workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
andy-takker committed Mar 2, 2024
1 parent 4207c62 commit 2f54f65
Show file tree
Hide file tree
Showing 24 changed files with 268 additions and 81 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
tags: |
andytakker/industry-game-rest:latest
andytakker/vk-parser:${{ steps.vars.outputs.sha_short }}
- name: Build and push frontend image
uses: docker/build-push-action@v5
with:
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
from aiohttp.web_exceptions import HTTPNotFound
from aiohttp.web_response import Response

from industry_game.utils.http.auth.base import require_authorization
from industry_game.utils.http.auth.base import AuthMixin, require_authorization
from industry_game.utils.http.deps import DependenciesMixin
from industry_game.utils.http.params import parse_path_param
from industry_game.utils.http.response import msgspec_json_response


class ReadByIdGameHandler(View, DependenciesMixin):
class GameDetailsHandler(View, DependenciesMixin, AuthMixin):
@require_authorization
async def get(self) -> Response:
game_id = parse_path_param(self.request, "game_id", int)
Expand Down
File renamed without changes.
File renamed without changes.
7 changes: 5 additions & 2 deletions industry_game/handlers/games/lobby/list_lobby.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from aiohttp.web import HTTPNotFound, Response, View

from industry_game.utils.http.auth.base import AuthMixin, require_authorization
from industry_game.utils.http.auth.base import (
AuthMixin,
require_admin_authorization,
)
from industry_game.utils.http.deps import DependenciesMixin
from industry_game.utils.http.params import (
PaginationParamsModel,
Expand All @@ -11,7 +14,7 @@


class ListGameLobbyHandler(View, DependenciesMixin, AuthMixin):
@require_authorization
@require_admin_authorization
async def get(self) -> Response:
game_id = parse_path_param(self.request, "game_id", int)
game = await self.game_storage.read_by_id(game_id=game_id)
Expand Down
3 changes: 1 addition & 2 deletions industry_game/handlers/ping.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import asyncio
import logging
from http import HTTPStatus

Expand All @@ -17,7 +16,7 @@ class PingHandler(View, DependenciesMixin):
async def get(self) -> Response:
try:
db = await self._ping()
except asyncio.TimeoutError:
except TimeoutError:
db = False
deps = {
"db": db,
Expand Down
2 changes: 1 addition & 1 deletion industry_game/handlers/players/login_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ async def parse_player_model(self) -> AuthUserModel:
try:
return AuthUserModel.model_validate_json(body)
except ValidationError:
raise HTTPBadRequest
raise HTTPBadRequest(reason="Incorrect user auth data")
8 changes: 4 additions & 4 deletions industry_game/services/rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
from yarl import URL

from industry_game.handlers.games.create_game import CreateGameHandler
from industry_game.handlers.games.list_game import ListGameHandler
from industry_game.handlers.games.game_details import GameDetailsHandler
from industry_game.handlers.games.game_list import ListGameHandler
from industry_game.handlers.games.game_update import UpdateGameHandler
from industry_game.handlers.games.lobby.add_user_to_lobby import (
AddUserToGameLobbyHandler,
)
Expand All @@ -22,8 +24,6 @@
from industry_game.handlers.games.lobby.read_lobby import (
ReadGameUserLobbyHandler,
)
from industry_game.handlers.games.read_by_id_game import ReadByIdGameHandler
from industry_game.handlers.games.update_game import UpdateGameHandler
from industry_game.handlers.ping import PingHandler
from industry_game.handlers.players.list_player import ListPlayerHandler
from industry_game.handlers.players.login_player import LoginPlayerHandler
Expand Down Expand Up @@ -83,7 +83,7 @@ class REST(AIOHTTPService):
# game handlers
(hdrs.METH_GET, "/api/v1/games/", ListGameHandler),
(hdrs.METH_POST, "/api/v1/games/", CreateGameHandler),
(hdrs.METH_GET, "/api/v1/games/{game_id}/", ReadByIdGameHandler),
(hdrs.METH_GET, "/api/v1/games/{game_id}/", GameDetailsHandler),
(hdrs.METH_POST, "/api/v1/games/{game_id}/", UpdateGameHandler),
# lobby handlers
(hdrs.METH_GET, "/api/v1/games/{game_id}/lobby/", ListGameLobbyHandler),
Expand Down
3 changes: 2 additions & 1 deletion industry_game/utils/lobby/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from industry_game.db.models import UserGameLobby as UserGameLobbyDb
from industry_game.utils.pagination import MetaPagination
from industry_game.utils.users.models import ShortUser


class Lobby(msgspec.Struct, frozen=True):
Expand All @@ -18,4 +19,4 @@ def from_model(cls, obj: UserGameLobbyDb) -> "Lobby":

class LobbyPagination(msgspec.Struct, frozen=True):
meta: MetaPagination
items: list[Lobby]
items: list[ShortUser]
11 changes: 7 additions & 4 deletions industry_game/utils/lobby/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
from sqlalchemy import delete, func, insert, select
from sqlalchemy.ext.asyncio import AsyncSession

from industry_game.db.models import User as UserDb
from industry_game.db.models import UserGameLobby as UserGameLobbyDb
from industry_game.utils.db import AbstractStorage, inject_session
from industry_game.utils.lobby.models import Lobby, LobbyPagination
from industry_game.utils.pagination import MetaPagination
from industry_game.utils.users.models import ShortUser


class LobbyStorage(AbstractStorage):
Expand Down Expand Up @@ -80,16 +82,17 @@ async def count(self, session: AsyncSession) -> int:
@inject_session
async def get_items(
self, session: AsyncSession, game_id: int, page: int, page_size: int
) -> list[Lobby]:
) -> list[ShortUser]:
query = (
select(UserGameLobbyDb)
select(UserDb)
.join(UserGameLobbyDb, UserDb.id == UserGameLobbyDb.user_id)
.where(UserGameLobbyDb.game_id == game_id)
.limit(page_size)
.offset((page - 1) * page_size)
)

games = await session.scalars(query)
items: list[Lobby] = []
items: list[ShortUser] = []
for game in games:
items.append(Lobby.from_model(game))
items.append(ShortUser.from_model(game))
return items
7 changes: 6 additions & 1 deletion industry_game/utils/timer.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ class Timer:
_end_time: float | None
_task: asyncio.Task | None

def __init__(self, coroutine: Awaitable, seconds: float, speed: float = 1) -> None:
def __init__(
self,
coroutine: Awaitable,
seconds: float,
speed: float = 1,
) -> None:
self._coroutine = coroutine
self._seconds = seconds
self._re_seconds = seconds
Expand Down
4 changes: 3 additions & 1 deletion industry_game/utils/users/base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from enum import StrEnum

from pydantic import BaseModel
from pydantic import BaseModel, ConfigDict

from industry_game.utils.msgspec import CustomStruct

Expand All @@ -16,6 +16,8 @@ class RegisterPlayerModel(BaseModel):


class AuthUserModel(BaseModel):
model_config = ConfigDict(str_min_length=8)

username: str
password: str

Expand Down
1 change: 0 additions & 1 deletion industry_game/utils/users/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ async def get_by_username_and_password_hash(
password_hash: str,
) -> FullUser | None:
stmt = select(UserDb).where(
UserDb.type == UserType.PLAYER,
UserDb.username == username,
UserDb.password_hash == password_hash,
)
Expand Down
56 changes: 25 additions & 31 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pre-commit = "^3.6.0"
bandit = "^1.7.7"
ruff = "^0.2.0"
aiomisc-pytest = "^1.1.1"
polyfactory = "^2.14.1"
factory-boy = "^3.3.0"

[build-system]
requires = ["poetry-core"]
Expand Down
29 changes: 14 additions & 15 deletions tests/plugins/factories/games.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,31 @@
from collections.abc import Callable
from datetime import UTC, datetime

import factory
import pytest
from polyfactory.factories.sqlalchemy_factory import SQLAlchemyFactory
from sqlalchemy.ext.asyncio import AsyncSession

from industry_game.db.models import Game, User
from industry_game.db.models import Game
from industry_game.utils.users.base import UserType
from tests.plugins.factories.users import UserFactory


def utc_now() -> datetime:
return datetime.now(tz=UTC)
class GameFactory(factory.Factory):
class Meta:
model = Game


class GameFactory(SQLAlchemyFactory[Game]):
__set_primary_key__ = False
__set_foreign_keys__ = False
__use_defaults__ = True

created_at = utc_now
updated_at = utc_now
id = factory.Sequence(lambda n: n + 1)
name = "New game"
description = "New game description"
finished_at = None
started_at = None

created_by = factory.SubFactory(UserFactory, type=UserType.ADMIN)


@pytest.fixture
def create_game(session: AsyncSession) -> Callable:
async def factory(created_by: User, **kwargs) -> Game:
game = GameFactory.build(created_by=created_by, **kwargs)
async def factory(**kwargs) -> Game:
game = GameFactory(**kwargs)
session.add(game)
await session.commit()
await session.flush(game)
Expand Down
30 changes: 19 additions & 11 deletions tests/plugins/factories/users.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,41 @@
from collections.abc import Callable
from typing import Any

import factory
import pytest
from polyfactory.factories.sqlalchemy_factory import SQLAlchemyFactory
from sqlalchemy.ext.asyncio import AsyncSession

from industry_game.db.models import User
from industry_game.utils.security import Passgen
from industry_game.utils.users.base import UserType


def empty_properties() -> dict[str, Any]:
return dict()
class UserPropertiesFactory(factory.Factory):
class Meta:
model = dict

name = "First Last Name"
telegram = "@tg_username"

class UserFactory(SQLAlchemyFactory[User]):
__set_primary_key__ = False

properties = empty_properties
class UserFactory(factory.Factory):
class Meta:
model = User

id = factory.Sequence(lambda n: n + 1)
username = "username"
type = UserType.PLAYER
password_hash = ""
properties = factory.SubFactory(UserPropertiesFactory)


@pytest.fixture
def create_user(session: AsyncSession, passgen: Passgen) -> Callable:
async def factory(**kwargs) -> User:
password = "secret"
password = kwargs.get("password", "secret00")
if "password" in kwargs:
password = kwargs["password"]
del kwargs["password"]
password_hash = passgen.hashpw(password)
user = UserFactory.build(**kwargs, password_hash=password_hash)
kwargs["password_hash"] = passgen.hashpw(password)
user = UserFactory(**kwargs)
session.add(user)
await session.commit()
await session.flush(user)
Expand Down
Loading

0 comments on commit 2f54f65

Please sign in to comment.