feat: defer Web Push updates until tomorrow (Closes #563)
CI / lint (pull_request) Successful in 1m16s
CI / build-release (pull_request) Successful in 5s
CI / release-candidate (pull_request) Has been skipped

This commit is contained in:
timmy committed 2026-08-11 10:25:56 +00:00
1 parent f4a4ed84c3
commit 7ce352553d
5 files changed
+213 -5

No files matched your search

+55
View File
@@ -426,6 +426,10 @@ class LaterOperationBatch(BaseModel):
operations: list[LaterOperation] = Field(min_length=1, max_length=50)
class NotificationLaterRequest(BaseModel):
wake_at: str = Field(min_length=1, max_length=100)
class NotificationReply(BaseModel):
body: str = Field(min_length=1, max_length=10_000)
@@ -3216,6 +3220,57 @@ async def read_notification(thread_id: int = PathParam(gt=0)) -> JSONResponse:
return JSONResponse({"id": thread_id, "status": "read"})
@app.patch("/api/v1/notifications/{thread_id}/later")
async def defer_notification(
payload: NotificationLaterRequest,
thread_id: int = PathParam(gt=0),
) -> JSONResponse:
login = await _confirmed_login()
try:
item = await asyncio.wait_for(
gitea_proxy.resolve_work_route("update", None, None, thread_id),
timeout=NOTIFICATION_DETAIL_TIMEOUT_SECONDS,
)
repository = item.get("repository")
if not isinstance(repository, str) or not repository:
raise ValueError("The update has no repository identity")
item_id = f"update:{repository}::{thread_id}"
result = await asyncio.to_thread(
_later_store().apply,
login,
f"push-tomorrow:{thread_id}:{payload.wake_at}",
"defer",
item_id,
wake_at=payload.wake_at,
)
except gitea_proxy.WorkRouteUnavailableError:
return JSONResponse(
{"error": "This update is no longer available to defer."},
status_code=409,
)
except ValueError as error:
raise HTTPException(status_code=422, detail=str(error))
except TimeoutError:
return JSONResponse(
{"error": "Deferring the update timed out. Please retry."},
status_code=503,
headers={"Retry-After": "1"},
)
except (OSError, sqlite3.Error):
return JSONResponse(
{"error": "Later synchronization is unavailable. Please retry."},
status_code=503,
headers={"Retry-After": "1"},
)
return JSONResponse({
"id": thread_id,
"status": "deferred",
"item_id": item_id,
"wake_at": payload.wake_at,
"revision": result["revision"],
})
@app.post("/api/v1/notifications/{thread_id}/acknowledge")
async def acknowledge_notification(thread_id: int = PathParam(gt=0)) -> JSONResponse:
try: