diff --git a/app/agenda/page.tsx b/app/agenda/page.tsx index c7d7cd7..1c5be71 100644 --- a/app/agenda/page.tsx +++ b/app/agenda/page.tsx @@ -242,35 +242,65 @@ export default async function CalendarPage() { console.log(`[AGENDA] Invalid calendar URL detected (${existingSync.externalCalendarUrl}), attempting to rediscover...`); try { const { discoverInfomaniakCalendars } = await import('@/lib/services/caldav-sync'); - const externalCalendars = await discoverInfomaniakCalendars( - account.email, - account.password! - ); - if (externalCalendars.length > 0) { - const mainCalendar = externalCalendars[0]; - console.log(`[AGENDA] Updating sync with correct calendar URL: ${mainCalendar.url}`); - await prisma.calendarSync.update({ - where: { id: existingSync.id }, - data: { - externalCalendarId: mainCalendar.id, - externalCalendarUrl: mainCalendar.url, - lastSyncError: null, // Clear error since we're fixing the URL - } - }); - // Reload the sync config - const updatedSync = await prisma.calendarSync.findUnique({ - where: { id: existingSync.id }, - include: { calendar: true } - }); - if (updatedSync) { - existingSync = updatedSync; - } + if (!account.password) { + console.error(`[AGENDA] Cannot rediscover calendars: missing password for ${account.email}`); } else { - console.log(`[AGENDA] No calendars found during rediscovery for ${account.email}`); + const externalCalendars = await discoverInfomaniakCalendars( + account.email, + account.password + ); + + console.log(`[AGENDA] Rediscovery result: found ${externalCalendars.length} calendars for ${account.email}`); + + if (externalCalendars.length > 0) { + const mainCalendar = externalCalendars[0]; + console.log(`[AGENDA] Updating sync with correct calendar URL: ${mainCalendar.url} (name: ${mainCalendar.name})`); + await prisma.calendarSync.update({ + where: { id: existingSync.id }, + data: { + externalCalendarId: mainCalendar.id, + externalCalendarUrl: mainCalendar.url, + lastSyncError: null, // Clear error since we're fixing the URL + } + }); + // Reload the sync config + const updatedSync = await prisma.calendarSync.findUnique({ + where: { id: existingSync.id }, + include: { calendar: true } + }); + if (updatedSync) { + existingSync = updatedSync; + console.log(`[AGENDA] Sync config updated successfully, new URL: ${updatedSync.externalCalendarUrl}`); + } + } else { + console.warn(`[AGENDA] No calendars found during rediscovery for ${account.email}. This may indicate:`); + console.warn(` - Authentication issue (wrong password)`); + console.warn(` - No calendars exist for this account`); + console.warn(` - CalDAV server issue`); + // Mark sync as having an error so user knows something is wrong + await prisma.calendarSync.update({ + where: { id: existingSync.id }, + data: { + lastSyncError: `No calendars found during rediscovery. Please check your Infomaniak account credentials and calendar access.`, + } + }); + } } - } catch (rediscoverError) { - console.error(`[AGENDA] Error rediscovering calendars:`, rediscoverError); + } catch (rediscoverError: any) { + console.error(`[AGENDA] Error rediscovering calendars for ${account.email}:`, { + error: rediscoverError?.message || String(rediscoverError), + stack: rediscoverError?.stack?.substring(0, 300), + }); + // Mark sync as having an error + await prisma.calendarSync.update({ + where: { id: existingSync.id }, + data: { + lastSyncError: `Rediscovery failed: ${rediscoverError?.message || 'Unknown error'}`, + } + }).catch(() => { + // Ignore update errors + }); } } diff --git a/lib/services/caldav-sync.ts b/lib/services/caldav-sync.ts index 2e1f2cb..7b23d62 100644 --- a/lib/services/caldav-sync.ts +++ b/lib/services/caldav-sync.ts @@ -48,18 +48,31 @@ export async function discoverInfomaniakCalendars( const client = await getInfomaniakCalDAVClient(email, password); // List all calendars using PROPFIND on root + logger.debug('Discovering Infomaniak calendars', { email }); const items = await client.getDirectoryContents('/'); + logger.debug('Found items in root directory', { + email, + itemsCount: items.length, + items: items.map(item => ({ filename: item.filename, type: item.type })), + }); + const calendars: CalDAVCalendar[] = []; for (const item of items) { // Skip non-directories, root, and special directories like /principals if (item.type !== 'directory' || item.filename === '/' || item.filename === '/principals') { + logger.debug('Skipping item', { + filename: item.filename, + type: item.type, + reason: item.type !== 'directory' ? 'not a directory' : 'special directory', + }); continue; } // Get calendar properties to verify it's actually a calendar try { + logger.debug('Checking if item is a calendar', { filename: item.filename }); const props = await client.customRequest(item.filename, { method: 'PROPFIND', headers: { @@ -77,11 +90,23 @@ export async function discoverInfomaniakCalendars( }); // Check if this is actually a calendar (has in resourcetype) - const isCalendar = props.data && props.data.includes(' ({ id: cal.id, name: cal.name, url: cal.url })), + }); + return calendars; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); const errorDetails = error instanceof Error ? { name: error.name, message: error.message, - stack: error.stack?.substring(0, 200), // First 200 chars of stack + stack: error.stack?.substring(0, 500), // More stack for debugging } : { raw: String(error) }; - // Use logger.log instead of logger.error for non-critical errors - // This prevents console.error from showing up in the browser console - // The error is still logged server-side but won't appear as a red error in the browser - logger.log('info', 'Infomaniak calendar discovery failed (non-critical)', { + // Log as error for debugging, but don't throw to avoid breaking the page + logger.error('Infomaniak calendar discovery failed', { email, error: errorMessage, errorDetails,