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:
@@ -68,6 +68,9 @@ async function request<T>(
|
||||
}
|
||||
|
||||
if (!res.ok) {
|
||||
// An expired/invalid token (401) clears the dead session. Banned users are
|
||||
// NOT logged out — they keep read access by design (USER_JOURNEYS §10) and
|
||||
// simply get a 403 "gesperrt" toast on writes.
|
||||
if (res.status === 401) {
|
||||
clearAuth();
|
||||
}
|
||||
|
||||
@@ -73,6 +73,23 @@ export class SlideQueue {
|
||||
return { wasCurrent: currentId === id };
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove every slide belonging to a user (banned with hide_uploads). Returns
|
||||
* true if the current head was one of them so the caller advances immediately.
|
||||
*/
|
||||
removeByUser(userId: string, currentId: string | null): { wasCurrent: boolean } {
|
||||
let wasCurrent = false;
|
||||
for (const [id, slide] of this.allKnown) {
|
||||
if (slide.user_id === userId) {
|
||||
if (id === currentId) wasCurrent = true;
|
||||
this.allKnown.delete(id);
|
||||
}
|
||||
}
|
||||
this.liveQueue = this.liveQueue.filter((s) => s.user_id !== userId);
|
||||
this.shuffleQueue = this.shuffleQueue.filter((s) => s.user_id !== userId);
|
||||
return { wasCurrent };
|
||||
}
|
||||
|
||||
/** Look up a slide by id — for the diashow page to render the current slide. */
|
||||
get(id: string): FeedUpload | undefined {
|
||||
return this.allKnown.get(id);
|
||||
|
||||
Reference in New Issue
Block a user