75 lines
2.5 KiB
Python
75 lines
2.5 KiB
Python
from fastapi import APIRouter, Header, HTTPException, Query
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.core.config import settings
|
|
from app.db.models import (
|
|
SupportRoleAssignment,
|
|
SupportUser,
|
|
Workspace,
|
|
WorkspaceChannelMapping,
|
|
)
|
|
from app.db.session import get_db
|
|
from fastapi import Depends
|
|
|
|
|
|
router = APIRouter(prefix="/internal", tags=["internal"])
|
|
|
|
|
|
@router.get("/notification-recipients")
|
|
def list_notification_recipients(
|
|
project_id: int = Query(gt=0),
|
|
channel_id: int = Query(gt=0),
|
|
api_key: str | None = Header(default=None, alias="x-api-key"),
|
|
db: Session = Depends(get_db),
|
|
) -> dict[str, object]:
|
|
"""Return project-scoped notification recipients to ABC API only.
|
|
|
|
Secretary is the source of truth for workspace/project administrators.
|
|
This endpoint is intentionally protected by the service API key and is
|
|
not exposed through the public user-facing API contract.
|
|
"""
|
|
if not settings.master_api_key or api_key != settings.master_api_key:
|
|
raise HTTPException(status_code=401, detail="internal service authentication failed")
|
|
|
|
mapping = (
|
|
db.query(WorkspaceChannelMapping)
|
|
.join(Workspace, Workspace.id == WorkspaceChannelMapping.workspace_id)
|
|
.filter(
|
|
WorkspaceChannelMapping.abc_project_id == project_id,
|
|
WorkspaceChannelMapping.abc_channel_id == str(channel_id),
|
|
WorkspaceChannelMapping.is_active.is_(True),
|
|
Workspace.is_active.is_(True),
|
|
Workspace.workspace_type == "SOFTWARE_APP",
|
|
)
|
|
.order_by(WorkspaceChannelMapping.id.desc())
|
|
.first()
|
|
)
|
|
if mapping is None:
|
|
return {"items": []}
|
|
|
|
assignments = (
|
|
db.query(SupportRoleAssignment)
|
|
.join(SupportUser)
|
|
.filter(
|
|
SupportRoleAssignment.workspace_id == mapping.workspace_id,
|
|
SupportRoleAssignment.role_code == "PROJECT_MANAGER",
|
|
SupportRoleAssignment.support_user_id == SupportUser.id,
|
|
SupportUser.status == "ACTIVE",
|
|
SupportUser.email.is_not(None),
|
|
)
|
|
.order_by(SupportRoleAssignment.id.asc())
|
|
.all()
|
|
)
|
|
|
|
items = []
|
|
seen: set[str] = set()
|
|
for assignment in assignments:
|
|
email = (assignment.user.email or "").strip()
|
|
normalized = email.lower()
|
|
if not normalized or normalized in seen:
|
|
continue
|
|
seen.add(normalized)
|
|
items.append({"email": email, "role": "PROJECT_ADMIN"})
|
|
|
|
return {"items": items}
|