Agenda refactor

This commit is contained in:
alma 2026-01-15 13:22:43 +01:00
parent 0cdf3dd691
commit 631524b8a8
3 changed files with 57 additions and 10 deletions

View File

@ -378,14 +378,14 @@ export default async function CalendarPage() {
// Trigger sync for Microsoft calendars that need it (async, don't wait) // Trigger sync for Microsoft calendars that need it (async, don't wait)
for (const syncConfig of microsoftSyncConfigs) { for (const syncConfig of microsoftSyncConfigs) {
// For Microsoft, use a more frequent check (2 minutes) for better reactivity // For Microsoft, use a more frequent check (1 minute) for better reactivity
// This allows new events to appear faster without overloading the API // This allows new events to appear faster without overloading the API
const microsoftMinSyncInterval = 2; // minutes const microsoftMinSyncInterval = 1; // minutes (reduced from 2 to 1 for faster sync)
const minutesSinceLastSync = syncConfig.lastSyncAt const minutesSinceLastSync = syncConfig.lastSyncAt
? (Date.now() - syncConfig.lastSyncAt.getTime()) / (1000 * 60) ? (Date.now() - syncConfig.lastSyncAt.getTime()) / (1000 * 60)
: Infinity; : Infinity;
// Sync if never synced, or if enough time has passed (use minimum of 2 min or configured frequency) // Sync if never synced, or if enough time has passed (use minimum of 1 min or configured frequency)
const needsSync = !syncConfig.lastSyncAt || const needsSync = !syncConfig.lastSyncAt ||
minutesSinceLastSync >= Math.min(microsoftMinSyncInterval, syncConfig.syncFrequency); minutesSinceLastSync >= Math.min(microsoftMinSyncInterval, syncConfig.syncFrequency);

View File

@ -98,22 +98,31 @@ export async function GET(req: NextRequest) {
}); });
// Extract mission calendars (excluding those already in personalCalendars) // Extract mission calendars (excluding those already in personalCalendars)
// Use a Set to avoid duplicate calendars by ID
const personalCalendarIds = new Set(personalCalendars.map(cal => cal.id));
const missionCalendars = missionUserRelations const missionCalendars = missionUserRelations
.flatMap(mu => mu.mission.calendars) .flatMap(mu => mu.mission.calendars)
.filter(cal => cal.userId !== session.user.id); // Exclude calendars owned by user (already in personalCalendars) .filter(cal => !personalCalendarIds.has(cal.id)); // Exclude calendars already in personalCalendars
// Combine personal and mission calendars // Combine personal and mission calendars
const calendars = [...personalCalendars, ...missionCalendars]; const calendars = [...personalCalendars, ...missionCalendars];
// Remove duplicate calendars by ID (in case same calendar appears multiple times)
const uniqueCalendars = Array.from(
new Map(calendars.map(cal => [cal.id, cal])).values()
);
logger.debug('[CALENDAR] Fetched calendars with events', { logger.debug('[CALENDAR] Fetched calendars with events', {
userId: session.user.id, userId: session.user.id,
count: calendars.length, personalCount: personalCalendars.length,
missionCount: missionCalendars.length,
totalCount: uniqueCalendars.length,
}); });
// Cache the results // Cache the results
await cacheCalendarData(session.user.id, calendars); await cacheCalendarData(session.user.id, uniqueCalendars);
return NextResponse.json(calendars); return NextResponse.json(uniqueCalendars);
} catch (error) { } catch (error) {
logger.error('[CALENDAR] Erreur lors de la récupération des calendriers', { logger.error('[CALENDAR] Erreur lors de la récupération des calendriers', {
error: error instanceof Error ? error.message : String(error), error: error instanceof Error ? error.message : String(error),

View File

@ -477,6 +477,14 @@ export async function syncMicrosoftCalendar(
? existingEventsByExternalId.get(microsoftId) ? existingEventsByExternalId.get(microsoftId)
: undefined; : undefined;
if (existingEvent) {
logger.debug('Matched event by externalEventId', {
microsoftId,
eventId: existingEvent.id,
title: caldavEvent.summary,
});
}
// Priority 2: Fallback to checking description for [MS_ID:xxx] (backward compatibility) // Priority 2: Fallback to checking description for [MS_ID:xxx] (backward compatibility)
if (!existingEvent && microsoftId) { if (!existingEvent && microsoftId) {
existingEvent = existingEvents.find((e) => { existingEvent = existingEvents.find((e) => {
@ -487,23 +495,53 @@ export async function syncMicrosoftCalendar(
} }
return false; return false;
}); });
if (existingEvent) {
logger.debug('Matched event by description [MS_ID]', {
microsoftId,
eventId: existingEvent.id,
title: caldavEvent.summary,
});
}
} }
// Priority 3: Fallback to title + date matching for events without externalEventId // Priority 3: Fallback to title + date matching for events without externalEventId
// IMPORTANT: Only match if the event doesn't have an externalEventId (to avoid false matches)
if (!existingEvent) { if (!existingEvent) {
existingEvent = existingEvents.find( existingEvent = existingEvents.find(
(e) => { (e) => {
// Access externalEventId safely (may not be in Prisma type if client not regenerated) // Access externalEventId safely (may not be in Prisma type if client not regenerated)
const hasExternalId = !!(e as any).externalEventId; const hasExternalId = !!(e as any).externalEventId;
if (!hasExternalId && // Only match events that don't have externalEventId yet // Only match events that don't have externalEventId yet (to avoid false matches)
e.title === caldavEvent.summary) { if (hasExternalId) {
return false; // Skip events that already have externalEventId
}
// Match by title and date (within 1 minute)
if (e.title === caldavEvent.summary) {
const timeDiff = Math.abs(new Date(e.start).getTime() - caldavEvent.start.getTime()); const timeDiff = Math.abs(new Date(e.start).getTime() - caldavEvent.start.getTime());
return timeDiff < 60000; // Within 1 minute if (timeDiff < 60000) { // Within 1 minute
logger.debug('Matched event by title + date (no externalEventId)', {
eventId: e.id,
title: caldavEvent.summary,
timeDiff,
});
return true;
}
} }
return false; return false;
} }
); );
} }
// Log if no match found (new event)
if (!existingEvent) {
logger.debug('No match found, will create new event', {
microsoftId,
title: caldavEvent.summary,
start: caldavEvent.start.toISOString(),
});
}
// Clean description (remove [MS_ID:xxx] prefix if present from previous syncs) // Clean description (remove [MS_ID:xxx] prefix if present from previous syncs)
const cleanedDescription = cleanDescription(caldavEvent.description); const cleanedDescription = cleanDescription(caldavEvent.description);