ENCOA-277, ENCOA-276, ENCOA-282, ENCOA-283

This commit is contained in:
Carlos-Mesquita
2024-12-21 19:23:53 +00:00
parent f6d387ce2d
commit 98a1636d0c
31 changed files with 2513 additions and 194 deletions

View File

@@ -0,0 +1,74 @@
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 'crossRefOwnership':
res.status(200).json(await crossRefOwnership(req.body));
break;
case 'getIds':
res.status(200).json(await getIds(req.body));
break;
default:
res.status(400).json({ error: 'Invalid operation!' })
}
} else {
res.status(400).end(`Method ${req.method} Not Allowed`)
}
}
async function crossRefOwnership(body: any): Promise<string[]> {
const { userId, classrooms } = body;
// First find which classrooms from input exist
const existingClassrooms = await db.collection('groups')
.find({ name: { $in: classrooms } })
.project({ name: 1, admin: 1, _id: 0 })
.toArray();
// From those existing classrooms, return the ones where user is NOT the admin
return existingClassrooms
.filter(classroom => classroom.admin !== userId)
.map(classroom => classroom.name);
}
async function getIds(body: any): Promise<Record<string, string>> {
const { names, userEmails } = body;
const existingGroups: any[] = await db.collection('groups')
.find({ name: { $in: names } })
.project({ name: 1, id: 1, _id: 0 })
.toArray();
const users: any[] = await db.collection('users')
.find({ email: { $in: userEmails } })
.project({ email: 1, id: 1, _id: 0 })
.toArray();
return {
groups: existingGroups.reduce((acc, group) => {
acc[group.name] = group.id;
return acc;
}, {} as Record<string, string>),
users: users.reduce((acc, user) => {
acc[user.email] = user.id;
return acc;
}, {} as Record<string, string>)
};
}

View File

@@ -0,0 +1,67 @@
// 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 formidable from "formidable-serverless";
import fs from "fs";
import FormData from 'form-data';
export default withIronSessionApiRoute(handler, sessionOptions);
async function handler(req: NextApiRequest, res: NextApiResponse) {
if (!req.session.user) {
return res.status(401).json({ ok: false });
}
const form = new formidable.IncomingForm();
try {
const files = await new Promise((resolve, reject) => {
form.parse(req, (err: any, _: any, files: any) => {
if (err) reject(err);
else resolve(files);
});
});
const audioFile = (files as any).audio;
if (!audioFile) {
return res.status(400).json({ ok: false, error: 'Audio file not found in request' });
}
const formData = new FormData();
const buffer = fs.readFileSync(audioFile.path);
formData.append('audio', buffer, audioFile.name);
try {
const response = await axios.post(
`${process.env.BACKEND_URL}/listening/transcribe`,
formData,
{
headers: {
...formData.getHeaders(),
Authorization: `Bearer ${process.env.BACKEND_JWT}`,
},
}
);
return res.status(200).json(response.data);
} finally {
if (fs.existsSync(audioFile.path)) {
fs.rmSync(audioFile.path);
}
}
} catch (error) {
console.error('Error:', error);
return res.status(500).json({ ok: false });
}
}
export const config = {
api: {
bodyParser: false,
},
};

View File

@@ -19,11 +19,20 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
}
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!' })
case 'crossRefEmails':
res.status(200).json(await crossRefEmails(req.body.emails));
break;
case 'dontExist':
res.status(200).json(await dontExist(req.body.emails))
break;
case 'entityCheck':
res.status(200).json(await entityCheck(req.body));
break;
case 'crossRefClassrooms':
res.status(200).json(await crossRefClassrooms(req.body.sets));
break;
default:
res.status(400).json({ error: 'Invalid operation!' })
}
} else {
res.status(400).end(`Method ${req.method} Not Allowed`)
@@ -44,4 +53,126 @@ async function crossRefEmails(emails: string[]) {
}
}
]).toArray();
}
}
async function dontExist(emails: string[]): Promise<string[]> {
const existingUsers = await db.collection('users')
.find(
{ email: { $in: emails } },
{ projection: { _id: 0, email: 1 } }
)
.toArray();
const existingEmails = new Set(existingUsers.map(u => u.email));
return emails.filter(email => !existingEmails.has(email));
}
async function entityCheck(body: Record<string, any>): Promise<string[]> {
const { entities, emails } = body;
const pipeline = [
// Match users with the provided emails
{
$match: {
email: { $in: emails }
}
},
// Match users who don't have any of the entities
{
$match: {
$or: [
// Either they have no entities array
{ entities: { $exists: false } },
// Or their entities array is empty
{ entities: { $size: 0 } },
// Or none of their entities match the provided IDs
{
entities: {
$not: {
$elemMatch: {
id: { $in: entities.map((e: any) => e.id) }
}
}
}
}
]
}
},
// Project only the email field
{
$project: {
_id: 0,
email: 1
}
}
];
const results = await db.collection('users').aggregate(pipeline).toArray();
return results.map((result: any) => result.email);
}
async function crossRefClassrooms(sets: { email: string, classroom: string }[]) {
const pipeline = [
// Match users with the provided emails
{
$match: {
email: { $in: sets.map(set => set.email) }
}
},
// Lookup groups that contain the user's ID in participants
{
$lookup: {
from: 'groups',
let: { userId: '$id', userEmail: '$email' },
pipeline: [
{
$match: {
$expr: {
$and: [
{ $in: ['$$userId', '$participants'] },
{
// Match the classroom that corresponds to this user's email
$let: {
vars: {
matchingSet: {
$arrayElemAt: [
{
$filter: {
input: sets,
cond: { $eq: ['$$this.email', '$$userEmail'] }
}
},
0
]
}
},
in: { $eq: ['$name', '$$matchingSet.classroom'] }
}
}
]
}
}
}
],
as: 'matchingGroups'
}
},
// Only keep users who have matching groups
{
$match: {
matchingGroups: { $ne: [] }
}
},
// Project only the email
{
$project: {
_id: 0,
email: 1
}
}
];
const results = await db.collection('users').aggregate(pipeline).toArray();
return results.map((result: any) => result.email);
}