Files
autoclip/backend/api/v1/collections.py
T
2025-08-21 01:05:23 +08:00

241 lines
11 KiB
Python

"""
合集API路由
"""
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from core.database import get_db
from services.collection_service import CollectionService
from schemas.collection import CollectionCreate, CollectionUpdate, CollectionResponse, CollectionListResponse
from schemas.base import PaginationParams
router = APIRouter()
def get_collection_service(db: Session = Depends(get_db)) -> CollectionService:
"""Dependency to get collection service."""
return CollectionService(db)
@router.post("/", response_model=CollectionResponse)
async def create_collection(
collection_data: CollectionCreate,
collection_service: CollectionService = Depends(get_collection_service)
):
"""Create a new collection."""
try:
collection = collection_service.create_collection(collection_data)
# Convert to response schema
status_obj = getattr(collection, 'status', None)
status_value = status_obj.value if hasattr(status_obj, 'value') else 'created'
return CollectionResponse(
id=str(getattr(collection, 'id', '')),
project_id=str(getattr(collection, 'project_id', '')),
name=str(getattr(collection, 'name', '')),
description=str(getattr(collection, 'description', '')) if getattr(collection, 'description', None) else None,
theme=getattr(collection, 'theme', None),
status=status_value,
tags=getattr(collection, 'tags', []) or [],
metadata=getattr(collection, 'collection_metadata', {}) or {},
created_at=getattr(collection, 'created_at', None) if isinstance(getattr(collection, 'created_at', None), (type(None), __import__('datetime').datetime)) else None,
updated_at=getattr(collection, 'updated_at', None) if isinstance(getattr(collection, 'updated_at', None), (type(None), __import__('datetime').datetime)) else None,
total_clips=getattr(collection, 'clips_count', 0) or 0
)
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
@router.get("/", response_model=CollectionListResponse)
async def get_collections(
page: int = Query(1, ge=1, description="Page number"),
size: int = Query(20, ge=1, le=100, description="Page size"),
project_id: Optional[str] = Query(None, description="Filter by project ID"),
collection_service: CollectionService = Depends(get_collection_service)
):
"""Get paginated collections."""
try:
from schemas.base import PaginationParams
from schemas.collection import CollectionFilter
pagination = PaginationParams(page=page, size=size)
filters = None
if project_id:
filters = CollectionFilter(project_id=project_id)
return collection_service.get_collections_paginated(pagination, filters)
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
@router.get("/{collection_id}", response_model=CollectionResponse)
async def get_collection(
collection_id: str,
include_content: bool = Query(False, description="是否包含完整内容"),
collection_service: CollectionService = Depends(get_collection_service)
):
"""Get a collection by ID (优化存储模式)."""
try:
collection = collection_service.get(collection_id)
if not collection:
raise HTTPException(status_code=404, detail="Collection not found")
# Convert to response schema
status_obj = getattr(collection, 'status', None)
status_value = status_obj.value if hasattr(status_obj, 'value') else 'created'
# 获取clip_ids
clip_ids = []
metadata = getattr(collection, 'collection_metadata', {}) or {}
if metadata and 'clip_ids' in metadata:
clip_ids = metadata['clip_ids']
# 如果需要完整内容,从文件系统获取
full_content = None
if include_content:
from repositories.collection_repository import CollectionRepository
collection_repo = CollectionRepository(collection_service.db)
full_content = collection_repo.get_collection_content(collection_id)
# 构建响应数据
response_data = {
"id": str(getattr(collection, 'id', '')),
"project_id": str(getattr(collection, 'project_id', '')),
"name": str(getattr(collection, 'name', '')),
"description": str(getattr(collection, 'description', '')) if getattr(collection, 'description', None) else None,
"theme": getattr(collection, 'theme', None),
"status": status_value,
"tags": getattr(collection, 'tags', []) or [],
"metadata": getattr(collection, 'collection_metadata', {}) or {},
"created_at": getattr(collection, 'created_at', None) if isinstance(getattr(collection, 'created_at', None), (type(None), __import__('datetime').datetime)) else None,
"updated_at": getattr(collection, 'updated_at', None) if isinstance(getattr(collection, 'updated_at', None), (type(None), __import__('datetime').datetime)) else None,
"total_clips": getattr(collection, 'clips_count', 0) or 0,
"clip_ids": clip_ids
}
# 如果需要完整内容,添加到响应中
if include_content and full_content:
response_data["full_content"] = full_content
return CollectionResponse(**response_data)
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
@router.put("/{collection_id}", response_model=CollectionResponse)
async def update_collection(
collection_id: str,
collection_data: CollectionUpdate,
collection_service: CollectionService = Depends(get_collection_service)
):
"""Update a collection."""
try:
collection = collection_service.update_collection(collection_id, collection_data)
if not collection:
raise HTTPException(status_code=404, detail="Collection not found")
# Convert to response schema
status_obj = getattr(collection, 'status', None)
status_value = status_obj.value if hasattr(status_obj, 'value') else 'created'
# 获取clip_ids
clip_ids = []
metadata = getattr(collection, 'collection_metadata', {}) or {}
if metadata and 'clip_ids' in metadata:
clip_ids = metadata['clip_ids']
return CollectionResponse(
id=str(getattr(collection, 'id', '')),
project_id=str(getattr(collection, 'project_id', '')),
name=str(getattr(collection, 'name', '')),
description=str(getattr(collection, 'description', '')) if getattr(collection, 'description', None) else None,
theme=getattr(collection, 'theme', None),
status=status_value,
tags=getattr(collection, 'tags', []) or [],
metadata=getattr(collection, 'collection_metadata', {}) or {},
created_at=getattr(collection, 'created_at', None) if isinstance(getattr(collection, 'created_at', None), (type(None), __import__('datetime').datetime)) else None,
updated_at=getattr(collection, 'updated_at', None) if isinstance(getattr(collection, 'updated_at', None), (type(None), __import__('datetime').datetime)) else None,
total_clips=getattr(collection, 'clips_count', 0) or 0,
clip_ids=clip_ids
)
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
@router.delete("/{collection_id}")
async def delete_collection(
collection_id: str,
collection_service: CollectionService = Depends(get_collection_service)
):
"""Delete a collection."""
try:
success = collection_service.delete(collection_id)
if not success:
raise HTTPException(status_code=404, detail="Collection not found")
return {"message": "Collection deleted successfully"}
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
@router.patch("/{collection_id}/reorder", response_model=CollectionResponse)
async def reorder_collection_clips(
collection_id: str,
clip_ids: List[str],
collection_service: CollectionService = Depends(get_collection_service)
):
"""Reorder clips in a collection."""
try:
# 获取合集
collection = collection_service.get(collection_id)
if not collection:
raise HTTPException(status_code=404, detail="Collection not found")
# 更新collection_metadata中的clip_ids
metadata = getattr(collection, 'collection_metadata', {}) or {}
metadata['clip_ids'] = clip_ids
# 直接更新数据库中的collection_metadata字段
from sqlalchemy import update
from models.collection import Collection
stmt = update(Collection).where(Collection.id == collection_id).values(
collection_metadata=metadata
)
collection_service.db.execute(stmt)
collection_service.db.commit()
# 重新获取更新后的合集
updated_collection = collection_service.get(collection_id)
if not updated_collection:
raise HTTPException(status_code=404, detail="Collection not found")
# Convert to response schema
status_obj = getattr(updated_collection, 'status', None)
status_value = status_obj.value if hasattr(status_obj, 'value') else 'created'
return CollectionResponse(
id=str(getattr(updated_collection, 'id', '')),
project_id=str(getattr(updated_collection, 'project_id', '')),
name=str(getattr(updated_collection, 'name', '')),
description=str(getattr(updated_collection, 'description', '')) if getattr(updated_collection, 'description', None) else None,
theme=getattr(updated_collection, 'theme', None),
status=status_value,
tags=getattr(updated_collection, 'tags', []) or [],
metadata=getattr(updated_collection, 'collection_metadata', {}) or {},
created_at=getattr(updated_collection, 'created_at', None) if isinstance(getattr(updated_collection, 'created_at', None), (type(None), __import__('datetime').datetime)) else None,
updated_at=getattr(updated_collection, 'updated_at', None) if isinstance(getattr(updated_collection, 'updated_at', None), (type(None), __import__('datetime').datetime)) else None,
total_clips=getattr(updated_collection, 'clips_count', 0) or 0,
clip_ids=clip_ids
)
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))