NeahStable/app/api/calendars/sync/route.ts
2026-01-14 13:47:36 +01:00

249 lines
6.5 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server";
import { getServerSession } from "next-auth/next";
import { authOptions } from "@/app/api/auth/options";
import { prisma } from "@/lib/prisma";
import { syncInfomaniakCalendar } from "@/lib/services/caldav-sync";
import { logger } from "@/lib/logger";
/**
* Create a calendar sync configuration
* POST /api/calendars/sync
*/
export async function POST(req: NextRequest) {
try {
const session = await getServerSession(authOptions);
if (!session?.user?.id) {
return NextResponse.json({ error: "Non authentifié" }, { status: 401 });
}
const { calendarId, mailCredentialId, externalCalendarUrl, externalCalendarId, syncFrequency } = await req.json();
if (!calendarId || !mailCredentialId || !externalCalendarUrl) {
return NextResponse.json(
{ error: "calendarId, mailCredentialId et externalCalendarUrl sont requis" },
{ status: 400 }
);
}
// Verify calendar belongs to user
const calendar = await prisma.calendar.findFirst({
where: {
id: calendarId,
userId: session.user.id,
},
});
if (!calendar) {
return NextResponse.json(
{ error: "Calendrier non trouvé" },
{ status: 404 }
);
}
// Verify mail credentials belong to user
const mailCreds = await prisma.mailCredentials.findFirst({
where: {
id: mailCredentialId,
userId: session.user.id,
},
});
if (!mailCreds) {
return NextResponse.json(
{ error: "Credentials non trouvés" },
{ status: 404 }
);
}
// Create or update sync configuration
const syncConfig = await prisma.calendarSync.upsert({
where: { calendarId },
create: {
calendarId,
mailCredentialId,
provider: 'infomaniak',
externalCalendarId: externalCalendarId || null,
externalCalendarUrl,
syncEnabled: true,
syncFrequency: syncFrequency || 15,
},
update: {
mailCredentialId,
externalCalendarId: externalCalendarId || null,
externalCalendarUrl,
syncFrequency: syncFrequency || 15,
syncEnabled: true,
},
});
// Trigger initial sync
try {
await syncInfomaniakCalendar(syncConfig.id, true);
} catch (syncError) {
logger.error('Error during initial sync', {
syncConfigId: syncConfig.id,
error: syncError instanceof Error ? syncError.message : String(syncError),
});
// Don't fail the request if sync fails, just log it
}
return NextResponse.json({ syncConfig });
} catch (error) {
logger.error('Error creating calendar sync', {
error: error instanceof Error ? error.message : String(error),
});
return NextResponse.json(
{
error: "Erreur lors de la création de la synchronisation",
details: error instanceof Error ? error.message : String(error),
},
{ status: 500 }
);
}
}
/**
* Trigger manual sync for a calendar
* PUT /api/calendars/sync
*/
export async function PUT(req: NextRequest) {
try {
const session = await getServerSession(authOptions);
if (!session?.user?.id) {
return NextResponse.json({ error: "Non authentifié" }, { status: 401 });
}
const { calendarSyncId } = await req.json();
if (!calendarSyncId) {
return NextResponse.json(
{ error: "calendarSyncId est requis" },
{ status: 400 }
);
}
// Verify sync config belongs to user
const syncConfig = await prisma.calendarSync.findUnique({
where: { id: calendarSyncId },
include: {
calendar: true,
},
});
if (!syncConfig || syncConfig.calendar.userId !== session.user.id) {
return NextResponse.json(
{ error: "Synchronisation non trouvée" },
{ status: 404 }
);
}
// Trigger sync
const result = await syncInfomaniakCalendar(calendarSyncId, true);
return NextResponse.json({ success: true, result });
} catch (error) {
logger.error('Error triggering calendar sync', {
error: error instanceof Error ? error.message : String(error),
});
return NextResponse.json(
{
error: "Erreur lors de la synchronisation",
details: error instanceof Error ? error.message : String(error),
},
{ status: 500 }
);
}
}
/**
* Get sync status for user calendars
* GET /api/calendars/sync
*/
export async function GET(req: NextRequest) {
try {
const session = await getServerSession(authOptions);
if (!session?.user?.id) {
return NextResponse.json({ error: "Non authentifié" }, { status: 401 });
}
const syncConfigs = await prisma.calendarSync.findMany({
where: {
calendar: {
userId: session.user.id,
},
},
include: {
calendar: true,
mailCredential: {
select: {
id: true,
email: true,
display_name: true,
},
},
},
});
return NextResponse.json({ syncConfigs });
} catch (error) {
logger.error('Error fetching sync configs', {
error: error instanceof Error ? error.message : String(error),
});
return NextResponse.json(
{ error: "Erreur serveur" },
{ status: 500 }
);
}
}
/**
* Delete sync configuration
* DELETE /api/calendars/sync
*/
export async function DELETE(req: NextRequest) {
try {
const session = await getServerSession(authOptions);
if (!session?.user?.id) {
return NextResponse.json({ error: "Non authentifié" }, { status: 401 });
}
const { calendarSyncId } = await req.json();
if (!calendarSyncId) {
return NextResponse.json(
{ error: "calendarSyncId est requis" },
{ status: 400 }
);
}
// Verify sync config belongs to user
const syncConfig = await prisma.calendarSync.findUnique({
where: { id: calendarSyncId },
include: {
calendar: true,
},
});
if (!syncConfig || syncConfig.calendar.userId !== session.user.id) {
return NextResponse.json(
{ error: "Synchronisation non trouvée" },
{ status: 404 }
);
}
await prisma.calendarSync.delete({
where: { id: calendarSyncId },
});
return NextResponse.json({ success: true });
} catch (error) {
logger.error('Error deleting sync config', {
error: error instanceof Error ? error.message : String(error),
});
return NextResponse.json(
{ error: "Erreur serveur" },
{ status: 500 }
);
}
}