ENCOA-277, ENCOA-276, ENCOA-282, ENCOA-283
This commit is contained in:
74
src/pages/api/groups/controller.ts
Normal file
74
src/pages/api/groups/controller.ts
Normal 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>)
|
||||
};
|
||||
}
|
||||
67
src/pages/api/transcribe/index.ts
Normal file
67
src/pages/api/transcribe/index.ts
Normal 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,
|
||||
},
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user