53 lines
1.9 KiB
Python
53 lines
1.9 KiB
Python
from fastapi import APIRouter, HTTPException
|
|
from fastapi.responses import FileResponse
|
|
import os
|
|
from pathlib import Path
|
|
from services.database import WORKSPACE_DIR, get_user_db_path
|
|
|
|
router = APIRouter(prefix="/api/assets", tags=["Assets Serving"])
|
|
|
|
@router.get("/{user_id}/avatars/{filename}")
|
|
async def serve_avatar(user_id: str, filename: str):
|
|
"""
|
|
Serve avatar images directly.
|
|
Public endpoint relying on unguessable filenames.
|
|
"""
|
|
# Sanitize user_id (simple check to prevent directory traversal)
|
|
safe_user_id = "".join(c for c in user_id if c.isalnum() or c in ('-', '_'))
|
|
if safe_user_id != user_id:
|
|
raise HTTPException(status_code=400, detail="Invalid user ID")
|
|
|
|
# Sanitize filename
|
|
safe_filename = os.path.basename(filename)
|
|
|
|
# Construct path
|
|
# workspace/workspace_{user_id}/assets/avatars/{filename}
|
|
file_path = Path(WORKSPACE_DIR) / f"workspace_{safe_user_id}" / "assets" / "avatars" / safe_filename
|
|
|
|
if not file_path.exists():
|
|
raise HTTPException(status_code=404, detail="Asset not found")
|
|
|
|
return FileResponse(file_path)
|
|
|
|
@router.get("/{user_id}/voice_samples/{filename}")
|
|
async def serve_voice_sample(user_id: str, filename: str):
|
|
"""
|
|
Serve voice sample audio files directly.
|
|
"""
|
|
# Sanitize user_id
|
|
safe_user_id = "".join(c for c in user_id if c.isalnum() or c in ('-', '_'))
|
|
if safe_user_id != user_id:
|
|
raise HTTPException(status_code=400, detail="Invalid user ID")
|
|
|
|
# Sanitize filename
|
|
safe_filename = os.path.basename(filename)
|
|
|
|
# Construct path
|
|
# workspace/workspace_{user_id}/assets/voice_samples/{filename}
|
|
file_path = Path(WORKSPACE_DIR) / f"workspace_{safe_user_id}" / "assets" / "voice_samples" / safe_filename
|
|
|
|
if not file_path.exists():
|
|
raise HTTPException(status_code=404, detail="Asset not found")
|
|
|
|
return FileResponse(file_path)
|