-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
perf: Reduced DB calls, improved error checks (#120)
- Loading branch information
1 parent
ddf551c
commit 3397125
Showing
1 changed file
with
126 additions
and
105 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,132 +1,153 @@ | ||
import type { NextApiRequest, NextApiResponse } from "next"; | ||
import type { NextApiRequest, NextApiResponse } from 'next' | ||
|
||
import { Status } from "@prisma/client"; | ||
import { differenceInMinutes, format, parseISO } from "date-fns"; | ||
import { prisma } from "~/server/prisma"; | ||
import { Status } from '@prisma/client' | ||
import { differenceInMinutes, format, parseISO } from 'date-fns' | ||
import { prisma } from '~/server/prisma' | ||
|
||
type RequestBody = { | ||
studentCardId: string; | ||
lectureId: string; | ||
}; | ||
studentCardId: string | ||
lectureId: string | ||
} | ||
|
||
export default async function handler( | ||
req: NextApiRequest, | ||
res: NextApiResponse, | ||
) { | ||
if (req.method === "POST") { | ||
//1 - Receive studentCardId and lectureId from request body | ||
const { lectureId, studentCardId } = req.body as RequestBody; | ||
if (req.method === 'POST') { | ||
// Receive studentCardId and lectureId from request body | ||
const { lectureId, studentCardId } = req.body as RequestBody | ||
|
||
if (req.query !== undefined) { | ||
res.status(400).send({ | ||
error: | ||
'Query parameters are invalid, please pass values in request body', | ||
}) | ||
return | ||
} | ||
|
||
if (req.body === undefined) { | ||
res.status(400).send({ error: 'Missing request body' }) | ||
return | ||
} | ||
|
||
// If request body is missing parameters, throw errorq | ||
if (!lectureId || !studentCardId) { | ||
res.status(400).send({ error: "Missing parameters in request body" }); | ||
return; | ||
res.status(400).send({ error: 'Missing parameters in request body' }) | ||
return | ||
} | ||
|
||
//2 - Check if studentCardId is valid and get its studentId | ||
try { | ||
const returnedData1 = await prisma.student | ||
.findUniqueOrThrow({ | ||
where: { | ||
// Check if student is enrolled in module, if not, throw error | ||
const result = await prisma.enrollment.findFirst({ | ||
where: { | ||
AND: { | ||
Module: { | ||
is: { | ||
Lectures: { | ||
some: { | ||
lectureId: lectureId, | ||
}, | ||
}, | ||
}, | ||
}, | ||
|
||
Student: { | ||
studentCardId: studentCardId, | ||
}, | ||
}, | ||
}, | ||
select: { | ||
Student: { | ||
select: { | ||
studentId: true, | ||
}, | ||
}) | ||
.catch((error) => { | ||
console.log("❌ Error", error); | ||
res.status(404).send({ error: "Student card ID not valid" }); | ||
return; | ||
}); | ||
|
||
// 3 - Check if lectureId is valid and get its moduleId | ||
const returnedData2 = await prisma.lecture | ||
.findUniqueOrThrow({ | ||
where: { | ||
lectureId: lectureId, | ||
}, | ||
}, | ||
Module: { | ||
select: { | ||
startTime: true, | ||
Module: { | ||
Lectures: { | ||
select: { | ||
moduleId: true, | ||
lectureId: true, | ||
startTime: true, | ||
}, | ||
|
||
where: { | ||
lectureId: lectureId, | ||
}, | ||
take: 1, | ||
}, | ||
}, | ||
}) | ||
.catch((error) => { | ||
console.log("❌ Error", error); | ||
res.status(404).send({ | ||
error: "Lecture ID not valid", | ||
}); | ||
return; | ||
}); | ||
|
||
// 4 - Check if student is enrolled in module, if not, throw error | ||
const returnedData3 = await prisma.enrollment | ||
.findFirstOrThrow({ | ||
where: { | ||
moduleId: returnedData2?.Module.moduleId, | ||
studentId: returnedData1?.studentId, | ||
}, | ||
select: { | ||
enrollmentId: true, | ||
}, | ||
}) | ||
.catch((error) => { | ||
console.log("❌ Error", error); | ||
res.status(404).send({ error: "Student not enrolled" }); | ||
return; | ||
}); | ||
|
||
//5 - Calculate the status of the attendance record based on the time | ||
const lectureStartTime = returnedData2?.startTime; | ||
const formattedDate = format(new Date(), "yyyy-MM-dd'T'HH:mm:ss.SSSX"); | ||
const currentTime = parseISO(formattedDate); | ||
|
||
if (!lectureStartTime) { | ||
res.status(404).send({ error: "Lecture start time not found" }); | ||
return; | ||
} | ||
const timeDiff = differenceInMinutes(currentTime, lectureStartTime); | ||
|
||
let calculatedStatus: Status = Status.PRESENT; | ||
|
||
if (-15 < timeDiff && timeDiff < 15) { | ||
// timediff = 5 | ||
calculatedStatus = Status.PRESENT; | ||
} else if (timeDiff > 15) { | ||
// timediff = 20 | ||
calculatedStatus = Status.LATE; | ||
} else if (timeDiff < -15) { | ||
// timediff -500 | ||
res | ||
.status(404) | ||
.send({ message: "Please retry closer to lecture start time" }); | ||
} | ||
|
||
//6 - Creating the attendance record in the database | ||
if (!returnedData1?.studentId) { | ||
res.status(404).send({ error: "Student not found" }); | ||
return; | ||
} | ||
const newAttendanceRecord = await prisma.attendanceRecord.create({ | ||
data: { | ||
studentId: returnedData1?.studentId, | ||
lectureId: lectureId, | ||
status: calculatedStatus, | ||
}, | ||
}); | ||
|
||
res.status(200).send({ | ||
message: "Attendance record created", | ||
status: newAttendanceRecord.status, | ||
}); | ||
} catch (error) { | ||
console.error("Error processing request:", error); | ||
res.status(500).send({ error: "Internal Server Error", details: error }); | ||
}, | ||
}) | ||
|
||
// Error handling | ||
if (!result) { | ||
res.status(404).send({ error: 'Enrollment not found' }) | ||
return | ||
} | ||
|
||
if (!result?.Module) { | ||
res.status(404).send({ error: 'Module not found' }) | ||
return | ||
} | ||
|
||
if (!result?.Module.Lectures[0]?.startTime) { | ||
res.status(404).send({ error: 'Lecture start time not found' }) | ||
return | ||
} | ||
|
||
if (!result?.Module.Lectures[0]?.lectureId) { | ||
res.status(404).send({ error: 'Lecture not found' }) | ||
return | ||
} | ||
|
||
if (!result?.Student) { | ||
res.status(404).send({ error: 'Student not found' }) | ||
return | ||
} | ||
|
||
if (!result?.Student.studentId) { | ||
res.status(404).send({ error: 'Student not found' }) | ||
return | ||
} | ||
|
||
// Calculate the status of the attendance record based on the time | ||
const lectureStartTime = result.Module.Lectures[0].startTime | ||
const formattedDate: string = format( | ||
new Date(), | ||
"yyyy-MM-dd'T'HH:mm:ss.SSSX", | ||
) | ||
const currentTime = parseISO(formattedDate) | ||
|
||
const timeDiff = differenceInMinutes(currentTime, lectureStartTime) | ||
|
||
let calculatedStatus: Status = Status.PRESENT | ||
|
||
if (-15 < timeDiff && timeDiff < 15) { | ||
calculatedStatus = Status.PRESENT | ||
} else if (timeDiff > 15) { | ||
calculatedStatus = Status.LATE | ||
} else if (timeDiff < -15) { | ||
res.status(404).send({ | ||
message: 'Too early! Please retry closer to lecture start time.', | ||
}) | ||
} | ||
|
||
// Creating the attendance record in the database with the calculated status | ||
const newAttendanceRecord = await prisma.attendanceRecord.create({ | ||
data: { | ||
studentId: result.Student.studentId, | ||
lectureId: result.Module.Lectures[0].lectureId, | ||
status: calculatedStatus, | ||
}, | ||
}) | ||
|
||
res.status(200).send({ | ||
message: 'Attendance record created', | ||
status: newAttendanceRecord.status, | ||
}) | ||
} else { | ||
res.status(405).json({ error: "Method Not Allowell" }); | ||
res.status(405).json({ | ||
error: 'Method not allowed, this endpoint only allows POST requests', | ||
}) | ||
} | ||
} |