сделал слои для таблицы участников проекта
This commit is contained in:
parent
8c7aa7358d
commit
1ed1731432
47
API/app/application/project_members_repository.py
Normal file
47
API/app/application/project_members_repository.py
Normal file
@ -0,0 +1,47 @@
|
||||
from typing import Optional, Sequence
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.domain.models import ProjectMember
|
||||
|
||||
|
||||
class ProjectMembersRepository:
|
||||
def __init__(self, db: AsyncSession):
|
||||
self.db = db
|
||||
|
||||
async def get_by_id(self, project_member_id: int) -> Optional[ProjectMember]:
|
||||
stmt = select(ProjectMember).filter_by(id=project_member_id)
|
||||
result = await self.db.execute(stmt)
|
||||
return result.scalars().first()
|
||||
|
||||
async def get_by_project_id(self, project_id: int) -> Sequence[ProjectMember]:
|
||||
stmt = select(ProjectMember).filter_by(project_id=project_id)
|
||||
result = await self.db.execute(stmt)
|
||||
return result.scalars().all()
|
||||
|
||||
async def get_by_profile_id(self, profile_id: int) -> Sequence[ProjectMember]:
|
||||
stmt = select(ProjectMember).filter_by(profile_id=profile_id)
|
||||
result = await self.db.execute(stmt)
|
||||
return result.scalars().all()
|
||||
|
||||
async def get_by_project_id_and_profile_id(self, project_id: int, profile_id: int) -> Optional[ProjectMember]:
|
||||
stmt = select(ProjectMember).filter_by(project_id=project_id, profile_id=profile_id)
|
||||
result = await self.db.execute(stmt)
|
||||
return result.scalars().first()
|
||||
|
||||
async def create_list(self, project_members: list[ProjectMember]) -> list[ProjectMember]:
|
||||
self.db.add_all(project_members)
|
||||
await self.db.commit()
|
||||
|
||||
for project_member in project_members:
|
||||
await self.db.refresh(project_member)
|
||||
|
||||
return project_members
|
||||
|
||||
async def delete_list_members(self, project_members: list[ProjectMember]) -> list[ProjectMember]:
|
||||
for project_member in project_members:
|
||||
await self.db.delete(project_member)
|
||||
|
||||
await self.db.commit()
|
||||
return project_members
|
||||
86
API/app/contollers/project_members_router.py
Normal file
86
API/app/contollers/project_members_router.py
Normal file
@ -0,0 +1,86 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.database.session import get_db
|
||||
from app.domain.entities.project_member import ProjectMemberEntity
|
||||
from app.infrastructure.dependencies import require_admin
|
||||
from app.infrastructure.project_members_service import ProjectMembersService
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get(
|
||||
'/by-project/{project_id}/',
|
||||
response_model=list[ProjectMemberEntity],
|
||||
summary='Get project members by project ID',
|
||||
description='Returns all project members with the specified project ID'
|
||||
)
|
||||
async def get_members_by_project_id(
|
||||
project_id: int,
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
service = ProjectMembersService(db)
|
||||
return await service.get_project_members_by_project_id(project_id)
|
||||
|
||||
|
||||
@router.get(
|
||||
'/by-profile/{profile_id}/',
|
||||
response_model=list[ProjectMemberEntity],
|
||||
summary='Get project members by profile ID',
|
||||
description='Returns all project member records where the profile is involved'
|
||||
)
|
||||
async def get_members_by_profile_id(
|
||||
profile_id: int,
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
service = ProjectMembersService(db)
|
||||
return await service.get_project_members_by_profile_id(profile_id)
|
||||
|
||||
|
||||
@router.post(
|
||||
'/{project_id}/',
|
||||
response_model=Optional[list[ProjectMemberEntity]],
|
||||
summary='Create a list of project members',
|
||||
description='Creates a list of project members for the specified project ID'
|
||||
)
|
||||
async def create_project_members(
|
||||
project_id: int,
|
||||
project_members: list[ProjectMemberEntity],
|
||||
db: AsyncSession = Depends(get_db),
|
||||
user=Depends(require_admin),
|
||||
):
|
||||
service = ProjectMembersService(db)
|
||||
return await service.create_list_project_members(project_id, project_members)
|
||||
|
||||
|
||||
@router.put(
|
||||
'/{project_id}/',
|
||||
response_model=Optional[list[ProjectMemberEntity]],
|
||||
summary='Update the list of project members',
|
||||
description='Deletes all current project members and creates new records'
|
||||
)
|
||||
async def update_project_members(
|
||||
project_id: int,
|
||||
project_members: list[ProjectMemberEntity],
|
||||
db: AsyncSession = Depends(get_db),
|
||||
user=Depends(require_admin),
|
||||
):
|
||||
service = ProjectMembersService(db)
|
||||
return await service.update_list_project_members(project_id, project_members)
|
||||
|
||||
|
||||
@router.delete(
|
||||
'/{project_id}/',
|
||||
summary='Delete all project members by project ID',
|
||||
description='Deletes all project members with the specified project ID',
|
||||
)
|
||||
async def delete_project_members(
|
||||
project_id: int,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
user=Depends(require_admin),
|
||||
):
|
||||
service = ProjectMembersService(db)
|
||||
await service.delete_project_members_by_project_id(project_id)
|
||||
return {"message": "All project members have been successfully deleted."}
|
||||
@ -0,0 +1,32 @@
|
||||
"""0003_добавил_поле_название_для_проектов_в_таблицу
|
||||
|
||||
Revision ID: be10a7640a29
|
||||
Revises: b4056dda0936
|
||||
Create Date: 2025-05-31 10:50:44.163131
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = 'be10a7640a29'
|
||||
down_revision: Union[str, None] = 'b4056dda0936'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('projects', sa.Column('title', sa.VARCHAR(length=150), nullable=False))
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('projects', 'title')
|
||||
# ### end Alembic commands ###
|
||||
@ -5,5 +5,6 @@ from pydantic import BaseModel
|
||||
|
||||
class ProjectEntity(BaseModel):
|
||||
id: Optional[int] = None
|
||||
title: str
|
||||
description: str
|
||||
repository_url: Optional[str] = None
|
||||
10
API/app/domain/entities/project_member.py
Normal file
10
API/app/domain/entities/project_member.py
Normal file
@ -0,0 +1,10 @@
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class ProjectMemberEntity(BaseModel):
|
||||
id: Optional[int] = None
|
||||
description: str
|
||||
project_id: int
|
||||
profile_id: int
|
||||
@ -7,6 +7,7 @@ from app.domain.models.base import AdvancedBaseModel
|
||||
class Project(AdvancedBaseModel):
|
||||
__tablename__ = 'projects'
|
||||
|
||||
title = Column(VARCHAR(150), nullable=False)
|
||||
description = Column(VARCHAR(150))
|
||||
repository_url = Column(String, nullable=False)
|
||||
|
||||
|
||||
130
API/app/infrastructure/project_members_service.py
Normal file
130
API/app/infrastructure/project_members_service.py
Normal file
@ -0,0 +1,130 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import HTTPException, status
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.application.profiles_repository import ProfilesRepository
|
||||
from app.application.project_members_repository import ProjectMembersRepository
|
||||
from app.application.projects_repository import ProjectsRepository
|
||||
from app.domain.entities.project_member import ProjectMemberEntity
|
||||
from app.domain.models import ProjectMember
|
||||
|
||||
|
||||
class ProjectMembersService:
|
||||
def __init__(self, db: AsyncSession):
|
||||
self.project_members_repository = ProjectMembersRepository(db)
|
||||
self.projects_repository = ProjectsRepository(db)
|
||||
self.profiles_repository = ProfilesRepository(db)
|
||||
|
||||
async def get_project_members_by_project_id(self, project_id: int) -> list[ProjectMemberEntity]:
|
||||
project_members = await self.project_members_repository.get_by_project_id(project_id)
|
||||
return [
|
||||
self.model_to_entity(project_member)
|
||||
for project_member in project_members
|
||||
]
|
||||
|
||||
async def get_project_members_by_profile_id(self, profile_id: int) -> list[ProjectMemberEntity]:
|
||||
project_members = await self.project_members_repository.get_by_profile_id(profile_id)
|
||||
return [
|
||||
self.model_to_entity(project_member)
|
||||
for project_member in project_members
|
||||
]
|
||||
|
||||
async def create_list_project_members(self, project_id: int, project_members: list[ProjectMemberEntity]) -> \
|
||||
Optional[
|
||||
list[ProjectMemberEntity]
|
||||
]:
|
||||
project = await self.projects_repository.get_by_id(project_id)
|
||||
|
||||
if not project:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail='The project with this ID was not found',
|
||||
)
|
||||
|
||||
project_members_models = []
|
||||
|
||||
for project_member in project_members:
|
||||
if project_member.project_id != project_id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail='The project ID from the request parameter and the project ID from the transmitted data do not match'
|
||||
)
|
||||
|
||||
profile = await self.profiles_repository.get_by_id(project_member.profile_id)
|
||||
|
||||
if not profile:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail='The profile with this ID was not found',
|
||||
)
|
||||
|
||||
project_members_models.append(
|
||||
self.entity_to_model(project_member)
|
||||
)
|
||||
|
||||
await self.project_members_repository.create_list(project_members_models)
|
||||
|
||||
return [
|
||||
self.model_to_entity(member)
|
||||
for member in project_members_models
|
||||
]
|
||||
|
||||
async def update_list_project_members(
|
||||
self,
|
||||
project_id: int,
|
||||
project_members: list[ProjectMemberEntity]
|
||||
) -> Optional[list[ProjectMemberEntity]]:
|
||||
project = await self.projects_repository.get_by_id(project_id)
|
||||
if not project:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail='The project with this ID was not found',
|
||||
)
|
||||
|
||||
old_members = await self.project_members_repository.get_by_project_id(project_id)
|
||||
|
||||
if old_members:
|
||||
await self.project_members_repository.delete_list_members(list(old_members))
|
||||
|
||||
return await self.create_list_project_members(project_id, project_members)
|
||||
|
||||
async def delete_project_members_by_project_id(self, project_id: int) -> Optional[list[ProjectMemberEntity]]:
|
||||
project = await self.projects_repository.get_by_id(project_id)
|
||||
if not project:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail='The project with this ID was not found',
|
||||
)
|
||||
|
||||
project_members = await self.project_members_repository.get_by_project_id(project_id)
|
||||
|
||||
if project_members:
|
||||
await self.project_members_repository.delete_list_members(list(project_members))
|
||||
|
||||
return [
|
||||
self.model_to_entity(project_member)
|
||||
for project_member in project_members
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def model_to_entity(project: ProjectMember) -> ProjectMemberEntity:
|
||||
return ProjectMemberEntity(
|
||||
id=project.id,
|
||||
description=project.description,
|
||||
project_id=project.project_id,
|
||||
profile_id=project.profile_id,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def entity_to_model(project: ProjectMemberEntity) -> ProjectMember:
|
||||
project_model = ProjectMember(
|
||||
description=project.description,
|
||||
project_id=project.project_id,
|
||||
profile_id=project.profile_id,
|
||||
)
|
||||
|
||||
if project.id:
|
||||
project_model.id = project.id
|
||||
|
||||
return project_model
|
||||
@ -32,6 +32,7 @@ class ProjectsService:
|
||||
if not project_model:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found")
|
||||
|
||||
project_model.title = project.title
|
||||
project_model.description = project.description
|
||||
project_model.repository_url = project.repository_url
|
||||
|
||||
@ -53,6 +54,7 @@ class ProjectsService:
|
||||
def model_to_entity(project_model: Project) -> ProjectEntity:
|
||||
return ProjectEntity(
|
||||
id=project_model.id,
|
||||
title=project_model.title,
|
||||
description=project_model.description,
|
||||
repository_url=project_model.repository_url,
|
||||
)
|
||||
@ -60,6 +62,7 @@ class ProjectsService:
|
||||
@staticmethod
|
||||
def entity_to_model(project_entity: ProjectEntity) -> Project:
|
||||
project_model = Project(
|
||||
title=project_entity.title,
|
||||
description=project_entity.description,
|
||||
repository_url=project_entity.repository_url,
|
||||
)
|
||||
|
||||
@ -4,6 +4,7 @@ from fastapi.middleware.cors import CORSMiddleware
|
||||
from app.contollers.auth_router import router as auth_router
|
||||
from app.contollers.profile_photos_router import router as profile_photos_router
|
||||
from app.contollers.profiles_router import router as profiles_router
|
||||
from app.contollers.project_members_router import router as project_members_router
|
||||
from app.contollers.projects_router import router as projects_router
|
||||
from app.contollers.register_router import router as register_router
|
||||
from app.contollers.teams_router import router as team_router
|
||||
@ -23,8 +24,9 @@ def start_app():
|
||||
)
|
||||
|
||||
api_app.include_router(auth_router, prefix=f'{settings.PREFIX}/auth', tags=['auth'])
|
||||
api_app.include_router(profile_photos_router, prefix=f'{settings.PREFIX}/profile_photos', tags=['profile_photos_router'])
|
||||
api_app.include_router(profile_photos_router, prefix=f'{settings.PREFIX}/profile_photos', tags=['profile_photos'])
|
||||
api_app.include_router(profiles_router, prefix=f'{settings.PREFIX}/profiles', tags=['profiles'])
|
||||
api_app.include_router(project_members_router, prefix=f'{settings.PREFIX}/project_members', tags=['project_members'])
|
||||
api_app.include_router(projects_router, prefix=f'{settings.PREFIX}/projects', tags=['projects'])
|
||||
api_app.include_router(register_router, prefix=f'{settings.PREFIX}/register', tags=['register'])
|
||||
api_app.include_router(team_router, prefix=f'{settings.PREFIX}/teams', tags=['teams'])
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user