From 198bbebd89d212faae3e45a22830bab66dec49e0 Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Sat, 17 Oct 2026 10:23:22 +0200 Subject: admin-tools: add export tools and improve duplicate finder Considered as duplicates are eequal qual changes submitted in the same hour. Bump dependencies. --- src/graduation-common.ts | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'src/graduation-common.ts') diff --git a/src/graduation-common.ts b/src/graduation-common.ts index 2d1f21d..fe244bc 100644 --- a/src/graduation-common.ts +++ b/src/graduation-common.ts @@ -248,6 +248,60 @@ async function deleteGraduationChange(graduation: Graduation, change: Graduation return await db.deleteEntries([change.changeId]); } +export function findDuplicateChanges( + changes: Array, +): Array> { + // Sets of potential duplicates + const duplicates: Array> = []; + + // Sort the changes first by studentId and than by time + changes.sort((a, b): number => { + // Sort by studentId first + if (a.studentId !== b.studentId) return a.studentId - b.studentId; + return a.date.getTime() - b.date.getTime(); + }); + + let candidates = []; + outer_loop: for (let i = 0; i < changes.length - 1; i++) { + const change = changes[i]; + const other = changes[i + 1]; + + for (const key in change) { + let similar; + switch (key) { + case "changeId": + continue; + case "date": + // Are the dates less than an hour apart? + similar = Math.abs(change.date.getTime() - other.date.getTime()) < 24 * 60 * 60 * 1000; + break; + case "context": + similar = JSON.stringify(change.context) === JSON.stringify(other.context); + break; + default: + const tkey = key as keyof GraduationChange; + similar = change[tkey] === other[tkey]; + } + if (!similar) { + // The input is sorted duplicates must be in consecutive order. + if (candidates.length > 0) { + duplicates.push(candidates); + candidates = []; + } + continue outer_loop; + } + } + + // Found candidates + if (candidates.length === 0) { + candidates.push(change, other); // New candidate pair + } else { + candidates.push(other); // Additional candidate found + } + } + return duplicates; +} + export { LEVEL_NAMES, LEVEL_IMAGES, -- cgit v1.2.3