From b056af78acff3aceb8cb1c3918afc9c35561b4bd Mon Sep 17 00:00:00 2001 From: Nathan FONTEYNE Date: Fri, 31 Jul 2026 12:19:13 +0200 Subject: [PATCH] update: add who refused and who did not give answer yet in ics feed description --- src/lib/icsFeed.js | 13 ++++++++++--- src/repositories/usersRepo.js | 8 ++++++++ src/routes/calendarFeed.js | 8 ++++++-- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/lib/icsFeed.js b/src/lib/icsFeed.js index 338b197..0420071 100644 --- a/src/lib/icsFeed.js +++ b/src/lib/icsFeed.js @@ -40,15 +40,22 @@ function foldLine(line) { return chunks.map((chunk, i) => (i === 0 ? chunk : ` ${chunk}`)).join('\r\n'); } -function rehearsalToEvent(rehearsal, { threshold, baseUrl }) { +function rehearsalToEvent(rehearsal, { threshold, baseUrl, allUsers }) { const status = computeRehearsalStatus(rehearsal.votes, threshold); const icsStatus = status === 'confirmed' ? 'CONFIRMED' : 'TENTATIVE'; const summary = status === 'confirmed' ? 'Répétition' : 'Répétition (proposition)'; const voteUrl = `${baseUrl}/calendar.html?rehearsalId=${rehearsal.id}`; + const accepted = rehearsal.votes.filter((v) => v.vote === 'accept').map((v) => v.name); + const refused = rehearsal.votes.filter((v) => v.vote === 'reject').map((v) => v.name); + const votedUserIds = new Set(rehearsal.votes.map((v) => v.userId)); + const pending = allUsers.filter((u) => !votedUserIds.has(u.id)).map((u) => u.name); + const description = [ `Votez ici : ${voteUrl}`, accepted.length ? `Ont accepté : ${accepted.join(', ')}` : "Personne n'a encore accepté.", + refused.length ? `Ont refusé : ${refused.join(', ')}` : "Personne n'a refusé.", + pending.length ? `En attente : ${pending.join(', ')}` : "Tout le monde a voté.", ].join('\n'); const lines = [ @@ -67,7 +74,7 @@ function rehearsalToEvent(rehearsal, { threshold, baseUrl }) { return lines; } -function buildRehearsalsFeed(rehearsals, { threshold, baseUrl }) { +function buildRehearsalsFeed(rehearsals, { threshold, baseUrl, allUsers }) { const lines = [ 'BEGIN:VCALENDAR', 'VERSION:2.0', @@ -75,7 +82,7 @@ function buildRehearsalsFeed(rehearsals, { threshold, baseUrl }) { 'CALSCALE:GREGORIAN', 'METHOD:PUBLISH', 'X-WR-CALNAME:Répétitions Octane', - ...rehearsals.flatMap((r) => rehearsalToEvent(r, { threshold, baseUrl })), + ...rehearsals.flatMap((r) => rehearsalToEvent(r, { threshold, baseUrl, allUsers })), 'END:VCALENDAR', ]; return lines.map(foldLine).join('\r\n'); diff --git a/src/repositories/usersRepo.js b/src/repositories/usersRepo.js index 5bc9fa8..ae1f350 100644 --- a/src/repositories/usersRepo.js +++ b/src/repositories/usersRepo.js @@ -92,6 +92,13 @@ async function findByIcsToken(token) { return rows[0] || null; } +// Minimal id/name list — used to work out who *hasn't* voted on a rehearsal +// yet (the ICS feed's "en attente" list), so no need for the full profile. +async function findAllNames() { + const { rows } = await pool.query('SELECT id, name FROM users ORDER BY name'); + return rows; +} + module.exports = { findById, upsertFromClaims, @@ -100,4 +107,5 @@ module.exports = { findAllWithActivity, ensureIcsToken, findByIcsToken, + findAllNames, }; diff --git a/src/routes/calendarFeed.js b/src/routes/calendarFeed.js index b0cd094..98ad226 100644 --- a/src/routes/calendarFeed.js +++ b/src/routes/calendarFeed.js @@ -17,12 +17,16 @@ router.get( const user = await usersRepo.findByIcsToken(req.params.token); if (!user) return res.status(404).send('Not found'); - const [rehearsals, settings] = await Promise.all([rehearsalsRepo.findUpcoming(), calendarRepo.getSlotSettings()]); + const [rehearsals, settings, allUsers] = await Promise.all([ + rehearsalsRepo.findUpcoming(), + calendarRepo.getSlotSettings(), + usersRepo.findAllNames(), + ]); // req.protocol honors X-Forwarded-Proto here — see app.set('trust proxy', 1) in app.js. const baseUrl = `${req.protocol}://${req.get('host')}`; res .type('text/calendar; charset=utf-8') - .send(buildRehearsalsFeed(rehearsals, { threshold: settings.rehearsalConfirmThreshold, baseUrl })); + .send(buildRehearsalsFeed(rehearsals, { threshold: settings.rehearsalConfirmThreshold, baseUrl, allUsers })); }) );