Agenda refactor
This commit is contained in:
parent
946a110054
commit
fd24dfbd21
@ -242,14 +242,20 @@ export default async function CalendarPage() {
|
|||||||
console.log(`[AGENDA] Invalid calendar URL detected (${existingSync.externalCalendarUrl}), attempting to rediscover...`);
|
console.log(`[AGENDA] Invalid calendar URL detected (${existingSync.externalCalendarUrl}), attempting to rediscover...`);
|
||||||
try {
|
try {
|
||||||
const { discoverInfomaniakCalendars } = await import('@/lib/services/caldav-sync');
|
const { discoverInfomaniakCalendars } = await import('@/lib/services/caldav-sync');
|
||||||
|
|
||||||
|
if (!account.password) {
|
||||||
|
console.error(`[AGENDA] Cannot rediscover calendars: missing password for ${account.email}`);
|
||||||
|
} else {
|
||||||
const externalCalendars = await discoverInfomaniakCalendars(
|
const externalCalendars = await discoverInfomaniakCalendars(
|
||||||
account.email,
|
account.email,
|
||||||
account.password!
|
account.password
|
||||||
);
|
);
|
||||||
|
|
||||||
|
console.log(`[AGENDA] Rediscovery result: found ${externalCalendars.length} calendars for ${account.email}`);
|
||||||
|
|
||||||
if (externalCalendars.length > 0) {
|
if (externalCalendars.length > 0) {
|
||||||
const mainCalendar = externalCalendars[0];
|
const mainCalendar = externalCalendars[0];
|
||||||
console.log(`[AGENDA] Updating sync with correct calendar URL: ${mainCalendar.url}`);
|
console.log(`[AGENDA] Updating sync with correct calendar URL: ${mainCalendar.url} (name: ${mainCalendar.name})`);
|
||||||
await prisma.calendarSync.update({
|
await prisma.calendarSync.update({
|
||||||
where: { id: existingSync.id },
|
where: { id: existingSync.id },
|
||||||
data: {
|
data: {
|
||||||
@ -265,12 +271,36 @@ export default async function CalendarPage() {
|
|||||||
});
|
});
|
||||||
if (updatedSync) {
|
if (updatedSync) {
|
||||||
existingSync = updatedSync;
|
existingSync = updatedSync;
|
||||||
|
console.log(`[AGENDA] Sync config updated successfully, new URL: ${updatedSync.externalCalendarUrl}`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log(`[AGENDA] No calendars found during rediscovery for ${account.email}`);
|
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
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -48,18 +48,31 @@ export async function discoverInfomaniakCalendars(
|
|||||||
const client = await getInfomaniakCalDAVClient(email, password);
|
const client = await getInfomaniakCalDAVClient(email, password);
|
||||||
|
|
||||||
// List all calendars using PROPFIND on root
|
// List all calendars using PROPFIND on root
|
||||||
|
logger.debug('Discovering Infomaniak calendars', { email });
|
||||||
const items = await client.getDirectoryContents('/');
|
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[] = [];
|
const calendars: CalDAVCalendar[] = [];
|
||||||
|
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
// Skip non-directories, root, and special directories like /principals
|
// Skip non-directories, root, and special directories like /principals
|
||||||
if (item.type !== 'directory' || item.filename === '/' || item.filename === '/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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get calendar properties to verify it's actually a calendar
|
// Get calendar properties to verify it's actually a calendar
|
||||||
try {
|
try {
|
||||||
|
logger.debug('Checking if item is a calendar', { filename: item.filename });
|
||||||
const props = await client.customRequest(item.filename, {
|
const props = await client.customRequest(item.filename, {
|
||||||
method: 'PROPFIND',
|
method: 'PROPFIND',
|
||||||
headers: {
|
headers: {
|
||||||
@ -77,11 +90,23 @@ export async function discoverInfomaniakCalendars(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Check if this is actually a calendar (has <c:calendar> in resourcetype)
|
// Check if this is actually a calendar (has <c:calendar> in resourcetype)
|
||||||
const isCalendar = props.data && props.data.includes('<c:calendar');
|
// Try multiple patterns to be more flexible with XML namespaces
|
||||||
|
const dataStr = props.data || '';
|
||||||
|
const isCalendar = dataStr.includes('<c:calendar') ||
|
||||||
|
dataStr.includes('calendar') ||
|
||||||
|
dataStr.includes('urn:ietf:params:xml:ns:caldav');
|
||||||
|
|
||||||
|
logger.debug('Calendar check result', {
|
||||||
|
filename: item.filename,
|
||||||
|
isCalendar,
|
||||||
|
hasData: !!props.data,
|
||||||
|
dataPreview: props.data ? props.data.substring(0, 500) : 'no data',
|
||||||
|
});
|
||||||
|
|
||||||
if (!isCalendar) {
|
if (!isCalendar) {
|
||||||
logger.debug('Skipping non-calendar directory', {
|
logger.debug('Skipping non-calendar directory', {
|
||||||
filename: item.filename,
|
filename: item.filename,
|
||||||
|
reason: 'resourcetype does not indicate calendar',
|
||||||
});
|
});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -90,12 +115,15 @@ export async function discoverInfomaniakCalendars(
|
|||||||
const displayName = extractDisplayName(props.data);
|
const displayName = extractDisplayName(props.data);
|
||||||
const color = extractCalendarColor(props.data);
|
const color = extractCalendarColor(props.data);
|
||||||
|
|
||||||
calendars.push({
|
const calendar = {
|
||||||
id: item.filename.replace(/^\//, '').replace(/\/$/, ''),
|
id: item.filename.replace(/^\//, '').replace(/\/$/, ''),
|
||||||
name: displayName || item.basename || 'Calendrier',
|
name: displayName || item.basename || 'Calendrier',
|
||||||
url: item.filename,
|
url: item.filename,
|
||||||
color: color,
|
color: color,
|
||||||
});
|
};
|
||||||
|
|
||||||
|
logger.debug('Found valid calendar', calendar);
|
||||||
|
calendars.push(calendar);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Error fetching calendar properties', {
|
logger.error('Error fetching calendar properties', {
|
||||||
calendar: item.filename,
|
calendar: item.filename,
|
||||||
@ -105,19 +133,23 @@ export async function discoverInfomaniakCalendars(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.info('Infomaniak calendar discovery completed', {
|
||||||
|
email,
|
||||||
|
calendarsFound: calendars.length,
|
||||||
|
calendars: calendars.map(cal => ({ id: cal.id, name: cal.name, url: cal.url })),
|
||||||
|
});
|
||||||
|
|
||||||
return calendars;
|
return calendars;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||||
const errorDetails = error instanceof Error ? {
|
const errorDetails = error instanceof Error ? {
|
||||||
name: error.name,
|
name: error.name,
|
||||||
message: error.message,
|
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) };
|
} : { raw: String(error) };
|
||||||
|
|
||||||
// Use logger.log instead of logger.error for non-critical errors
|
// Log as error for debugging, but don't throw to avoid breaking the page
|
||||||
// This prevents console.error from showing up in the browser console
|
logger.error('Infomaniak calendar discovery failed', {
|
||||||
// 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)', {
|
|
||||||
email,
|
email,
|
||||||
error: errorMessage,
|
error: errorMessage,
|
||||||
errorDetails,
|
errorDetails,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user