from __future__ import annotations from fastapi import APIRouter, Body, Request, Depends from typing import Any from app.api.v1.endpoints.platform import ok, fail from app.db.platform_store import get_platform_store from app.core.auth import get_current_user, has_resource_access, is_admin router = APIRouter(prefix="/resources", tags=["resource"]) def _actor(request: Request) -> str | None: auth = request.headers.get("Authorization", "") token = auth.replace("Bearer ", "").strip() return token or None @router.get("/{resource_type}/{resource_id}/acl") def get_acl(resource_type: str, resource_id: str, current_user: dict = Depends(get_current_user)) -> dict[str, Any]: """查询资源 ACL,返回按主体分组的权限列表。""" if not has_resource_access(resource_type, resource_id, current_user, "read"): raise fail(403, "no permission to access resource ACL") return ok(get_platform_store().resource_acl(resource_type, resource_id)) @router.put("/{resource_type}/{resource_id}/acl") def set_acl( resource_type: str, resource_id: str, payload: dict[str, Any] = Body(...), request: Request = None, current_user: dict = Depends(get_current_user), ) -> dict[str, Any]: """设置资源 ACL,body: { entries: [{ subject_type, subject_id, permissions: [] }] }""" if not is_admin(current_user) and not has_resource_access(resource_type, resource_id, current_user, "write"): raise fail(403, "only resource owner or admin can update ACL") entries = payload.get("entries") or [] allowed = {"read", "write", "execute", "download", "delete", "admin"} for entry in entries: if entry.get("principal_type") not in {"user", "role"} or not entry.get("principal_id"): raise fail(400, "invalid ACL principal") if any(permission not in allowed for permission in entry.get("permissions") or []): raise fail(400, "invalid ACL permission") result = get_platform_store().set_resource_acl(resource_type, resource_id, entries) get_platform_store().record_audit( action="resource.acl.set", actor_id=_actor(request) if request else None, target_type=resource_type, target_id=resource_id, detail=f"entries={len(entries)}", ) return ok(result)