My-Weekly-ToDo-List/src/app/api/calendar/outlook/callback/route.ts

110 lines
3.9 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
import { getServerSession } from 'next-auth';
import { authOptions } from "@/lib/auth";
import { prisma } from '@/lib/prisma';
import { getTokens, getUserCalendars } from '@/lib/outlook-calendar';
export const dynamic = 'force-dynamic';
export async function GET(request: NextRequest) {
const baseUrl = process.env.NEXTAUTH_URL || request.url;
try {
const session = await getServerSession(authOptions);
if (!session?.user?.email) {
return NextResponse.redirect(new URL('/auth/login', baseUrl));
}
const { searchParams } = new URL(request.url);
const code = searchParams.get('code');
const error = searchParams.get('error');
if (error) {
console.error('Outlook OAuth error:', error);
return NextResponse.redirect(new URL('/?error=outlook_auth_failed', baseUrl));
}
if (!code) {
return NextResponse.redirect(new URL('/?error=no_code', baseUrl));
}
// Exchange code for tokens
const tokenData = await getTokens(code);
const accessToken = tokenData.access_token;
const refreshToken = tokenData.refresh_token;
const expiresIn = tokenData.expires_in;
// Fetch user's calendars to store initial list
const calendars = await getUserCalendars(accessToken);
const userId = (session.user as any).id;
const user = userId
? await prisma.user.findUnique({ where: { id: userId } })
: await prisma.user.findUnique({ where: { email: session.user.email } });
if (!user) {
return NextResponse.redirect(new URL('/auth/login', baseUrl));
}
// Calculate expiry date
const expiresAt = new Date();
expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn);
// Check for existing connection
const existingConnection = await prisma.calendarConnection.findFirst({
where: {
userId: user.id,
provider: 'outlook'
}
});
const calendarData = calendars.map(cal => ({
id: cal.id,
title: cal.name,
isPrimary: cal.isDefaultCalendar,
selected: true,
editable: cal.canEdit
}));
if (existingConnection) {
await prisma.calendarConnection.update({
where: { id: existingConnection.id },
data: {
accessToken,
refreshToken,
expiresAt,
calendars: calendarData,
updatedAt: new Date()
}
});
} else {
// Create new connection
await prisma.calendarConnection.create({
data: {
userId: user.id,
provider: 'outlook',
accessToken,
refreshToken,
expiresAt,
calendars: calendarData,
}
});
}
// Redirect to a client-side page that re-establishes the session
// Direct redirects from Microsoft OAuth may lose the session cookie (SameSite policy)
const redirectUrl = new URL('/auth/oauth-complete', baseUrl);
redirectUrl.searchParams.set('provider', 'outlook');
redirectUrl.searchParams.set('status', 'connected');
return NextResponse.redirect(redirectUrl);
} catch (error) {
console.error('Error in Outlook callback:', error);
const redirectUrl = new URL('/auth/oauth-complete', baseUrl);
redirectUrl.searchParams.set('provider', 'outlook');
redirectUrl.searchParams.set('status', 'error');
redirectUrl.searchParams.set('message', 'outlook_callback_failed');
return NextResponse.redirect(redirectUrl);
}
}