|
18 | 18 | import json |
19 | 19 | import threading |
20 | 20 |
|
21 | | -from fastapi import APIRouter, Depends, Request |
| 21 | +from fastapi import APIRouter, Depends, Request, Response |
22 | 22 | from fastapi.responses import JSONResponse |
23 | 23 | from sse_starlette.sse import EventSourceResponse, ServerSentEvent |
24 | 24 |
|
|
32 | 32 | validate_jwt_token, |
33 | 33 | ) |
34 | 34 | from comicarr.app.system import service as system_service |
| 35 | +from comicarr.app.system import support_bundle as support_bundle_module |
35 | 36 |
|
36 | 37 | router = APIRouter(prefix="/api", tags=["system"]) |
37 | 38 |
|
@@ -625,3 +626,53 @@ async def release_acquisition_canary( |
625 | 626 | reason=reason, |
626 | 627 | ) |
627 | 628 | return _repair_response(result) |
| 629 | + |
| 630 | + |
| 631 | +# --------------------------------------------------------------------------- |
| 632 | +# Support bundle |
| 633 | +# --------------------------------------------------------------------------- |
| 634 | + |
| 635 | + |
| 636 | +@router.post("/system/support-bundle", dependencies=[Depends(require_session)]) |
| 637 | +def create_support_bundle(ctx: AppContext = Depends(get_context)): |
| 638 | + """Generate and download a Support bundle ZIP (session-authenticated only).""" |
| 639 | + try: |
| 640 | + artifact = support_bundle_module.generate_support_bundle(ctx) |
| 641 | + except support_bundle_module.SupportBundleInProgress: |
| 642 | + body = support_bundle_module.error_body("support_bundle_in_progress") |
| 643 | + return JSONResponse( |
| 644 | + status_code=409, |
| 645 | + content=body, |
| 646 | + headers={"Retry-After": "2"}, |
| 647 | + ) |
| 648 | + except support_bundle_module.SupportBundleUnavailable: |
| 649 | + return JSONResponse( |
| 650 | + status_code=503, |
| 651 | + content=support_bundle_module.error_body("support_bundle_unavailable"), |
| 652 | + ) |
| 653 | + except support_bundle_module.SupportBundleValidationFailed: |
| 654 | + return JSONResponse( |
| 655 | + status_code=500, |
| 656 | + content=support_bundle_module.error_body("support_bundle_validation_failed"), |
| 657 | + ) |
| 658 | + except support_bundle_module.SupportBundleError as exc: |
| 659 | + status = 503 if exc.code == "support_bundle_unavailable" else 500 |
| 660 | + return JSONResponse(status_code=status, content=support_bundle_module.error_body(exc.code)) |
| 661 | + except Exception as e: |
| 662 | + logger.error("[SUPPORT-BUNDLE] unexpected adapter failure: %s" % type(e).__name__) |
| 663 | + return JSONResponse( |
| 664 | + status_code=500, |
| 665 | + content=support_bundle_module.error_body("support_bundle_generation_failed"), |
| 666 | + ) |
| 667 | + |
| 668 | + return Response( |
| 669 | + content=artifact.content, |
| 670 | + media_type="application/zip", |
| 671 | + headers={ |
| 672 | + "Content-Disposition": f'attachment; filename="{artifact.filename}"', |
| 673 | + "Cache-Control": "no-store, private", |
| 674 | + "Pragma": "no-cache", |
| 675 | + "X-Comicarr-Support-Bundle-Contract": str(artifact.contract_version), |
| 676 | + "X-Comicarr-Support-Bundle-Status": artifact.status, |
| 677 | + }, |
| 678 | + ) |
0 commit comments