1
0
Fork 0

feat(awards): add cleanupDuplicateAwards utility and CLI tool skeleton

This commit is contained in:
Jason Fraley 2026-09-02 16:14:12 -04:00
parent 2e1fbf8006
commit a1bdf4ffb1
2 changed files with 96 additions and 0 deletions

View file

@ -160,3 +160,85 @@ export async function notifyAwardGrants(
console.error("[Awards] Failed to send award-grant notifications:", err); console.error("[Awards] Failed to send award-grant notifications:", err);
} }
} }
export interface CleanupResult {
profilesChecked: number;
profilesModified: number;
duplicatesRemoved: number;
details: { profileId: number; removed: number }[];
}
export async function cleanupDuplicateAwards(
payload: PayloadType,
): Promise<CleanupResult> {
const result: CleanupResult = {
profilesChecked: 0,
profilesModified: 0,
duplicatesRemoved: 0,
details: [],
};
let page = 1;
let hasMore = true;
while (hasMore) {
const profiles = await payload.find({
collection: "profiles",
limit: 500,
page,
depth: 0,
overrideAccess: true,
});
result.profilesChecked += profiles.totalDocs;
for (const profile of profiles.docs) {
const awards = (profile as unknown as ProgressionDoc).progression?.awards;
if (!awards || awards.length <= 1) continue;
const seen = new Map<number, { entry: AwardGrantEntry; index: number }>();
const indicesToRemove: number[] = [];
for (let i = 0; i < awards.length; i++) {
const entry = awards[i];
const id = awardIdOf(entry);
if (id === null) continue;
const existing = seen.get(id);
if (existing) {
if (entry.awardedAt < existing.entry.awardedAt) {
indicesToRemove.push(existing.index);
seen.set(id, { entry, index: i });
} else {
indicesToRemove.push(i);
}
} else {
seen.set(id, { entry, index: i });
}
}
if (indicesToRemove.length > 0) {
const cleaned = awards.filter((_, i) => !indicesToRemove.includes(i));
await payload.update({
collection: "profiles",
id: profile.id,
data: {
progression: {
...(profile as unknown as ProgressionDoc).progression,
awards: cleaned,
},
},
overrideAccess: true,
});
result.profilesModified += 1;
result.duplicatesRemoved += indicesToRemove.length;
result.details.push({ profileId: profile.id, removed: indicesToRemove.length });
}
}
hasMore = page < profiles.totalPages;
page += 1;
}
return result;
}

View file

@ -0,0 +1,14 @@
import { getPayload } from "payload";
import config from "@payload-config";
(async () => {
const payload = await getPayload({ config });
// payload.logger.log("Retrieving user profiles...");
// await payload.find({
// collection: "profiles",
// overrideAccess: true,
// select
// })
})();