fix(housekeeping): restore people partial compatibility
This commit is contained in:
1 parent
fcd1dfd96e
commit
a6a288d9ff
6 files changed
+412
-11
No files matched your search
@@ -54,3 +54,46 @@ it("keeps one ACL check while delegating a positive bulk adjustment", async () =
|
||||
{ userIds: [7, 8], amount: 25, type: "credits" },
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps the pre-Task12 positive-adjust result when currency RCON throws after the database commit", async () => {
|
||||
execute.mockResolvedValueOnce({
|
||||
ok: true,
|
||||
data: {
|
||||
before: { completed: 0, total: 1, failedIds: [] },
|
||||
after: {
|
||||
completed: 1,
|
||||
total: 1,
|
||||
failedIds: [],
|
||||
externalSyncFailures: [
|
||||
{
|
||||
userId: 7,
|
||||
reason:
|
||||
"Database applied; emulator sync failed. Do not retry automatically.",
|
||||
},
|
||||
],
|
||||
},
|
||||
completion: {
|
||||
status: "partial",
|
||||
external: "failed",
|
||||
audit: "persisted",
|
||||
},
|
||||
},
|
||||
correlationId: "legacy-positive-adjust",
|
||||
completion: {
|
||||
status: "partial",
|
||||
external: "failed",
|
||||
audit: "persisted",
|
||||
},
|
||||
});
|
||||
|
||||
await expect(
|
||||
bulkAdjustCurrency({ userIds: [7], amount: 25, type: "credits" }),
|
||||
).resolves.toEqual({
|
||||
ok: true,
|
||||
data: {
|
||||
adjusted: 0,
|
||||
total: 1,
|
||||
failedIds: [{ userId: 7, reason: "Database error" }],
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -91,4 +91,64 @@ describe("legacy bulk user wrappers", () => {
|
||||
{ userId: 9, untilUnix: 1234 },
|
||||
);
|
||||
});
|
||||
|
||||
it.each([
|
||||
[
|
||||
"currency",
|
||||
"users.bulk-currency",
|
||||
() => bulkGiveCurrency({ userIds: [7], amount: 100, type: "credits" }),
|
||||
],
|
||||
[
|
||||
"badge",
|
||||
"users.bulk-badge",
|
||||
() => bulkGiveBadge({ userIds: [7], badgeCode: "ADM" }),
|
||||
],
|
||||
] as const)(
|
||||
"restores the pre-Task12 legacy result when %s RCON throws after the database commit",
|
||||
async (_kind, operation, invoke) => {
|
||||
execute.mockResolvedValueOnce({
|
||||
ok: true,
|
||||
data: {
|
||||
before: { completed: 0, total: 1, failedIds: [] },
|
||||
after: {
|
||||
completed: 1,
|
||||
total: 1,
|
||||
failedIds: [],
|
||||
externalSyncFailures: [
|
||||
{
|
||||
userId: 7,
|
||||
reason:
|
||||
"Database applied; emulator sync failed. Do not retry automatically.",
|
||||
},
|
||||
],
|
||||
},
|
||||
completion: {
|
||||
status: "partial",
|
||||
external: "failed",
|
||||
audit: "persisted",
|
||||
},
|
||||
},
|
||||
correlationId: "legacy-external-sync-failure",
|
||||
completion: {
|
||||
status: "partial",
|
||||
external: "failed",
|
||||
audit: "persisted",
|
||||
},
|
||||
});
|
||||
|
||||
await expect(invoke()).resolves.toEqual({
|
||||
ok: true,
|
||||
data: {
|
||||
given: 0,
|
||||
total: 1,
|
||||
failedIds: [{ userId: 7, reason: "Database error" }],
|
||||
},
|
||||
});
|
||||
expect(execute).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
operation,
|
||||
expect.anything(),
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
@@ -52,6 +52,35 @@ function failedIds(value: unknown): Array<{ userId: number; reason: string }> {
|
||||
: [];
|
||||
}
|
||||
|
||||
function legacyBulkOutcome(
|
||||
after: Readonly<Record<string, unknown>> | null,
|
||||
userIds: readonly number[],
|
||||
): {
|
||||
readonly completed: number;
|
||||
readonly total: number;
|
||||
readonly failedIds: Array<{ userId: number; reason: string }>;
|
||||
} {
|
||||
const databaseFailures = failedIds(after?.failedIds);
|
||||
const externalSyncFailures = failedIds(after?.externalSyncFailures).map(
|
||||
({ userId }) => ({ userId, reason: "Database error" }),
|
||||
);
|
||||
const pendingFailures = [...databaseFailures, ...externalSyncFailures];
|
||||
const orderedFailures = userIds.flatMap((userId) => {
|
||||
const index = pendingFailures.findIndex(
|
||||
(failure) => failure.userId === userId,
|
||||
);
|
||||
return index === -1 ? [] : pendingFailures.splice(index, 1);
|
||||
});
|
||||
return {
|
||||
completed: Math.max(
|
||||
0,
|
||||
numberValue(after?.completed) - externalSyncFailures.length,
|
||||
),
|
||||
total: numberValue(after?.total),
|
||||
failedIds: [...orderedFailures, ...pendingFailures],
|
||||
};
|
||||
}
|
||||
|
||||
export async function bulkUnban({
|
||||
userIds,
|
||||
}: {
|
||||
@@ -113,12 +142,13 @@ export async function bulkGiveCurrency({
|
||||
type,
|
||||
});
|
||||
if (!result.ok) return { ok: false, error: "Bulk currency failed" };
|
||||
const outcome = legacyBulkOutcome(result.data.after, userIds);
|
||||
return {
|
||||
ok: true,
|
||||
data: {
|
||||
given: numberValue(result.data.after?.completed),
|
||||
total: numberValue(result.data.after?.total),
|
||||
failedIds: failedIds(result.data.after?.failedIds),
|
||||
given: outcome.completed,
|
||||
total: outcome.total,
|
||||
failedIds: outcome.failedIds,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -142,12 +172,13 @@ export async function bulkGiveBadge({
|
||||
badgeCode,
|
||||
});
|
||||
if (!result.ok) return { ok: false, error: "Bulk badge failed" };
|
||||
const outcome = legacyBulkOutcome(result.data.after, userIds);
|
||||
return {
|
||||
ok: true,
|
||||
data: {
|
||||
given: numberValue(result.data.after?.completed),
|
||||
total: numberValue(result.data.after?.total),
|
||||
failedIds: failedIds(result.data.after?.failedIds),
|
||||
given: outcome.completed,
|
||||
total: outcome.total,
|
||||
failedIds: outcome.failedIds,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -178,12 +209,13 @@ export async function bulkAdjustCurrency({
|
||||
type,
|
||||
});
|
||||
if (!result.ok) return { ok: false, error: "Currency adjustment failed" };
|
||||
const outcome = legacyBulkOutcome(result.data.after, userIds);
|
||||
return {
|
||||
ok: true,
|
||||
data: {
|
||||
adjusted: numberValue(result.data.after?.completed),
|
||||
total: numberValue(result.data.after?.total),
|
||||
failedIds: failedIds(result.data.after?.failedIds),
|
||||
adjusted: outcome.completed,
|
||||
total: outcome.total,
|
||||
failedIds: outcome.failedIds,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user