Initial commit
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
// 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 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user