294 lines
11 KiB
Python
294 lines
11 KiB
Python
from typing import Optional
|
|
|
|
from fastapi import APIRouter, Depends, Form, Header
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.core.response import success_response
|
|
from app.db import get_db_session
|
|
from app.services.audit_log_service import AuditLogService
|
|
from app.services.auth_service import AuthService
|
|
from app.services.governance_service import GovernanceService
|
|
|
|
router = APIRouter(prefix="/governance", tags=["governance"])
|
|
ROUTE_PERMISSION_SCOPE = "governance_management"
|
|
ROUTE_PERMISSION_ACTIONS = {
|
|
"assets_list": "governance:assets:list",
|
|
"asset_detail": "governance:assets:detail",
|
|
"assignments_list": "governance:assignments:list",
|
|
"assignment_save": "governance:assignments:save",
|
|
"decision_submit": "governance:decisions:submit",
|
|
"evidence_save": "governance:evidences:save",
|
|
"release_summary": "governance:releases:summary",
|
|
"release_detail": "governance:releases:detail",
|
|
"formal_launch_import_preview": "governance:imports:formal_launch:preview",
|
|
"formal_launch_import": "governance:imports:formal_launch",
|
|
}
|
|
|
|
|
|
def get_governance_service(db: Session = Depends(get_db_session)) -> GovernanceService:
|
|
return GovernanceService(db)
|
|
|
|
|
|
def get_audit_log_service(db: Session = Depends(get_db_session)) -> AuditLogService:
|
|
return AuditLogService(db)
|
|
|
|
|
|
def require_current_user(
|
|
authorization: Optional[str] = Header(default=None),
|
|
db: Session = Depends(get_db_session),
|
|
):
|
|
return AuthService(db).require_current_user(authorization)
|
|
|
|
|
|
@router.get("/assets")
|
|
def list_governance_assets(
|
|
page: int = 1,
|
|
page_size: int = 20,
|
|
asset_type: Optional[str] = None,
|
|
governance_status: Optional[str] = None,
|
|
review_status: Optional[str] = None,
|
|
production_status: Optional[str] = None,
|
|
assignment_role: Optional[str] = None,
|
|
governance_service: GovernanceService = Depends(get_governance_service),
|
|
current_user: dict = Depends(require_current_user),
|
|
):
|
|
return success_response(
|
|
governance_service.list_assets(
|
|
current_user=current_user,
|
|
page=page,
|
|
page_size=page_size,
|
|
asset_type=asset_type,
|
|
governance_status=governance_status,
|
|
review_status=review_status,
|
|
production_status=production_status,
|
|
assignment_role=assignment_role,
|
|
)
|
|
)
|
|
|
|
|
|
@router.get("/assets/{governance_asset_id}")
|
|
def get_governance_asset_detail(
|
|
governance_asset_id: str,
|
|
governance_service: GovernanceService = Depends(get_governance_service),
|
|
current_user: dict = Depends(require_current_user),
|
|
):
|
|
return success_response(governance_service.get_asset_detail(current_user, governance_asset_id))
|
|
|
|
|
|
@router.get("/assignments")
|
|
def list_governance_assignments(
|
|
page: int = 1,
|
|
page_size: int = 20,
|
|
assignment_role: Optional[str] = None,
|
|
status_filter: Optional[str] = None,
|
|
assignee_user_id: Optional[str] = None,
|
|
governance_asset_id: Optional[str] = None,
|
|
governance_service: GovernanceService = Depends(get_governance_service),
|
|
current_user: dict = Depends(require_current_user),
|
|
):
|
|
return success_response(
|
|
governance_service.list_assignments(
|
|
current_user=current_user,
|
|
page=page,
|
|
page_size=page_size,
|
|
assignment_role=assignment_role,
|
|
status_filter=status_filter,
|
|
assignee_user_id=assignee_user_id,
|
|
governance_asset_id=governance_asset_id,
|
|
)
|
|
)
|
|
|
|
|
|
@router.post("/assignments")
|
|
def save_governance_assignment(
|
|
governance_asset_id: str = Form(...),
|
|
assignment_role: str = Form(...),
|
|
assignee_user_id: Optional[str] = Form(default=None),
|
|
assignee_name: Optional[str] = Form(default=None),
|
|
due_at: Optional[str] = Form(default=None),
|
|
status_value: Optional[str] = Form(default=None),
|
|
priority: Optional[str] = Form(default=None),
|
|
notes: Optional[str] = Form(default=None),
|
|
assignment_id: Optional[str] = Form(default=None),
|
|
is_active: bool = Form(default=True),
|
|
governance_service: GovernanceService = Depends(get_governance_service),
|
|
audit_log_service: AuditLogService = Depends(get_audit_log_service),
|
|
current_user: dict = Depends(require_current_user),
|
|
):
|
|
result = governance_service.save_assignment(
|
|
current_user=current_user,
|
|
governance_asset_id=governance_asset_id,
|
|
assignment_role=assignment_role,
|
|
assignee_user_id=assignee_user_id,
|
|
assignee_name=assignee_name,
|
|
due_at=due_at,
|
|
status_value=status_value,
|
|
priority=priority,
|
|
notes=notes,
|
|
assignment_id=assignment_id,
|
|
is_active=is_active,
|
|
)
|
|
audit_log_service.record_event(
|
|
tenant_id=current_user.get("tenant_id"),
|
|
user_id=current_user.get("id"),
|
|
action="save_governance_assignment",
|
|
resource_type="governance_assignment",
|
|
resource_id=result["id"],
|
|
detail_json={
|
|
"governance_asset_id": result["governance_asset_id"],
|
|
"assignment_role": result["assignment_role"],
|
|
"assignee_user_id": result["assignee_user_id"],
|
|
"assignee_name": result["assignee_name"],
|
|
"actor_role": current_user.get("role"),
|
|
"status": result["status"],
|
|
"priority": result["priority"],
|
|
"is_active": result["is_active"],
|
|
},
|
|
)
|
|
return success_response(result)
|
|
|
|
|
|
@router.post("/decisions")
|
|
def submit_governance_decision(
|
|
governance_asset_id: str = Form(...),
|
|
assignment_id: Optional[str] = Form(default=None),
|
|
decision_role: str = Form(...),
|
|
decision_result: str = Form(...),
|
|
decision_summary: Optional[str] = Form(default=None),
|
|
required_changes: Optional[str] = Form(default=None),
|
|
decided_by_name: Optional[str] = Form(default=None),
|
|
decision_at: Optional[str] = Form(default=None),
|
|
metadata_json: Optional[str] = Form(default=None),
|
|
governance_service: GovernanceService = Depends(get_governance_service),
|
|
audit_log_service: AuditLogService = Depends(get_audit_log_service),
|
|
current_user: dict = Depends(require_current_user),
|
|
):
|
|
result = governance_service.submit_decision(
|
|
current_user=current_user,
|
|
governance_asset_id=governance_asset_id,
|
|
assignment_id=assignment_id,
|
|
decision_role=decision_role,
|
|
decision_result=decision_result,
|
|
decision_summary=decision_summary,
|
|
required_changes=required_changes,
|
|
decided_by_name=decided_by_name,
|
|
decision_at=decision_at,
|
|
metadata_json=metadata_json,
|
|
)
|
|
audit_log_service.record_event(
|
|
tenant_id=current_user.get("tenant_id"),
|
|
user_id=current_user.get("id"),
|
|
action="submit_governance_decision",
|
|
resource_type="governance_decision",
|
|
resource_id=result["decision"]["id"],
|
|
detail_json={
|
|
"governance_asset_id": governance_asset_id,
|
|
"assignment_id": assignment_id,
|
|
"decision_role": result["decision"]["decision_role"],
|
|
"decision_result": result["decision"]["decision_result"],
|
|
"actor_role": current_user.get("role"),
|
|
},
|
|
)
|
|
return success_response(result)
|
|
|
|
|
|
@router.post("/evidences")
|
|
def save_governance_evidence(
|
|
governance_asset_id: str = Form(...),
|
|
decision_id: Optional[str] = Form(default=None),
|
|
file_id: Optional[str] = Form(default=None),
|
|
evidence_type: Optional[str] = Form(default=None),
|
|
storage_type: Optional[str] = Form(default=None),
|
|
external_url: Optional[str] = Form(default=None),
|
|
file_name: Optional[str] = Form(default=None),
|
|
checksum: Optional[str] = Form(default=None),
|
|
status_value: Optional[str] = Form(default=None),
|
|
reviewer_name: Optional[str] = Form(default=None),
|
|
collected_at: Optional[str] = Form(default=None),
|
|
metadata_json: Optional[str] = Form(default=None),
|
|
governance_service: GovernanceService = Depends(get_governance_service),
|
|
audit_log_service: AuditLogService = Depends(get_audit_log_service),
|
|
current_user: dict = Depends(require_current_user),
|
|
):
|
|
result = governance_service.save_evidence(
|
|
current_user=current_user,
|
|
governance_asset_id=governance_asset_id,
|
|
decision_id=decision_id,
|
|
file_id=file_id,
|
|
evidence_type=evidence_type,
|
|
storage_type=storage_type,
|
|
external_url=external_url,
|
|
file_name=file_name,
|
|
checksum=checksum,
|
|
status_value=status_value,
|
|
reviewer_name=reviewer_name,
|
|
collected_at=collected_at,
|
|
metadata_json=metadata_json,
|
|
)
|
|
audit_log_service.record_event(
|
|
tenant_id=current_user.get("tenant_id"),
|
|
user_id=current_user.get("id"),
|
|
action="save_governance_evidence",
|
|
resource_type="governance_evidence",
|
|
resource_id=result["evidence"]["id"],
|
|
detail_json={
|
|
"governance_asset_id": governance_asset_id,
|
|
"decision_id": decision_id,
|
|
"actor_role": current_user.get("role"),
|
|
"status": result["evidence"]["status"],
|
|
"storage_type": result["evidence"]["storage_type"],
|
|
"external_url": result["evidence"]["external_url"],
|
|
"file_id": result["evidence"]["file_id"],
|
|
},
|
|
)
|
|
return success_response(result)
|
|
|
|
|
|
@router.get("/releases/summary")
|
|
def get_governance_release_summary(
|
|
governance_service: GovernanceService = Depends(get_governance_service),
|
|
current_user: dict = Depends(require_current_user),
|
|
):
|
|
return success_response(governance_service.get_release_summary(current_user))
|
|
|
|
|
|
@router.get("/releases/{release_batch_id}")
|
|
def get_governance_release_detail(
|
|
release_batch_id: str,
|
|
governance_service: GovernanceService = Depends(get_governance_service),
|
|
current_user: dict = Depends(require_current_user),
|
|
):
|
|
return success_response(governance_service.get_release_detail(current_user, release_batch_id))
|
|
|
|
|
|
@router.get("/imports/formal-launch/preview")
|
|
def preview_formal_launch_governance_import(
|
|
governance_service: GovernanceService = Depends(get_governance_service),
|
|
current_user: dict = Depends(require_current_user),
|
|
):
|
|
return success_response(governance_service.preview_formal_launch_import(current_user))
|
|
|
|
|
|
@router.post("/imports/formal-launch")
|
|
def import_formal_launch_governance(
|
|
batch_name: Optional[str] = Form(default=None),
|
|
governance_service: GovernanceService = Depends(get_governance_service),
|
|
audit_log_service: AuditLogService = Depends(get_audit_log_service),
|
|
current_user: dict = Depends(require_current_user),
|
|
):
|
|
result = governance_service.import_formal_launch(current_user, batch_name=batch_name)
|
|
audit_log_service.record_event(
|
|
tenant_id=current_user.get("tenant_id"),
|
|
user_id=current_user.get("id"),
|
|
action="import_formal_launch_governance",
|
|
resource_type="governance_import",
|
|
resource_id=result["release_batch"]["id"],
|
|
detail_json={
|
|
"batch_name": result["release_batch"]["batch_name"],
|
|
"actor_role": current_user.get("role"),
|
|
"status": result["release_batch"]["status"],
|
|
"imported": result["imported"],
|
|
},
|
|
)
|
|
return success_response(result)
|