Merged with develop

This commit is contained in:
Tiago Ribeiro
2024-12-30 19:04:18 +00:00
37 changed files with 955 additions and 645 deletions

View File

@@ -6,9 +6,11 @@ import { deleteEntity, getEntity, getEntityWithRoles } from "@/utils/entities.be
import client from "@/lib/mongodb";
import { Entity } from "@/interfaces/entity";
import { doesEntityAllow } from "@/utils/permissions";
import { getUser } from "@/utils/users.be";
import { getEntityUsers, getUser } from "@/utils/users.be";
import { requestUser } from "@/utils/api";
import { isAdmin } from "@/utils/users";
import { filterBy, mapBy } from "@/utils";
import { User } from "@/interfaces/user";
const db = client.db(process.env.MONGODB_DB);
@@ -66,5 +68,27 @@ async function patch(req: NextApiRequest, res: NextApiResponse) {
return res.status(200).json({ ok: entity.acknowledged });
}
if (req.body.payment) {
const entity = await db.collection<Entity>("entities").updateOne({ id }, { $set: { payment: req.body.payment } });
return res.status(200).json({ ok: entity.acknowledged });
}
if (req.body.expiryDate !== undefined) {
const entity = await getEntity(id)
const result = await db.collection<Entity>("entities").updateOne({ id }, { $set: { expiryDate: req.body.expiryDate } });
const users = await getEntityUsers(id, 0, {
subscriptionExpirationDate: entity?.expiryDate,
$and: [
{ type: { $ne: "admin" } },
{ type: { $ne: "developer" } },
]
})
await db.collection<User>("users").updateMany({ id: { $in: mapBy(users, 'id') } }, { $set: { subscriptionExpirationDate: req.body.expiryDate } })
return res.status(200).json({ ok: result.acknowledged });
}
return res.status(200).json({ ok: true });
}

View File

