Making OData Refresh a background process

This commit is contained in:
Ian Roddis committed 2026-08-05 16:26:52 -03:00
1 parent 2e7976e382
commit cf8d72f73e
4 files changed
+157 -34

No files matched your search

+92 -30
View File
@@ -1366,6 +1366,19 @@ async def save_imported_part_config(
return HTMLResponse("Configuration saved.", status_code=200)
_IMPORTED_PARTS_REFRESH_TARGET_ID = "imported-parts-section"
async def _imported_parts_table_ctx(
db: AsyncSession, *, sync_result: str | None = None, sync_error: str | None = None
) -> dict:
return {
**await _default_imported_parts_table_ctx(db),
"sync_result": sync_result,
"sync_error": sync_error,
}
@router.post("/imported-parts/refresh", response_class=HTMLResponse)
async def refresh_imported_parts(
request: Request,
@@ -1373,46 +1386,95 @@ async def refresh_imported_parts(
actor: User = Depends(web_require("imported_parts:write")),
):
config = await imported_part_config_crud.get(db)
async def _imported_table_ctx(sync_result=None, sync_error=None):
return {
**await _default_imported_parts_table_ctx(db),
"sync_result": sync_result,
"sync_error": sync_error,
}
if not config or not config.odata_url:
return templates.TemplateResponse(
request,
"admin/_imported_parts_table.html",
await _imported_table_ctx(sync_error="OData URL is not configured."),
)
try:
records = await odata_service.fetch(
config.odata_url, config.username, config.password
)
created, updated = await imported_part_crud.upsert_bulk(db, records)
await audit_crud.log(
db,
actor=actor,
action="update",
resource_type="ImportedPart",
resource_id=None,
description=f"OData sync: {created} created, {updated} updated ({len(records)} total records)",
)
return templates.TemplateResponse(
request,
"admin/_imported_parts_table.html",
await _imported_table_ctx(
sync_result=f"Sync complete: {created} created, {updated} updated."
await _imported_parts_table_ctx(
db, sync_error="OData URL is not configured."
),
)
except Exception as exc:
actor_id = actor.id
async def _run(job_id: str) -> None:
async with AsyncSessionLocal() as db:
config = await imported_part_config_crud.get(db)
if not config or not config.odata_url:
await jobs.mark_error(job_id, "OData URL is not configured.")
return
try:
records = await odata_service.fetch(
config.odata_url, config.username, config.password
)
created, updated = await imported_part_crud.upsert_bulk(db, records)
except Exception as exc:
await jobs.mark_error(job_id, f"Sync failed: {exc}")
return
actor_row = await user_crud.get(db, actor_id)
await audit_crud.log(
db,
actor=actor_row,
action="update",
resource_type="ImportedPart",
resource_id=None,
description=(
f"OData sync: {created} created, {updated} updated "
f"({len(records)} total records)"
),
)
await jobs.mark_done(
job_id,
message=f"Sync complete: {created} created, {updated} updated.",
)
job = await jobs.start("imported_parts_refresh", _run)
return templates.TemplateResponse(
request,
"admin/_job_progress.html",
{
"container_id": _IMPORTED_PARTS_REFRESH_TARGET_ID,
"poll_url": f"/admin/imported-parts/refresh/jobs/{job.id}",
"job": job,
},
)
@router.get("/imported-parts/refresh/jobs/{job_id}", response_class=HTMLResponse)
async def imported_parts_refresh_job_status(
request: Request,
job_id: str,
db: AsyncSession = Depends(get_db),
_: User = Depends(web_require("imported_parts:write")),
):
job = await jobs.get(db, job_id)
if job is None:
return templates.TemplateResponse(
request,
"admin/_imported_parts_table.html",
await _imported_table_ctx(sync_error=f"Sync failed: {exc}"),
await _imported_parts_table_ctx(
db, sync_error="Refresh job not found — it may have expired."
),
)
if job.status == "running":
return templates.TemplateResponse(
request,
"admin/_job_progress.html",
{
"container_id": _IMPORTED_PARTS_REFRESH_TARGET_ID,
"poll_url": f"/admin/imported-parts/refresh/jobs/{job_id}",
"job": job,
},
)
return templates.TemplateResponse(
request,
"admin/_imported_parts_table.html",
await _imported_parts_table_ctx(
db,
sync_result=job.message if job.status == "done" else None,
sync_error=job.message if job.status == "error" else None,
),
)
@router.get("/imported-parts/filter", response_class=HTMLResponse)