fix: Support local file storage uploads in addition to S3
Build and Push Outline MCP Docker Image / build (push) Successful in 8s

The upload endpoint now detects whether Outline uses local file storage
(multipart form POST) or S3 (pre-signed PUT URL) and handles both.
This commit is contained in:
2026-05-25 02:44:13 +00:00
parent d637394c0e
commit c68bb66de1
+30 -7
View File
@@ -633,27 +633,50 @@ async def upload_endpoint(request: Request) -> JSONResponse:
status_code=502, status_code=502,
) )
attachment_data = create_response.get("data", {}) response_data = create_response.get("data", {})
upload_url = attachment_data.get("uploadUrl") upload_url = response_data.get("uploadUrl")
form_fields = response_data.get("form", {})
attachment_data = response_data.get("attachment", {})
if not upload_url: if not upload_url:
return JSONResponse( return JSONResponse(
{"ok": False, "error": "Outline API did not return an uploadUrl"}, {"ok": False, "error": "Outline API did not return an uploadUrl"},
status_code=502, status_code=502,
) )
# 3. Stream the request body directly to S3 upload_url # Resolve relative uploadUrl against the Outline base URL
if upload_url.startswith("/"):
upload_url = f"{OUTLINE_API_URL}{upload_url}"
is_local_storage = bool(form_fields)
# 3. Upload the file content to storage
try: try:
# Pre-signed S3 PUT URLs usually enforce exact headers body = await request.body()
if is_local_storage:
# Local/database file storage: POST multipart form with fields from Outline
logger.info(f"Uploading via local storage endpoint (size={size} bytes)")
files = {"file": (filename, body, content_type)}
async with httpx.AsyncClient() as client:
post_response = await client.post(
upload_url,
data=form_fields,
files=files,
headers={"Authorization": f"Bearer {OUTLINE_API_TOKEN}"},
timeout=600.0,
)
post_response.raise_for_status()
else:
# S3-compatible storage: PUT directly to pre-signed URL
headers = { headers = {
"Content-Type": content_type, "Content-Type": content_type,
"Content-Length": str(size), "Content-Length": str(size),
} }
logger.info(f"Streaming file content to S3 storage (size={size} bytes)")
logger.info(f"Streaming file content to storage (size={size} bytes)")
async with httpx.AsyncClient() as client: async with httpx.AsyncClient() as client:
put_response = await client.put( put_response = await client.put(
upload_url, upload_url,
content=request.stream(), content=body,
headers=headers, headers=headers,
timeout=600.0, timeout=600.0,
) )