fix(review-2): high — read-only ban model, failed-compression cleanup, live SSE eviction

H1: corrected a round-1 over-reach. Bans are read-only per USER_JOURNEYS §10:
    the base AuthUser extractor no longer rejects banned users (they keep read
    access); Require{Host,Admin} and write handlers enforce the ban via
    auth.is_banned → 403 (incl. self-unban). Demoted hosts still lose powers
    immediately (live DB role) and are bounced off the dashboard. Also fixed the
    login/recover redirect regression on unauthenticated 401.

H2: failed compression now self-heals instead of leaving a permanent broken
    card — refund the quota, delete the orphaned original, soft-delete the row;
    the frontend toasts the uploader and evicts the card on upload-error.

H3: self-delete, ban-with-hide (user-hidden), and comment-deletes now broadcast
    SSE; feed, diashow, and lightbox evict the affected content live instead of
    waiting for a reload. sse-eviction.spec.ts covers it.

Riders: feed/+page.svelte also carries the medium truncated-delta pill; host.rs
also carries the low atomic release_gallery claim; admin/+page.svelte also drops
the dead compression_concurrency control (medium).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
fabi
2026-07-02 22:19:43 +02:00
parent dba4d3f932
commit 80179357a7
13 changed files with 245 additions and 20 deletions

View File

@@ -313,6 +313,14 @@ pub async fn delete_upload(
Upload::soft_delete_in_event(&state.pool, upload_id, auth.event_id).await?;
// Evict the card live on every other feed + the projector diashow — otherwise
// a self-deleted post lingers until each viewer manually reloads. Same event
// the host-delete path already emits and the frontend already handles.
let _ = state.sse_tx.send(crate::state::SseEvent::new(
"upload-deleted",
serde_json::json!({ "upload_id": upload_id }).to_string(),
));
Ok(StatusCode::NO_CONTENT)
}