Skip to content

Commit

Permalink
Merge pull request #7 from The-Galley/develop
Browse files Browse the repository at this point in the history
Release 0.2.2
  • Loading branch information
andy-takker authored Mar 2, 2024
2 parents aa8b7ba + 3bb2004 commit 641f4c5
Show file tree
Hide file tree
Showing 18 changed files with 106 additions and 12 deletions.
16 changes: 11 additions & 5 deletions industry_game/handlers/games/lobby/read_lobby.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from aiohttp.web import HTTPNotFound, Response, View
from aiohttp.web import Response, View

from industry_game.utils.http.auth.base import (
AuthMixin,
Expand All @@ -7,14 +7,20 @@
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
from industry_game.utils.lobby.models import LobbyStatus, LobbyStatusType


class ReadGameUserLobbyHandler(View, DependenciesMixin, AuthMixin):
@require_player_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)
if game is None:
raise HTTPNotFound
return msgspec_json_response(game)
lobby = await self.lobby_storage.read_by_id(
game_id=game_id,
user_id=self.user.id,
)
if lobby is None:
status = LobbyStatusType.NOT_CHECKED_IN
else:
status = LobbyStatusType.CHECKED_IN
return msgspec_json_response(LobbyStatus(status=status))
12 changes: 12 additions & 0 deletions industry_game/utils/lobby/models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from enum import StrEnum, unique

import msgspec

from industry_game.db.models import UserGameLobby as UserGameLobbyDb
Expand All @@ -20,3 +22,13 @@ def from_model(cls, obj: UserGameLobbyDb) -> "Lobby":
class LobbyPagination(msgspec.Struct, frozen=True):
meta: MetaPagination
items: list[ShortUser]


@unique
class LobbyStatusType(StrEnum):
CHECKED_IN = "CHECKED_IN"
NOT_CHECKED_IN = "NOT_CHECKED_IN"


class LobbyStatus(msgspec.Struct, frozen=True):
status: StrEnum
8 changes: 5 additions & 3 deletions 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, ConfigDict
from pydantic import BaseModel, ConfigDict, Field

from industry_game.utils.msgspec import CustomStruct

Expand All @@ -11,8 +11,10 @@ class UserType(StrEnum):


class RegisterPlayerModel(BaseModel):
username: str
password: str
username: str = Field(min_length=8)
password: str = Field(min_length=8)
telegram: str = Field(min_length=2)
name: str = Field(min_length=5)


class AuthUserModel(BaseModel):
Expand Down
4 changes: 4 additions & 0 deletions industry_game/utils/users/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,15 @@ class FullUser(CustomStruct, frozen=True):
id: int
type: UserType
username: str
telegram: str
name: str

@classmethod
def from_model(self, obj: UserDb) -> "FullUser":
return FullUser(
id=obj.id,
type=obj.type,
username=obj.username,
telegram=obj.properties.get("telegram", ""),
name=obj.properties.get("name", ""),
)
4 changes: 4 additions & 0 deletions industry_game/utils/users/processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ async def register(self, player: RegisterPlayerModel) -> AuthToken:
user = await self.player_storage.create(
username=player.username,
password_hash=self.passgen.hashpw(player.password),
properties={
"telegram": player.telegram,
"name": player.name,
},
)
token = self.authorization_provider.generate_token(user=user)
return AuthToken(token=token)
Expand Down
8 changes: 4 additions & 4 deletions industry_game/utils/users/storage.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import asyncio
from collections.abc import Mapping

from sqlalchemy import func, insert, select
from sqlalchemy.ext.asyncio import AsyncSession
Expand All @@ -18,13 +19,15 @@ async def create(
*,
username: str,
password_hash: str,
properties: Mapping[str, str],
commit: bool = True,
) -> FullUser:
stmt = (
insert(UserDb)
.values(
username=username,
password_hash=password_hash,
properties=properties,
)
.returning(UserDb)
)
Expand All @@ -50,10 +53,7 @@ async def read_by_username(
session: AsyncSession,
username: str,
) -> FullUser | None:
stmt = select(UserDb).where(
UserDb.type == UserType.PLAYER,
UserDb.username == username,
)
stmt = select(UserDb).where(UserDb.username == username)
obj = (await session.scalars(stmt)).first()
return FullUser.from_model(obj) if obj else None

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
66 changes: 66 additions & 0 deletions tests/api/players/test_player_register.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
from http import HTTPStatus

import pytest
from aiohttp.test_utils import TestClient
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from yarl import URL

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

API_URL = URL("/api/v1/players/register/")


async def test_player_register_successful_status_created(
api_client: TestClient,
):
response = await api_client.post(
API_URL,
json={
"username": "username",
"password": "password",
"telegram": "telegram",
"name": "your name",
},
)
assert response.status == HTTPStatus.CREATED


async def test_player_register_successful_check_db(
api_client: TestClient,
session: AsyncSession,
):
await api_client.post(
API_URL,
json={
"username": "username",
"password": "password",
"telegram": "telegram",
"name": "your name",
},
)
user = (
await session.scalars(select(User).where(User.username == "username"))
).one()

assert user.username == "username"
assert user.type == UserType.PLAYER


@pytest.mark.parametrize("user_type", (UserType.ADMIN, UserType.PLAYER))
async def test_player_register_same_username_error_conflict(
api_client: TestClient, create_user, user_type
):
user = await create_user(type=user_type)

response = await api_client.post(
API_URL,
json={
"username": user.username,
"password": "password",
"telegram": "telegram",
"name": "your name",
},
)
assert response.status == HTTPStatus.BAD_REQUEST
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 comments on commit 641f4c5

Please sign in to comment.