feat: projects create, update, delete

This commit is contained in:
2025-08-13 15:01:22 +04:00
parent 71c0901909
commit 5e20da8356
4 changed files with 156 additions and 7 deletions

View File

@ -1,7 +1,12 @@
from datetime import datetime
from typing import Optional
from sqlalchemy import select
from sqlalchemy.orm import selectinload
from models.project import Project
from repositories.base import BaseRepository
from schemas.project import CreateProjectSchema, UpdateProjectSchema
class ProjectRepository(BaseRepository):
@ -9,3 +14,39 @@ class ProjectRepository(BaseRepository):
stmt = select(Project).where(Project.is_deleted.is_(False))
result = await self.session.execute(stmt)
return list(result.scalars().all())
async def get_by_id(self, project_id: int) -> Optional[Project]:
stmt = (
select(Project)
.where(Project.id == project_id, Project.is_deleted.is_(False))
.options(selectinload(Project.boards))
)
result = await self.session.execute(stmt)
return result.scalar_one_or_none()
async def create(self, data: CreateProjectSchema) -> Project:
project_data = data.model_dump()
project_data["created_at"] = datetime.now()
project = Project(**project_data)
self.session.add(project)
await self.session.commit()
await self.session.refresh(project)
return project
async def update(self, project: Project, data: UpdateProjectSchema) -> Project:
project.name = data.name if data.name else project.name
self.session.add(project)
await self.session.commit()
await self.session.refresh(project)
return project
async def delete(self, project: Project, is_soft: bool):
if not is_soft:
await self.session.delete(project)
await self.session.commit()
return
project.is_deleted = True
self.session.add(project)
await self.session.commit()

View File

@ -1,7 +1,14 @@
from fastapi import APIRouter
from fastapi import APIRouter, Query
from backend.dependecies import SessionDependency
from schemas.project import GetProjectsResponse
from schemas.project import (
GetProjectsResponse,
CreateProjectResponse,
CreateProjectRequest,
UpdateProjectResponse,
UpdateProjectRequest,
DeleteProjectResponse,
)
from services import ProjectService
project_router = APIRouter(
@ -18,3 +25,40 @@ async def get_projects(
session: SessionDependency,
):
return await ProjectService(session).get_projects()
@project_router.post(
"/",
response_model=CreateProjectResponse,
operation_id="create_project",
)
async def create_project(
session: SessionDependency,
request: CreateProjectRequest,
):
return await ProjectService(session).create_project(request)
@project_router.patch(
"/{projectId}",
response_model=UpdateProjectResponse,
operation_id="update_project",
)
async def update_project(
session: SessionDependency,
request: UpdateProjectRequest,
project_id: int = Query(alias="projectId"),
):
return await ProjectService(session).update_project(project_id, request)
@project_router.delete(
"/{projectId}",
response_model=DeleteProjectResponse,
operation_id="delete_project",
)
async def delete_project(
session: SessionDependency,
project_id: int = Query(alias="projectId"),
):
return await ProjectService(session).delete_project(project_id)

View File

@ -1,15 +1,22 @@
from schemas.base import BaseSchema
from typing import Optional
from schemas.base import BaseSchema, BaseResponse
# region Entity
class BaseProjectSchema(BaseSchema):
class ProjectSchema(BaseSchema):
id: int
name: str
class ProjectSchema(BaseProjectSchema):
id: int
class CreateProjectSchema(BaseSchema):
name: str
class UpdateProjectSchema(BaseSchema):
name: Optional[str] = None
# endregion
@ -17,6 +24,14 @@ class ProjectSchema(BaseProjectSchema):
# region Requests
class CreateProjectRequest(BaseSchema):
project: CreateProjectSchema
class UpdateProjectRequest(BaseSchema):
project: UpdateProjectSchema
# endregion
# region Responses
@ -26,4 +41,16 @@ class GetProjectsResponse(BaseSchema):
projects: list[ProjectSchema]
class CreateProjectResponse(BaseResponse):
project: ProjectSchema
class UpdateProjectResponse(BaseResponse):
pass
class DeleteProjectResponse(BaseResponse):
pass
# endregion Responses

View File

@ -1,7 +1,16 @@
from fastapi import HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from repositories import ProjectRepository
from schemas.project import GetProjectsResponse, ProjectSchema
from schemas.project import (
GetProjectsResponse,
ProjectSchema,
CreateProjectRequest,
CreateProjectResponse,
UpdateProjectRequest,
UpdateProjectResponse,
DeleteProjectResponse,
)
class ProjectService:
@ -13,3 +22,31 @@ class ProjectService:
return GetProjectsResponse(
projects=[ProjectSchema.model_validate(project) for project in projects]
)
async def create_project(
self, request: CreateProjectRequest
) -> CreateProjectResponse:
project = await self.repository.create(request.project)
return CreateProjectResponse(
project=ProjectSchema.model_validate(project),
message="Проект успешно создан",
)
async def update_project(
self, project_id: int, request: UpdateProjectRequest
) -> UpdateProjectResponse:
project = await self.repository.get_by_id(project_id)
if not project:
raise HTTPException(status_code=404, detail="Проект не найден")
await self.repository.update(project, request.project)
return UpdateProjectResponse(message="Проект успешно обновлен")
async def delete_project(self, project_id: int) -> DeleteProjectResponse:
project = await self.repository.get_by_id(project_id)
if not project:
raise HTTPException(status_code=404, detail="Проект не найден")
is_soft_needed: bool = len(project.boards) > 0
await self.repository.delete(project, is_soft_needed)
return DeleteProjectResponse(message="Проект успешно удален")