testing yuk
This commit is contained in:
@@ -2,14 +2,14 @@ import { NextRequest, NextResponse } from 'next/server';
|
||||
import * as XLSX from 'xlsx';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
// GET method for testing the route
|
||||
// GET method untuk testing route
|
||||
export async function GET() {
|
||||
return NextResponse.json({ message: 'Upload route is working' });
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
// Get form data from request
|
||||
// Ambil form data dari request
|
||||
const formData = await request.formData();
|
||||
const file = formData.get('file') as File;
|
||||
|
||||
@@ -17,23 +17,23 @@ export async function POST(request: NextRequest) {
|
||||
return NextResponse.json({ message: 'File tidak ditemukan' }, { status: 400 });
|
||||
}
|
||||
|
||||
// Validate file size (max 10MB)
|
||||
// Validasi ukuran file (maksimal 10MB)
|
||||
if (file.size > 10 * 1024 * 1024) {
|
||||
return NextResponse.json({ message: 'File terlalu besar. Maksimal 10MB' }, { status: 400 });
|
||||
}
|
||||
|
||||
// Process file data based on file type
|
||||
// Proses data file berdasarkan tipe file
|
||||
let validData = [];
|
||||
let errors: string[] = [];
|
||||
|
||||
if (file.name.endsWith('.csv') || file.type === 'text/csv') {
|
||||
// Process as CSV
|
||||
// Proses sebagai CSV
|
||||
const fileContent = await file.text();
|
||||
const result = await processCSVData(fileContent);
|
||||
validData = result.validData;
|
||||
errors = result.errors;
|
||||
} else {
|
||||
// Process as Excel
|
||||
// Proses sebagai Excel
|
||||
const fileBuffer = await file.arrayBuffer();
|
||||
const result = await processExcelData(fileBuffer);
|
||||
validData = result.validData;
|
||||
@@ -47,10 +47,10 @@ export async function POST(request: NextRequest) {
|
||||
}, { status: 400 });
|
||||
}
|
||||
|
||||
// Insert valid data into the database
|
||||
// Insert data valid ke database
|
||||
const { imported, errorCount, errorMessages } = await insertDataToDatabase(validData);
|
||||
|
||||
// Combine all error messages
|
||||
// Gabungkan semua pesan error
|
||||
const allErrors = [...errors, ...errorMessages];
|
||||
|
||||
return NextResponse.json({
|
||||
@@ -69,17 +69,17 @@ export async function POST(request: NextRequest) {
|
||||
}
|
||||
}
|
||||
|
||||
// Function to process Excel data
|
||||
// Fungsi untuk memproses data Excel
|
||||
async function processExcelData(fileBuffer: ArrayBuffer) {
|
||||
try {
|
||||
// Parse Excel file
|
||||
// Parse file Excel
|
||||
const workbook = XLSX.read(fileBuffer, { type: 'array' });
|
||||
|
||||
if (!workbook.SheetNames || workbook.SheetNames.length === 0) {
|
||||
return { validData: [], errors: ['File Excel tidak memiliki sheet'] };
|
||||
}
|
||||
|
||||
// Get first sheet
|
||||
// Ambil sheet pertama
|
||||
const sheetName = workbook.SheetNames[0];
|
||||
const worksheet = workbook.Sheets[sheetName];
|
||||
|
||||
@@ -87,7 +87,7 @@ async function processExcelData(fileBuffer: ArrayBuffer) {
|
||||
return { validData: [], errors: ['Sheet pertama tidak ditemukan'] };
|
||||
}
|
||||
|
||||
// Convert to JSON with proper typing
|
||||
// Konversi ke JSON dengan tipe yang tepat
|
||||
const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 }) as any[][];
|
||||
|
||||
if (jsonData.length === 0) {
|
||||
@@ -98,11 +98,11 @@ async function processExcelData(fileBuffer: ArrayBuffer) {
|
||||
return { validData: [], errors: ['File Excel hanya memiliki header, tidak ada data'] };
|
||||
}
|
||||
|
||||
// Convert Excel data to CSV-like format for processing
|
||||
// Konversi data Excel ke format seperti CSV untuk diproses
|
||||
const headers = jsonData[0].map(h => String(h).toLowerCase());
|
||||
const rows = jsonData.slice(1);
|
||||
|
||||
// Process the data using the common function
|
||||
// Proses data menggunakan fungsi yang sama
|
||||
return processData(headers, rows);
|
||||
} catch (error) {
|
||||
console.error('Error processing Excel data:', error);
|
||||
@@ -110,7 +110,7 @@ async function processExcelData(fileBuffer: ArrayBuffer) {
|
||||
}
|
||||
}
|
||||
|
||||
// Function to process CSV data
|
||||
// Fungsi untuk memproses data CSV
|
||||
async function processCSVData(fileContent: string) {
|
||||
const lines = fileContent.split(/\r?\n/).filter(line => line.trim() !== '');
|
||||
|
||||
@@ -118,19 +118,19 @@ async function processCSVData(fileContent: string) {
|
||||
return { validData: [], errors: ['File CSV kosong'] };
|
||||
}
|
||||
|
||||
// Get headers from first line
|
||||
// Ambil header dari baris pertama
|
||||
const headerLine = lines[0].toLowerCase();
|
||||
const headers = headerLine.split(',').map(h => h.trim());
|
||||
|
||||
// Process data rows
|
||||
// Proses baris data
|
||||
const rows = lines.slice(1).map(line => line.split(',').map(v => v.trim()));
|
||||
|
||||
return processData(headers, rows);
|
||||
}
|
||||
|
||||
// Common function to process data regardless of source format
|
||||
// Fungsi umum untuk memproses data terlepas dari format sumber
|
||||
function processData(headers: string[], rows: any[][]) {
|
||||
// Define expected headers and their possible variations
|
||||
// Definisikan header yang diharapkan dan variasi yang mungkin
|
||||
const expectedHeaderMap = {
|
||||
nim: ['nim', 'nomor induk', 'nomor mahasiswa'],
|
||||
nama_beasiswa: ['nama_beasiswa', 'nama beasiswa', 'namabeasiswa', 'beasiswa', 'nama'],
|
||||
@@ -138,7 +138,7 @@ function processData(headers: string[], rows: any[][]) {
|
||||
jenis_beasiswa: ['jenis_beasiswa', 'jenis beasiswa', 'jenisbeasiswa', 'jenis']
|
||||
};
|
||||
|
||||
// Map actual headers to expected headers
|
||||
// Map header aktual ke header yang diharapkan
|
||||
const headerMap: { [key: string]: number } = {};
|
||||
for (const [expectedHeader, variations] of Object.entries(expectedHeaderMap)) {
|
||||
const index = headers.findIndex(h =>
|
||||
@@ -149,7 +149,7 @@ function processData(headers: string[], rows: any[][]) {
|
||||
}
|
||||
}
|
||||
|
||||
// Check required headers
|
||||
// Cek header yang wajib ada
|
||||
const requiredHeaders = ['nim', 'nama_beasiswa', 'sumber_beasiswa', 'jenis_beasiswa'];
|
||||
const missingHeaders = requiredHeaders.filter(h => headerMap[h] === undefined);
|
||||
|
||||
@@ -164,34 +164,34 @@ function processData(headers: string[], rows: any[][]) {
|
||||
const errors = [];
|
||||
const validJenis = ['Pemerintah', 'Non-Pemerintah'];
|
||||
|
||||
// Process data rows
|
||||
// Proses baris data
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
const values = rows[i];
|
||||
if (!values || values.length === 0) continue;
|
||||
|
||||
try {
|
||||
// Extract values using header map
|
||||
// Ekstrak nilai menggunakan header map
|
||||
const nim = String(values[headerMap.nim] || '').trim();
|
||||
const nama_beasiswa = String(values[headerMap.nama_beasiswa] || '').trim();
|
||||
const sumber_beasiswa = String(values[headerMap.sumber_beasiswa] || '').trim();
|
||||
let jenis_beasiswa = String(values[headerMap.jenis_beasiswa] || '').trim();
|
||||
|
||||
// Validate required fields
|
||||
// Validasi field yang wajib diisi
|
||||
if (!nim || !nama_beasiswa || !sumber_beasiswa || !jenis_beasiswa) {
|
||||
errors.push(`Baris ${i+2}: Data tidak lengkap (NIM: ${nim || 'kosong'})`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Normalize jenis beasiswa
|
||||
// Normalisasi jenis beasiswa
|
||||
jenis_beasiswa = normalizeJenisBeasiswa(jenis_beasiswa);
|
||||
|
||||
// Validate jenis beasiswa
|
||||
// Validasi jenis beasiswa
|
||||
if (!validJenis.includes(jenis_beasiswa)) {
|
||||
errors.push(`Baris ${i+2}: Jenis beasiswa tidak valid "${jenis_beasiswa}" untuk NIM ${nim}. Harus salah satu dari: ${validJenis.join(', ')}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add to valid data
|
||||
// Tambahkan ke data valid
|
||||
validData.push({
|
||||
nim,
|
||||
nama_beasiswa,
|
||||
@@ -207,7 +207,7 @@ function processData(headers: string[], rows: any[][]) {
|
||||
return { validData, errors };
|
||||
}
|
||||
|
||||
// Function to normalize jenis beasiswa values
|
||||
// Fungsi untuk menormalisasi nilai jenis beasiswa
|
||||
function normalizeJenisBeasiswa(value: string): string {
|
||||
const lowerValue = value.toLowerCase();
|
||||
|
||||
@@ -219,20 +219,20 @@ function normalizeJenisBeasiswa(value: string): string {
|
||||
return 'Non-Pemerintah';
|
||||
}
|
||||
|
||||
return value; // Return original if no match
|
||||
return value; // Return original jika tidak ada match
|
||||
}
|
||||
|
||||
// Function to insert data into database
|
||||
// Fungsi untuk insert data ke database
|
||||
async function insertDataToDatabase(data: any[]) {
|
||||
let imported = 0;
|
||||
let errorCount = 0;
|
||||
const errorMessages: string[] = [];
|
||||
|
||||
// First, validate all NIMs exist before processing
|
||||
// Pertama, validasi semua NIM ada sebelum diproses
|
||||
const uniqueNims = [...new Set(data.map(item => item.nim))];
|
||||
const nimValidationMap = new Map();
|
||||
|
||||
// Batch check all NIMs for existence
|
||||
// Cek batch semua NIM untuk keberadaan
|
||||
for (const nim of uniqueNims) {
|
||||
try {
|
||||
const { data: mahasiswaData, error: checkError } = await supabase
|
||||
@@ -251,7 +251,7 @@ async function insertDataToDatabase(data: any[]) {
|
||||
}
|
||||
}
|
||||
|
||||
// Process each data item
|
||||
// Proses setiap item data
|
||||
for (const item of data) {
|
||||
try {
|
||||
const nimValidation = nimValidationMap.get(item.nim);
|
||||
@@ -263,7 +263,7 @@ async function insertDataToDatabase(data: any[]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if beasiswa already exists for this mahasiswa and nama_beasiswa
|
||||
// Cek apakah beasiswa sudah ada untuk mahasiswa ini dan nama_beasiswa
|
||||
const { data: existingBeasiswa, error: beasiswaCheckError } = await supabase
|
||||
.from('beasiswa_mahasiswa')
|
||||
.select('id_beasiswa')
|
||||
@@ -272,7 +272,7 @@ async function insertDataToDatabase(data: any[]) {
|
||||
.single();
|
||||
|
||||
if (existingBeasiswa) {
|
||||
// Update existing beasiswa
|
||||
// Update beasiswa yang sudah ada
|
||||
const { error: updateError } = await supabase
|
||||
.from('beasiswa_mahasiswa')
|
||||
.update({
|
||||
@@ -288,7 +288,7 @@ async function insertDataToDatabase(data: any[]) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// Insert new beasiswa
|
||||
// Insert beasiswa baru
|
||||
const { error: insertError } = await supabase
|
||||
.from('beasiswa_mahasiswa')
|
||||
.insert({
|
||||
|
||||
Reference in New Issue
Block a user