Add form-based storage endpoint for browser submissions

The POST /storage endpoint required Bearer token auth and JSON body,
which didn't work with browser form submissions using cookies. Added
new /storage/add endpoint that accepts form data and cookie auth.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
gilesb
2026-01-10 00:19:36 +00:00
parent fb5c46330d
commit 8bef9afb1f

View File

@@ -27,7 +27,7 @@ logging.basicConfig(
)
logger = logging.getLogger(__name__)
from fastapi import FastAPI, HTTPException, Request, Response, Depends, Cookie
from fastapi import FastAPI, HTTPException, Request, Response, Depends, Cookie, Form
from fastapi.responses import JSONResponse, HTMLResponse, RedirectResponse, FileResponse
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from pydantic import BaseModel
@@ -3120,6 +3120,72 @@ async def add_storage(req: AddStorageRequest, user: User = Depends(get_required_
return {"id": storage_id, "message": f"Storage provider added: {provider_name}"}
@app.post("/storage/add")
async def add_storage_form(
request: Request,
provider_type: str = Form(...),
provider_name: 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),
path: Optional[str] = Form(None),
):
"""Add a storage provider via HTML form (cookie auth)."""
username = get_user_from_cookie(request)
if not username:
return HTMLResponse('<div class="text-red-400">Not authenticated</div>', status_code=401)
# Validate provider type
if provider_type not in ["pinata", "web3storage", "local"]:
return HTMLResponse(f'<div class="text-red-400">Invalid provider type: {provider_type}</div>')
# Build config based on provider type
config = {}
if provider_type == "pinata":
if not api_key or not secret_key:
return HTMLResponse('<div class="text-red-400">Pinata requires API Key and Secret Key</div>')
config = {"api_key": api_key, "secret_key": secret_key}
elif provider_type == "web3storage":
if not api_token:
return HTMLResponse('<div class="text-red-400">web3.storage requires API Token</div>')
config = {"api_token": api_token}
elif provider_type == "local":
if not path:
return HTMLResponse('<div class="text-red-400">Local storage requires a path</div>')
config = {"path": path}
# Test the provider connection before saving
provider = storage_providers.create_provider(provider_type, {
**config,
"capacity_gb": capacity_gb
})
if not provider:
return HTMLResponse('<div class="text-red-400">Failed to create provider with given config</div>')
success, message = await provider.test_connection()
if not success:
return HTMLResponse(f'<div class="text-red-400">Provider connection failed: {message}</div>')
# Save to database
name = provider_name or f"{provider_type}-{username}"
storage_id = await db.add_user_storage(
username=username,
provider_type=provider_type,
provider_name=name,
config=config,
capacity_gb=capacity_gb
)
if not storage_id:
return HTMLResponse('<div class="text-red-400">Failed to save storage provider</div>')
return HTMLResponse(f'''
<div class="text-green-400 mb-2">Storage provider "{name}" added successfully!</div>
<script>setTimeout(() => window.location.reload(), 1500);</script>
''')
@app.get("/storage/{storage_id}")
async def get_storage(storage_id: int, user: User = Depends(get_required_user)):
"""Get a specific storage provider."""
@@ -3312,7 +3378,7 @@ async def ui_storage_page(username: str, storages: list, request: Request) -> HT
</div>
<div id="add-form" class="hidden bg-dark-600 rounded-lg p-4">
<form id="storage-form" hx-post="/storage" hx-target="#add-result" hx-swap="innerHTML">
<form id="storage-form" hx-post="/storage/add" hx-target="#add-result" hx-swap="innerHTML">
<input type="hidden" name="provider_type" id="provider_type">
<div id="pinata-fields" class="hidden space-y-4">
@@ -3383,30 +3449,6 @@ async def ui_storage_page(username: str, storages: list, request: Request) -> HT
function hideAddForm() {{
document.getElementById('add-form').classList.add('hidden');
}}
// Handle form submission to build proper JSON
document.getElementById('storage-form').addEventListener('htmx:configRequest', function(evt) {{
const formData = new FormData(evt.detail.elt);
const providerType = formData.get('provider_type');
const config = {{}};
if (providerType === 'pinata') {{
config.api_key = formData.get('api_key');
config.secret_key = formData.get('secret_key');
}} else if (providerType === 'web3storage') {{
config.api_token = formData.get('api_token');
}} else if (providerType === 'local') {{
config.path = formData.get('path');
}}
evt.detail.headers['Content-Type'] = 'application/json';
evt.detail.parameters = JSON.stringify({{
provider_type: providerType,
provider_name: formData.get('provider_name') || null,
config: config,
capacity_gb: parseInt(formData.get('capacity_gb'))
}});
}});
</script>
'''