feat(catalog): prevent and repair Arcturus emulator data errors
Block invalid catalog_items writes at the API level (points currency allowlist, non-negative prices, positive amount, limited stack >= sold count, unique sibling order numbers) and auto-assign unique order numbers on bulk create. Add a catalog-maintenance scan + transactional repair that fixes pre-existing rows: resets unsupported points_type, clamps negative costs, sets amount to 1, raises limited_stack, renumbers duplicate orders and deletes offers with missing page/item references. Surface the issue count and a fix button in the admin maintenance panel. Also: add enabled/retired flag to clone sources, classify poster and currency furniture in item-kind, and remove the obsolete update-Nitrov3.sh.
This commit is contained in:
1 parent
ad65d80d41
commit
3e69b72513
26 files changed
+17651
-3844
No files matched your search
@@ -22,7 +22,7 @@ describe("offer compatibility", () => {
|
||||
expect(parseFurnitureIds("12;23;12")).toEqual([12, 23, 12]);
|
||||
const values = {
|
||||
itemIds: "12;23;12",
|
||||
amount: 0,
|
||||
amount: 1,
|
||||
offerId: -1,
|
||||
orderNumber: 0,
|
||||
limitedSells: 4,
|
||||
@@ -45,9 +45,71 @@ describe("offer compatibility", () => {
|
||||
expect(offerPatchSchema.safeParse({ costCredits: Infinity }).success).toBe(
|
||||
false,
|
||||
);
|
||||
expect(offerPatchSchema.parse({ offerId: 0, amount: 0 })).toEqual({
|
||||
expect(offerPatchSchema.parse({ offerId: 0, amount: 1 })).toEqual({
|
||||
offerId: 0,
|
||||
amount: 0,
|
||||
amount: 1,
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("emulator offer constraints", () => {
|
||||
it("rejects negative costCredits and costPoints", () => {
|
||||
expect(offerPatchSchema.safeParse({ costCredits: -1 }).success).toBe(false);
|
||||
expect(offerPatchSchema.safeParse({ costPoints: -5 }).success).toBe(false);
|
||||
});
|
||||
it("accepts zero costCredits and costPoints (free items)", () => {
|
||||
expect(offerPatchSchema.parse({ costCredits: 0, costPoints: 0 })).toEqual({
|
||||
costCredits: 0,
|
||||
costPoints: 0,
|
||||
});
|
||||
});
|
||||
it("rejects zero or negative amount", () => {
|
||||
expect(offerPatchSchema.safeParse({ amount: 0 }).success).toBe(false);
|
||||
expect(offerPatchSchema.safeParse({ amount: -1 }).success).toBe(false);
|
||||
});
|
||||
it("accepts positive amount", () => {
|
||||
expect(offerPatchSchema.parse({ amount: 1 })).toEqual({ amount: 1 });
|
||||
});
|
||||
it("rejects unsupported pointsType values", () => {
|
||||
expect(offerPatchSchema.safeParse({ pointsType: 101 }).success).toBe(
|
||||
false,
|
||||
);
|
||||
expect(offerPatchSchema.safeParse({ pointsType: 103 }).success).toBe(
|
||||
false,
|
||||
);
|
||||
expect(offerPatchSchema.safeParse({ pointsType: -1 }).success).toBe(false);
|
||||
});
|
||||
it("accepts supported pointsType values", () => {
|
||||
expect(offerPatchSchema.parse({ pointsType: 0 })).toEqual({
|
||||
pointsType: 0,
|
||||
});
|
||||
expect(offerPatchSchema.parse({ pointsType: 5 })).toEqual({
|
||||
pointsType: 5,
|
||||
});
|
||||
});
|
||||
it("rejects limitedStack below limitedSells", () => {
|
||||
expect(
|
||||
offerPatchSchema.safeParse({ limitedStack: 0, limitedSells: 1 })
|
||||
.success,
|
||||
).toBe(false);
|
||||
expect(
|
||||
offerPatchSchema.safeParse({ limitedStack: 5, limitedSells: 10 })
|
||||
.success,
|
||||
).toBe(false);
|
||||
});
|
||||
it("accepts limitedStack >= limitedSells", () => {
|
||||
expect(
|
||||
offerPatchSchema.parse({ limitedStack: 10, limitedSells: 5 }),
|
||||
).toEqual({ limitedStack: 10, limitedSells: 5 });
|
||||
expect(
|
||||
offerPatchSchema.parse({ limitedStack: 0, limitedSells: 0 }),
|
||||
).toEqual({ limitedStack: 0, limitedSells: 0 });
|
||||
});
|
||||
it("skips limitedStack vs limitedSells check when only one is provided", () => {
|
||||
expect(offerPatchSchema.parse({ limitedStack: 0 })).toEqual({
|
||||
limitedStack: 0,
|
||||
});
|
||||
expect(offerPatchSchema.parse({ limitedSells: 5 })).toEqual({
|
||||
limitedSells: 5,
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user