Files
xiaoxia-saas/apps/api/app/api/routes/asset_libraries.py
T
Xiaoxia AI cb2e20ffd4
CI/CD Pipeline / Validate Code Quality And Tests (push) Has been cancelled
Deploy / Deploy Staging (push) Has been cancelled
Deploy / Deploy Production (push) Failing after 2059h43m50s
Deploy / Build Production Runtime Images (push) Failing after 2059h52m45s
fix(api): enforce workspace access on project media routes
2026-06-22 19:37:57 +08:00

87 lines
3.6 KiB
Python

from typing import Any
from app.auth import AuthenticatedUser, get_current_user
from app.dependencies import get_asset_library_repository, get_project_repository, get_workspace_member_repository
from app.schemas.asset_library import (
AssetLibraryResponse,
CreateAssetLibraryRequest,
ListAssetLibrariesResponse,
)
from fastapi import APIRouter, Depends, HTTPException, status
from packages.application import (
CreateAssetLibraryCommand,
CreateAssetLibraryUseCase,
GetProjectUseCase,
ListAssetLibrariesUseCase,
)
from packages.domain import AssetLibraryKind
from packages.ports.workspace_member_repository import WorkspaceMemberRepository
router = APIRouter()
def _require_workspace_member(
workspace_id: str,
authenticated_user: AuthenticatedUser,
workspace_member_repository: WorkspaceMemberRepository,
) -> None:
member = workspace_member_repository.find_by_workspace_and_user(workspace_id, authenticated_user.user.id)
if member is None:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Workspace access denied")
def _to_asset_library_response(item) -> AssetLibraryResponse:
return AssetLibraryResponse(
id=item.id,
workspace_id=item.workspace_id,
project_id=item.project_id,
name=item.name,
kind=item.kind.value,
asset_count=item.asset_count,
total_size=item.total_size,
)
@router.get("", response_model=ListAssetLibrariesResponse)
def list_asset_libraries(
project_id: str,
kind: str | None = None,
authenticated_user: AuthenticatedUser = Depends(get_current_user),
asset_library_repository: Any = Depends(get_asset_library_repository),
project_repository: Any = Depends(get_project_repository),
workspace_member_repository: WorkspaceMemberRepository = Depends(get_workspace_member_repository),
) -> ListAssetLibrariesResponse:
project = GetProjectUseCase(project_repository).execute(project_id)
if project is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found")
_require_workspace_member(project.workspace_id, authenticated_user, workspace_member_repository)
use_case = ListAssetLibrariesUseCase(asset_library_repository)
parsed_kind = AssetLibraryKind(kind) if kind else None
items = use_case.execute(project_id, kind=parsed_kind)
return ListAssetLibrariesResponse(items=[_to_asset_library_response(item) for item in items])
@router.post("", response_model=AssetLibraryResponse)
def create_asset_library(
request: CreateAssetLibraryRequest,
authenticated_user: AuthenticatedUser = Depends(get_current_user),
asset_library_repository: Any = Depends(get_asset_library_repository),
project_repository: Any = Depends(get_project_repository),
workspace_member_repository: WorkspaceMemberRepository = Depends(get_workspace_member_repository),
) -> AssetLibraryResponse:
project = GetProjectUseCase(project_repository).execute(request.project_id)
if project is None or project.workspace_id != request.workspace_id:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found")
_require_workspace_member(request.workspace_id, authenticated_user, workspace_member_repository)
use_case = CreateAssetLibraryUseCase(asset_library_repository)
item = use_case.execute(
CreateAssetLibraryCommand(
workspace_id=request.workspace_id,
project_id=request.project_id,
name=request.name,
kind=AssetLibraryKind(request.kind),
)
)
return _to_asset_library_response(item)