Agenda refactor
This commit is contained in:
parent
1d2a72ce8c
commit
fe6655f913
@ -595,6 +595,7 @@ export default async function CalendarPage() {
|
||||
}
|
||||
|
||||
// Auto-sync Infomaniak calendars if needed (background, don't block page load)
|
||||
// Reload sync configs after URL corrections to get updated URLs
|
||||
const infomaniakSyncConfigs = await prisma.calendarSync.findMany({
|
||||
where: {
|
||||
provider: 'infomaniak',
|
||||
@ -609,6 +610,12 @@ export default async function CalendarPage() {
|
||||
|
||||
// Trigger sync for Infomaniak calendars that need it (async, don't wait)
|
||||
for (const syncConfig of infomaniakSyncConfigs) {
|
||||
// Skip sync if URL is still invalid (should have been fixed above, but double-check)
|
||||
if (syncConfig.externalCalendarUrl === '/principals' || !syncConfig.externalCalendarUrl || syncConfig.externalCalendarUrl === '/') {
|
||||
console.log(`[AGENDA] Skipping Infomaniak sync ${syncConfig.id} - invalid calendar URL: ${syncConfig.externalCalendarUrl}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const minutesSinceLastSync = syncConfig.lastSyncAt
|
||||
? (Date.now() - syncConfig.lastSyncAt.getTime()) / (1000 * 60)
|
||||
: Infinity;
|
||||
@ -617,7 +624,7 @@ export default async function CalendarPage() {
|
||||
const needsSync = !syncConfig.lastSyncAt ||
|
||||
minutesSinceLastSync >= syncConfig.syncFrequency;
|
||||
|
||||
console.log(`[AGENDA] Infomaniak sync config ${syncConfig.id}: lastSyncAt=${syncConfig.lastSyncAt}, minutesSinceLastSync=${minutesSinceLastSync.toFixed(1)}, needsSync=${needsSync}, syncFrequency=${syncConfig.syncFrequency}`);
|
||||
console.log(`[AGENDA] Infomaniak sync config ${syncConfig.id}: lastSyncAt=${syncConfig.lastSyncAt}, minutesSinceLastSync=${minutesSinceLastSync.toFixed(1)}, needsSync=${needsSync}, syncFrequency=${syncConfig.syncFrequency}, calendarUrl=${syncConfig.externalCalendarUrl}`);
|
||||
|
||||
if (needsSync) {
|
||||
console.log(`[AGENDA] Triggering background sync for Infomaniak calendar ${syncConfig.id}`);
|
||||
|
||||
@ -453,25 +453,49 @@ export async function syncInfomaniakCalendar(
|
||||
|
||||
// For updates, we cannot modify calendarId and userId (they are relations)
|
||||
// For creates, we need them
|
||||
const baseEventData = {
|
||||
// Build event data dynamically to handle case where externalEventId field doesn't exist yet
|
||||
const baseEventData: any = {
|
||||
title: caldavEvent.summary,
|
||||
description: caldavEvent.description || null,
|
||||
start: caldavEvent.start,
|
||||
end: caldavEvent.end,
|
||||
location: caldavEvent.location || null,
|
||||
isAllDay: caldavEvent.allDay,
|
||||
externalEventId: caldavEvent.uid, // Store UID for reliable matching
|
||||
};
|
||||
|
||||
// Only add externalEventId if migration has been applied
|
||||
// We'll try to add it, and if it fails, we'll retry without it
|
||||
if (caldavEvent.uid) {
|
||||
baseEventData.externalEventId = caldavEvent.uid;
|
||||
}
|
||||
|
||||
if (existingEvent) {
|
||||
// Update existing event (without calendarId and userId - they are relations)
|
||||
try {
|
||||
await prisma.event.update({
|
||||
where: { id: existingEvent.id },
|
||||
data: baseEventData,
|
||||
});
|
||||
updated++;
|
||||
} catch (updateError: any) {
|
||||
// If externalEventId field doesn't exist, retry without it
|
||||
if (updateError?.message?.includes('externalEventId') || updateError?.code === 'P2009') {
|
||||
logger.warn('externalEventId field not available, updating without it', {
|
||||
eventId: existingEvent.id,
|
||||
});
|
||||
const { externalEventId, ...dataWithoutExternalId } = baseEventData;
|
||||
await prisma.event.update({
|
||||
where: { id: existingEvent.id },
|
||||
data: dataWithoutExternalId,
|
||||
});
|
||||
updated++;
|
||||
} else {
|
||||
throw updateError;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Create new event (with calendarId and userId)
|
||||
try {
|
||||
await prisma.event.create({
|
||||
data: {
|
||||
...baseEventData,
|
||||
@ -480,6 +504,23 @@ export async function syncInfomaniakCalendar(
|
||||
},
|
||||
});
|
||||
created++;
|
||||
} catch (createError: any) {
|
||||
// If externalEventId field doesn't exist, retry without it
|
||||
if (createError?.message?.includes('externalEventId') || createError?.code === 'P2009') {
|
||||
logger.warn('externalEventId field not available, creating without it');
|
||||
const { externalEventId, ...dataWithoutExternalId } = baseEventData;
|
||||
await prisma.event.create({
|
||||
data: {
|
||||
...dataWithoutExternalId,
|
||||
calendarId: syncConfig.calendarId,
|
||||
userId: syncConfig.calendar.userId,
|
||||
},
|
||||
});
|
||||
created++;
|
||||
} else {
|
||||
throw createError;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -499,18 +499,25 @@ export async function syncMicrosoftCalendar(
|
||||
|
||||
// For updates, we cannot modify calendarId and userId (they are relations)
|
||||
// For creates, we need them
|
||||
const baseEventData = {
|
||||
// Build event data dynamically to handle case where externalEventId field doesn't exist yet
|
||||
const baseEventData: any = {
|
||||
title: caldavEvent.summary,
|
||||
description: cleanedDescription, // Clean description without [MS_ID:xxx] prefix
|
||||
start: caldavEvent.start,
|
||||
end: caldavEvent.end,
|
||||
location: caldavEvent.location || null,
|
||||
isAllDay: caldavEvent.allDay,
|
||||
externalEventId: microsoftId, // Store Microsoft ID for reliable matching
|
||||
};
|
||||
|
||||
// Only add externalEventId if migration has been applied
|
||||
// We'll try to add it, and if it fails, we'll retry without it
|
||||
if (microsoftId) {
|
||||
baseEventData.externalEventId = microsoftId;
|
||||
}
|
||||
|
||||
if (existingEvent) {
|
||||
// Update existing event (without calendarId and userId - they are relations)
|
||||
try {
|
||||
await prisma.event.update({
|
||||
where: { id: existingEvent.id },
|
||||
data: baseEventData,
|
||||
@ -521,8 +528,25 @@ export async function syncMicrosoftCalendar(
|
||||
title: caldavEvent.summary,
|
||||
microsoftId,
|
||||
});
|
||||
} catch (updateError: any) {
|
||||
// If externalEventId field doesn't exist, retry without it
|
||||
if (updateError?.message?.includes('externalEventId') || updateError?.code === 'P2009') {
|
||||
logger.warn('externalEventId field not available, updating without it', {
|
||||
eventId: existingEvent.id,
|
||||
});
|
||||
const { externalEventId, ...dataWithoutExternalId } = baseEventData;
|
||||
await prisma.event.update({
|
||||
where: { id: existingEvent.id },
|
||||
data: dataWithoutExternalId,
|
||||
});
|
||||
updated++;
|
||||
} else {
|
||||
throw updateError;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Create new event (with calendarId and userId)
|
||||
try {
|
||||
const newEvent = await prisma.event.create({
|
||||
data: {
|
||||
...baseEventData,
|
||||
@ -537,6 +561,23 @@ export async function syncMicrosoftCalendar(
|
||||
microsoftId,
|
||||
start: caldavEvent.start.toISOString(),
|
||||
});
|
||||
} catch (createError: any) {
|
||||
// If externalEventId field doesn't exist, retry without it
|
||||
if (createError?.message?.includes('externalEventId') || createError?.code === 'P2009') {
|
||||
logger.warn('externalEventId field not available, creating without it');
|
||||
const { externalEventId, ...dataWithoutExternalId } = baseEventData;
|
||||
const newEvent = await prisma.event.create({
|
||||
data: {
|
||||
...dataWithoutExternalId,
|
||||
calendarId: syncConfig.calendarId,
|
||||
userId: syncConfig.calendar.userId,
|
||||
},
|
||||
});
|
||||
created++;
|
||||
} else {
|
||||
throw createError;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
49
scripts/apply-external-event-id-migration.sql
Normal file
49
scripts/apply-external-event-id-migration.sql
Normal file
@ -0,0 +1,49 @@
|
||||
-- Script to manually apply externalEventId migration
|
||||
-- Run this directly on your PostgreSQL database
|
||||
|
||||
-- Check if columns exist
|
||||
SELECT
|
||||
column_name,
|
||||
data_type
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = 'Event'
|
||||
AND column_name IN ('externalEventId', 'externalEventUrl');
|
||||
|
||||
-- Add externalEventId column if it doesn't exist
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'Event' AND column_name = 'externalEventId'
|
||||
) THEN
|
||||
ALTER TABLE "Event" ADD COLUMN "externalEventId" TEXT;
|
||||
RAISE NOTICE 'Added externalEventId column';
|
||||
ELSE
|
||||
RAISE NOTICE 'externalEventId column already exists';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Add externalEventUrl column if it doesn't exist
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'Event' AND column_name = 'externalEventUrl'
|
||||
) THEN
|
||||
ALTER TABLE "Event" ADD COLUMN "externalEventUrl" TEXT;
|
||||
RAISE NOTICE 'Added externalEventUrl column';
|
||||
ELSE
|
||||
RAISE NOTICE 'externalEventUrl column already exists';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Create index on externalEventId if it doesn't exist
|
||||
CREATE INDEX IF NOT EXISTS "Event_externalEventId_idx" ON "Event"("externalEventId");
|
||||
|
||||
-- Verify columns were added
|
||||
SELECT
|
||||
column_name,
|
||||
data_type
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = 'Event'
|
||||
AND column_name IN ('externalEventId', 'externalEventUrl');
|
||||
Loading…
Reference in New Issue
Block a user