Skip to content

Commit

Permalink
chore: all endpoints created
Browse files Browse the repository at this point in the history
  • Loading branch information
fivan999 committed Oct 31, 2024
1 parent ace17ac commit 7ba7d2d
Show file tree
Hide file tree
Showing 11 changed files with 95 additions and 19 deletions.
File renamed without changes.
Empty file removed src/api/dependencies/__init__.py
Empty file.
2 changes: 1 addition & 1 deletion src/modules/users/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

from fastapi import Depends

from src.api.dependencies.db import DbSessionDep
from src.modules.users.repository import SqlUserRepository
from src.storages.sql.dependencies import DbSessionDep


async def get_sql_user_repository(db_session: DbSessionDep) -> SqlUserRepository:
Expand Down
2 changes: 1 addition & 1 deletion src/modules/users/routes.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from fastapi import APIRouter

from src.api.dependencies.auth import CurrentUserIdDep
from src.api.dependencies import CurrentUserIdDep
from src.api.exceptions import IncorrectCredentialsException
from src.modules.users.dependencies import SqlUserRepositoryDep
from src.modules.users.schemes import ViewUserScheme
Expand Down
2 changes: 1 addition & 1 deletion src/modules/workshops/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

from fastapi import Depends

from src.api.dependencies.db import DbSessionDep
from src.modules.workshops.repository import SqlCheckInRepository, SqlWorkshopRepository
from src.storages.sql.dependencies import DbSessionDep


async def get_sql_workshop_repository(db_session: DbSessionDep) -> SqlWorkshopRepository:
Expand Down
43 changes: 37 additions & 6 deletions src/modules/workshops/repository.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,39 @@
from sqlalchemy import delete, insert, select, update
from sqlalchemy import delete, select, update
from sqlalchemy.dialects.postgresql import insert
from sqlalchemy.ext.asyncio import AsyncSession

from src.modules.workshops.schemes import ViewWorkshopScheme
from src.modules.workshops.schemes import CreateWorkshopScheme, ViewWorkshopScheme
from src.storages.sql.models.workshops import CheckIn, Workshop


class SqlWorkshopRepository:
def __init__(self, session: AsyncSession) -> None:
self.session = session

async def create(self, workshop: CreateWorkshopScheme) -> ViewWorkshopScheme | None:
to_insert = workshop.model_dump()
to_insert["remain_places"] = workshop.capacity
query = insert(Workshop).values(**to_insert).on_conflict_do_nothing().returning(Workshop)
workshop = await self.session.execute(query)
workshop = workshop.scalar()
await self.session.commit()
if workshop is not None:
return ViewWorkshopScheme.model_validate(workshop, from_attributes=True)

async def read_all(self) -> list[ViewWorkshopScheme]:
query = select(Workshop)
workshops = await self.session.execute(query)
workshops = workshops.scalars()
return [ViewWorkshopScheme.model_validate(wk, from_attributes=True) for wk in workshops]

async def get_list_by_user_id(self, user_id: int) -> list[ViewWorkshopScheme]:
request = select(Workshop).join(Workshop.check_ins).where(CheckIn.user_id == user_id)
workshops = await self.session.execute(request)
workshops = workshops.scalars()
return [ViewWorkshopScheme.model_validate(wk, from_attributes=True) for wk in workshops]

