Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .idea/.gitignore

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

25 changes: 25 additions & 0 deletions .idea/inspectionProfiles/Project_Default.xml

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

6 changes: 6 additions & 0 deletions .idea/inspectionProfiles/profiles_settings.xml

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

8 changes: 8 additions & 0 deletions .idea/minecraft.iml

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

7 changes: 7 additions & 0 deletions .idea/misc.xml

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

8 changes: 8 additions & 0 deletions .idea/modules.xml

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

6 changes: 6 additions & 0 deletions .idea/vcs.xml

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

3 changes: 3 additions & 0 deletions server/.env.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
DATABASE_URL="sqlite+aiosqlite:///./database.sqlite3"
JWT_ALG='HS256'
JWT_KEY='JWT_KEY'
2 changes: 1 addition & 1 deletion server/README.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
pip install --index-url http://packages.webflare.ru:8888/simple --trusted-host packages.webflare.ru pyjwt
pip install --index-url http://packages.webflare.ru:8888/simple --trusted-host packages.webflare.ru uv
Empty file added server/__init__.py
Empty file.
32 changes: 32 additions & 0 deletions server/src/application/interface/server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from collections.abc import Sequence
from typing import Protocol
from uuid import UUID

from sqlalchemy.ext.asyncio import AsyncSession

from server.src.application.rest.v1.schemas.server import CreateServerDTO, UpdateServerDTO, \
FetchListParamsDTO
from server.src.core.database.table import Server


class IServerService(Protocol):
async def fetch_list(
self, input_dto: FetchListParamsDTO
) -> Sequence[Server]: ...


async def fetch_by_id(
self, input_dto: UUID
) -> Server: ...

async def create(
self, input_dto: CreateServerDTO
) -> Server: ...

async def update(
self, input_dto: tuple[UUID, UpdateServerDTO]
) -> Server: ...

async def delete(
self, input_dto: UUID
) -> None: ...
7 changes: 7 additions & 0 deletions server/src/application/rest/di.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from server.src.application.interface.server import IServerService
from server.src.application.use_case.server import ServerService
from server.src.core.database.di import db


def get_server_service() -> IServerService:
return ServerService(provider=db)
12 changes: 12 additions & 0 deletions server/src/application/rest/schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from pydantic import BaseModel, ConfigDict, Field


class BaseDTO(BaseModel):
model_config = ConfigDict(
from_attributes=True
)


class PaginationDTO(BaseDTO):
limit: int = Field(ge=10, le=100, default=10)
offset: int = Field(ge=0, le=100, default=0)
81 changes: 81 additions & 0 deletions server/src/application/rest/v1/api/server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
from collections.abc import Sequence
from http import HTTPStatus
from uuid import UUID

from fastapi import APIRouter, Depends
from fastapi.params import Query

from server.src.application.interface.server import IServerService
from server.src.application.rest.di import get_server_service
from server.src.application.rest.v1.schemas.server import ServerDTO, FetchListParamsDTO, CreateServerDTO, \
UpdateServerDTO

router = APIRouter(prefix="/servers", tags=["Server"])


@router.get(
path="/",
response_model=Sequence[ServerDTO],
status_code=HTTPStatus.OK
)
async def fetch_list(
params: FetchListParamsDTO = Query(),
service: IServerService = Depends(get_server_service)
) -> Sequence[ServerDTO]:
result = service.fetch_list(input_dto=params)
return [ServerDTO.model_validate(result)]


@router.get(
path="/{server_id}",
response_model=ServerDTO,
status_code=HTTPStatus.OK
)
async def fetch_by_id(
server_id: UUID,
service: IServerService = Depends(get_server_service)
) -> ServerDTO:
result = service.fetch_by_id(input_dto=server_id)
return ServerDTO.model_validate(result)


@router.post(
path="/",
response_model=ServerDTO,
status_code=HTTPStatus.CREATED
)
async def create(
create_data: CreateServerDTO,
service: IServerService = Depends(get_server_service)
) -> ServerDTO:
result = service.create(input_dto=create_data)
return ServerDTO.model_validate(result)


@router.put(
path="/{server_id}",
response_model=ServerDTO,
status_code=HTTPStatus.OK
)
async def update(
server_id: UUID,
update_data: UpdateServerDTO,
service: IServerService = Depends(get_server_service)
) -> ServerDTO:
result = service.update(
input_dto=(server_id, update_data)
)
return ServerDTO.model_validate(result)


