""" Storage provider routes for L1 server. Manages user storage backends (Pinata, web3.storage, local, etc.) """ from typing import Optional, Dict, Any from fastapi import APIRouter, Request, Depends, HTTPException, Form from fastapi.responses import HTMLResponse, RedirectResponse from pydantic import BaseModel from artdag_common import render from artdag_common.middleware import wants_html, wants_json from ..dependencies import get_database, get_current_user, require_auth, get_templates from ..services.auth_service import UserContext from ..services.storage_service import StorageService, STORAGE_PROVIDERS_INFO, VALID_PROVIDER_TYPES router = APIRouter() # Import storage_providers module import storage_providers as sp_module def get_storage_service(): """Get storage service instance.""" import database return StorageService(database, sp_module) class AddStorageRequest(BaseModel): provider_type: str config: Dict[str, Any] capacity_gb: int = 5 provider_name: Optional[str] = None class UpdateStorageRequest(BaseModel): config: Optional[Dict[str, Any]] = None capacity_gb: Optional[int] = None is_active: Optional[bool] = None @router.get("") async def list_storage( request: Request, storage_service: StorageService = Depends(get_storage_service), ): """List user's storage providers. HTML for browsers, JSON for API.""" from ..services.auth_service import AuthService from ..dependencies import get_redis_client auth_service = AuthService(get_redis_client()) ctx = auth_service.get_user_from_cookie(request) if not ctx: if wants_json(request): raise HTTPException(401, "Authentication required") return RedirectResponse(url="/auth", status_code=302) storages = await storage_service.list_storages(ctx.actor_id) if wants_json(request): return {"storages": storages} # Render HTML template templates = get_templates(request) return render(templates, "storage/list.html", request, storages=storages, user=ctx, providers_info=STORAGE_PROVIDERS_INFO, ) @router.post("") async def add_storage( req: AddStorageRequest, request: Request, storage_service: StorageService = Depends(get_storage_service), ): """Add a storage provider via API.""" ctx = await require_auth(request) storage_id, error = await storage_service.add_storage( actor_id=ctx.actor_id, provider_type=req.provider_type, config=req.config, capacity_gb=req.capacity_gb, provider_name=req.provider_name, ) if error: raise HTTPException(400, error) return {"id": storage_id, "message": "Storage provider added"} @router.post("/add") async def add_storage_form( request: Request, provider_type: str = Form(...), provider_name: Optional[str] = Form(None), description: Optional[str] = Form(None), capacity_gb: int = Form(5), api_key: Optional[str] = Form(None), secret_key: Optional[str] = Form(None), api_token: Optional[str] = Form(None), project_id: Optional[str] = Form(None), project_secret: Optional[str] = Form(None), access_key: Optional[str] = Form(None), bucket: Optional[str] = Form(None), path: Optional[str] = Form(None), storage_service: StorageService = Depends(get_storage_service), ): """Add a storage provider via HTML form.""" from ..services.auth_service import AuthService from ..dependencies import get_redis_client auth_service = AuthService(get_redis_client()) ctx = auth_service.get_user_from_cookie(request) if not ctx: return HTMLResponse('
Not authenticated
', status_code=401) # Build config from form form_data = { "api_key": api_key, "secret_key": secret_key, "api_token": api_token, "project_id": project_id, "project_secret": project_secret, "access_key": access_key, "bucket": bucket, "path": path, } config, error = storage_service.build_config_from_form(provider_type, form_data) if error: return HTMLResponse(f'
{error}
') storage_id, error = await storage_service.add_storage( actor_id=ctx.actor_id, provider_type=provider_type, config=config, capacity_gb=capacity_gb, provider_name=provider_name, description=description, ) if error: return HTMLResponse(f'
{error}
') return HTMLResponse(f'''
Storage provider added successfully!
''') @router.get("/{storage_id}") async def get_storage( storage_id: int, request: Request, storage_service: StorageService = Depends(get_storage_service), ): """Get a specific storage provider.""" ctx = await require_auth(request) storage = await storage_service.get_storage(storage_id, ctx.actor_id) if not storage: raise HTTPException(404, "Storage provider not found") return storage @router.patch("/{storage_id}") async def update_storage( storage_id: int, req: UpdateStorageRequest, request: Request, storage_service: StorageService = Depends(get_storage_service), ): """Update a storage provider.""" ctx = await require_auth(request) success, error = await storage_service.update_storage( storage_id=storage_id, actor_id=ctx.actor_id, config=req.config, capacity_gb=req.capacity_gb, is_active=req.is_active, ) if error: raise HTTPException(400, error) return {"message": "Storage provider updated"} @router.delete("/{storage_id}") async def delete_storage( storage_id: int, request: Request, storage_service: StorageService = Depends(get_storage_service), ): """Remove a storage provider.""" from ..services.auth_service import AuthService from ..dependencies import get_redis_client auth_service = AuthService(get_redis_client()) ctx = auth_service.get_user_from_cookie(request) if not ctx: raise HTTPException(401, "Not authenticated") success, error = await storage_service.delete_storage(storage_id, ctx.actor_id) if error: raise HTTPException(400, error) if wants_html(request): return HTMLResponse("") return {"message": "Storage provider removed"} @router.post("/{storage_id}/test") async def test_storage( storage_id: int, request: Request, storage_service: StorageService = Depends(get_storage_service), ): """Test storage provider connectivity.""" from ..services.auth_service import AuthService from ..dependencies import get_redis_client auth_service = AuthService(get_redis_client()) ctx = auth_service.get_user_from_cookie(request) if not ctx: if wants_html(request): return HTMLResponse('Not authenticated', status_code=401) raise HTTPException(401, "Not authenticated") success, message = await storage_service.test_storage(storage_id, ctx.actor_id) if wants_html(request): color = "green" if success else "red" return HTMLResponse(f'{message}') return {"success": success, "message": message} @router.get("/type/{provider_type}") async def storage_type_page( provider_type: str, request: Request, storage_service: StorageService = Depends(get_storage_service), ): """Page for managing storage configs of a specific type.""" from ..services.auth_service import AuthService from ..dependencies import get_redis_client auth_service = AuthService(get_redis_client()) ctx = auth_service.get_user_from_cookie(request) if not ctx: return RedirectResponse(url="/auth", status_code=302) if provider_type not in STORAGE_PROVIDERS_INFO: raise HTTPException(404, "Invalid provider type") storages = await storage_service.list_by_type(ctx.actor_id, provider_type) provider_info = STORAGE_PROVIDERS_INFO[provider_type] templates = get_templates(request) return render(templates, "storage/type.html", request, provider_type=provider_type, provider_info=provider_info, storages=storages, user=ctx, )