async def get_by_id(self, workshop_id: int) -> ViewWorkshopScheme | None:
request = select(Workshop).where(workshop_id=workshop_id)
request = select(Workshop).where(Workshop.id == workshop_id)
workshop = await self.session.execute(request)
workshop = workshop.scalar()
if workshop is not None:
Expand All @@ -36,22 +53,36 @@ def __init__(self, session: AsyncSession, workshops_repository: SqlWorkshopRepos
self.session = session
self.workshops_repository = workshops_repository

async def exists(self, workshop_id: int, user_id: int) -> bool:
query = select(CheckIn).where(CheckIn.workshop_id == workshop_id, CheckIn.user_id == user_id)
result = await self.session.execute(query)
result = result.scalar()
return bool(result)

async def create(self, workshop_id: int, user_id: int) -> bool:
workshop = await self.workshops_repository.get_by_id(workshop_id)
if workshop is None or workshop.remain_places == 0:
return False

exists = await self.exists(workshop_id, user_id)
if exists:
return False

request = insert(CheckIn).values(workshop_id=workshop_id, user_id=user_id)
await self.session.execute(request)
await self.workshops_repository.update_remain_places(workshop_id, -1)
await self.session.commit()

return True

async def delete(self, workshop_id: int, user_id: int) -> bool:
workshop = await self.workshops_repository.get_by_id(workshop_id)
if workshop is None:
exists = await self.exists(workshop_id, user_id)
if not exists:
return False
request = delete(CheckIn).where(workshop_id=workshop_id, user_id=user_id)

request = delete(CheckIn).where(CheckIn.workshop_id == workshop_id, CheckIn.user_id == user_id)
await self.session.execute(request)
await self.workshops_repository.update_remain_places(workshop_id, 1)
await self.session.commit()

return True
32 changes: 30 additions & 2 deletions src/modules/workshops/routes.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from fastapi import APIRouter, Response, status

from src.api.dependencies.auth import CurrentUserIdDep
from src.api.dependencies import CurrentUserIdDep
from src.api.exceptions import IncorrectCredentialsException
from src.modules.workshops.dependencies import SqlCheckInRepositoryDep, SqlWorkshopRepositoryDep
from src.modules.workshops.schemes import ViewWorkshopScheme
from src.modules.workshops.schemes import CreateWorkshopScheme, ViewWorkshopScheme

router = APIRouter(
prefix="/workshops",
Expand All @@ -14,6 +14,34 @@
)


@router.get(
"/",
status_code=status.HTTP_200_OK,
responses={
status.HTTP_200_OK: {"description": "All workshops"},
},
)
async def read_all_workshops(workshop_repository: SqlWorkshopRepositoryDep) -> list[ViewWorkshopScheme]:
return await workshop_repository.read_all()


@router.post(
"/create",
status_code=status.HTTP_201_CREATED,
responses={
status.HTTP_201_CREATED: {"description": "Workshop successfully created"},
status.HTTP_400_BAD_REQUEST: {"description": "Creation failed"},
},
)
async def create_workshop(
user_id: CurrentUserIdDep, workshop_repository: SqlWorkshopRepositoryDep, workshop: CreateWorkshopScheme
) -> ViewWorkshopScheme:
workshop = await workshop_repository.create(workshop)
if workshop:
return workshop
return Response(status_code=status.HTTP_400_BAD_REQUEST)


@router.post(
"/check-in/{workshop_id}",
status_code=status.HTTP_200_OK,
Expand Down
20 changes: 19 additions & 1 deletion src/modules/workshops/schemes.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import datetime

from pydantic import BaseModel
from pydantic import BaseModel, Field, NaiveDatetime, model_validator

_now = datetime.datetime.now().replace(second=0, microsecond=0, tzinfo=None)


class ViewWorkshopScheme(BaseModel):
Expand All @@ -12,3 +14,19 @@ class ViewWorkshopScheme(BaseModel):
dtend: datetime.datetime
capacity: int
remain_places: int


class CreateWorkshopScheme(BaseModel):
name: str
alias: str
description: str
capacity: int

dtstart: NaiveDatetime = Field(example=_now)
dtend: NaiveDatetime = Field(example=_now)

@model_validator(mode="after")
def order_times(self):
if self.dtstart >= self.dtend:
raise ValueError("`dtstart` must be less than `dtend`")
return self
File renamed without changes.
3 changes: 1 addition & 2 deletions src/storages/sql/models/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from sqlalchemy.orm import relationship

from src.storages.sql.models.base import Base
from src.storages.sql.models.workshops import CheckIn
from src.storages.sql.utils import *


Expand All @@ -27,4 +26,4 @@ class User(Base):
"User's name"
role: Mapped[UserRole] = mapped_column(Enum(UserRole), default=UserRole.DEFAULT)
"User's role"
check_ins: Mapped[list["CheckIn"]] = relationship("CheckIn", back_populates="user")
check_ins = relationship("CheckIn", back_populates="user")
10 changes: 5 additions & 5 deletions src/storages/sql/models/workshops.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import datetime

from sqlalchemy import ForeignKey, Integer, String, Text
from sqlalchemy import DateTime, ForeignKey, Integer, String, Text
from sqlalchemy.orm import Mapped, mapped_column, relationship

from src.storages.sql.models.base import Base
Expand All @@ -17,19 +17,19 @@ class Workshop(Base):
alias: Mapped[str] = mapped_column(String(255), unique=True)
description: Mapped[str] = mapped_column(Text, nullable=True)

dtstart: Mapped[datetime.datetime] = mapped_column()
dtend: Mapped[datetime.datetime] = mapped_column()
dtstart: Mapped[datetime.datetime] = mapped_column(DateTime)
dtend: Mapped[datetime.datetime] = mapped_column(DateTime)

capacity: Mapped[int] = mapped_column()
remain_places: Mapped[int] = mapped_column()

check_ins: Mapped[list["CheckIn"]] = relationship("CheckIn", back_populates="workshop")
check_ins = relationship("CheckIn", back_populates="workshop")


class CheckIn(Base):
__tablename__ = "workshops_checkins"

user_id: Mapped[int] = mapped_column(Integer, ForeignKey("users.id", ondelete="CASCADE"), primary_key=True)
workshop_id: Mapped[int] = mapped_column(Integer, ForeignKey("workshops.id", ondelete="CASCADE"), primary_key=True)
workshop: Mapped["Workshop"] = relationship("Workshop", back_populates="check_ins")
workshop = relationship("Workshop", back_populates="check_ins")
user = relationship("User", back_populates="check_ins")

0 comments on commit 7ba7d2d

Please sign in to comment.