Files
encoach_frontend/src/pages/api/users/controller.ts
Carlos-Mesquita bac2a08748 ENCOA-289
2024-12-24 11:52:34 +00:00

344 lines
8.5 KiB
TypeScript

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;
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));
break;
case 'getIds':
res.status(200).json(await getIds(req.body.emails));
break;
case 'assignToEntity':
await assignToEntity(req.body);
res.status(200).json({"ok": true});
break;
case 'getEntities':
res.status(200).json(await getEntities(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();
}
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<Array<{
email: string;
names?: 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) }
}
}
}
}
]
}
},
// Unwind the entities array (if it exists)
{
$unwind: {
path: "$entities",
preserveNullAndEmptyArrays: true
}
},
// Lookup entity details from entities collection
{
$lookup: {
from: 'entities',
localField: 'entities.id',
foreignField: 'id',
as: 'entityDetails'
}
},
// Unwind the entityDetails array
{
$unwind: {
path: "$entityDetails",
preserveNullAndEmptyArrays: true
}
},
// Group by email to collect all entity names in an array
{
$group: {
_id: "$email",
email: { $first: "$email" },
name: {
$push: {
$cond: [
{ $ifNull: ["$entityDetails.label", false] },
"$entityDetails.label",
"$$REMOVE"
]
}
}
}
},
// Final projection to clean up
{
$project: {
_id: 0,
email: 1,
name: 1
}
}
];
const results = await db.collection('users').aggregate(pipeline).toArray();
return results.map(result => ({
email: result.email as string,
names: result.name as string[] | undefined
}));
}
async function crossRefClassrooms(body: any) {
const { sets, entity } = body as { sets: { email: string, classroom: string }[], entity: 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'] },
{
$let: {
vars: {
matchingSet: {
$arrayElemAt: [
{
$filter: {
input: sets,
cond: { $eq: ['$$this.email', '$$userEmail'] }
}
},
0
]
}
},
in: { $eq: ['$name', '$$matchingSet.classroom'] }
}
}
]
}
}
},
// Lookup admin's entities
{
$lookup: {
from: 'users',
let: { adminId: '$admin' },
pipeline: [
{
$match: {
$expr: { $eq: ['$id', '$$adminId'] }
}
}
],
as: 'adminInfo'
}
},
// Filter where admin has the target entity
{
$match: {
$expr: {
$in: [
entity,
{
$map: {
input: { $arrayElemAt: ['$adminInfo.entities', 0] },
as: 'entityObj',
in: '$$entityObj.id'
}
}
]
}
}
}
],
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);
}
async function getIds(emails: string[]): Promise<Array<{ email: string; id: string }>> {
const users = await db.collection('users')
.find({ email: { $in: emails } })
.project({ email: 1, id: 1, _id: 0 })
.toArray();
return users.map(user => ({
email: user.email,
id: user.id
}));
}
async function getEntities(emails: string[]): Promise<Array<{ email: string; entityLabels: string[] }>> {
const users = await db.collection('users')
.find({ email: { $in: emails } })
.project({ email: 1, entities: 1, _id: 0 })
.toArray();
const entityIds = [...new Set(
users.flatMap(user =>
(user.entities || []).map((entity: any) => entity.id)
)
)];
const entityRecords = await db.collection('entities')
.find({ id: { $in: entityIds } })
.project({ id: 1, label: 1, _id: 0 })
.toArray();
const entityMap = new Map(
entityRecords.map(entity => [entity.id, entity.label])
);
return users.map(user => ({
email: user.email,
entityLabels: (user.entities || [])
.map((entity: any) => entityMap.get(entity.id))
.filter((label: string): label is string => !!label)
}));
}
async function assignToEntity(body: any) {
const { ids, entity } = body;
if (!Array.isArray(ids) || ids.length === 0 || !entity) {
return;
}
const users = await db.collection('users')
.find({ id: { $in: ids } })
.project({ id: 1, entities: 1 })
.toArray();
const toUpdateUsers = users.filter((u) => u.entities[0].id !== entity);
if (toUpdateUsers.length > 0) {
const writes = users.map(user => ({
updateOne: {
filter: { id: user.id },
update: {
$set: {
entities: [{
id: entity,
role: user.entities?.[0]?.role
}]
}
}
}
}));
db.collection('users').bulkWrite(writes);
}
}