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(), }) diff --git a/app/api/grades/[id]/route.ts b/app/api/grades/[id]/route.ts index 0141f63..ebc1a24 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 } ) @@ -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) { diff --git a/app/api/grades/route.ts b/app/api/grades/route.ts index b9da63d..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,22 +63,22 @@ 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 = 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/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: [], 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) { 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) { 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 }, }, 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" &&