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 'existantGroupIds': res.status(200).json(await existantGroupIds(req.body.names)); break; case 'crossRefOwnership': res.status(200).json(await crossRefOwnership(req.body)); break; case 'getIds': res.status(200).json(await getIds(req.body)); break; case 'deletePriorEntitiesGroups': await deletePriorEntitiesGroups(req.body); res.status(200).json({ ok: true }); 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 { const { userId, classrooms, entity } = body; const existingClassrooms = await db.collection('groups') .find({ name: { $in: classrooms }, admin: { $ne: userId } }) .project({ name: 1, admin: 1, _id: 0 }) .toArray(); if (existingClassrooms.length === 0) { return []; } const adminUsers = await db.collection('users') .find({ id: { $in: existingClassrooms.map(classroom => classroom.admin) } }) .project({ id: 1, entities: 1, _id: 0 }) .toArray(); const adminEntitiesMap = new Map( adminUsers.map(admin => [ admin.id, admin.entities?.map((e: any) => e.id) || [] ]) ); return Array.from(new Set( existingClassrooms .filter(classroom => { const adminEntities = adminEntitiesMap.get(classroom.admin) || []; return adminEntities.includes(entity); }) .map(classroom => classroom.name) )); } async function getIds(body: any): Promise> { 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), users: users.reduce((acc, user) => { acc[user.email] = user.id; return acc; }, {} as Record) }; } async function deletePriorEntitiesGroups(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, _id: 0 }) .toArray(); // if the user doesn't have the target entity mark them for all groups deletion const toDeleteUserIds = users .filter(user => !user.entities?.some((e: any) => e.id === entity)) .map(user => user.id); if (toDeleteUserIds.length === 0) { return; } const affectedGroups = await db.collection('groups') .find({ participants: { $in: toDeleteUserIds } }) .project({ id: 1, _id: 0 }) .toArray(); await db.collection('groups').updateMany( { participants: { $in: toDeleteUserIds } }, { $pull: { participants: { $in: toDeleteUserIds } } } as any ); // delete groups that were updated and have no participants await db.collection('groups').deleteMany({ id: { $in: affectedGroups.map(g => g.id) }, participants: { $size: 0 } }); } async function existantGroupIds(names: string[]) { const existingGroups = await db.collection('groups') .find({ name: { $in: names } }) .project({ id: 1, name: 1, _id: 0 }) .toArray(); return existingGroups.reduce((acc, group) => { acc[group.name] = group.id; return acc; }, {} as Record); }