new features

This commit is contained in:
Daniil
2026-02-27 23:33:56 +03:00
parent 937e58859a
commit dc04efe0fb
41 changed files with 2067 additions and 141 deletions
+2 -1
View File
@@ -2,7 +2,7 @@ from __future__ import annotations
import uuid
from sqlalchemy import ForeignKey, String, Text
from sqlalchemy import ForeignKey, JSON, String, Text
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column
@@ -23,3 +23,4 @@ class Project(Base, BaseModelMixin):
language: Mapped[str] = mapped_column(String(4), default="auto")
folder: Mapped[str | None] = mapped_column(String(1024), nullable=True)
status: Mapped[str] = mapped_column(String(16), default="DRAFT")
workspace_state: Mapped[dict | None] = mapped_column(JSON, nullable=True)
+25 -5
View File
@@ -2,7 +2,7 @@ from __future__ import annotations
import uuid
from sqlalchemy import Select, select
from sqlalchemy import Select, or_, select
from sqlalchemy.ext.asyncio import AsyncSession
from cpv3.modules.projects.models import Project
@@ -16,13 +16,31 @@ class ProjectRepository:
def __init__(self, session: AsyncSession) -> None:
self._session = session
async def list_all(self, *, requester: User) -> list[Project]:
async def list_all(
self,
*,
requester: User,
search: str | None = None,
status: str | None = None,
) -> list[Project]:
stmt: Select[tuple[Project]] = select(Project).where(
Project.is_active.is_(True)
)
if not requester.is_staff:
stmt = stmt.where(Project.owner_id == requester.id)
if search:
pattern = f"%{search}%"
stmt = stmt.where(
or_(
Project.name.ilike(pattern),
Project.description.ilike(pattern),
)
)
if status:
stmt = stmt.where(Project.status == status)
result = await self._session.execute(stmt.order_by(Project.created_at.desc()))
return list(result.scalars().all())
@@ -34,14 +52,16 @@ class ProjectRepository:
)
return result.scalar_one_or_none()
async def create(self, *, requester: User, data: ProjectCreate) -> Project:
async def create(
self, *, requester: User, data: ProjectCreate, folder: str, status: str,
) -> Project:
project = Project(
owner_id=requester.id,
name=data.name,
description=data.description,
language=data.language,
folder=data.folder,
status=data.status,
folder=folder,
status=status,
)
self._session.add(project)
+8 -2
View File
@@ -2,7 +2,7 @@ from __future__ import annotations
import uuid
from fastapi import APIRouter, Depends, HTTPException, Response, status
from fastapi import APIRouter, Depends, HTTPException, Query, Response, status
from sqlalchemy.ext.asyncio import AsyncSession
from cpv3.infrastructure.auth import get_current_user
@@ -16,11 +16,17 @@ router = APIRouter(prefix="/api/projects", tags=["Projects"])
@router.get("/", response_model=list[ProjectRead])
async def list_all_projects(
search: str | None = Query(None, description="Поиск по названию или описанию"),
status_filter: str | None = Query(
None, alias="status", description="Фильтр по статусу проекта"
),
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
) -> list[ProjectRead]:
service = ProjectService(db)
projects = await service.list_projects(requester=current_user)
projects = await service.list_projects(
requester=current_user, search=search, status=status_filter,
)
return [ProjectRead.model_validate(p) for p in projects]
+3 -2
View File
@@ -19,6 +19,8 @@ class ProjectRead(Schema):
folder: str | None
status: ProjectStatusEnum
workspace_state: dict | None
is_active: bool
created_at: datetime
updated_at: datetime
@@ -28,8 +30,6 @@ class ProjectCreate(Schema):
name: str
description: str | None = None
language: str = "auto"
folder: str | None = None
status: ProjectStatusEnum = "DRAFT"
class ProjectUpdate(Schema):
@@ -38,3 +38,4 @@ class ProjectUpdate(Schema):
language: str | None = None
folder: str | None = None
status: ProjectStatusEnum | None = None
workspace_state: dict | None = None
+14 -3
View File
@@ -16,14 +16,25 @@ class ProjectService:
def __init__(self, session: AsyncSession) -> None:
self._repo = ProjectRepository(session)
async def list_projects(self, *, requester: User) -> list[Project]:
return await self._repo.list_all(requester=requester)
async def list_projects(
self,
*,
requester: User,
search: str | None = None,
status: str | None = None,
) -> list[Project]:
return await self._repo.list_all(
requester=requester, search=search, status=status,
)
async def get_project(self, project_id: uuid.UUID) -> Project | None:
return await self._repo.get_by_id(project_id)
async def create_project(self, *, requester: User, data: ProjectCreate) -> Project:
return await self._repo.create(requester=requester, data=data)
folder = f"/{requester.username}/{data.name}"
return await self._repo.create(
requester=requester, data=data, folder=folder, status="DRAFT",
)
async def update_project(self, project: Project, data: ProjectUpdate) -> Project:
return await self._repo.update(project, data)