feat(awards): add cleanupDuplicateAwards utility and CLI tool skeleton
This commit is contained in:
parent
2e1fbf8006
commit
a1bdf4ffb1
2 changed files with 96 additions and 0 deletions
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
||||||
14
src/tools/cli/grant_award.ts
Normal file
14
src/tools/cli/grant_award.ts
Normal 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
|
||||||
|
// })
|
||||||
|
})();
|
||||||
Loading…
Reference in a new issue