feat: add distribution release and recovery controls

This commit is contained in:
巫凤萍
2026-08-12 11:12:23 +08:00
parent ddad4b7659
commit 7ef150e08b
16 changed files with 717 additions and 33 deletions

View File

@@ -0,0 +1,58 @@
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import test from "node:test";
import {
DistributionReleaseError,
distributionReleaseBlockReason,
} from "../lib/distribution-release-service.ts";
test("allows only unfinished assignments to return to the claim pool", () => {
assert.equal(
distributionReleaseBlockReason({
publishUrl: null,
resultSubmittedAt: null,
taskType: "content_publish",
}),
null,
);
assert.equal(
distributionReleaseBlockReason({
publishUrl: "https://www.xiaohongshu.com/discovery/item/example",
resultSubmittedAt: null,
taskType: "content_publish",
}),
"已回填发布链接的笔记不能释放",
);
assert.equal(
distributionReleaseBlockReason({
publishUrl: null,
resultSubmittedAt: "2026-08-12 09:00:00",
taskType: "screenshot_collect",
}),
"已提交结果截图的任务不能释放",
);
assert.equal(new DistributionReleaseError("blocked", 409).status, 409);
});
test("releases a claim atomically and restores all counters", async () => {
const [service, database, actionRoute, adminApp] = await Promise.all([
readFile(new URL("../lib/distribution-release-service.ts", import.meta.url), "utf8"),
readFile(new URL("../lib/database.ts", import.meta.url), "utf8"),
readFile(new URL("../app/api/action/route.ts", import.meta.url), "utf8"),
readFile(new URL("../app/admin-app.tsx", import.meta.url), "utf8"),
]);
assert.match(database, /async transaction<T>/);
assert.match(service, /FOR UPDATE/);
assert.match(service, /DELETE FROM distributions WHERE id = \?/);
assert.match(service, /UPDATE contents SET status = 'available'/);
assert.match(service, /claimed_quantity = GREATEST\(claimed_quantity - 1, 0\)/);
assert.match(service, /claimed_total = GREATEST\(claimed_total - 1, 0\)/);
assert.match(service, /UPDATE claims/);
assert.match(service, /UPDATE delegation_bundles/);
assert.match(actionRoute, /body\.action === "release_distribution"/);
assert.match(actionRoute, /isManagerRequest/);
assert.match(adminApp, /确认释放这篇笔记/);
assert.match(adminApp, /已释放,可重新领取/);
assert.match(adminApp, /role="alertdialog"/);
});