diff --git a/app/agenda/page.tsx b/app/agenda/page.tsx index 4af70b3..b47ecc5 100644 --- a/app/agenda/page.tsx +++ b/app/agenda/page.tsx @@ -752,13 +752,27 @@ export default async function CalendarPage() { calendarsWithSync.forEach(cal => { const eventCount = cal.events?.length || 0; console.log(`[AGENDA] Calendar: ${cal.name}, provider: ${cal.syncConfig?.provider}, syncEnabled: ${cal.syncConfig?.syncEnabled}, hasMailCredential: ${!!cal.syncConfig?.mailCredential}, events: ${eventCount}`); - if (eventCount > 0 && cal.syncConfig?.provider === 'microsoft') { - console.log(`[AGENDA] Microsoft calendar events:`, cal.events.slice(0, 5).map(e => ({ + if (cal.syncConfig?.provider === 'microsoft') { + // Log all Microsoft events with details + console.log(`[AGENDA] Microsoft calendar ${cal.id} events (${eventCount}):`, cal.events.map(e => ({ id: e.id, title: e.title, start: e.start, - end: e.end + end: e.end, + isAllDay: e.isAllDay, + description: e.description ? e.description.substring(0, 50) : null }))); + + // Also check directly in DB to see if there are more events + prisma.event.count({ + where: { calendarId: cal.id } + }).then((dbCount) => { + if (dbCount !== eventCount) { + console.log(`[AGENDA] WARNING: Calendar ${cal.id} has ${eventCount} events in query but ${dbCount} in DB`); + } + }).catch((err) => { + console.error('[AGENDA] Error counting events in DB:', err); + }); } }); diff --git a/lib/services/microsoft-calendar-sync.ts b/lib/services/microsoft-calendar-sync.ts index e380c7f..e088bc8 100644 --- a/lib/services/microsoft-calendar-sync.ts +++ b/lib/services/microsoft-calendar-sync.ts @@ -138,20 +138,34 @@ export async function fetchMicrosoftEvents( }; // Add date filter if provided - // Note: Microsoft Graph API filter for events needs to handle both timed and all-day events - // For all-day events, start/dateTime might not exist, so we use start/date instead + // Note: Microsoft Graph API filter syntax + // For timed events: start/dateTime + // For all-day events: start/date + // We need to handle both cases if (startDate && endDate) { - // Microsoft Graph API expects ISO format for date filters - // For all-day events, use start/date (YYYY-MM-DD format) - // For timed events, use start/dateTime (ISO format) - const startDateStr = startDate.toISOString().split('T')[0]; // YYYY-MM-DD - const endDateStr = endDate.toISOString().split('T')[0]; // YYYY-MM-DD + // Format dates for Microsoft Graph API + // For dateTime: ISO 8601 format (e.g., 2026-01-14T21:00:00Z) + // For date: YYYY-MM-DD format + const startDateStr = startDate.toISOString().split('T')[0]; + const endDateStr = endDate.toISOString().split('T')[0]; const startDateTimeStr = startDate.toISOString(); const endDateTimeStr = endDate.toISOString(); - // Filter: events where start is within range - // Handle both timed events (start/dateTime) and all-day events (start/date) + // Microsoft Graph API filter: match events where start is within range + // This handles both timed events (dateTime) and all-day events (date) + // The filter checks if either dateTime OR date is within range params.$filter = `(start/dateTime ge '${startDateTimeStr}' or start/date ge '${startDateStr}') and (start/dateTime le '${endDateTimeStr}' or start/date le '${endDateStr}')`; + + logger.debug('Microsoft Graph API filter', { + filter: params.$filter, + startDate: startDateStr, + endDate: endDateStr, + startDateTime: startDateTimeStr, + endDateTime: endDateTimeStr, + }); + } else { + // If no date filter, get all events (might be too many, but useful for debugging) + logger.warn('No date filter provided, fetching all events (this might be slow)'); } logger.debug('Fetching Microsoft events with params', { @@ -178,12 +192,27 @@ export async function fetchMicrosoftEvents( }); const events = response.data.value || []; - logger.debug('Microsoft Graph API response', { + logger.info('Microsoft Graph API response', { calendarId, eventCount: events.length, hasValue: !!response.data.value, + status: response.status, + // Log first few event IDs to verify they're being returned + eventIds: events.slice(0, 5).map(e => e.id), }); + // Log if we got fewer events than expected + if (events.length === 0 && startDate && endDate) { + logger.warn('No events returned from Microsoft Graph API', { + calendarId, + dateRange: { + start: startDate.toISOString(), + end: endDate.toISOString(), + }, + filter: params.$filter, + }); + } + return events; } catch (error) { logger.error('Error fetching Microsoft events', { @@ -309,6 +338,7 @@ export async function syncMicrosoftCalendar( endDate ); + // Log all events, not just first 10 logger.info('Fetched Microsoft events', { calendarSyncId, eventCount: microsoftEvents.length, @@ -316,7 +346,7 @@ export async function syncMicrosoftCalendar( start: startDate.toISOString(), end: endDate.toISOString() }, - events: microsoftEvents.slice(0, 10).map(e => ({ + allEvents: microsoftEvents.map(e => ({ id: e.id, subject: e.subject, start: e.start.dateTime || e.start.date, @@ -458,6 +488,11 @@ export async function syncMicrosoftCalendar( }); } + // Verify events were actually saved to DB + const eventsInDb = await prisma.event.count({ + where: { calendarId: syncConfig.calendarId } + }); + logger.info('Microsoft calendar sync completed', { calendarSyncId, calendarId: syncConfig.calendarId, @@ -466,6 +501,7 @@ export async function syncMicrosoftCalendar( created, updated, deleted, + eventsInDb, }); // Log summary of created/updated events @@ -475,6 +511,16 @@ export async function syncMicrosoftCalendar( newEventsCreated: created, eventsUpdated: updated, totalEventsInCalendar: caldavEvents.length, + eventsInDbAfterSync: eventsInDb, + }); + } + + // Log warning if events count doesn't match + if (caldavEvents.length > 0 && eventsInDb === 0) { + logger.error('WARNING: Events were fetched but none were saved to DB', { + calendarSyncId, + fetchedCount: caldavEvents.length, + dbCount: eventsInDb, }); }