// app/api/admin/allowed-students/import/route.ts import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; import { getServerSession } from 'next-auth'; import { authOptions } from '@/lib/auth-options'; import { prisma } from '@/lib/prisma'; import { normalizeEmail } from '@/lib/normalize-email'; // Check if user is admin async function checkAdmin(req: NextRequest) { const session = await getServerSession(authOptions); if (!session?.user?.email) { return null; } const role = (session as any)?.user?.role ?? null; if (!(role === 'admin' || role === 'superadmin')) { return null; } return session; } // POST import students from CSV export async function POST(req: NextRequest) { try { const session = await checkAdmin(req); if (!session) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const formData = await req.formData(); const file = formData.get('file') as File; if (!file) { return NextResponse.json({ error: 'No file provided' }, { status: 400 }); } // Read file const text = await file.text(); const lines = text.split('\n').filter((line) => line.trim().length > 0); if (lines.length === 0) { return NextResponse.json({ error: 'CSV file is empty' }, { status: 400 }); } // Skip header row if it exists (assume first line is header if email doesn't look like email) let startIndex = 0; if (lines[0].toLowerCase().includes('email')) { startIndex = 1; } const results = { imported: 0, updated: 0, errors: [] as Array<{ row: number; email: string; error: string }>, }; for (let i = startIndex; i < lines.length; i++) { const line = lines[i].trim(); if (!line) continue; const [email, levels] = line.split(',').map((v) => v.trim()); const normalizedEmail = normalizeEmail(email); if (!normalizedEmail || !levels) { results.errors.push({ row: i + 1, email: email || 'N/A', error: 'Invalid format: expected "email,courseCodes"', }); continue; } // Validate email format if (!email.includes('@')) { results.errors.push({ row: i + 1, email, error: 'Invalid email format', }); continue; } // Validate levels are valid course codes const levelArray = levels.split('|').map((l) => l.trim()); let invalidLevel = null; for (const level of levelArray) { const course = await prisma.course.findUnique({ where: { code: level } }); if (!course) { invalidLevel = level; break; } } if (invalidLevel) { results.errors.push({ row: i + 1, email, error: `Course code '${invalidLevel}' not found`, }); continue; } try { // Check if student already exists const existing = await prisma.allowedStudent.findFirst({ where: { email: { equals: normalizedEmail, mode: 'insensitive', }, }, }); if (existing) { // Update existing await prisma.allowedStudent.update({ where: { id: existing.id }, data: { email: normalizedEmail, levels: levelArray.join(','), active: true, }, }); results.updated++; } else { // Create new await prisma.allowedStudent.create({ data: { email: normalizedEmail, levels: levelArray.join(','), active: true, }, }); results.imported++; } } catch (err) { results.errors.push({ row: i + 1, email, error: `Database error: ${(err as any)?.message || 'Unknown error'}`, }); } } return NextResponse.json(results); } catch (err) { console.error('POST /api/admin/allowed-students/import error', err); return NextResponse.json( { error: 'Failed to import students' }, { status: 500 } ); } }