Files
encoach_frontend/src/pages/api/assignments/index.ts
2023-12-07 23:07:35 +00:00

145 lines
3.9 KiB
TypeScript

// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type {NextApiRequest, NextApiResponse} from "next";
import {app} from "@/firebase";
import {getFirestore, collection, getDocs, query, where, setDoc, doc} from "firebase/firestore";
import {withIronSessionApiRoute} from "iron-session/next";
import {sessionOptions} from "@/lib/session";
import {uuidv4} from "@firebase/util";
import { Module } from "@/interfaces";
import { getExams } from "@/utils/exams.be";
import { Exam } from "@/interfaces/exam";
import { flatten } from "lodash";
const db = getFirestore(app);
export default withIronSessionApiRoute(handler, sessionOptions);
async function handler(req: NextApiRequest, res: NextApiResponse) {
if (!req.session.user) {
res.status(401).json({ok: false});
return;
}
if (req.method === "GET") return GET(req, res);
if (req.method === "POST") return POST(req, res);
res.status(404).json({ok: false});
}
async function GET(req: NextApiRequest, res: NextApiResponse) {
const q = query(collection(db, "assignments"));
const snapshot = await getDocs(q);
const docs = snapshot.docs.map((doc) => ({
id: doc.id,
...doc.data(),
}));
res.status(200).json(docs);
}
interface ExamWithUser {
module: Module;
id: string;
assignee: string;
}
function getRandomIndex(arr: any[]): number {
const randomIndex = Math.floor(Math.random() * arr.length);
return randomIndex;
}
const generateExams = async (
generateMultiple: Boolean,
selectedModules: Module[],
assignees: string[]
): Promise<ExamWithUser[]> => {
if (generateMultiple) {
// for optimization purposes, it would be better to create a new endpoint that returned the answers for all users at once
const allExams = await assignees.map(async (assignee) => {
const selectedModulePromises = await selectedModules.map(
async (module: Module) => {
try {
const exams: Exam[] = await getExams(db, module, "true", assignee);
const exam = exams[getRandomIndex(exams)];
if (exam) {
return { module: exam.module, id: exam.id, assignee };
}
return null;
} catch (e) {
console.error(e);
return null;
}
},
[]
);
const newModules = await Promise.all(selectedModulePromises);
return newModules;
}, []);
const exams = flatten(await Promise.all(allExams)).filter(
(x) => x !== null
) as ExamWithUser[];
return exams;
}
const selectedModulePromises = await selectedModules.map(
async (module: Module) => {
const exams: Exam[] = await getExams(db, module, "false", undefined);
const exam = exams[getRandomIndex(exams)];
if (exam) {
return { module: exam.module, id: exam.id };
}
return null;
}
);
const exams = await Promise.all(selectedModulePromises);
const examesFiltered = exams.filter((x) => x !== null) as ExamWithUser[];
return flatten(
assignees.map((assignee) =>
examesFiltered.map((exam) => ({ ...exam, assignee }))
)
);
};
async function POST(req: NextApiRequest, res: NextApiResponse) {
const {
selectedModules,
assignees,
// Generarte multiple true would generate an unique exam for eacah user
// false would generate the same exam for all usersa
generateMultiple = false,
...body
} = req.body as {
selectedModules: Module[];
assignees: string[];
generateMultiple: Boolean;
};
const exams: ExamWithUser[] = await generateExams(
generateMultiple,
selectedModules,
assignees
);
if (exams.length === 0) {
res
.status(400)
.json({ ok: false, error: "No exams found for the selected modules" });
return;
}
await setDoc(doc(db, "assignments", uuidv4()), {
assigner: req.session.user?.id,
assignees,
results: [],
exams,
...body,
});
res.status(200).json({ ok: true });
}