Skip to content

Commit

Permalink
fix error with attendance
Browse files Browse the repository at this point in the history
  • Loading branch information
adhi0331 committed Dec 19, 2024
2 parents 64411cc + e59620c commit e5ebafd
Show file tree
Hide file tree
Showing 80 changed files with 3,406 additions and 912 deletions.
74 changes: 74 additions & 0 deletions backend/src/controllers/image.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* Functions that process image route requests.
*/

import { NextFunction, Request, Response } from "express";
import mongoose from "mongoose";

import { InternalError } from "../errors";
import { ServiceError } from "../errors/service";
import { ValidationError } from "../errors/validation";
import { Image } from "../models/image";
import StudentModel from "../models/student";
import UserModel from "../models/user";
import { handleImageParsing } from "../util/image";

import { OwnerRequestBody } from "./types/types";
import { EditPhotoRequestBody } from "./types/userTypes";

export const editPhoto = (req: EditPhotoRequestBody, res: Response, nxt: NextFunction) => {
try {
//Validation logic inside handleImageParsing
handleImageParsing(req, res, nxt);
} catch (e) {
console.log(e);
nxt(e);
}
};

export const getPhoto = async (
req: Request<Record<string, never>, Record<string, never>, OwnerRequestBody>,
res: Response,
nxt: NextFunction,
) => {
try {
const { ownerId, ownerType, imageId } = req.body;

if (!mongoose.Types.ObjectId.isValid(imageId)) {
return res
.status(ValidationError.INVALID_MONGO_ID.status)
.send({ error: ValidationError.INVALID_MONGO_ID.message });
}

let owner = null;

if (ownerType === "user") {
owner = await UserModel.findById(ownerId);
} else if (ownerType === "student") {
owner = await StudentModel.findById(ownerId);
}

if (!owner) {
throw ValidationError.USER_NOT_FOUND;
}

const image = await Image.findById(imageId);
if (!image) {
throw ValidationError.IMAGE_NOT_FOUND;
}

if (image.ownerId !== ownerId) {
throw ValidationError.IMAGE_USER_MISMATCH;
}

return res.status(200).set("Content-type", image.mimetype).send(image.buffer);
} catch (e) {
console.log(e);
if (e instanceof ServiceError) {
nxt(e);
}
return res
.status(InternalError.ERROR_GETTING_IMAGE.status)
.send(InternalError.ERROR_GETTING_IMAGE.displayMessage(true));
}
};
144 changes: 114 additions & 30 deletions backend/src/controllers/student.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@

import { RequestHandler } from "express";
import { validationResult } from "express-validator";
import createHttpError from "http-errors";
import mongoose, { HydratedDocument } from "mongoose";

