Merge branch 'develop' into feature-report-export
This commit is contained in:
23
src/pages/api/code/[id].ts
Normal file
23
src/pages/api/code/[id].ts
Normal file
@@ -0,0 +1,23 @@
|
||||
// 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, getDoc, deleteDoc} from "firebase/firestore";
|
||||
import {withIronSessionApiRoute} from "iron-session/next";
|
||||
import {sessionOptions} from "@/lib/session";
|
||||
import {uuidv4} from "@firebase/util";
|
||||
|
||||
const db = getFirestore(app);
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (req.method === "GET") return GET(req, res);
|
||||
|
||||
res.status(404).json({ok: false});
|
||||
}
|
||||
|
||||
async function GET(req: NextApiRequest, res: NextApiResponse) {
|
||||
const {id} = req.query;
|
||||
|
||||
const snapshot = await getDoc(doc(db, "codes", id as string));
|
||||
|
||||
res.status(200).json({...snapshot.data(), id: snapshot.id});
|
||||
}
|
||||
@@ -48,6 +48,8 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
await setDoc(codeRef, {type, code, creator: req.session.user!.id, expiryDate});
|
||||
|
||||
if (emails && emails.length > index) {
|
||||
await setDoc(codeRef, {email: emails[index]}, {merge: true});
|
||||
|
||||
const transport = prepareMailer();
|
||||
const mailOptions = prepareMailOptions(
|
||||
{
|
||||
@@ -2,12 +2,16 @@
|
||||
import type {NextApiRequest, NextApiResponse} from "next";
|
||||
import {withIronSessionApiRoute} from "iron-session/next";
|
||||
import {sessionOptions} from "@/lib/session";
|
||||
import axios from "axios";
|
||||
import axios, {AxiosResponse} from "axios";
|
||||
import formidable from "formidable-serverless";
|
||||
import {ref, uploadBytes} from "firebase/storage";
|
||||
import fs from "fs";
|
||||
import {storage} from "@/firebase";
|
||||
import {app, storage} from "@/firebase";
|
||||
import {doc, getDoc, getFirestore, setDoc} from "firebase/firestore";
|
||||
import {Stat} from "@/interfaces/user";
|
||||
import {speakingReverseMarking} from "@/utils/score";
|
||||
|
||||
const db = getFirestore(app);
|
||||
export default withIronSessionApiRoute(handler, sessionOptions);
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
@@ -36,20 +40,41 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
}),
|
||||
);
|
||||
|
||||
const backendRequest = await axios.post(
|
||||
`${process.env.BACKEND_URL}/speaking_task_3`,
|
||||
{answers: uploadingAudios},
|
||||
res.status(200).json(null);
|
||||
|
||||
console.log("🌱 - Still processing");
|
||||
const backendRequest = await evaluate({answers: uploadingAudios});
|
||||
console.log("🌱 - Process complete");
|
||||
|
||||
const correspondingStat = (await getDoc(doc(db, "stats", fields.id))).data() as Stat;
|
||||
const solutions = correspondingStat.solutions.map((x) => ({...x, evaluation: backendRequest.data, solution: uploadingAudios}));
|
||||
await setDoc(
|
||||
doc(db, "stats", fields.id),
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${process.env.BACKEND_JWT}`,
|
||||
solutions,
|
||||
score: {
|
||||
correct: speakingReverseMarking[backendRequest.data.overall],
|
||||
missing: 0,
|
||||
total: 100,
|
||||
},
|
||||
},
|
||||
{merge: true},
|
||||
);
|
||||
|
||||
res.status(200).json({...backendRequest.data, answer: uploadingAudios});
|
||||
console.log("🌱 - Updated the DB");
|
||||
});
|
||||
}
|
||||
|
||||
async function evaluate(body: {answers: object[]}): Promise<AxiosResponse> {
|
||||
const backendRequest = await axios.post(`${process.env.BACKEND_URL}/speaking_task_3`, body, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${process.env.BACKEND_JWT}`,
|
||||
},
|
||||
});
|
||||
|
||||
if (typeof backendRequest.data === "string") return evaluate(body);
|
||||
return backendRequest;
|
||||
}
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: false,
|
||||
|
||||
@@ -2,12 +2,16 @@
|
||||
import type {NextApiRequest, NextApiResponse} from "next";
|
||||
import {withIronSessionApiRoute} from "iron-session/next";
|
||||
import {sessionOptions} from "@/lib/session";
|
||||
import axios from "axios";
|
||||
import axios, {AxiosResponse} from "axios";
|
||||
import formidable from "formidable-serverless";
|
||||
import {ref, uploadBytes} from "firebase/storage";
|
||||
import fs from "fs";
|
||||
import {storage} from "@/firebase";
|
||||
import {app, storage} from "@/firebase";
|
||||
import {doc, getDoc, getFirestore, setDoc} from "firebase/firestore";
|
||||
import {Stat} from "@/interfaces/user";
|
||||
import {speakingReverseMarking} from "@/utils/score";
|
||||
|
||||
const db = getFirestore(app);
|
||||
export default withIronSessionApiRoute(handler, sessionOptions);
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
@@ -26,21 +30,46 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const binary = fs.readFileSync((audioFile as any).path).buffer;
|
||||
const snapshot = await uploadBytes(audioFileRef, binary);
|
||||
|
||||
const backendRequest = await axios.post(
|
||||
`${process.env.BACKEND_URL}/speaking_task_3`,
|
||||
{answers: [{question: fields.question, answer: snapshot.metadata.fullPath}]},
|
||||
res.status(200).json(null);
|
||||
|
||||
console.log("🌱 - Still processing");
|
||||
const backendRequest = await evaluate({answers: [{question: fields.question, answer: snapshot.metadata.fullPath}]});
|
||||
fs.rmSync((audioFile as any).path);
|
||||
console.log("🌱 - Process complete");
|
||||
|
||||
const correspondingStat = (await getDoc(doc(db, "stats", fields.id))).data() as Stat;
|
||||
const solutions = correspondingStat.solutions.map((x) => ({
|
||||
...x,
|
||||
evaluation: backendRequest.data,
|
||||
solution: snapshot.metadata.fullPath,
|
||||
}));
|
||||
await setDoc(
|
||||
doc(db, "stats", fields.id),
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${process.env.BACKEND_JWT}`,
|
||||
solutions,
|
||||
score: {
|
||||
correct: speakingReverseMarking[backendRequest.data.overall],
|
||||
total: 100,
|
||||
missing: 0,
|
||||
},
|
||||
},
|
||||
{merge: true},
|
||||
);
|
||||
|
||||
fs.rmSync((audioFile as any).path);
|
||||
res.status(200).json({...backendRequest.data, fullPath: snapshot.metadata.fullPath});
|
||||
console.log("🌱 - Updated the DB");
|
||||
});
|
||||
}
|
||||
|
||||
async function evaluate(body: {answers: object[]}): Promise<AxiosResponse> {
|
||||
const backendRequest = await axios.post(`${process.env.BACKEND_URL}/speaking_task_3`, body, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${process.env.BACKEND_JWT}`,
|
||||
},
|
||||
});
|
||||
|
||||
if (typeof backendRequest.data === "string") return evaluate(body);
|
||||
return backendRequest;
|
||||
}
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: false,
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type {NextApiRequest, NextApiResponse} from "next";
|
||||
import {getFirestore, doc, getDoc} from "firebase/firestore";
|
||||
import {getFirestore, doc, getDoc, setDoc} from "firebase/firestore";
|
||||
import {withIronSessionApiRoute} from "iron-session/next";
|
||||
import {sessionOptions} from "@/lib/session";
|
||||
import axios from "axios";
|
||||
import axios, {AxiosResponse} from "axios";
|
||||
import {app} from "@/firebase";
|
||||
import {Stat} from "@/interfaces/user";
|
||||
import {writingReverseMarking} from "@/utils/score";
|
||||
|
||||
interface Body {
|
||||
question: string;
|
||||
answer: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
const db = getFirestore(app);
|
||||
export default withIronSessionApiRoute(handler, sessionOptions);
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
@@ -18,11 +23,36 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
return;
|
||||
}
|
||||
|
||||
const backendRequest = await axios.post(`${process.env.BACKEND_URL}/writing_task2`, req.body as Body, {
|
||||
res.status(200).json(null);
|
||||
|
||||
console.log("🌱 - Still processing");
|
||||
const backendRequest = await evaluate(req.body as Body);
|
||||
console.log("🌱 - Process complete");
|
||||
|
||||
const correspondingStat = (await getDoc(doc(db, "stats", req.body.id))).data() as Stat;
|
||||
const solutions = correspondingStat.solutions.map((x) => ({...x, evaluation: backendRequest.data}));
|
||||
await setDoc(
|
||||
doc(db, "stats", (req.body as Body).id),
|
||||
{
|
||||
solutions,
|
||||
score: {
|
||||
correct: writingReverseMarking[backendRequest.data.overall],
|
||||
total: 100,
|
||||
missing: 0,
|
||||
},
|
||||
},
|
||||
{merge: true},
|
||||
);
|
||||
console.log("🌱 - Updated the DB");
|
||||
}
|
||||
|
||||
async function evaluate(body: Body): Promise<AxiosResponse> {
|
||||
const backendRequest = await axios.post(`${process.env.BACKEND_URL}/writing_task2`, body as Body, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${process.env.BACKEND_JWT}`,
|
||||
},
|
||||
});
|
||||
|
||||
res.status(backendRequest.status).json(backendRequest.data);
|
||||
if (typeof backendRequest.data === "string") return evaluate(body);
|
||||
return backendRequest;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type {NextApiRequest, NextApiResponse} from "next";
|
||||
import {app} from "@/firebase";
|
||||
import {app, storage} from "@/firebase";
|
||||
import {getFirestore, collection, getDocs, getDoc, doc, deleteDoc, setDoc} from "firebase/firestore";
|
||||
import {withIronSessionApiRoute} from "iron-session/next";
|
||||
import {sessionOptions} from "@/lib/session";
|
||||
import {Group} from "@/interfaces/user";
|
||||
import {Payment} from "@/interfaces/paypal";
|
||||
import {deleteObject, ref} from "firebase/storage";
|
||||
|
||||
const db = getFirestore(app);
|
||||
|
||||
@@ -44,11 +46,14 @@ async function del(req: NextApiRequest, res: NextApiResponse) {
|
||||
const {id} = req.query as {id: string};
|
||||
|
||||
const snapshot = await getDoc(doc(db, "payments", id));
|
||||
const data = snapshot.data() as Payment;
|
||||
|
||||
const user = req.session.user;
|
||||
if (user.type === "admin" || user.type === "developer") {
|
||||
await deleteDoc(snapshot.ref);
|
||||
if (data.commissionTransfer) await deleteObject(ref(storage, data.commissionTransfer));
|
||||
if (data.corporateTransfer) await deleteObject(ref(storage, data.corporateTransfer));
|
||||
|
||||
await deleteDoc(snapshot.ref);
|
||||
res.status(200).json({ok: true});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,194 +1,180 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { app, storage } from "@/firebase";
|
||||
import {
|
||||
getFirestore,
|
||||
getDoc,
|
||||
doc,
|
||||
updateDoc,
|
||||
deleteField,
|
||||
} from "firebase/firestore";
|
||||
import { withIronSessionApiRoute } from "iron-session/next";
|
||||
import { sessionOptions } from "@/lib/session";
|
||||
import { FilesStorage } from "@/interfaces/storage.files";
|
||||
import type {NextApiRequest, NextApiResponse} from "next";
|
||||
import {app, storage} from "@/firebase";
|
||||
import {getFirestore, getDoc, doc, updateDoc, deleteField, setDoc} from "firebase/firestore";
|
||||
import {withIronSessionApiRoute} from "iron-session/next";
|
||||
import {sessionOptions} from "@/lib/session";
|
||||
import {FilesStorage} from "@/interfaces/storage.files";
|
||||
|
||||
import { Payment } from "@/interfaces/paypal";
|
||||
import {Payment} from "@/interfaces/paypal";
|
||||
import fs from "fs";
|
||||
import {
|
||||
ref,
|
||||
uploadBytes,
|
||||
deleteObject,
|
||||
getDownloadURL,
|
||||
} from "firebase/storage";
|
||||
import {ref, uploadBytes, deleteObject, getDownloadURL} from "firebase/storage";
|
||||
import formidable from "formidable-serverless";
|
||||
|
||||
const db = getFirestore(app);
|
||||
|
||||
const getPaymentField = (type: FilesStorage) => {
|
||||
switch (type) {
|
||||
case "commission":
|
||||
return "commissionTransfer";
|
||||
case "corporate":
|
||||
return "corporateTransfer";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
switch (type) {
|
||||
case "commission":
|
||||
return "commissionTransfer";
|
||||
case "corporate":
|
||||
return "corporateTransfer";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelete = async (
|
||||
paymentId: string,
|
||||
paymentField: "commissionTransfer" | "corporateTransfer"
|
||||
) => {
|
||||
const paymentRef = doc(db, "payments", paymentId);
|
||||
const paymentDoc = await getDoc(paymentRef);
|
||||
const { [paymentField]: paymentFieldPath } = paymentDoc.data() as Payment;
|
||||
// Create a reference to the file to delete
|
||||
const documentRef = ref(storage, paymentFieldPath);
|
||||
await deleteObject(documentRef);
|
||||
await updateDoc(paymentRef, {
|
||||
[paymentField]: deleteField(),
|
||||
});
|
||||
const handleDelete = async (paymentId: string, paymentField: "commissionTransfer" | "corporateTransfer") => {
|
||||
const paymentRef = doc(db, "payments", paymentId);
|
||||
const paymentDoc = await getDoc(paymentRef);
|
||||
const {[paymentField]: paymentFieldPath} = paymentDoc.data() as Payment;
|
||||
// Create a reference to the file to delete
|
||||
const documentRef = ref(storage, paymentFieldPath);
|
||||
await deleteObject(documentRef);
|
||||
await updateDoc(paymentRef, {
|
||||
[paymentField]: deleteField(),
|
||||
isPaid: false,
|
||||
});
|
||||
};
|
||||
|
||||
const handleUpload = async (
|
||||
req: NextApiRequest,
|
||||
paymentId: string,
|
||||
paymentField: "commissionTransfer" | "corporateTransfer"
|
||||
) =>
|
||||
new Promise((resolve, reject) => {
|
||||
const form = formidable({ keepExtensions: true });
|
||||
form.parse(req, async (err: any, fields: any, files: any) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const { file } = files;
|
||||
const fileName = Date.now() + "-" + file.name;
|
||||
const fileRef = ref(storage, fileName);
|
||||
const handleUpload = async (req: NextApiRequest, paymentId: string, paymentField: "commissionTransfer" | "corporateTransfer") =>
|
||||
new Promise((resolve, reject) => {
|
||||
const form = formidable({keepExtensions: true});
|
||||
form.parse(req, async (err: any, fields: any, files: any) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const {file} = files;
|
||||
const fileName = Date.now() + "-" + file.name;
|
||||
const fileRef = ref(storage, fileName);
|
||||
|
||||
const binary = fs.readFileSync(file.path).buffer;
|
||||
const snapshot = await uploadBytes(fileRef, binary);
|
||||
fs.rmSync(file.path);
|
||||
const binary = fs.readFileSync(file.path).buffer;
|
||||
const snapshot = await uploadBytes(fileRef, binary);
|
||||
fs.rmSync(file.path);
|
||||
|
||||
const paymentRef = doc(db, "payments", paymentId);
|
||||
const paymentRef = doc(db, "payments", paymentId);
|
||||
|
||||
await updateDoc(paymentRef, {
|
||||
[paymentField]: snapshot.ref.fullPath,
|
||||
});
|
||||
resolve(snapshot.ref.fullPath);
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
await updateDoc(paymentRef, {
|
||||
[paymentField]: snapshot.ref.fullPath,
|
||||
});
|
||||
resolve(snapshot.ref.fullPath);
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
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.session.user) {
|
||||
res.status(401).json({ok: false});
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.method === "GET") return await get(req, res);
|
||||
if (req.method === "POST") return await post(req, res);
|
||||
if (req.method === "DELETE") return await del(req, res);
|
||||
if (req.method === "PATCH") return await patch(req, res);
|
||||
if (req.method === "GET") return await get(req, res);
|
||||
if (req.method === "POST") return await post(req, res);
|
||||
if (req.method === "DELETE") return await del(req, res);
|
||||
if (req.method === "PATCH") return await patch(req, res);
|
||||
|
||||
res.status(404).json(undefined);
|
||||
res.status(404).json(undefined);
|
||||
}
|
||||
|
||||
async function get(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { type, paymentId } = req.query as {
|
||||
type: FilesStorage;
|
||||
paymentId: string;
|
||||
};
|
||||
const paymentField = getPaymentField(type);
|
||||
const {type, paymentId} = req.query as {
|
||||
type: FilesStorage;
|
||||
paymentId: string;
|
||||
};
|
||||
const paymentField = getPaymentField(type);
|
||||
|
||||
if (paymentField === null) {
|
||||
res.status(500).json({ error: "Failed to identify payment field" });
|
||||
return;
|
||||
}
|
||||
const paymentRef = doc(db, "payments", paymentId);
|
||||
const { [paymentField]: paymentFieldPath } = (
|
||||
await getDoc(paymentRef)
|
||||
).data() as Payment;
|
||||
if (paymentField === null) {
|
||||
res.status(500).json({error: "Failed to identify payment field"});
|
||||
return;
|
||||
}
|
||||
const paymentRef = doc(db, "payments", paymentId);
|
||||
const {[paymentField]: paymentFieldPath} = (await getDoc(paymentRef)).data() as Payment;
|
||||
|
||||
// Create a reference to the file to delete
|
||||
const documentRef = ref(storage, paymentFieldPath);
|
||||
const url = await getDownloadURL(documentRef);
|
||||
res.status(200).json({ url, name: documentRef.name });
|
||||
// Create a reference to the file to delete
|
||||
const documentRef = ref(storage, paymentFieldPath);
|
||||
const url = await getDownloadURL(documentRef);
|
||||
res.status(200).json({url, name: documentRef.name});
|
||||
}
|
||||
|
||||
async function post(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { type, paymentId } = req.query as {
|
||||
type: FilesStorage;
|
||||
paymentId: string;
|
||||
};
|
||||
const paymentField = getPaymentField(type);
|
||||
const {type, paymentId} = req.query as {
|
||||
type: FilesStorage;
|
||||
paymentId: string;
|
||||
};
|
||||
const paymentField = getPaymentField(type);
|
||||
|
||||
if (paymentField === null) {
|
||||
res.status(500).json({ error: "Failed to identify payment field" });
|
||||
return;
|
||||
}
|
||||
if (paymentField === null) {
|
||||
res.status(500).json({error: "Failed to identify payment field"});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const ref = await handleUpload(req, paymentId, paymentField);
|
||||
res.status(200).json({ ref });
|
||||
} catch (error) {
|
||||
res.status(500).json({ error });
|
||||
}
|
||||
try {
|
||||
const ref = await handleUpload(req, paymentId, paymentField);
|
||||
|
||||
const updatedDoc = (await getDoc(doc(db, "payments", paymentId))).data() as Payment;
|
||||
if (updatedDoc.commissionTransfer && updatedDoc.corporateTransfer) {
|
||||
await setDoc(doc(db, "payments", paymentId), {isPaid: true}, {merge: true});
|
||||
}
|
||||
res.status(200).json({ref});
|
||||
} catch (error) {
|
||||
res.status(500).json({error});
|
||||
}
|
||||
}
|
||||
|
||||
async function del(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { type, paymentId } = req.query as {
|
||||
type: FilesStorage;
|
||||
paymentId: string;
|
||||
};
|
||||
const paymentField = getPaymentField(type);
|
||||
if (paymentField === null) {
|
||||
res.status(500).json({ error: "Failed to identify payment field" });
|
||||
return;
|
||||
}
|
||||
const {type, paymentId} = req.query as {
|
||||
type: FilesStorage;
|
||||
paymentId: string;
|
||||
};
|
||||
const paymentField = getPaymentField(type);
|
||||
if (paymentField === null) {
|
||||
res.status(500).json({error: "Failed to identify payment field"});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await handleDelete(paymentId, paymentField);
|
||||
res.status(200).json({ ok: true });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: "Failed to delete file" });
|
||||
}
|
||||
try {
|
||||
await handleDelete(paymentId, paymentField);
|
||||
res.status(200).json({ok: true});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({error: "Failed to delete file"});
|
||||
}
|
||||
}
|
||||
|
||||
async function patch(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { type, paymentId } = req.query as {
|
||||
type: FilesStorage;
|
||||
paymentId: string;
|
||||
};
|
||||
const paymentField = getPaymentField(type);
|
||||
if (paymentField === null) {
|
||||
res.status(500).json({ error: "Failed to identify payment field" });
|
||||
return;
|
||||
}
|
||||
const {type, paymentId} = req.query as {
|
||||
type: FilesStorage;
|
||||
paymentId: string;
|
||||
};
|
||||
const paymentField = getPaymentField(type);
|
||||
if (paymentField === null) {
|
||||
res.status(500).json({error: "Failed to identify payment field"});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await handleDelete(paymentId, paymentField);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: "Failed to delete file" });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await handleDelete(paymentId, paymentField);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({error: "Failed to delete file"});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const ref = await handleUpload(req, paymentId, paymentField);
|
||||
res.status(200).json({ ref });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: "Failed to upload file" });
|
||||
}
|
||||
try {
|
||||
const ref = await handleUpload(req, paymentId, paymentField);
|
||||
res.status(200).json({ref});
|
||||
} catch (err) {
|
||||
res.status(500).json({error: "Failed to upload file"});
|
||||
}
|
||||
}
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: false,
|
||||
},
|
||||
api: {
|
||||
bodyParser: false,
|
||||
},
|
||||
};
|
||||
|
||||
23
src/pages/api/stats/[id].ts
Normal file
23
src/pages/api/stats/[id].ts
Normal file
@@ -0,0 +1,23 @@
|
||||
// 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, getDoc, deleteDoc} from "firebase/firestore";
|
||||
import {withIronSessionApiRoute} from "iron-session/next";
|
||||
import {sessionOptions} from "@/lib/session";
|
||||
import {uuidv4} from "@firebase/util";
|
||||
|
||||
const db = getFirestore(app);
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (req.method === "GET") return GET(req, res);
|
||||
|
||||
res.status(404).json({ok: false});
|
||||
}
|
||||
|
||||
async function GET(req: NextApiRequest, res: NextApiResponse) {
|
||||
const {id} = req.query;
|
||||
|
||||
const snapshot = await getDoc(doc(db, "stats", id as string));
|
||||
|
||||
res.status(200).json({...snapshot.data(), id: snapshot.id});
|
||||
}
|
||||
@@ -1,29 +1,23 @@
|
||||
// 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, doc, setDoc, addDoc} from "firebase/firestore";
|
||||
import {getFirestore, collection, getDocs, query, where, setDoc, doc, getDoc, deleteDoc} from "firebase/firestore";
|
||||
import {withIronSessionApiRoute} from "iron-session/next";
|
||||
import {sessionOptions} from "@/lib/session";
|
||||
import {uuidv4} from "@firebase/util";
|
||||
|
||||
const db = getFirestore(app);
|
||||
|
||||
export default withIronSessionApiRoute(handler, sessionOptions);
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (req.method === "GET") return GET(req, res);
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (!req.session.user) {
|
||||
res.status(401).json({ok: false});
|
||||
return;
|
||||
}
|
||||
|
||||
const {id: user} = req.query;
|
||||
const q = query(collection(db, "stats"), where("user", "==", user));
|
||||
|
||||
const snapshot = await getDocs(q);
|
||||
|
||||
res.status(200).json(
|
||||
snapshot.docs.map((doc) => ({
|
||||
id: doc.id,
|
||||
...doc.data(),
|
||||
})),
|
||||
);
|
||||
res.status(404).json({ok: false});
|
||||
}
|
||||
|
||||
async function GET(req: NextApiRequest, res: NextApiResponse) {
|
||||
const {id} = req.query;
|
||||
|
||||
const snapshot = await getDoc(doc(db, "stats", id as string));
|
||||
|
||||
res.status(200).json({...snapshot.data(), id: snapshot.id});
|
||||
}
|
||||
@@ -42,7 +42,7 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
|
||||
}
|
||||
|
||||
const stats = req.body as Stat[];
|
||||
await stats.forEach(async (stat) => await addDoc(collection(db, "stats"), stat));
|
||||
await stats.forEach(async (stat) => await setDoc(doc(db, "stats", stat.id), stat));
|
||||
|
||||
const groupedStatsByAssignment = groupBy(
|
||||
stats.filter((x) => !!x.assignment),
|
||||
|
||||
@@ -25,8 +25,8 @@ async function update(req: NextApiRequest, res: NextApiResponse) {
|
||||
|
||||
const q = query(collection(db, "stats"), where("user", "==", req.session.user.id));
|
||||
const stats = (await getDocs(q)).docs.map((doc) => ({
|
||||
id: doc.id,
|
||||
...(doc.data() as Stat),
|
||||
id: doc.id,
|
||||
})) as Stat[];
|
||||
|
||||
const groupedStats = groupBySession(stats);
|
||||
|
||||
29
src/pages/api/stats/user/[user].ts
Normal file
29
src/pages/api/stats/user/[user].ts
Normal file
@@ -0,0 +1,29 @@
|
||||
// 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, doc, setDoc, addDoc} from "firebase/firestore";
|
||||
import {withIronSessionApiRoute} from "iron-session/next";
|
||||
import {sessionOptions} from "@/lib/session";
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
const {user} = req.query;
|
||||
const q = query(collection(db, "stats"), where("user", "==", user));
|
||||
|
||||
const snapshot = await getDocs(q);
|
||||
|
||||
res.status(200).json(
|
||||
snapshot.docs.map((doc) => ({
|
||||
id: doc.id,
|
||||
...doc.data(),
|
||||
})),
|
||||
);
|
||||
}
|
||||
@@ -4,14 +4,14 @@ import {app, storage} from "@/firebase";
|
||||
import {getFirestore, collection, getDocs, getDoc, doc, setDoc, query, where} from "firebase/firestore";
|
||||
import {withIronSessionApiRoute} from "iron-session/next";
|
||||
import {sessionOptions} from "@/lib/session";
|
||||
import {User} from "@/interfaces/user";
|
||||
import {Group, User} from "@/interfaces/user";
|
||||
import {getDownloadURL, getStorage, ref, uploadBytes} from "firebase/storage";
|
||||
import {getAuth, signInWithEmailAndPassword, updateEmail, updatePassword} from "firebase/auth";
|
||||
import {errorMessages} from "@/constants/errors";
|
||||
import moment from "moment";
|
||||
import ShortUniqueId from "short-unique-id";
|
||||
import {Payment} from "@/interfaces/paypal";
|
||||
import { toFixedNumber } from "@/utils/number";
|
||||
import {toFixedNumber} from "@/utils/number";
|
||||
const db = getFirestore(app);
|
||||
const auth = getAuth(app);
|
||||
|
||||
@@ -22,10 +22,10 @@ export default withIronSessionApiRoute(handler, sessionOptions);
|
||||
// but if it is not inserted as a string, some UI components will not work (Invalid Date)
|
||||
const addPaymentRecord = async (data: any) => {
|
||||
await setDoc(doc(db, "payments", data.id), data);
|
||||
}
|
||||
};
|
||||
const managePaymentRecords = async (user: User, userId: string | undefined): Promise<boolean> => {
|
||||
try {
|
||||
if(user.type === 'corporate' && userId) {
|
||||
if (user.type === "corporate" && userId) {
|
||||
const shortUID = new ShortUniqueId();
|
||||
const data: Payment = {
|
||||
id: shortUID.randomUUID(8),
|
||||
@@ -38,34 +38,35 @@ const managePaymentRecords = async (user: User, userId: string | undefined): Pro
|
||||
isPaid: false,
|
||||
date: new Date().toISOString(),
|
||||
};
|
||||
|
||||
|
||||
const corporatePayments = await getDocs(query(collection(db, "payments"), where("corporate", "==", userId)));
|
||||
if(corporatePayments.docs.length === 0) {
|
||||
if (corporatePayments.docs.length === 0) {
|
||||
await addPaymentRecord(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const hasPaymentPaidAndExpiring = corporatePayments.docs.filter((doc) => {
|
||||
const data = doc.data();
|
||||
return data.isPaid
|
||||
&& moment().isAfter(moment(user.subscriptionExpirationDate).subtract(30, "days"))
|
||||
&& moment().isBefore(moment(user.subscriptionExpirationDate));
|
||||
return (
|
||||
data.isPaid &&
|
||||
moment().isAfter(moment(user.subscriptionExpirationDate).subtract(30, "days")) &&
|
||||
moment().isBefore(moment(user.subscriptionExpirationDate))
|
||||
);
|
||||
});
|
||||
|
||||
if(hasPaymentPaidAndExpiring.length > 0) {
|
||||
if (hasPaymentPaidAndExpiring.length > 0) {
|
||||
await addPaymentRecord(data);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
// if this process fails it should not stop the rest of the process
|
||||
console.log(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (!req.session.user) {
|
||||
@@ -108,6 +109,23 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
const credential = await signInWithEmailAndPassword(auth, req.session.user.email, updatedUser.password);
|
||||
await updateEmail(credential.user, updatedUser.email);
|
||||
|
||||
if (req.session.user.type === "student") {
|
||||
const corporateAdmins = ((await getDocs(collection(db, "users"))).docs.map((x) => ({...x.data(), id: x.id})) as User[])
|
||||
.filter((x) => x.type === "corporate")
|
||||
.map((x) => x.id);
|
||||
const groups = ((await getDocs(collection(db, "groups"))).docs.map((x) => ({...x.data(), id: x.id})) as Group[]).filter(
|
||||
(x) => x.participants.includes(req.session.user!.id) && corporateAdmins.includes(x.admin),
|
||||
);
|
||||
|
||||
groups.forEach(async (group) => {
|
||||
await setDoc(
|
||||
doc(db, "groups", group.id),
|
||||
{participants: group.participants.filter((x) => x !== req.session.user!.id)},
|
||||
{merge: true},
|
||||
);
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
res.status(400).json({error: "E002", message: errorMessages.E002});
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user