Browse Source

feat(api): me media orphans list and batch delete

Made-with: Cursor
main
npmrun 9 hours ago
parent
commit
16c1f7c888
  1. 35
      server/api/me/media/orphans-delete.post.ts
  2. 38
      server/api/me/media/orphans.get.ts

35
server/api/me/media/orphans-delete.post.ts

@ -0,0 +1,35 @@
import { deleteMediaAssetsForUser } from "#server/service/media";
const MAX_BATCH = 50;
export default defineWrappedResponseHandler(async (event) => {
const user = await event.context.auth.requireUser();
const body = await readBody<{ ids?: unknown }>(event);
if (body === null || typeof body !== "object" || !("ids" in body)) {
throw createError({ statusCode: 400, statusMessage: "请求体须包含 ids 数组" });
}
const { ids } = body;
if (!Array.isArray(ids)) {
throw createError({ statusCode: 400, statusMessage: "ids 必须为数组" });
}
if (ids.length > MAX_BATCH) {
throw createError({ statusCode: 400, statusMessage: `单次最多删除 ${MAX_BATCH}` });
}
const numericIds: number[] = [];
for (const x of ids) {
if (typeof x !== "number" || !Number.isInteger(x) || x < 1) {
throw createError({ statusCode: 400, statusMessage: "ids 须均为正整数" });
}
numericIds.push(x);
}
if (numericIds.length === 0) {
return R.success({ deleted: 0 });
}
const deleted = await deleteMediaAssetsForUser(user.id, numericIds);
return R.success({ deleted });
});

38
server/api/me/media/orphans.get.ts

@ -0,0 +1,38 @@
import { listOrphanCandidatesForUser } from "#server/service/media";
type OrphanFilter = "all" | "deletable" | "cooling";
function parseFilter(raw: string | undefined): OrphanFilter {
const v = raw === undefined || raw === "" ? "all" : raw;
if (v === "all" || v === "deletable" || v === "cooling") {
return v;
}
throw createError({ statusCode: 400, statusMessage: "filter 须为 all、deletable 或 cooling" });
}
function parsePositiveInt(raw: string | undefined, fallback: number, label: string): number {
if (raw === undefined || raw === "") {
return fallback;
}
const n = Number(raw);
if (!Number.isInteger(n) || n < 1) {
throw createError({ statusCode: 400, statusMessage: `${label} 须为正整数` });
}
return n;
}
export default defineWrappedResponseHandler(async (event) => {
const user = await event.context.auth.requireUser();
const q = getQuery(event);
const filter = parseFilter(typeof q.filter === "string" ? q.filter : undefined);
const page = parsePositiveInt(typeof q.page === "string" ? q.page : undefined, 1, "page");
const pageSizeRaw = parsePositiveInt(
typeof q.pageSize === "string" ? q.pageSize : undefined,
20,
"pageSize",
);
const pageSize = Math.min(pageSizeRaw, 100);
const { items, total } = await listOrphanCandidatesForUser(user.id, filter, page, pageSize);
return R.success({ items, total });
});
Loading…
Cancel
Save