PMFlow/backend/app/api/task_briefs.py

196 lines
5.9 KiB
Python

"""增量任务包中心 API。"""
from __future__ import annotations
from typing import Optional
from fastapi import APIRouter, Depends
from fastapi.responses import JSONResponse
from pydantic import BaseModel, Field
from sqlalchemy.ext.asyncio import AsyncSession
from ..core.response import error_response, success_response
from ..core.database import get_db
from ..dependencies import get_current_user
from ..models import User
from ..services.auth import has_any_role
from ..services.operation_log_service import log_operation
from ..services.task_brief import TaskBriefService
router = APIRouter(prefix="/task-briefs", tags=["task_briefs"])
class TemplateCreateRequest(BaseModel):
name: str
content: str
description: Optional[str] = None
class TemplateUpdateRequest(BaseModel):
name: Optional[str] = None
content: Optional[str] = None
description: Optional[str] = None
class GenerateTaskBriefRequest(BaseModel):
title: str
template_id: Optional[str] = None
changed_files: list[str] = Field(default_factory=list)
scope_summary: Optional[str] = None
def _require_manager(current_user: User) -> Optional[JSONResponse]:
if has_any_role(str(current_user.role or ""), ["OWNER", "REVIEWER"]):
return None
return JSONResponse(status_code=403, content=error_response(403, "仅管理员可执行该操作"))
@router.get("/center")
async def list_task_brief_center(
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
tenant_id = int(current_user.tenant_id)
items = await TaskBriefService.list_center(db, tenant_id=tenant_id)
return success_response({"items": items})
@router.get("/templates")
async def list_task_brief_templates(
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
tenant_id = int(current_user.tenant_id)
items = await TaskBriefService.list_templates(db, tenant_id=tenant_id)
return success_response({"items": items})
@router.post("/templates")
async def create_task_brief_template(
body: TemplateCreateRequest,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
denied = _require_manager(current_user)
if denied is not None:
return denied
tenant_id = int(current_user.tenant_id)
item = await TaskBriefService.create_template(
db,
tenant_id=tenant_id,
operator_user_id=int(current_user.id),
name=body.name,
content=body.content,
description=body.description,
)
await log_operation(
db,
tenant_id=tenant_id,
user_id=int(current_user.id),
project_id=None,
entity_type="task_brief_template",
entity_id=str(item.get("id") or ""),
action="create",
before_data=None,
after_data=item,
remark="创建任务包模板",
)
await db.commit()
return success_response(item)
@router.put("/templates/{template_id}")
async def update_task_brief_template(
template_id: str,
body: TemplateUpdateRequest,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
denied = _require_manager(current_user)
if denied is not None:
return denied
tenant_id = int(current_user.tenant_id)
before_items = await TaskBriefService.list_templates(db, tenant_id=tenant_id)
before = next((item for item in before_items if str(item.get("id") or "") == str(template_id)), None)
item = await TaskBriefService.update_template(
db,
tenant_id=tenant_id,
operator_user_id=int(current_user.id),
template_id=template_id,
name=body.name,
content=body.content,
description=body.description,
)
if item is None:
await db.rollback()
return JSONResponse(status_code=404, content=error_response(404, "模板不存在"))
await log_operation(
db,
tenant_id=tenant_id,
user_id=int(current_user.id),
project_id=None,
entity_type="task_brief_template",
entity_id=str(template_id),
action="update",
before_data=before,
after_data=item,
remark="更新任务包模板",
)
await db.commit()
return success_response(item)
@router.get("/runs")
async def list_task_brief_runs(
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
tenant_id = int(current_user.tenant_id)
items = await TaskBriefService.list_runs(db, tenant_id=tenant_id)
return success_response({"items": items})
@router.post("/generate")
async def generate_task_brief(
body: GenerateTaskBriefRequest,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
denied = _require_manager(current_user)
if denied is not None:
return denied
tenant_id = int(current_user.tenant_id)
result = await TaskBriefService.generate_brief(
db,
tenant_id=tenant_id,
operator_user_id=int(current_user.id),
title=body.title,
template_id=body.template_id,
changed_files=body.changed_files,
scope_summary=body.scope_summary,
)
await log_operation(
db,
tenant_id=tenant_id,
user_id=int(current_user.id),
project_id=None,
entity_type="task_brief_run",
entity_id=str((result.get("run") or {}).get("id") or ""),
action="generate",
before_data=None,
after_data=result,
remark="生成增量任务包",
)
await db.commit()
return success_response(result)
@router.get("/contract-sync")
async def get_task_brief_contract_sync(
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
tenant_id = int(current_user.tenant_id)
data = await TaskBriefService.get_contract_sync_status(db, tenant_id=tenant_id)
return success_response(data)