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 { 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): Promise> { 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> { 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> { 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); } }