feat: implement message CRUD and dark mode

- Add Message, Recipient models and migration
- Create message API routes (GET, POST, PATCH, DELETE)
- Fix IDOR vulnerability in PATCH (verify ownership before delete)
- Add dashboard and message pages (list, new, detail)
- Add UI components (card, input, label, textarea)
- Enable dark mode in layout
- Add session user id typing to NextAuth
- Add AGENTS.md memory bank documentation
This commit is contained in:
Yusuf İpek
2025-12-24 15:07:20 +03:00
parent c2da0437d0
commit 1626106a8b
17 changed files with 851 additions and 3 deletions
+80
View File
@@ -0,0 +1,80 @@
import { NextResponse } from "next/server";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth/options";
import { prisma } from "@/lib/prisma";
export async function PATCH(
req: Request,
{ params }: { params: Promise<{ messageId: string }> }
) {
const { messageId } = await params;
const session = await getServerSession(authOptions);
if (!session?.user?.id) {
return new NextResponse("Unauthorized", { status: 401 });
}
try {
const body = await req.json();
const { title, content, recipients, checkInterval } = body;
const existingMessage = await prisma.message.findUnique({
where: { id: messageId, userId: session.user.id },
});
if (!existingMessage) {
return new NextResponse("Unauthorized", { status: 401 });
}
// Delete existing recipients and recreate them for simplicity in update
await prisma.recipient.deleteMany({
where: { messageId: messageId },
});
const message = await prisma.message.update({
where: {
id: messageId,
userId: session.user.id,
},
data: {
title,
content,
checkInterval,
recipients: {
create: recipients.map((email: string) => ({ email })),
},
},
});
return NextResponse.json(message);
} catch (error) {
console.error("MESSAGE_PATCH_ERROR", error);
return new NextResponse("Internal Server Error", { status: 500 });
}
}
export async function DELETE(
req: Request,
{ params }: { params: Promise<{ messageId: string }> }
) {
const { messageId } = await params;
const session = await getServerSession(authOptions);
if (!session?.user?.id) {
return new NextResponse("Unauthorized", { status: 401 });
}
try {
const message = await prisma.message.delete({
where: {
id: messageId,
userId: session.user.id,
},
});
return NextResponse.json(message);
} catch (error) {
console.error("MESSAGE_DELETE_ERROR", error);
return new NextResponse("Internal Server Error", { status: 500 });
}
}