diff --git a/api/app.py b/api/app.py deleted file mode 100644 index 6eb0a91..0000000 --- a/api/app.py +++ /dev/null @@ -1,46 +0,0 @@ -from collections.abc import AsyncIterable - -from fastapi import FastAPI -from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker - -from api.depends import ( # new_unit_of_work,; new_user_repository,; new_user_service, - create_engine, - create_session_maker, - new_session, -) -from api.models import BaseModel - - -async def lifespan(app: FastAPI) -> AsyncIterable[None]: - engine = app.dependency_overrides[AsyncEngine]() - - async with engine.begin() as conn: - await conn.run_sync(BaseModel.metadata.create_all) - - yield - - async with engine.begin() as conn: - await conn.run_sync(BaseModel.metadata.drop_all) - - -def init_dependencies(app: FastAPI) -> None: - app.dependency_overrides[AsyncEngine] = create_engine - app.dependency_overrides[async_sessionmaker[AsyncSession]] = create_session_maker - app.dependency_overrides[AsyncSession] = new_session - # app.dependency_overrides[UserRepository] = new_user_repository - # app.dependency_overrides[UnitOfWork] = new_unit_of_work - # app.dependency_overrides[UserService] = new_user_service - - -def create_app() -> FastAPI: - app = FastAPI( - lifespan=lifespan, - ) - - # app.include_router(user_router) - - init_dependencies(app) - return app - - -app = create_app() diff --git a/api/app_builder/__init__.py b/api/app_builder/__init__.py new file mode 100644 index 0000000..d46edad --- /dev/null +++ b/api/app_builder/__init__.py @@ -0,0 +1,3 @@ +from .main import app_factory + +__all__ = ("app_factory",) diff --git a/api/app_builder/main.py b/api/app_builder/main.py new file mode 100644 index 0000000..17db72d --- /dev/null +++ b/api/app_builder/main.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI + +from .routers import init_routers + + +def app_factory() -> FastAPI: + app = FastAPI() + init_routers(app) + return app diff --git a/api/app_builder/routers.py b/api/app_builder/routers.py new file mode 100644 index 0000000..f537b5c --- /dev/null +++ b/api/app_builder/routers.py @@ -0,0 +1,7 @@ +from fastapi import FastAPI + +from api.presentation.routers import healthcheck_router + + +def init_routers(app: FastAPI) -> None: + app.include_router(healthcheck_router) diff --git a/api/repositories/__init__.py b/api/application/__init__.py similarity index 100% rename from api/repositories/__init__.py rename to api/application/__init__.py diff --git a/api/application/contracts/healht_check/__init__.py b/api/application/contracts/healht_check/__init__.py new file mode 100644 index 0000000..a529436 --- /dev/null +++ b/api/application/contracts/healht_check/__init__.py @@ -0,0 +1,3 @@ +from .ping_response import PingResponse + +__all__ = ("PingResponse",) diff --git a/api/schemas/token_schema.py b/api/application/contracts/healht_check/ping_response.py similarity index 50% rename from api/schemas/token_schema.py rename to api/application/contracts/healht_check/ping_response.py index a4d8831..f780fca 100644 --- a/api/schemas/token_schema.py +++ b/api/application/contracts/healht_check/ping_response.py @@ -2,6 +2,5 @@ from dataclasses import dataclass @dataclass(frozen=True) -class TokenDTO: - access_token: str - token_type: str +class PingResponse: + status: str diff --git a/api/config.py b/api/config.py deleted file mode 100644 index c945de9..0000000 --- a/api/config.py +++ /dev/null @@ -1,47 +0,0 @@ -import os -from dataclasses import dataclass -from functools import lru_cache - -import yaml # type: ignore - - -@dataclass(frozen=True) -class DBSettings: - pg_user: str - pg_pass: str - pg_host: str - pg_port: int - pg_db: str - - @property - def db_url(self) -> str: - return "postgresql+asyncpg://{}:{}@{}:{}/{}".format( - self.pg_user, - self.pg_pass, - self.pg_host, - self.pg_port, - self.pg_db, - ) - - -@dataclass(frozen=True) -class RedisSettings: - redis_host: str - redis_port: int - - -@dataclass(frozen=True) -class Settings: - db: DBSettings - redis: RedisSettings - - -@lru_cache -def get_settings(): - with open(os.getenv("CONFIG_PATH", "./config/api_config.yml")) as f: - config_data: dict = yaml.safe_load(f) - - return Settings( - db=DBSettings(**config_data["db"]), - redis=RedisSettings(**config_data["redis"]), - ) diff --git a/api/depends.py b/api/depends.py deleted file mode 100644 index 5801a34..0000000 --- a/api/depends.py +++ /dev/null @@ -1,92 +0,0 @@ -from collections.abc import AsyncIterable, Callable -from typing import Annotated - -from fastapi import Depends -from sqlalchemy.ext.asyncio import ( - AsyncEngine, - AsyncSession, - async_sessionmaker, - create_async_engine, -) - -from api.config import get_settings - - -class Stub: - """ - This class is used to prevent fastapi from digging into - real dependencies attributes detecting them as request data - - So instead of - `interactor: Annotated[Interactor, Depends()]` - Write - `interactor: Annotated[Interactor, Depends(Stub(Interactor))]` - - And then you can declare how to create it: - `app.dependency_overrids[Interactor] = some_real_factory` - - """ - - def __init__(self, dependency: Callable, **kwargs): - self._dependency = dependency - self._kwargs = kwargs - - def __call__(self): - raise NotImplementedError - - def __eq__(self, other) -> bool: - if isinstance(other, Stub): - return self._dependency == other._dependency and self._kwargs == other._kwargs - else: - if not self._kwargs: - return self._dependency == other - return False - - def __hash__(self): - if not self._kwargs: - return hash(self._dependency) - serial = ( - self._dependency, - *self._kwargs.items(), - ) - return hash(serial) - - -# def new_user_repository( -# session: Annotated[AsyncSession, Depends(Stub(AsyncSession))], -# ) -> UserRepository: -# return SqlalchemyUserRepository(session) -# -# -# def new_unit_of_work( -# session: Annotated[AsyncSession, Depends(Stub(AsyncSession))], -# ) -> UnitOfWork: -# return SqlalchemyUnitOfWork(session) -# - - -def create_engine() -> AsyncEngine: - return create_async_engine(url=get_settings().db.db_url) - - -def create_session_maker( - engine: Annotated[AsyncEngine, Depends(Stub(AsyncEngine))], -) -> async_sessionmaker[AsyncSession]: - return async_sessionmaker(engine, expire_on_commit=False) - - -async def new_session( - session_maker: Annotated[ - async_sessionmaker[AsyncSession], - Depends(Stub(async_sessionmaker[AsyncSession])), - ], -) -> AsyncIterable[AsyncSession]: - async with session_maker() as session: - yield session - - -# def new_user_service( -# uow: Annotated[UnitOfWork, Depends()], -# user_repository: Annotated[UserRepository, Depends()], -# ) -> UserService: -# return UserService(uow, user_repository) diff --git a/api/models/__init__.py b/api/models/__init__.py deleted file mode 100644 index 099086c..0000000 --- a/api/models/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -from .base_model import BaseModel -from .refers_model import RefersModel -from .user_model import UserModel - -__all__ = ( - "BaseModel", - "UserModel", - "RefersModel", -) diff --git a/api/models/base_model.py b/api/models/base_model.py deleted file mode 100644 index ebba932..0000000 --- a/api/models/base_model.py +++ /dev/null @@ -1,13 +0,0 @@ -import uuid - -from sqlalchemy.dialects.postgresql import UUID -from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column - - -class BaseModel(DeclarativeBase): - __abstract__ = True - - id: Mapped[uuid.UUID] = mapped_column( - UUID(as_uuid=True), - primary_key=True, - ) diff --git a/api/models/refers_model.py b/api/models/refers_model.py deleted file mode 100644 index f2a5b42..0000000 --- a/api/models/refers_model.py +++ /dev/null @@ -1,18 +0,0 @@ -from uuid import UUID - -from sqlalchemy import ForeignKey -from sqlalchemy.orm import Mapped, mapped_column, relationship - -from api.models import BaseModel - - -class RefersModel(BaseModel): - __tablename__ = "refers" - - referer: Mapped[UUID] = mapped_column(ForeignKey("user.id")) - referals: Mapped[list["UserModel"]] = relationship( - "UserModel", - backref="refers", - lazy="selectin", - ) - is_active: Mapped[bool] diff --git a/api/models/user_model.py b/api/models/user_model.py deleted file mode 100644 index cf9db50..0000000 --- a/api/models/user_model.py +++ /dev/null @@ -1,11 +0,0 @@ -from sqlalchemy.orm import Mapped, mapped_column - -from api.models import BaseModel - - -class UserModel(BaseModel): - __tablename__ = "user" - - name: Mapped[str] - email: Mapped[str] = mapped_column(unique=True) - hashed_password: Mapped[str] diff --git a/api/routers/__init__.py b/api/presentation/__init__.py similarity index 100% rename from api/routers/__init__.py rename to api/presentation/__init__.py diff --git a/api/presentation/routers/__init__.py b/api/presentation/routers/__init__.py new file mode 100644 index 0000000..e568ca9 --- /dev/null +++ b/api/presentation/routers/__init__.py @@ -0,0 +1,3 @@ +from .ping import healthcheck_router + +__all__ = ("healthcheck_router",) diff --git a/api/presentation/routers/ping.py b/api/presentation/routers/ping.py new file mode 100644 index 0000000..334e183 --- /dev/null +++ b/api/presentation/routers/ping.py @@ -0,0 +1,13 @@ +from fastapi import APIRouter + +from api.application.contracts.healht_check import PingResponse + +healthcheck_router = APIRouter( + prefix="/ping", + tags=["HealthCheck"], +) + + +@healthcheck_router.get("/", status_code=200, response_model=PingResponse) +async def ping_pong() -> PingResponse: + return PingResponse(status="System OK") diff --git a/api/schemas/__init__.py b/api/schemas/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/api/schemas/refers_schema.py b/api/schemas/refers_schema.py deleted file mode 100644 index 3fe569b..0000000 --- a/api/schemas/refers_schema.py +++ /dev/null @@ -1,28 +0,0 @@ -from dataclasses import dataclass -from datetime import datetime -from uuid import UUID - - -@dataclass(frozen=True) -class LifetimeRequestDTO: - days: int = 0 - hours: int = 0 - minutes: int = 30 - - -@dataclass(frozen=True) -class ReferRequestDTO: - lifetime: LifetimeRequestDTO - - -@dataclass(frozen=True) -class RefererResponseDTO: - name: str - email: str - - -@dataclass(frozen=True) -class ReferResponseDTO: - refer_id: UUID - expire_at: datetime - referer: RefererResponseDTO diff --git a/api/schemas/user_schema.py b/api/schemas/user_schema.py deleted file mode 100644 index 2516b9c..0000000 --- a/api/schemas/user_schema.py +++ /dev/null @@ -1,16 +0,0 @@ -from dataclasses import dataclass -from uuid import UUID - - -@dataclass(frozen=True) -class UserRequestDTO: - name: str - email: str - password: str - - -@dataclass(frozen=True) -class UserResponseDTO: - id: UUID - name: str - email: str diff --git a/api/services/__init__.py b/api/services/__init__.py deleted file mode 100644 index b30026f..0000000 --- a/api/services/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .user import UserService - -__all__ = ("UserService",) diff --git a/api/uow/__init__.py b/api/uow/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/docker-compose.yml b/docker-compose.yml index 1b84ef5..c571f96 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -42,9 +42,9 @@ services: volumes: - ./config/api_config.yml:/usr/src/service_man/config/api_config.yml - ./api:/usr/src/service_man/api - - ./alembic.ini:/usr/src/service_man/alembic.ini + # - ./alembic.ini:/usr/src/service_man/alembic.ini - command: /bin/bash -c 'cd /usr/src/service_man && poetry run uvicorn api.app:create_app --host 0.0.0.0 --reload --factory' + command: /bin/bash -c 'cd /usr/src/service_man && poetry run uvicorn api.app_builder.main:app_factory --host 0.0.0.0 --reload --factory' # bot: # container_name: bot diff --git a/manage.py b/manage.py index 1f78bf2..ecc58d3 100644 --- a/manage.py +++ b/manage.py @@ -2,7 +2,7 @@ if __name__ == "__main__": import uvicorn uvicorn.run( - app="api.app:create_app", + app="api.app_builder.main:app_factory", host="0.0.0.0", port=8000, reload=True, diff --git a/tg_bot/app.py b/tg_bot/app.py deleted file mode 100644 index 78c61af..0000000 --- a/tg_bot/app.py +++ /dev/null @@ -1,7 +0,0 @@ -from fastapi import FastAPI - - -def create_app() -> FastAPI: - app = FastAPI() - - return app