@@ -7,6 +7,9 @@ import { Exam, ExamBase, InstructorGender, Variant } from "@/interfaces/exam";
import { getExams } from "@/utils/exams.be";
import { Module } from "@/interfaces";
import { getUserCorporate } from "@/utils/groups.be";
import { requestUser } from "@/utils/api";
import { isAdmin } from "@/utils/users";
import { mapBy } from "@/utils";
const db = client.db(process.env.MONGODB_DB);
@@ -37,25 +40,20 @@ async function GET(req: NextApiRequest, res: NextApiResponse) {
}
async function POST(req: NextApiRequest, res: NextApiResponse) {
if (!req.session.user) {
res.status(401).json({ ok: false });
return;
}
const user = await requestUser(req, res)
if (!user) return res.status(401).json({ ok: false });
const { module } = req.query as { module: string };
const corporate = await getUserCorporate(req.session.user.id);
const session = client.startSession();
const entities = isAdmin(user) ? [] : mapBy(user.entities, 'id')
try {
const exam = {
...req.body,
module: module,
owners: [
...(["mastercorporate", "corporate"].includes(req.session.user.type) ? [req.session.user.id] : []),
...(!!corporate ? [corporate.id] : []),
],
createdBy: req.session.user.id,
entities,
createdBy: user.id,
createdAt: new Date().toISOString(),
};

View File

@@ -1,6 +1,13 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import { CorporateUser, User } from "@/interfaces/user";
import client from "@/lib/mongodb";
import { getLinkedUsers } from "@/utils/users.be";
import { uniqBy } from "lodash";
import type { NextApiRequest, NextApiResponse } from "next";
import { v4 } from "uuid";
import fs from 'fs'
import { findBy, mapBy } from "@/utils";
import { addUsersToEntity, getEntitiesWithRoles } from "@/utils/entities.be";
const db = client.db(process.env.MONGODB_DB);

View File

@@ -1,15 +1,19 @@
// 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 {Group, User} from "@/interfaces/user";
import {DurationUnit, Package, Payment} from "@/interfaces/paypal";
import {v4} from "uuid";
import type { NextApiRequest, NextApiResponse } from "next";
import { withIronSessionApiRoute } from "iron-session/next";
import { sessionOptions } from "@/lib/session";
import { Group, User } from "@/interfaces/user";
import { DurationUnit, Package, Payment } from "@/interfaces/paypal";
import { v4 } from "uuid";
import ShortUniqueId from "short-unique-id";
import axios from "axios";
import {IntentionResult, PaymentIntention, TransactionResult} from "@/interfaces/paymob";
import { IntentionResult, PaymentIntention, TransactionResult } from "@/interfaces/paymob";
import moment from "moment";
import client from "@/lib/mongodb";
import { getEntity } from "@/utils/entities.be";
import { Entity } from "@/interfaces/entity";
import { getEntityUsers } from "@/utils/users.be";
import { mapBy } from "@/utils";
const db = client.db(process.env.MONGODB_DB);
@@ -22,21 +26,22 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
const authToken = await authenticatePaymob();
console.log("WEBHOOK: ", transactionResult);
if (!checkTransaction(authToken, transactionResult.transaction.order.id)) return res.status(404).json({ok: false});
if (!transactionResult.transaction.success) return res.status(400).json({ok: false});
if (!checkTransaction(authToken, transactionResult.transaction.order.id)) return res.status(404).json({ ok: false });
if (!transactionResult.transaction.success) return res.status(400).json({ ok: false });
const {userID, duration, duration_unit} = transactionResult.intention.extras.creation_extras as {
const { userID, duration, duration_unit, entity: entityID } = transactionResult.intention.extras.creation_extras as {
userID: string;
duration: number;
duration_unit: DurationUnit;
entity: string
};
const user = await db.collection("users").findOne<User>({ id: userID as string });
if (!user || !duration || !duration_unit) return res.status(404).json({ok: false});
if (!user || !duration || !duration_unit) return res.status(404).json({ ok: false });
const subscriptionExpirationDate = user.subscriptionExpirationDate;
if (!subscriptionExpirationDate) return res.status(200).json({ok: false});
if (!subscriptionExpirationDate) return res.status(200).json({ ok: false });
const initialDate = moment(subscriptionExpirationDate).isAfter(moment()) ? moment(subscriptionExpirationDate) : moment();
@@ -44,8 +49,8 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
await db.collection("users").updateOne(
{ id: userID as string },
{ $set: {subscriptionExpirationDate: updatedSubscriptionExpirationDate, status: "active"} }
);
{ $set: { subscriptionExpirationDate: updatedSubscriptionExpirationDate, status: "active" } }
);
await db.collection("paypalpayments").insertOne({
id: v4(),
@@ -60,22 +65,19 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
value: transactionResult.transaction.amount_cents / 1000,
});
if (user.type === "corporate") {
const groups = await db.collection("groups").find<Group>({ admin: user.id }).toArray();
if (entityID) {
const entity = await getEntity(entityID)
await db.collection<Entity>("entities").updateOne({ id: entityID }, { $set: { expiryDate: req.body.expiryDate } });
const participants = (await Promise.all(
groups.flatMap((x) => x.participants).map(async (x) => ({...(await db.collection("users").findOne({ id: x}))})),
)) as User[];
const sameExpiryDateParticipants = participants.filter(
(x) => x.subscriptionExpirationDate === subscriptionExpirationDate && x.status !== "disabled",
);
const users = await getEntityUsers(entityID, 0, {
subscriptionExpirationDate: entity?.expiryDate,
$and: [
{ type: { $ne: "admin" } },
{ type: { $ne: "developer" } },
]
})
for (const participant of sameExpiryDateParticipants) {
await db.collection("users").updateOne(
{ id: participant.id },
{ $set: {subscriptionExpirationDate: updatedSubscriptionExpirationDate, status: "active"} }
);
}
await db.collection<User>("users").updateMany({ id: { $in: mapBy(users, 'id') } }, { $set: { subscriptionExpirationDate: req.body.expiryDate } })
}
res.status(200).json({
@@ -84,19 +86,19 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
}
const authenticatePaymob = async () => {
const response = await axios.post<{token: string}>(
const response = await axios.post<{ token: string }>(
"https://oman.paymob.com/api/auth/tokens",
{
api_key: process.env.PAYMOB_API_KEY,
},
{headers: {Authorization: `Bearer ${process.env.PAYMOB_SECRET_KEY}`}},
{ headers: { Authorization: `Bearer ${process.env.PAYMOB_SECRET_KEY}` } },
);
return response.data.token;
};
const checkTransaction = async (token: string, orderID: number) => {
const response = await axios.post("https://oman.paymob.com/api/ecommerce/orders/transaction_inquiry", {auth_token: token, order_id: orderID});
const response = await axios.post("https://oman.paymob.com/api/ecommerce/orders/transaction_inquiry", { auth_token: token, order_id: orderID });
return response.status === 200;
};

View File

@@ -1,15 +1,15 @@
import {MODULES} from "@/constants/ielts";
import {app} from "@/firebase";
import {Module} from "@/interfaces";
import {Stat, User} from "@/interfaces/user";
import {sessionOptions} from "@/lib/session";
import {calculateBandScore} from "@/utils/score";
import {groupByModule, groupBySession} from "@/utils/stats";
import { MODULES } from "@/constants/ielts";
import { app } from "@/firebase";
import { Module } from "@/interfaces";
import { Stat, User } from "@/interfaces/user";
import { sessionOptions } from "@/lib/session";
import { calculateAverageLevel, calculateBandScore } from "@/utils/score";
import { groupByModule, groupBySession } from "@/utils/stats";
import { MODULE_ARRAY } from "@/utils/moduleUtils";
import client from "@/lib/mongodb";
import {withIronSessionApiRoute} from "iron-session/next";
import {groupBy} from "lodash";
import {NextApiRequest, NextApiResponse} from "next";
import { withIronSessionApiRoute } from "iron-session/next";
import { groupBy } from "lodash";
import { NextApiRequest, NextApiResponse } from "next";
import { requestUser } from "@/utils/api";
const db = client.db(process.env.MONGODB_DB);
@@ -29,8 +29,8 @@ async function update(req: NextApiRequest, res: NextApiResponse) {
const stats = await db.collection("stats").find<Stat>({ user: user.id }).toArray();
const groupedStats = groupBySession(stats);
const sessionLevels: {[key in Module]: {correct: number; total: number}}[] = Object.keys(groupedStats).map((key) => {
const sessionStats = groupedStats[key].map((stat) => ({module: stat.module, correct: stat.score.correct, total: stat.score.total}));
const sessionLevels: { [key in Module]: { correct: number; total: number } }[] = Object.keys(groupedStats).map((key) => {
const sessionStats = groupedStats[key].map((stat) => ({ module: stat.module, correct: stat.score.correct, total: stat.score.total }));
const sessionLevels = {
reading: {
correct: 0,
@@ -59,8 +59,8 @@ async function update(req: NextApiRequest, res: NextApiResponse) {
if (moduleStats.length === 0) return;
const moduleScore = moduleStats.reduce(
(accumulator, current) => ({correct: accumulator.correct + current.correct, total: accumulator.total + current.total}),
{correct: 0, total: 0},
(accumulator, current) => ({ correct: accumulator.correct + current.correct, total: accumulator.total + current.total }),
{ correct: 0, total: 0 },
);
sessionLevels[module] = moduleScore;
@@ -72,24 +72,24 @@ async function update(req: NextApiRequest, res: NextApiResponse) {
const readingLevel = sessionLevels
.map((x) => x.reading)
.filter((x) => x.total > 0)
.reduce((acc, cur) => ({total: acc.total + cur.total, correct: acc.correct + cur.correct}), {total: 0, correct: 0});
.reduce((acc, cur) => ({ total: acc.total + cur.total, correct: acc.correct + cur.correct }), { total: 0, correct: 0 });
const listeningLevel = sessionLevels
.map((x) => x.listening)
.filter((x) => x.total > 0)
.reduce((acc, cur) => ({total: acc.total + cur.total, correct: acc.correct + cur.correct}), {total: 0, correct: 0});
.reduce((acc, cur) => ({ total: acc.total + cur.total, correct: acc.correct + cur.correct }), { total: 0, correct: 0 });
const writingLevel = sessionLevels
.map((x) => x.writing)
.filter((x) => x.total > 0)
.reduce((acc, cur) => ({total: acc.total + cur.total, correct: acc.correct + cur.correct}), {total: 0, correct: 0});
.reduce((acc, cur) => ({ total: acc.total + cur.total, correct: acc.correct + cur.correct }), { total: 0, correct: 0 });
const speakingLevel = sessionLevels
.map((x) => x.speaking)
.filter((x) => x.total > 0)
.reduce((acc, cur) => ({total: acc.total + cur.total, correct: acc.correct + cur.correct}), {total: 0, correct: 0});
.reduce((acc, cur) => ({ total: acc.total + cur.total, correct: acc.correct + cur.correct }), { total: 0, correct: 0 });
const levelLevel = sessionLevels
const levelLevel = sessionLevels
.map((x) => x.level)
.filter((x) => x.total > 0)
.reduce((acc, cur) => ({total: acc.total + cur.total, correct: acc.correct + cur.correct}), {total: 0, correct: 0});
.reduce((acc, cur) => ({ total: acc.total + cur.total, correct: acc.correct + cur.correct }), { total: 0, correct: 0 });
const levels = {
@@ -100,12 +100,14 @@ async function update(req: NextApiRequest, res: NextApiResponse) {
level: calculateBandScore(levelLevel.correct, levelLevel.total, "level", user.focus),
};
const averageLevel = calculateAverageLevel(levels)
await db.collection("users").updateOne(
{ id: user.id},
{ $set: {levels} }
{ id: user.id },
{ $set: { levels, averageLevel } }
);
res.status(200).json({ok: true});
res.status(200).json({ ok: true });
} else {
res.status(401).json(undefined);
}