Skip to content

Commit 27e8888

Browse files
committed
fix: clean up non-existing cursus_users from db
cursus_users are deleted from Intra's database upon unregistration from a piscine or kickoff through Apply v2
1 parent 57852b2 commit 27e8888

File tree

1 file changed

+59
-0
lines changed

1 file changed

+59
-0
lines changed

src/intra/cleanup.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,64 @@ const cleanupDuplicateProjectUsers = async function(): Promise<void> {
4343
}
4444
};
4545

46+
const cleanupNonExistentCursusUsers = async function(api: Fast42): Promise<void> {
47+
// This function makes sure to clean up cursus_users that no longer exist in the API.
48+
// This can happen when an applicant unsubscribes from a kickoff or a piscine through Apply.
49+
// Fetch cursus_users from the database, limited with a begin_at within the past year or the future.
50+
// If cleanup further is needed, manually delete all cursus_users from the database and reseed.
51+
const cursusUsers = await prisma.cursusUser.findMany({
52+
select: {
53+
id: true,
54+
user_id: true,
55+
cursus_id: true,
56+
},
57+
where: {
58+
begin_at: {
59+
gte: new Date(Date.now() - 365 * 24 * 60 * 60 * 1000), // within the past year
60+
},
61+
},
62+
});
63+
64+
// Fetch these cursus_users again from the API, by AMOUNT_PER_PAGE per page using filters
65+
const AMOUNT_PER_PAGE = 30;
66+
const pagesToFetch = Math.ceil(cursusUsers.length / AMOUNT_PER_PAGE);
67+
console.log(`Found ${cursusUsers.length} cursus_users in the database. Cleaning up non-existent ones (will take ${pagesToFetch} API calls)...`);
68+
for (let i = 0; i < cursusUsers.length; i += AMOUNT_PER_PAGE) {
69+
const page = cursusUsers.slice(i, i + AMOUNT_PER_PAGE);
70+
const ids = page.map((cursusUser) => cursusUser.id);
71+
try {
72+
console.log(`Cursus_user cleanup: Fetching page ${i / AMOUNT_PER_PAGE + 1} of ${pagesToFetch}...`);
73+
const cursusUsersData = await fetchSingle42ApiPage(api, '/cursus_users', {
74+
'filter[id]': ids.join(','),
75+
'page[size]': AMOUNT_PER_PAGE.toString(),
76+
'page[number]': '1',
77+
});
78+
if (!cursusUsersData || cursusUsersData.length === 0) {
79+
console.warn(`No cursus_users found at all for ids ${ids.join(', ')}, this is possibly a bug, skipping deletion!`);
80+
continue;
81+
}
82+
const fetchedIds = cursusUsersData.map((cursusUser: { id: number }) => cursusUser.id);
83+
// Find the ids that are not in the fetched data
84+
const nonExistentIds = ids.filter((id) => !fetchedIds.includes(id));
85+
if (nonExistentIds.length > 0) {
86+
console.log(`Removing ${nonExistentIds.length} non-existent local cursus_users with ids: ${nonExistentIds.join(', ')}`);
87+
await prisma.cursusUser.deleteMany({
88+
where: {
89+
id: {
90+
in: nonExistentIds,
91+
},
92+
},
93+
});
94+
}
95+
}
96+
catch (err) {
97+
console.error(`Error fetching cursus_users for ids ${ids.join(', ')}: ${err}`);
98+
continue;
99+
}
100+
}
101+
console.log('Finished cleaning up non-existent cursus_users.');
102+
};
103+
46104
const anonymizeUsers = async function(api: Fast42): Promise<void> {
47105
// Fetch all users where the anonymize_date is in the past, not null and the login does not yet start with 3b3
48106
const users = await prisma.user.findMany({
@@ -92,5 +150,6 @@ const anonymizeUsers = async function(api: Fast42): Promise<void> {
92150
export const cleanupDB = async function(api: Fast42): Promise<void> {
93151
console.info('Cleaning up the database...');
94152
await cleanupDuplicateProjectUsers();
153+
await cleanupNonExistentCursusUsers(api);
95154
await anonymizeUsers(api);
96155
};

0 commit comments

Comments
 (0)