@router.delete(
path="/{server_id}",
response_model=ServerDTO,
status_code=HTTPStatus.NO_CONTENT
)
async def delete(
server_id: UUID,
service: IServerService = Depends(get_server_service)
) -> ServerDTO:
result = service.delete(input_dto=server_id)
return ServerDTO.model_validate(result)
52 changes: 52 additions & 0 deletions server/src/application/rest/v1/schemas/server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from enum import Enum
from pydantic import HttpUrl, Field, IPvAnyAddress, constr
from server.src.application.rest.schemas import BaseDTO, PaginationDTO


class ServerStatus(Enum):
ONLINE = "online"
OFFLINE = "offline"


class ServerDTO(BaseDTO):
id: int
img_url: HttpUrl | None
name: str
domain: str
ip_address: IPvAnyAddress
port: int
version: str
max_players: int
online_players: int
status: ServerStatus
type: str


class CreateServerDTO(BaseDTO):
img_url: HttpUrl | None = Field(default=None)
name: str = Field(min_length=5, max_length=100)
domain: str
ip_address: IPvAnyAddress
port: int = Field(default=25565)
version: constr(pattern=r'^\d+\.\d+(\.\d+)?$')
max_players: int = Field(ge=1)
online_players: int = Field(ge=0)
status: ServerStatus = Field(default=ServerStatus.ONLINE)
type: str


class UpdateServerDTO(BaseDTO):
img_url: HttpUrl | None = Field(default=None)
name: str | None = Field(min_length=5, max_length=100)
domain: str | None
ip_address: IPvAnyAddress | None
port: int | None
version: constr(pattern=r'^\d+\.\d+(\.\d+)?$') | None
max_players: int = Field(ge=1) | None
online_players: int = Field(ge=0) | None
status: ServerStatus | None
type: str | None


class FetchListParamsDTO(PaginationDTO):
pass
68 changes: 68 additions & 0 deletions server/src/application/use_case/server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from collections.abc import Sequence
from uuid import UUID
from sqlalchemy import select, delete, insert, update

from server.src.application.interface.server import IServerService
from server.src.application.rest.v1.schemas.server import CreateServerDTO, UpdateServerDTO, \
FetchListParamsDTO
from server.src.core.database.di import DBProvaider
from server.src.core.database.table import Server


class ServerService(IServerService):

def __init__(
self, provider: DBProvaider
) -> None:
self.session = provider.session

async def fetch_list(
self, input_dto: FetchListParamsDTO
) -> Sequence[Server]:
query = (
select(Server)
.offset(input_dto.offset)
.limit(input_dto.limit)
)
return (await self.session.scalars(query)).all()

async def fetch_by_id(
self, input_dto: UUID
) -> Server:
query = (
select(Server)
.where(Server.id == input_dto)
)
return (await self.session.scalars(query)).one()

async def create(
self, input_dto: CreateServerDTO
) -> Server:
stmt = (
insert(Server)
.values(
input_dto.model_dump()
)
.returning(Server)
)
return (await self.session.scalars(stmt)).one()

async def update(
self, input_dto: tuple[UUID, UpdateServerDTO]
) -> Server:
server_id, update_data = input_dto
stmt = (
update(Server)
.where(Server.id == server_id)
.values(**update_data.model_dump(
exclude_unset=True
))
.returning(Server)
)
return (await self.session.scalars(stmt)).one()

async def delete(
self, input_dto: UUID
) -> None:
stmt = delete(Server).where(Server.id == input_dto)
await self.session.execute(stmt)
14 changes: 14 additions & 0 deletions server/src/core/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from pydantic_settings import BaseSettings, SettingsConfigDict


class Settings(BaseSettings):
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
extra="ignore"
)
DATABASE_URL: str ="sqlite+aiosqlite:///./database.sqlite3"
JWT_ALG: str ='HS256'
JWT_KEY: str ='JWT_KEY'

settings = Settings()
27 changes: 27 additions & 0 deletions server/src/core/database/di.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from src.core.database.utils import Database
from src.core.config import settings, Settings

class DBProvaider:
serves: Database = Database()
settings: Settings = settings

serves.create_engine(
settings.DATABASE_URL,
)

serves.create_session()

session = serves.session
async def get_session(self):
async with self.session as session:
try:
yield session
await session.flush()
except Exception as e:
await session.rollback()
raise e
finally:
await session.close()


db = DBProvaider()
Loading