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); } }