from datetime import datetime from sqlalchemy import select, update, func, delete from sqlalchemy.orm import selectinload from card_attributes import CardAttributesCommandHandler from models import Project, Board, Module from schemas.project import * from services.base import BaseService class ProjectService(BaseService): async def get_projects(self) -> GetProjectsResponse: board_count_sub = ( select( Board.project_id, func.count(Board.id).label('boards_count'), ) .group_by(Board.project_id) .subquery() ) stmt = ( select( Project, func.coalesce(board_count_sub.c.boards_count, 0), ) .outerjoin(board_count_sub, Project.id == board_count_sub.c.project_id) .options( selectinload(Project.attributes), selectinload(Project.modules), ) .where(Project.is_deleted == False) .order_by(Project.id) ) project_data = (await self.session.execute(stmt)).all() projects = [] for project, boards_count in project_data: project_schema = FullProjectSchema( id=project.id, name=project.name, boards_count=boards_count, attributes=project.attributes, modules=project.modules, tags=project.tags, ) projects.append(project_schema) return GetProjectsResponse(projects=projects) async def create_project(self, request: CreateProjectRequest) -> CreateProjectResponse: project = Project( name=request.project.name, created_at=datetime.now(), ) self.session.add(project) await self.session.commit() return UpdateProjectResponse(ok=True, message="Проект успешно создан") async def update_project(self, request: UpdateProjectRequest) -> UpdateProjectResponse: stmt = ( update(Project) .where(Project.id == request.project.id) .values(name=request.project.name) ) await self.session.execute(stmt) await self.session.commit() return UpdateProjectResponse(ok=True, message="Проект успешно изменен") async def delete_project(self, project_id: int) -> DeleteProjectResponse: stmt_boards = select(Board).where(Board.project_id == project_id) boards = (await self.session.scalars(stmt_boards)).all() if len(boards) == 0: stmt = ( delete(Project) .where(Project.id == project_id) ) else: stmt = ( update(Project) .where(Project.id == project_id) .values(is_deleted=True) ) await self.session.execute(stmt) await self.session.commit() return DeleteProjectResponse(ok=True, message="Проект успешно удален") async def get_all_modules(self) -> GetAllModulesResponse: stmt = ( select(Module) .where(Module.is_deleted == False) ) modules = await self.session.scalars(stmt) return GetAllModulesResponse(modules=modules.all()) async def update_project_modules(self, request: UpdateModulesRequest) -> UpdateModulesResponse: project: Optional[Project] = await self.session.get(Project, request.project_id) if not project: return UpdateModulesResponse(ok=False, message=f"Проект с ID {request.project_id} не найден") modules_stmt = ( select(Module) .where(Module.id.in_(request.module_ids)) ) modules = (await self.session.scalars(modules_stmt)).all() project.modules = modules await self.session.commit() return UpdateModulesResponse(ok=True, message="Модули успешно обновлены") async def update_project_attributes(self, request: UpdateAttributesRequest) -> UpdateAttributesResponse: project: Optional[Project] = await self.session.get(Project, request.project_id) if not project: return UpdateAttributesResponse(ok=False, message=f"Проект с ID {request.project_id} не найден") card_attrs_handler = CardAttributesCommandHandler(self.session) await card_attrs_handler.set_project_attributes(project, request.attribute_ids) return UpdateAttributesResponse(ok=True, message="Атрибуты успешно обновлены")