From f69ca010b80703389fffe75fc6dca907e53df74d Mon Sep 17 00:00:00 2001 From: diogo464 Date: Mon, 11 Aug 2025 13:40:27 +0100 Subject: basic file upload --- frontend/app/api/upload/route.ts | 127 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 frontend/app/api/upload/route.ts (limited to 'frontend/app/api') diff --git a/frontend/app/api/upload/route.ts b/frontend/app/api/upload/route.ts new file mode 100644 index 0000000..eb1ecaa --- /dev/null +++ b/frontend/app/api/upload/route.ts @@ -0,0 +1,127 @@ +import { NextRequest, NextResponse } from 'next/server' +import { writeFile, unlink } from 'fs/promises' +import { tmpdir } from 'os' +import { join } from 'path' +import { randomUUID } from 'crypto' +import { Auth_get_user, Auth_user_can_upload } from '@/lib/auth' +import { Drive_import } from '@/lib/drive' +import { UPLOAD_MAX_FILE_SIZE, UPLOAD_MAX_FILES } from '@/lib/constants' +import { revalidatePath } from 'next/cache' + +export async function POST(request: NextRequest) { + try { + // Check user authentication and permissions + const user = await Auth_get_user() + if (!user.isLoggedIn) { + return NextResponse.json({ error: 'User not authenticated' }, { status: 401 }) + } + + if (!Auth_user_can_upload(user)) { + return NextResponse.json({ error: 'User does not have upload permissions' }, { status: 403 }) + } + + // Parse form data + const formData = await request.formData() + const files = formData.getAll('files') as File[] + const targetPath = formData.get('targetPath') as string || '' + + // Validate files + if (!files || files.length === 0) { + return NextResponse.json({ error: 'No files provided' }, { status: 400 }) + } + + if (files.length > UPLOAD_MAX_FILES) { + return NextResponse.json({ + error: `Too many files. Maximum ${UPLOAD_MAX_FILES} files allowed` + }, { status: 400 }) + } + + // Validate each file + for (const file of files) { + if (file.size > UPLOAD_MAX_FILE_SIZE) { + return NextResponse.json({ + error: `File '${file.name}' exceeds maximum size of ${UPLOAD_MAX_FILE_SIZE / (1024 * 1024)}MB` + }, { status: 400 }) + } + } + + const uploadResults = [] + const tempFiles: string[] = [] + + try { + // Process each file + for (const file of files) { + // Create temporary file + const tempFileName = `${randomUUID()}-${file.name}` + const tempFilePath = join(tmpdir(), tempFileName) + tempFiles.push(tempFilePath) + + // Save file to temporary location + const bytes = await file.arrayBuffer() + const buffer = Buffer.from(bytes) + await writeFile(tempFilePath, buffer) + + // Determine target drive path + const driveFilePath = targetPath ? `${targetPath}/${file.name}` : `/${file.name}` + + try { + // Import file using Drive_import + await Drive_import(tempFilePath, driveFilePath, user.email) + uploadResults.push({ + filename: file.name, + success: true, + message: 'File uploaded successfully' + }) + } catch (error) { + console.error(`Failed to import file ${file.name}:`, error) + uploadResults.push({ + filename: file.name, + success: false, + message: error instanceof Error ? error.message : 'Unknown error during import' + }) + } + } + + // Clean up temporary files + for (const tempFile of tempFiles) { + try { + await unlink(tempFile) + } catch (error) { + console.error(`Failed to delete temp file ${tempFile}:`, error) + } + } + + // Revalidate the target path to refresh the directory listing + revalidatePath(`/drive${targetPath}`) + revalidatePath('/drive') + + // Check if any uploads succeeded + const successfulUploads = uploadResults.filter(result => result.success) + const failedUploads = uploadResults.filter(result => !result.success) + + return NextResponse.json({ + success: true, + message: `${successfulUploads.length} files uploaded successfully${failedUploads.length > 0 ? `, ${failedUploads.length} failed` : ''}`, + results: uploadResults + }) + + } catch (error) { + // Clean up temporary files on error + for (const tempFile of tempFiles) { + try { + await unlink(tempFile) + } catch (cleanupError) { + console.error(`Failed to delete temp file during cleanup ${tempFile}:`, cleanupError) + } + } + throw error + } + + } catch (error) { + console.error('Upload error:', error) + return NextResponse.json( + { error: error instanceof Error ? error.message : 'Internal server error' }, + { status: 500 } + ) + } +} \ No newline at end of file -- cgit