54 lines
1.9 KiB
Python
54 lines
1.9 KiB
Python
from __future__ import annotations
|
|
|
|
import asyncio
|
|
from datetime import datetime
|
|
from typing import Any, Literal, Optional
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from pydantic import BaseModel, Field
|
|
from sqlalchemy import and_, or_, select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from ...core.logging import get_logger
|
|
from ...core.response import success_response
|
|
from ...core.database import AsyncSessionLocal, get_db
|
|
from ...dependencies.auth import get_current_user
|
|
from ...dependencies.tenant import get_tenant_id
|
|
from ...models import DecisionRecord, IngestEvent, PlanBundle, PortfolioSnapshot, Project, ReplyReceipt, User, UserProject, WorkItem
|
|
from ...services.auth import has_any_role
|
|
from ...services.ai_pmo.ai_pmo_cadence import AIPMOCadenceService
|
|
from ...services.ai_pmo.ai_pmo_kernel import AIPMOKernelService
|
|
|
|
router = APIRouter(prefix="/ai-pmo", tags=["AI PMO"])
|
|
logger = get_logger(__name__)
|
|
FRONT_NOISE_INTENTS = {"query.read_only", "query.answer"}
|
|
|
|
|
|
def _can_view_all_work_items(user: User) -> bool:
|
|
return has_any_role(str(getattr(user, "role", "") or ""), ["OWNER", "REVIEWER"])
|
|
|
|
|
|
def _visible_work_item_filter(*, current_user: User, tenant_id: int):
|
|
if _can_view_all_work_items(current_user):
|
|
return True
|
|
return or_(
|
|
WorkItem.owner_user_id == int(current_user.id),
|
|
WorkItem.project_id.in_(
|
|
select(Project.id)
|
|
.outerjoin(
|
|
UserProject,
|
|
and_(
|
|
UserProject.tenant_id == Project.tenant_id,
|
|
UserProject.project_id == Project.id,
|
|
UserProject.user_id == int(current_user.id),
|
|
),
|
|
)
|
|
.where(
|
|
and_(
|
|
Project.tenant_id == int(tenant_id),
|
|
or_(Project.owner_id == int(current_user.id), UserProject.user_id.is_not(None)),
|
|
)
|
|
)
|
|
),
|
|
)
|