import EnrollmentModel from "../models/enrollment";
import { Image } from "../models/image";
import ProgramModel from "../models/program";
import ProgressNoteModel from "../models/progressNote";
import StudentModel from "../models/student";
import { Enrollment } from "../types/enrollment";
import { createEnrollment, editEnrollment } from "../util/enrollment";
Expand All @@ -23,16 +25,25 @@ export const createStudent: RequestHandler = async (req, res, next) => {

validationErrorParser(errors);

const newStudentId = new mongoose.Types.ObjectId();

const { enrollments, ...studentData } = req.body as StudentRequest;
const newStudent = await StudentModel.create(studentData);

// create enrollments for the student
await Promise.all(
const createdEnrollments = await Promise.all(
enrollments.map(async (program: Enrollment) => {
await createEnrollment({ ...program, studentId: newStudent._id });
return await EnrollmentModel.create({ ...program, studentId: newStudentId });
}),
);

res.status(201).json(newStudent);
const newStudent = await StudentModel.create({
...studentData,
enrollments: createdEnrollments.map((enrollment) => enrollment._id),
});

const populatedStudent = await StudentModel.findById(newStudent._id).populate("enrollments");

res.status(201).json(populatedStudent);
} catch (error) {
next(error);
}
Expand All @@ -50,58 +61,131 @@ export const editStudent: RequestHandler = async (req, res, next) => {
if (studentId !== studentData._id.toString()) {
return res.status(400).json({ message: "Invalid student ID" });
}
const updatedStudent = await StudentModel.findByIdAndUpdate(studentId, studentData, {
new: true,
});
if (!updatedStudent) {
return res.status(404).json({ message: "Student not found" });

if (!enrollments) {
const updatedStudent = await StudentModel.findByIdAndUpdate(
studentId,
{ ...studentData },
{
new: true,
},
);
if (!updatedStudent) {
return res.status(404).json({ message: "Student not found" });
}

return res.status(200).json(updatedStudent);
}

// update enrollments for the student
await Promise.all(
const updatedEnrollments = await Promise.all(
enrollments.map(async (enrollment: Enrollment) => {
const enrollmentExists = await EnrollmentModel.findById(enrollment._id);
const enrollmentBody = { ...enrollment, studentId: new mongoose.Types.ObjectId(studentId) };
if (!enrollmentExists) await createEnrollment(enrollmentBody);
else await editEnrollment(enrollmentBody);
const program = await ProgramModel.findById({ _id: enrollment.programId });
if (program?.type === "regular") {
enrollmentBody.schedule = program.daysOfWeek;
}
if (!enrollmentExists) {
return await createEnrollment(enrollmentBody);
} else {
return await editEnrollment(enrollmentBody);
}
}),
);

res.status(200).json({ ...updatedStudent, enrollments });
const updatedStudent = await StudentModel.findByIdAndUpdate(
studentId,
{ ...studentData, enrollments: updatedEnrollments.map((enrollment) => enrollment?._id) },
{
new: true,
},
);
if (!updatedStudent) {
return res.status(404).json({ message: "Student not found" });
}

const populatedStudent = await StudentModel.findById(updatedStudent._id).populate(
"enrollments",
);

console.log({ populatedStudent });

res.status(200).json(populatedStudent);
} catch (error) {
next(error);
}
};

export const getAllStudents: RequestHandler = async (_, res, next) => {
export const getAllStudents: RequestHandler = async (req, res, next) => {
try {
const students = await StudentModel.find();

// gather all enrollments for each student and put them in student.programs
const hydratedStudents = await Promise.all(
students.map(async (student) => {
const enrollments = await EnrollmentModel.find({ studentId: student._id });
return { ...student.toObject(), programs: enrollments };
}),
);
const students = await StudentModel.find().populate("enrollments");

// Even though this is a get request, we have verifyAuthToken middleware that sets the accountType in the request body
const { accountType } = req.body;

Check warning on line 125 in backend/src/controllers/student.ts

View workflow job for this annotation

GitHub Actions / Backend lint and style check

Unsafe assignment of an `any` value

// Ensure that documents that are marked admin are not returned to non-admin users
if (accountType !== "admin") {
students.forEach((student) => {
student.documents = student.documents.filter(
(doc) => !doc.markedAdmin,
) as typeof student.documents;
});
}

res.status(200).json(hydratedStudents);
res.status(200).json(students);
} catch (error) {
next(error);
}
};

export const getStudent: RequestHandler = async (req, res, next) => {
try {
const id = req.params.id;
const errors = validationResult(req);

const student = await StudentModel.findById(id);
const { accountType } = req.body;

Check warning on line 146 in backend/src/controllers/student.ts

View workflow job for this annotation

GitHub Actions / Backend lint and style check

Unsafe assignment of an `any` value

if (student === null) {
throw createHttpError(404, "Student not found");
validationErrorParser(errors);

const studentId = req.params.id;
const studentData = await StudentModel.findById(req.params.id);

if (!studentData) {
return res.status(404).json({ message: "Student not found" });
}

// Ensure that documents that are marked admin are not returned to non-admin users
if (accountType !== "admin") {
studentData.documents = studentData.documents.filter(
(doc) => !doc.markedAdmin,
) as typeof studentData.documents;
}

const enrollments = await EnrollmentModel.find({ studentId });

res.status(200).json({ ...studentData.toObject(), enrollments });
} catch (error) {
next(error);
}
};

export const deleteStudent: RequestHandler = async (req, res, next) => {
try {
const errors = validationResult(req);
validationErrorParser(errors);

const studentId = req.params.id;
const deletedStudent = await StudentModel.findById(studentId);
if (!deletedStudent) {
return res.status(404).json({ message: "Student not found" });
}

res.status(200).json(student);
await EnrollmentModel.deleteMany({ studentId });
await ProgressNoteModel.deleteMany({ studentId });
await Image.deleteMany({ userId: studentId });
await StudentModel.deleteOne({ _id: studentId });

res.status(200).json(deletedStudent);
} catch (error) {
next(error);
}
Expand Down
18 changes: 18 additions & 0 deletions backend/src/controllers/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,21 @@ export type UserId = {
};

export type UserIdRequestBody = Request & UserId;

// Add type so that if uploadType is "create", new field imgeId is required
type NewUploadType = {
uploadType: "new";
imageId: string;
};

type EditUploadType = {
uploadType: "edit";
imageId: never;
};

export type OwnerInfo = {
ownerId: string;
ownerType: string;
} & (NewUploadType | EditUploadType);

export type OwnerRequestBody = Request & OwnerInfo;
13 changes: 10 additions & 3 deletions backend/src/controllers/types/userTypes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Request } from "express";

import { UserId } from "./types";
import { OwnerInfo, UserId } from "./types";

export type CreateUserRequestBody = {
name: string;
Expand Down Expand Up @@ -32,7 +32,10 @@ export type UpdateAccountTypeRequestBody = UserId & {
export type SaveImageRequest = {
body: {
previousImageId: string;
userId: string;
ownerId: string;
ownerType: string;
uploadType: string;
imageId: string;
};
file: {
buffer: Buffer;
Expand All @@ -42,6 +45,10 @@ export type SaveImageRequest = {
};
};

export type EditPhotoRequestBody = Request<Record<string, never>, Record<string, never>, UserId> & {
export type EditPhotoRequestBody = Request<
Record<string, never>,
Record<string, never>,
OwnerInfo
> & {
rawBody?: Buffer;
};
Loading

0 comments on commit e5ebafd

Please sign in to comment.