From 098f99043d3905660d7a6529b23d17e2914702dd Mon Sep 17 00:00:00 2001 From: Bhathiya Vicum Date: Mon, 20 Apr 2026 22:21:15 +0530 Subject: [PATCH 01/10] fix(profile): prevent empty name causing Teacher validation error --- app/api/profile/route.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/api/profile/route.ts b/app/api/profile/route.ts index a3d98bf..89fc2e3 100644 --- a/app/api/profile/route.ts +++ b/app/api/profile/route.ts @@ -22,7 +22,7 @@ export async function GET(req: NextRequest) { const clerkUser = await currentUser() const created = await Teacher.create({ clerkId: userId, - name: clerkUser?.fullName ?? '', + name: clerkUser?.fullName?.trim() || clerkUser?.firstName?.trim() || "Unknown User", email: clerkUser?.emailAddresses[0]?.emailAddress ?? '', department: '', subjects: [], From b5f7a1e744deeba3b805a46cee2217b96381f24c Mon Sep 17 00:00:00 2001 From: Bhathiya Vicum Date: Mon, 20 Apr 2026 22:44:26 +0530 Subject: [PATCH 02/10] fix(grades): resolve circular JSON error in grades POST --- app/api/grades/route.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/api/grades/route.ts b/app/api/grades/route.ts index b9da63d..d37502d 100644 --- a/app/api/grades/route.ts +++ b/app/api/grades/route.ts @@ -73,7 +73,7 @@ export async function POST(req: NextRequest) { const max = data.maxMarks! const term = data.term ?? 'Term 1' - const grade = Grade.findOneAndUpdate( + const grade = await Grade.findOneAndUpdate( { teacherId: userId, studentId: data.studentId, subject: data.subject, term }, { $set: { ...data, term, teacherId: userId, grade: calcGrade(data.marks, max) } }, { upsert: true, new: true } From a3d811fe1e8fbdec1c2af5b00ee16a00437196c1 Mon Sep 17 00:00:00 2001 From: Bhathiya Vicum Date: Mon, 20 Apr 2026 22:44:26 +0530 Subject: [PATCH 03/10] fix(students): add missing validation check for request body --- app/api/grades/route.ts | 2 +- app/api/students/route.ts | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/app/api/grades/route.ts b/app/api/grades/route.ts index b9da63d..d37502d 100644 --- a/app/api/grades/route.ts +++ b/app/api/grades/route.ts @@ -73,7 +73,7 @@ export async function POST(req: NextRequest) { const max = data.maxMarks! const term = data.term ?? 'Term 1' - const grade = Grade.findOneAndUpdate( + const grade = await Grade.findOneAndUpdate( { teacherId: userId, studentId: data.studentId, subject: data.subject, term }, { $set: { ...data, term, teacherId: userId, grade: calcGrade(data.marks, max) } }, { upsert: true, new: true } diff --git a/app/api/students/route.ts b/app/api/students/route.ts index 8f3dcc2..e756d5c 100644 --- a/app/api/students/route.ts +++ b/app/api/students/route.ts @@ -84,17 +84,28 @@ export async function POST(req: NextRequest) { try { await connectDB() - + let body try { body = await req.json() } catch { return NextResponse.json({ error: 'Malformed JSON' }, { status: 400 }) } - - StudentSchema.safeParse(body) - const student = await Student.create({ ...(body as Record), teacherId: userId }) + const parsed = StudentSchema.safeParse(body) + + if (!parsed.success) { + return NextResponse.json( + { error: parsed.error.flatten() }, + { status: 400 } + ) + } + + const student = await Student.create({ + ...parsed.data, + teacherId: userId + }) + return NextResponse.json(student, { status: 201 }) } catch (error) { if (error instanceof Error) { From dc2a08a5db29564115076e4178a5b5b403e2c489 Mon Sep 17 00:00:00 2001 From: Bhathiya Vicum Date: Tue, 21 Apr 2026 00:11:35 +0530 Subject: [PATCH 04/10] fix(announcements): add default audience field --- app/api/announcements/route.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/api/announcements/route.ts b/app/api/announcements/route.ts index c922561..7c7f7c7 100644 --- a/app/api/announcements/route.ts +++ b/app/api/announcements/route.ts @@ -7,7 +7,7 @@ import { z } from 'zod' const AnnouncementSchema = z.object({ title: z.string().min(1), content: z.string().min(1), - audience: z.string().optional(), + audience: z.string().optional().default('all'), category: z.enum(['academic', 'events', 'admin', 'general']).optional(), pinned: z.boolean().optional(), }) From e1ddfe214d9b2dbc3aa3cdc76eec2d68437d6a71 Mon Sep 17 00:00:00 2001 From: Bhathiya Vicum Date: Tue, 21 Apr 2026 00:16:34 +0530 Subject: [PATCH 05/10] fix(grades): restrict grade updates to owner only --- app/api/grades/[id]/route.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/api/grades/[id]/route.ts b/app/api/grades/[id]/route.ts index 0141f63..80a48c5 100644 --- a/app/api/grades/[id]/route.ts +++ b/app/api/grades/[id]/route.ts @@ -35,7 +35,7 @@ export async function PUT(req: NextRequest, ctx: { params: Promise<{ id: string await connectDB() const grade = await Grade.findOneAndUpdate( - { _id: id }, + { _id: id, teacherId: userId }, sanitizedBody, { new: true } ) From 1b2e0bee410e60145ae77812dd4e61197d2e109e Mon Sep 17 00:00:00 2001 From: Bhathiya Vicum Date: Tue, 21 Apr 2026 00:21:24 +0530 Subject: [PATCH 06/10] fix(grades): restrict grade deletion to owner only --- app/api/grades/[id]/route.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/api/grades/[id]/route.ts b/app/api/grades/[id]/route.ts index 80a48c5..ebc1a24 100644 --- a/app/api/grades/[id]/route.ts +++ b/app/api/grades/[id]/route.ts @@ -56,12 +56,15 @@ export async function DELETE(_req: NextRequest, ctx: { params: Promise<{ id: str try { const { id } = await ctx.params await connectDB() - const deleted = await Grade.findOneAndDelete({ _id: id }) - + const deleted = await Grade.findOneAndDelete({ + _id: id, + teacherId: userId + }) + if (!deleted) { return NextResponse.json({ error: 'Grade not found' }, { status: 404 }) } - + return NextResponse.json({ success: true }) } catch (error) { if (error instanceof Error) { From 4fe3ca5b8a514d178b05f793d32bbc30f74c83b7 Mon Sep 17 00:00:00 2001 From: Bhathiya Vicum Date: Tue, 21 Apr 2026 00:40:57 +0530 Subject: [PATCH 07/10] fix(students): improve authorization and input validation in update/delete routes --- app/api/students/[id]/route.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/app/api/students/[id]/route.ts b/app/api/students/[id]/route.ts index 2eaaf93..aaf01b4 100644 --- a/app/api/students/[id]/route.ts +++ b/app/api/students/[id]/route.ts @@ -35,7 +35,7 @@ export async function PUT(req: NextRequest, ctx: { params: Promise<{ id: string await connectDB() const student = await Student.findOneAndUpdate( - { _id: id }, + { _id: id, teacherId: userId }, sanitizedBody, { new: true } ) @@ -65,12 +65,15 @@ export async function DELETE(_req: NextRequest, ctx: { params: Promise<{ id: str } await connectDB() - const deleted = await Student.findOneAndDelete({ _id: id }) - + const deleted = await Student.findOneAndDelete({ + _id: id, + teacherId: userId + }) + if (!deleted) { return NextResponse.json({ error: 'Student not found' }, { status: 404 }) } - + return NextResponse.json({ success: true }) } catch (error) { if (error instanceof Error) { From 4034a328703425af2b4bca3e780299583957014c Mon Sep 17 00:00:00 2001 From: Bhathiya Vicum Date: Tue, 21 Apr 2026 00:59:57 +0530 Subject: [PATCH 08/10] fix(grades): ensure studentId is cast to ObjectId in GET query --- app/api/grades/route.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/app/api/grades/route.ts b/app/api/grades/route.ts index d37502d..643d668 100644 --- a/app/api/grades/route.ts +++ b/app/api/grades/route.ts @@ -3,6 +3,7 @@ import { NextRequest, NextResponse } from 'next/server' import { connectDB } from '@/lib/mongodb' import { Grade } from '@/models/Grade' import { z } from 'zod' +import mongoose from 'mongoose' const GradeSchema = z.object({ studentId: z.string().min(1), @@ -41,7 +42,11 @@ export async function GET(req: NextRequest) { const subject = searchParams.get('subject') const query: Record = { teacherId: userId } - if (studentId) query.studentId = studentId + + if (studentId && mongoose.Types.ObjectId.isValid(studentId)) { + query.studentId = new mongoose.Types.ObjectId(studentId) + } + if (subject) query.subject = subject const grades = await Grade.find(query).sort({ createdAt: -1 }).lean() @@ -58,21 +63,21 @@ export async function POST(req: NextRequest) { try { await connectDB() - + let body try { body = await req.json() } catch { return NextResponse.json({ error: 'Invalid JSON in request body' }, { status: 400 }) } - + const parsed = GradeSchema.safeParse(body) if (!parsed.success) return NextResponse.json({ error: parsed.error.flatten() }, { status: 400 }) const data = parsed.data const max = data.maxMarks! const term = data.term ?? 'Term 1' - + const grade = await Grade.findOneAndUpdate( { teacherId: userId, studentId: data.studentId, subject: data.subject, term }, { $set: { ...data, term, teacherId: userId, grade: calcGrade(data.marks, max) } }, From 6909cbb4584c95eed8bef65110cb388c41929bf6 Mon Sep 17 00:00:00 2001 From: Bhathiya Vicum Date: Tue, 21 Apr 2026 01:06:19 +0530 Subject: [PATCH 09/10] fix(attendance): validate class field to prevent empty values --- models/Attendance.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/models/Attendance.ts b/models/Attendance.ts index 3f05fb1..1ead556 100644 --- a/models/Attendance.ts +++ b/models/Attendance.ts @@ -17,7 +17,15 @@ const AttendanceSchema = new Schema( teacherId: { type: String, required: true, index: true }, studentId: { type: Schema.Types.ObjectId, ref: 'Student', required: true }, studentName: { type: String, required: true }, - class: { type: String, required: true }, + class: { + type: String, + required: true, + trim: true, + validate: { + validator: (v: string) => v.trim().length > 0, + message: 'Class cannot be empty', + }, + }, date: { type: String, required: true }, status: { type: String, enum: ['present', 'absent', 'late'], required: true }, }, From 563beff18c7b77967775e0ada4bbd413a33094b3 Mon Sep 17 00:00:00 2001 From: Bhathiya Vicum Date: Tue, 21 Apr 2026 01:13:16 +0530 Subject: [PATCH 10/10] fix(grade): prevent invalid marks in findOneAndUpdate --- models/Grade.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/models/Grade.ts b/models/Grade.ts index 311b757..e64290e 100644 --- a/models/Grade.ts +++ b/models/Grade.ts @@ -39,10 +39,10 @@ GradeSchema.pre("save", function () { }); GradeSchema.pre("findOneAndUpdate", function () { - const update = this.getUpdate() as Record; + const update = this.getUpdate() as any; if (update && typeof update === "object") { - const marks = update.marks; - const maxMarks = update.maxMarks; + const marks = update?.$set?.marks ?? update?.marks; + const maxMarks = update?.$set?.maxMarks ?? update?.maxMarks; if ( marks !== undefined && typeof marks === "number" && maxMarks !== undefined && typeof maxMarks === "number" &&