Coverage for src/lexigram/admin/controllers/resource/imports.py: 40%
20 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-21 14:56 +0800
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-21 14:56 +0800
1"""Import example/report downloads for the resource controller."""
3from __future__ import annotations
5from typing import TYPE_CHECKING, Any
7from starlette.requests import Request
8from starlette.responses import HTMLResponse, Response
10if TYPE_CHECKING:
11 from lexigram.admin.controllers.resource import ResourceController
15class ResourceImportMixin:
16 """Import example and report downloads."""
18 def _find_import_action(self) -> Any:
19 """Return the configured ImportAction, or None."""
20 return getattr(self, "_import_action", None)
22 async def import_example(self: ResourceController, request: Request) -> Response:
23 """Serve the resource's import example CSV template as a download."""
24 action = self._find_import_action()
25 if action is None or not action.example_csv():
26 return HTMLResponse(
27 "<h1>Import not configured for this resource</h1>",
28 status_code=404,
29 )
30 return Response(
31 content=action.example_csv(),
32 media_type="text/csv",
33 headers={
34 "Content-Disposition": (
35 f'attachment; filename="{action.example_filename}"'
36 )
37 },
38 )
40 async def import_report(self: ResourceController, request: Request) -> Response:
41 """Serve a stored failed-import report as a CSV download."""
42 action = self._find_import_action()
43 report_id = request.query_params.get("report_id", "")
44 content = action.report_csv(report_id) if action else None
45 if content is None:
46 return HTMLResponse("<h1>Report not found</h1>", status_code=404)
47 filename = action.report_filename(report_id) or "import-errors.csv"
48 return Response(
49 content=content,
50 media_type="text/csv",
51 headers={"Content-Disposition": f'attachment; filename="{filename}"'},
52 )