feat: file blocks
Pull request / title (pull_request) Successful in 1s
CI / test (pull_request) Successful in 1m8s
CI / image (apps/api/Dockerfile, t5de-hub-api) (pull_request) Skipped
CI / image (apps/web/Dockerfile, t5de-hub-web) (pull_request) Skipped

Moderators block a file network-wide by its sha256, from a product's files or the console's new Blocks tab, which
first shows the products using it. Blocking removes those products (their creators are told and may appeal), puts
a `block` change in the changes feed of every catalog hosting it, and refuses uploads with it; moderators see who
tried. Unblocking lets it in again; the products it removed stay removed until restored.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
dhkatzandClaude Opus 5.5 committed 2026-11-05 14:32:08 -08:00
1 parent 7299e10b08
commit ba423f32d8
18 files changed
+4074 -10

No files matched your search

+31
View File
@@ -0,0 +1,31 @@
"use server";
// File blocks, from the console.
import { revalidatePath } from "next/cache";
import { api, unwrap } from "@/lib/api";
import { attempt, field, type ActionState } from "@/lib/actions";
const done = (sha256: string) => {
revalidatePath("/console/blocks");
revalidatePath(`/console/blocks/${sha256}`);
revalidatePath("/console/products");
};
/** Blocks a file network-wide, removing the products using it. */
export async function blockFile(_: ActionState, form: FormData): Promise<ActionState> {
const sha256 = field(form, "sha256");
return attempt(async () => {
const { removed } = unwrap(await api.blocks({ sha256 }).put({ reason: field(form, "reason") }));
done(sha256);
return removed.length ? `Blocked. Removed ${removed.length === 1 ? "1 product" : `${removed.length} products`}.` : "Blocked.";
});
}
/** Unblocks a file. The products it removed stay removed. */
export async function unblockFile(_: ActionState, form: FormData): Promise<ActionState> {
const sha256 = field(form, "sha256");
return attempt(async () => {
unwrap(await api.blocks({ sha256 }).delete({ reason: field(form, "reason") }));
done(sha256);
return "Unblocked.";
});
}