fix: resolve stale session ID in someday-lists and calendar/events routes
All handlers in someday-lists/route.ts and calendar/events/route.ts were using (session.user as any).id which can be stale after DB restore/migration. Fixed to look up by session.user.email instead — matching the pattern already established in tasks/route.ts and calendar/sync/route.ts. This was causing other users to see empty someday lists while their tasks (fetched via the already-fixed tasks route) still had somedayListId references, triggering false RESCUE recoveries on every load. Also fixed outlook/callback/route.ts fallback which could still use stale ID. v1.81.19
This commit is contained in:
parent
4cab83e545
commit
0371532e7d
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "my-weekly-todo-list",
|
||||
"version": "1.81.18",
|
||||
"version": "1.81.19",
|
||||
"description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
@ -48,13 +48,17 @@ export async function POST(request: NextRequest) {
|
||||
return NextResponse.json({ error: 'Missing required fields' }, { status: 400 });
|
||||
}
|
||||
|
||||
const userId = (session.user as any).id;
|
||||
const connection = await findConnectionForCalendar(userId, calendarId);
|
||||
const connection = await findConnectionForCalendar(session.user.email, calendarId);
|
||||
|
||||
if (!connection) {
|
||||
return NextResponse.json({ error: 'Calendar connection not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
// Resolve real DB user ID for cache operations
|
||||
const dbUser = await prisma.user.findUnique({ where: { email: session.user.email }, select: { id: true } });
|
||||
const userId = dbUser?.id;
|
||||
if (!userId) return NextResponse.json({ error: 'User not found' }, { status: 404 });
|
||||
|
||||
const event = await createCalendarEvent(connection, calendarId, {
|
||||
title,
|
||||
description,
|
||||
@ -114,13 +118,16 @@ export async function PATCH(request: NextRequest) {
|
||||
return NextResponse.json({ error: 'Missing required fields' }, { status: 400 });
|
||||
}
|
||||
|
||||
const userId = (session.user as any).id;
|
||||
const connection = await findConnectionForCalendar(userId, calendarId);
|
||||
const connection = await findConnectionForCalendar(session.user.email, calendarId);
|
||||
|
||||
if (!connection) {
|
||||
return NextResponse.json({ error: 'Calendar connection not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
const dbUser2 = await prisma.user.findUnique({ where: { email: session.user.email }, select: { id: true } });
|
||||
const userId = dbUser2?.id;
|
||||
if (!userId) return NextResponse.json({ error: 'User not found' }, { status: 404 });
|
||||
|
||||
// For "all events" edit mode on recurring events, use the series master ID
|
||||
let targetEventId = eventId;
|
||||
if (editMode === 'all' && recurringEventId) {
|
||||
@ -191,13 +198,16 @@ export async function DELETE(request: NextRequest) {
|
||||
return NextResponse.json({ error: 'Missing required fields' }, { status: 400 });
|
||||
}
|
||||
|
||||
const userId = (session.user as any).id;
|
||||
const connection = await findConnectionForCalendar(userId, calendarId);
|
||||
const connection = await findConnectionForCalendar(session.user.email, calendarId);
|
||||
|
||||
if (!connection) {
|
||||
return NextResponse.json({ error: 'Calendar connection not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
const dbUser3 = await prisma.user.findUnique({ where: { email: session.user.email }, select: { id: true } });
|
||||
const userId = dbUser3?.id;
|
||||
if (!userId) return NextResponse.json({ error: 'User not found' }, { status: 404 });
|
||||
|
||||
await deleteCalendarEvent(connection, calendarId, eventId, deleteMode);
|
||||
|
||||
// Remove from cache - await to ensure consistency
|
||||
|
||||
@ -38,10 +38,8 @@ export async function GET(request: NextRequest) {
|
||||
// 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 } });
|
||||
// Always look up by email — session ID can be stale after DB restore/migration
|
||||
const user = await prisma.user.findUnique({ where: { email: session.user.email } });
|
||||
|
||||
if (!user) {
|
||||
return NextResponse.redirect(new URL('/auth/login', baseUrl));
|
||||
|
||||
@ -6,18 +6,29 @@ import { notifyUser } from '@/lib/sse';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function resolveUserId(email: string): Promise<string | null> {
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { email },
|
||||
select: { id: true }
|
||||
});
|
||||
return user?.id ?? null;
|
||||
}
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const session = await getServerSession(authOptions);
|
||||
|
||||
if (!session?.user) {
|
||||
if (!session?.user?.email) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Unauthorized' },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
const userId = (session.user as any).id;
|
||||
const userId = await resolveUserId(session.user.email);
|
||||
if (!userId) {
|
||||
return NextResponse.json({ error: 'User not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
const lists = await prisma.somedayList.findMany({
|
||||
where: { userId },
|
||||
@ -44,14 +55,18 @@ export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const session = await getServerSession(authOptions);
|
||||
|
||||
if (!session?.user) {
|
||||
if (!session?.user?.email) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Unauthorized' },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
const userId = (session.user as any).id;
|
||||
const userId = await resolveUserId(session.user.email);
|
||||
if (!userId) {
|
||||
return NextResponse.json({ error: 'User not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
const { title } = await request.json();
|
||||
|
||||
if (!title) {
|
||||
@ -92,13 +107,18 @@ export async function DELETE(request: NextRequest) {
|
||||
try {
|
||||
const session = await getServerSession(authOptions);
|
||||
|
||||
if (!session?.user) {
|
||||
if (!session?.user?.email) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Unauthorized' },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
const userId = await resolveUserId(session.user.email);
|
||||
if (!userId) {
|
||||
return NextResponse.json({ error: 'User not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
const { searchParams } = new URL(request.url);
|
||||
const id = searchParams.get('id');
|
||||
|
||||
@ -114,27 +134,13 @@ export async function DELETE(request: NextRequest) {
|
||||
where: { id }
|
||||
});
|
||||
|
||||
if (!list || list.userId !== (session.user as any).id) {
|
||||
if (!list || list.userId !== userId) {
|
||||
return NextResponse.json(
|
||||
{ error: 'List not found or unauthorized' },
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
// Delete list (tasks cascade delete is not set in schema for tasks->list, check schema)
|
||||
// In schema: tasks defined as `tasks Task[]`.
|
||||
// We updated schema: `user User ... onDelete: Cascade`. `tasks` are separate.
|
||||
// We need to verify if deleting list deletes tasks or unlinks them.
|
||||
// Schema: `somedayList SomedayList? @relation...`
|
||||
// If we want cascade delete tasks in the list, we should check relations.
|
||||
// Prisma default is usually not cascade for optional relations unless specified.
|
||||
// Let's assume we want to keep tasks or delete them? Usually delete list = delete tasks in it.
|
||||
// Let's explicitly delete tasks first or rely on schema if configured.
|
||||
// Schema update I did: `tasks Task[]`. `Task` has `somedayListId`.
|
||||
// I didn't add `onDelete: Cascade` to the `somedayList` relation in `Task`.
|
||||
// So I should clean up tasks manually or update schema.
|
||||
// For now, let's delete tasks in the list.
|
||||
|
||||
// Soft-delete tasks in this list (they can be recovered from trash)
|
||||
await prisma.task.updateMany({
|
||||
where: { somedayListId: id },
|
||||
@ -145,7 +151,7 @@ export async function DELETE(request: NextRequest) {
|
||||
where: { id }
|
||||
});
|
||||
|
||||
notifyUser((session.user as any).id, "list-changed", { action: "deleted" });
|
||||
notifyUser(userId, "list-changed", { action: "deleted" });
|
||||
return NextResponse.json({ success: true });
|
||||
} catch (error) {
|
||||
console.error('Error deleting someday list:', error);
|
||||
@ -160,32 +166,34 @@ export async function PATCH(request: NextRequest) {
|
||||
try {
|
||||
const session = await getServerSession(authOptions);
|
||||
|
||||
if (!session?.user) {
|
||||
if (!session?.user?.email) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Unauthorized' },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
const userId = await resolveUserId(session.user.email);
|
||||
if (!userId) {
|
||||
return NextResponse.json({ error: 'User not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
const body = await request.json();
|
||||
|
||||
// Handle Reordering (Array of { id, order })
|
||||
if (Array.isArray(body)) {
|
||||
const updates = body.map(async (item: { id: string; order: number }) => {
|
||||
// Verify ownership for each or just assume if one matches?
|
||||
// Better to be safe, but for performance in batch, we might trust ID if valid.
|
||||
// Let's verify ownership implicitly by where clause.
|
||||
return prisma.somedayList.updateMany({
|
||||
where: {
|
||||
id: item.id,
|
||||
userId: (session.user as any).id
|
||||
userId
|
||||
},
|
||||
data: { order: item.order }
|
||||
});
|
||||
});
|
||||
|
||||
await Promise.all(updates);
|
||||
notifyUser((session.user as any).id, "list-changed", { action: "reordered" });
|
||||
notifyUser(userId, "list-changed", { action: "reordered" });
|
||||
return NextResponse.json({ success: true });
|
||||
}
|
||||
|
||||
@ -204,7 +212,7 @@ export async function PATCH(request: NextRequest) {
|
||||
where: { id }
|
||||
});
|
||||
|
||||
if (!existingList || existingList.userId !== (session.user as any).id) {
|
||||
if (!existingList || existingList.userId !== userId) {
|
||||
return NextResponse.json(
|
||||
{ error: 'List not found or unauthorized' },
|
||||
{ status: 404 }
|
||||
@ -220,7 +228,7 @@ export async function PATCH(request: NextRequest) {
|
||||
data
|
||||
});
|
||||
|
||||
notifyUser((session.user as any).id, "list-changed", { action: "updated" });
|
||||
notifyUser(userId, "list-changed", { action: "updated" });
|
||||
return NextResponse.json({ list });
|
||||
} catch (error) {
|
||||
console.error('Error updating someday list:', error);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user