Exam generation rework, batch user tables, fastapi endpoint switch
This commit is contained in:
@@ -51,7 +51,7 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
|
||||
return currentUser;
|
||||
}));
|
||||
|
||||
const backendRequest = await axios.post(`${process.env.BACKEND_URL}/batch_users`, { makerID: maker.id, users: usersWithPasswordHashes }, {
|
||||
const backendRequest = await axios.post(`${process.env.BACKEND_URL}/user/import`, { makerID: maker.id, users: usersWithPasswordHashes }, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${process.env.BACKEND_JWT}`,
|
||||
},
|
||||
|
||||
@@ -84,7 +84,7 @@ async function getCorrespondingStat(id: string, index: number): Promise<Stat> {
|
||||
}
|
||||
|
||||
async function evaluate(body: {answers: object[]}, variant?: "initial" | "final"): Promise<AxiosResponse> {
|
||||
const backendRequest = await axios.post(`${process.env.BACKEND_URL}/speaking_task_${variant === "initial" ? "1" : "3"}`, body, {
|
||||
const backendRequest = await axios.post(`${process.env.BACKEND_URL}/grade/speaking/${variant === "initial" ? "1" : "3"}`, body, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${process.env.BACKEND_JWT}`,
|
||||
},
|
||||
|
||||
@@ -79,7 +79,7 @@ async function getCorrespondingStat(id: string, index: number): Promise<Stat> {
|
||||
}
|
||||
|
||||
async function evaluate(body: {answer: string; question: string}, task: number): Promise<AxiosResponse> {
|
||||
const backendRequest = await axios.post(`${process.env.BACKEND_URL}/speaking_task_2`, body, {
|
||||
const backendRequest = await axios.post(`${process.env.BACKEND_URL}/grade/speaking/2`, body, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${process.env.BACKEND_JWT}`,
|
||||
},
|
||||
|
||||
@@ -69,7 +69,7 @@ async function getCorrespondingStat(id: string, index: number): Promise<Stat> {
|
||||
async function evaluate(body: Body): Promise<AxiosResponse> {
|
||||
const taskNumber = body.task.toString() !== "1" && body.task.toString() !== "2" ? "1" : body.task.toString();
|
||||
|
||||
const backendRequest = await axios.post(`${process.env.BACKEND_URL}/writing_task${taskNumber}`, body as Body, {
|
||||
const backendRequest = await axios.post(`${process.env.BACKEND_URL}/grade/writing/${taskNumber}`, body as Body, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${process.env.BACKEND_JWT}`,
|
||||
},
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type {NextApiRequest, NextApiResponse} from "next";
|
||||
import {withIronSessionApiRoute} from "iron-session/next";
|
||||
import {sessionOptions} from "@/lib/session";
|
||||
import {Difficulty, Exam} from "@/interfaces/exam";
|
||||
import {Module} from "@/interfaces";
|
||||
import axios from "axios";
|
||||
|
||||
export default withIronSessionApiRoute(handler, sessionOptions);
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (req.method === "GET") return get(req, res);
|
||||
if (req.method === "POST") return post(req, res);
|
||||
|
||||
return res.status(404).json({ok: false});
|
||||
}
|
||||
|
||||
async function get(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (!req.session.user) return res.status(401).json({ok: false});
|
||||
|
||||
const {endpoint, topic, exercises, difficulty} = req.query as {
|
||||
module: Module;
|
||||
endpoint: string;
|
||||
topic?: string;
|
||||
exercises?: string[] | string;
|
||||
difficulty?: Difficulty;
|
||||
};
|
||||
const url = `${process.env.BACKEND_URL}/${endpoint}`;
|
||||
|
||||
const params = new URLSearchParams();
|
||||
if (topic) params.append("topic", topic);
|
||||
if (exercises) (typeof exercises === "string" ? [exercises] : exercises).forEach((exercise) => params.append("exercises", exercise));
|
||||
if (difficulty) params.append("difficulty", difficulty);
|
||||
|
||||
const result = await axios.get(`${url}${params.toString().length > 0 ? `?${params.toString()}` : ""}`, {
|
||||
headers: {Authorization: `Bearer ${process.env.BACKEND_JWT}`},
|
||||
});
|
||||
|
||||
res.status(200).json(result.data);
|
||||
}
|
||||
|
||||
async function post(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (!req.session.user) return res.status(401).json({ok: false});
|
||||
|
||||
const {endpoint, topic, exercises} = req.query as {module: Module; endpoint: string[]; topic?: string; exercises?: string[]};
|
||||
const url = `${process.env.BACKEND_URL}/${endpoint.join("/")}`;
|
||||
|
||||
const result = await axios.post(
|
||||
`${url}${topic && exercises ? `?topic=${topic.toLowerCase()}&exercises=${exercises.join("&exercises=")}` : ""}`,
|
||||
req.body,
|
||||
{
|
||||
headers: {Authorization: `Bearer ${process.env.BACKEND_JWT}`},
|
||||
},
|
||||
);
|
||||
|
||||
res.status(200).json(result.data);
|
||||
}
|
||||
79
src/pages/api/exam/[module]/import.ts
Normal file
79
src/pages/api/exam/[module]/import.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: false
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { withIronSessionApiRoute } from "iron-session/next";
|
||||
import { sessionOptions } from "@/lib/session";
|
||||
import axios from "axios";
|
||||
import formidable from 'formidable';
|
||||
import FormData from 'form-data';
|
||||
import { readFileSync } from 'fs';
|
||||
|
||||
export default withIronSessionApiRoute(handler, sessionOptions);
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (req.method === "POST") return post(req, res);
|
||||
|
||||
return res.status(404).json({ ok: false });
|
||||
}
|
||||
|
||||
|
||||
async function post(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (!req.session.user) return res.status(401).json({ ok: false });
|
||||
|
||||
try {
|
||||
const form = formidable({
|
||||
multiples: true,
|
||||
});
|
||||
|
||||
const [_, files] = await form.parse(req);
|
||||
const formData = new FormData();
|
||||
|
||||
if (files.exercises?.[0]) {
|
||||
const file = files.exercises[0];
|
||||
const buffer = readFileSync(file.filepath);
|
||||
|
||||
formData.append('exercises', buffer, {
|
||||
filename: file.originalFilename!,
|
||||
contentType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
knownLength: buffer.length
|
||||
});
|
||||
}
|
||||
|
||||
if (files.solutions?.[0]) {
|
||||
const file = files.solutions[0];
|
||||
const buffer = readFileSync(file.filepath);
|
||||
|
||||
formData.append('solutions', buffer, {
|
||||
filename: file.originalFilename!,
|
||||
contentType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
knownLength: buffer.length
|
||||
});
|
||||
}
|
||||
|
||||
const result = await axios.post(
|
||||
`${process.env.BACKEND_URL}/${req.query.module}/import`,
|
||||
formData,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${process.env.BACKEND_JWT}`,
|
||||
...formData.getHeaders()
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).json(result.data);
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(500).json({
|
||||
error: 'Upload failed',
|
||||
details: error instanceof Error ? error.message : 'Unknown error'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
47
src/pages/api/exam/generate/[...module].ts
Normal file
47
src/pages/api/exam/generate/[...module].ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { withIronSessionApiRoute } from "iron-session/next";
|
||||
import { sessionOptions } from "@/lib/session";
|
||||
import axios from "axios";
|
||||
import queryToURLSearchParams from "@/utils/query.to.url.params";
|
||||
|
||||
export default withIronSessionApiRoute(handler, sessionOptions);
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (req.method === "GET") return get(req, res);
|
||||
if (req.method === "POST") return post(req, res);
|
||||
|
||||
return res.status(404).json({ ok: false });
|
||||
}
|
||||
|
||||
async function get(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (!req.session.user) return res.status(401).json({ ok: false });
|
||||
|
||||
const queryParams = queryToURLSearchParams(req);
|
||||
const endpoint = queryParams.getAll('module').join("/");
|
||||
|
||||
queryParams.delete('module');
|
||||
|
||||
const result = await axios.get(`${process.env.BACKEND_URL}/${endpoint}${queryParams.size > 0 ? `?${queryParams.toString()}` : ""}`, {
|
||||
headers: { Authorization: `Bearer ${process.env.BACKEND_JWT}` },
|
||||
});
|
||||
res.status(200).json(result.data);
|
||||
}
|
||||
|
||||
async function post(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (!req.session.user) return res.status(401).json({ ok: false });
|
||||
|
||||
const queryParams = queryToURLSearchParams(req);
|
||||
let endpoint = queryParams.getAll('module').join("/");
|
||||
if (endpoint.startsWith("level")) {
|
||||
endpoint = "level"
|
||||
}
|
||||
|
||||
const result = await axios.post(`${process.env.BACKEND_URL}/${endpoint}`,
|
||||
req.body,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${process.env.BACKEND_JWT}` },
|
||||
},
|
||||
);
|
||||
|
||||
res.status(200).json(result.data);
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type {NextApiRequest, NextApiResponse} from "next";
|
||||
import {withIronSessionApiRoute} from "iron-session/next";
|
||||
import {sessionOptions} from "@/lib/session";
|
||||
import axios from "axios";
|
||||
import queryToURLSearchParams from "@/utils/query.to.url.params";
|
||||
|
||||
export default withIronSessionApiRoute(handler, sessionOptions);
|
||||
|
||||
@@ -12,16 +12,19 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
return res.status(404).json({ok: false});
|
||||
}
|
||||
|
||||
|
||||
async function post(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (!req.session.user) return res.status(401).json({ok: false});
|
||||
|
||||
const body = req.body;
|
||||
const params = new URLSearchParams();
|
||||
const queryParams = queryToURLSearchParams(req);
|
||||
const endpoint = queryParams.getAll('module').join("/");
|
||||
|
||||
Object.keys(body).forEach((key) => params.append(key, body[key]));
|
||||
const result = await axios.get(`${process.env.BACKEND_URL}/custom_level?${params.toString()}`, {
|
||||
headers: {Authorization: `Bearer ${process.env.BACKEND_JWT}`},
|
||||
});
|
||||
const result = await axios.post(`${process.env.BACKEND_URL}/${endpoint}`,
|
||||
req.body,
|
||||
{
|
||||
headers: {Authorization: `Bearer ${process.env.BACKEND_JWT}`},
|
||||
},
|
||||
);
|
||||
|
||||
res.status(200).json(result.data);
|
||||
}
|
||||
}
|
||||
@@ -94,7 +94,7 @@ interface SkillsFeedbackResponse extends SkillsFeedbackRequest {
|
||||
|
||||
const getSkillsFeedback = async (sections: SkillsFeedbackRequest[]) => {
|
||||
const backendRequest = await axios.post(
|
||||
`${process.env.BACKEND_URL}/grading_summary`,
|
||||
`${process.env.BACKEND_URL}/grade/summary`,
|
||||
{ sections },
|
||||
{
|
||||
headers: {
|
||||
|
||||
@@ -20,7 +20,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
|
||||
async function post(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
const response = await axios.post(`${process.env.BACKEND_URL}/training_content`, req.body, {
|
||||
const response = await axios.post(`${process.env.BACKEND_URL}/training/`, req.body, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${process.env.BACKEND_JWT}`,
|
||||
},
|
||||
|
||||
47
src/pages/api/users/controller.ts
Normal file
47
src/pages/api/users/controller.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
|
||||
import { sessionOptions } from '@/lib/session';
|
||||
import { withIronSessionApiRoute } from 'iron-session/next';
|
||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||
import client from "@/lib/mongodb";
|
||||
|
||||
const db = client.db(process.env.MONGODB_DB);
|
||||
|
||||
export default withIronSessionApiRoute(handler, sessionOptions);
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { op } = req.query
|
||||
|
||||
if (req.method === 'GET') {
|
||||
switch (op) {
|
||||
default:
|
||||
res.status(400).json({ error: 'Invalid operation!' })
|
||||
}
|
||||
}
|
||||
else if (req.method === 'POST') {
|
||||
switch (op) {
|
||||
case 'crossRefEmails':
|
||||
res.status(200).json(await crossRefEmails(req.body.emails))
|
||||
break;
|
||||
default:
|
||||
res.status(400).json({ error: 'Invalid operation!' })
|
||||
}
|
||||
} else {
|
||||
res.status(400).end(`Method ${req.method} Not Allowed`)
|
||||
}
|
||||
}
|
||||
|
||||
async function crossRefEmails(emails: string[]) {
|
||||
return await db.collection("users").aggregate([
|
||||
{
|
||||
$match: {
|
||||
email: { $in: emails }
|
||||
}
|
||||
},
|
||||
{
|
||||
$project: {
|
||||
_id: 0,
|
||||
email: 1
|
||||
}
|
||||
}
|
||||
]).toArray();
|
||||
}
|
||||
Reference in New Issue
Block a user