From be1ea4009dd3dea1cef04933aadeaf069ee0ac02 Mon Sep 17 00:00:00 2001 From: AlexSserb Date: Mon, 4 Aug 2025 18:48:58 +0400 Subject: [PATCH] feat: patch and get statuses endpoints --- main.py | 1 + repositories/__init__.py | 3 +++ repositories/board.py | 7 ++----- repositories/status.py | 31 +++++++++++++++++++++++++++++++ routes/__init__.py | 3 ++- routes/board.py | 2 +- routes/deal.py | 2 +- routes/project.py | 2 +- routes/status.py | 39 +++++++++++++++++++++++++++++++++++++++ schemas/board.py | 2 -- schemas/status.py | 35 ++++++++++++++++++++++++++++++++++- services/__init__.py | 3 +++ services/board.py | 2 +- services/deal.py | 2 +- services/project.py | 2 +- services/status.py | 25 +++++++++++++++++++++++++ 16 files changed, 146 insertions(+), 15 deletions(-) create mode 100644 repositories/status.py create mode 100644 routes/status.py create mode 100644 services/status.py diff --git a/main.py b/main.py index fe66520..b85c27b 100644 --- a/main.py +++ b/main.py @@ -20,6 +20,7 @@ app.add_middleware( routers_list = [ routes.project_router, routes.board_router, + routes.status_router, routes.deal_router, ] for router in routers_list: diff --git a/repositories/__init__.py b/repositories/__init__.py index 3d898e9..1911db0 100644 --- a/repositories/__init__.py +++ b/repositories/__init__.py @@ -1 +1,4 @@ +from .board import BoardRepository as BoardRepository +from .deal import DealRepository as DealRepository from .project import ProjectRepository as ProjectRepository +from .status import StatusRepository as StatusRepository diff --git a/repositories/board.py b/repositories/board.py index e07e065..63a392b 100644 --- a/repositories/board.py +++ b/repositories/board.py @@ -1,5 +1,4 @@ from sqlalchemy import select -from sqlalchemy.orm import selectinload from models import Board from repositories.base import BaseRepository @@ -8,10 +7,8 @@ from schemas.board import UpdateBoardSchema class BoardRepository(BaseRepository): async def get_all(self, project_id: int) -> list[Board]: - stmt = ( - select(Board) - .where(Board.is_deleted.is_(False), Board.project_id == project_id) - .options(selectinload(Board.statuses)) + stmt = select(Board).where( + Board.is_deleted.is_(False), Board.project_id == project_id ) result = await self.session.execute(stmt) return list(result.scalars().all()) diff --git a/repositories/status.py b/repositories/status.py new file mode 100644 index 0000000..7b15c15 --- /dev/null +++ b/repositories/status.py @@ -0,0 +1,31 @@ +from sqlalchemy import select + +from models import Status +from repositories.base import BaseRepository +from schemas.status import UpdateStatusSchema + + +class StatusRepository(BaseRepository): + async def get_all(self, board_id: int) -> list[Status]: + stmt = ( + select(Status) + .where(Status.is_deleted.is_(False), Status.board_id == board_id) + ) + result = await self.session.execute(stmt) + return list(result.scalars().all()) + + async def get_by_id(self, status_id: int) -> Status | None: + stmt = select(Status).where( + Status.id == status_id, Status.is_deleted.is_(False) + ) + result = await self.session.execute(stmt) + return result.scalar_one_or_none() + + async def update(self, status: Status, data: UpdateStatusSchema) -> Status: + status.lexorank = data.lexorank if data.lexorank else status.lexorank + status.name = data.name if data.name else status.name + + self.session.add(status) + await self.session.commit() + await self.session.refresh(status) + return status diff --git a/routes/__init__.py b/routes/__init__.py index b6072fb..28f53b5 100644 --- a/routes/__init__.py +++ b/routes/__init__.py @@ -1,3 +1,4 @@ -from .project import project_router as project_router from .board import board_router as board_router from .deal import deal_router as deal_router +from .project import project_router as project_router +from .status import status_router as status_router diff --git a/routes/board.py b/routes/board.py index aef8d2a..ee52019 100644 --- a/routes/board.py +++ b/routes/board.py @@ -2,7 +2,7 @@ from fastapi import APIRouter, Path from backend.dependecies import SessionDependency from schemas.board import GetBoardsResponse, UpdateBoardRequest, UpdateBoardResponse -from services.board import BoardService +from services import BoardService board_router = APIRouter( prefix="/board", diff --git a/routes/deal.py b/routes/deal.py index 5afeecc..72f2422 100644 --- a/routes/deal.py +++ b/routes/deal.py @@ -2,7 +2,7 @@ from fastapi import APIRouter, Path from backend.dependecies import SessionDependency from schemas.deal import GetDealsResponse -from services.deal import DealService +from services import DealService deal_router = APIRouter( prefix="/deal", diff --git a/routes/project.py b/routes/project.py index 12d8ee0..d7eedb2 100644 --- a/routes/project.py +++ b/routes/project.py @@ -2,7 +2,7 @@ from fastapi import APIRouter from backend.dependecies import SessionDependency from schemas.project import GetProjectsResponse -from services.project import ProjectService +from services import ProjectService project_router = APIRouter( prefix="/project", diff --git a/routes/status.py b/routes/status.py new file mode 100644 index 0000000..55d0aaf --- /dev/null +++ b/routes/status.py @@ -0,0 +1,39 @@ +from fastapi import APIRouter, Path + +from backend.dependecies import SessionDependency +from schemas.status import ( + UpdateStatusRequest, + UpdateStatusResponse, + GetStatusesResponse, +) +from services import StatusService + +status_router = APIRouter( + prefix="/status", + tags=["status"], +) + + +@status_router.get( + "/{boardId}", + response_model=GetStatusesResponse, + operation_id="get_statuses", +) +async def get_statuses( + session: SessionDependency, + board_id: int = Path(alias="boardId"), +): + return await StatusService(session).get_statuses(board_id) + + +@status_router.patch( + "/{statusId}", + response_model=UpdateStatusResponse, + operation_id="update_status", +) +async def update_status( + session: SessionDependency, + request: UpdateStatusRequest, + status_id: int = Path(alias="statusId"), +): + return await StatusService(session).update_status(status_id, request) diff --git a/schemas/board.py b/schemas/board.py index 68bf7a5..4094b1d 100644 --- a/schemas/board.py +++ b/schemas/board.py @@ -1,5 +1,4 @@ from schemas.base import BaseSchema, BaseResponse -from schemas.status import StatusSchema # region Entity @@ -12,7 +11,6 @@ class BaseBoardSchema(BaseSchema): class BoardSchema(BaseBoardSchema): id: int lexorank: str - statuses: list[StatusSchema] class UpdateBoardSchema(BaseSchema): diff --git a/schemas/status.py b/schemas/status.py index f76a663..d0f40e7 100644 --- a/schemas/status.py +++ b/schemas/status.py @@ -1,4 +1,7 @@ -from schemas.base import BaseSchema +from schemas.base import BaseSchema, BaseResponse + + +# region Entities class BaseStatusSchema(BaseSchema): @@ -8,3 +11,33 @@ class BaseStatusSchema(BaseSchema): class StatusSchema(BaseStatusSchema): id: int lexorank: str + + +class UpdateStatusSchema(BaseSchema): + name: str | None = None + lexorank: str | None = None + + +# endregion + +# region Requests + + +class UpdateStatusRequest(BaseSchema): + status: UpdateStatusSchema + + +# endregion + +# region Responses + + +class GetStatusesResponse(BaseSchema): + statuses: list[StatusSchema] + + +class UpdateStatusResponse(BaseResponse): + pass + + +# endregion diff --git a/services/__init__.py b/services/__init__.py index f20d044..19d4325 100644 --- a/services/__init__.py +++ b/services/__init__.py @@ -1 +1,4 @@ +from .board import BoardService as BoardService +from .deal import DealService as DealService from .project import ProjectService as ProjectService +from .status import StatusService as StatusService diff --git a/services/board.py b/services/board.py index aa2584a..8ad9d0b 100644 --- a/services/board.py +++ b/services/board.py @@ -1,7 +1,7 @@ from fastapi import HTTPException from sqlalchemy.ext.asyncio import AsyncSession -from repositories.board import BoardRepository +from repositories import BoardRepository from schemas.board import ( GetBoardsResponse, BoardSchema, diff --git a/services/deal.py b/services/deal.py index e8c9e13..5df5379 100644 --- a/services/deal.py +++ b/services/deal.py @@ -1,6 +1,6 @@ from sqlalchemy.ext.asyncio import AsyncSession -from repositories.deal import DealRepository +from repositories import DealRepository from schemas.deal import GetDealsResponse, DealSchema diff --git a/services/project.py b/services/project.py index da9dfe1..7622315 100644 --- a/services/project.py +++ b/services/project.py @@ -1,6 +1,6 @@ from sqlalchemy.ext.asyncio import AsyncSession -from repositories.project import ProjectRepository +from repositories import ProjectRepository from schemas.project import GetProjectsResponse, ProjectSchema diff --git a/services/status.py b/services/status.py new file mode 100644 index 0000000..7a02df2 --- /dev/null +++ b/services/status.py @@ -0,0 +1,25 @@ +from fastapi import HTTPException +from sqlalchemy.ext.asyncio import AsyncSession + +from repositories import StatusRepository +from schemas.board import UpdateBoardResponse +from schemas.status import UpdateStatusRequest, GetStatusesResponse, StatusSchema + + +class StatusService: + def __init__(self, session: AsyncSession): + self.repository = StatusRepository(session) + + async def get_statuses(self, board_id: int) -> GetStatusesResponse: + statuses = await self.repository.get_all(board_id) + return GetStatusesResponse( + statuses=[StatusSchema.model_validate(status) for status in statuses] + ) + + async def update_status(self, status_id: int, request: UpdateStatusRequest): + status = await self.repository.get_by_id(status_id) + if not status: + raise HTTPException(status_code=404, detail="Статус не найден") + + await self.repository.update(status, request.status) + return UpdateBoardResponse(message="Статус успешно обновлен")