import { NextRequest, NextResponse } from 'next/server' import { validateUploadSecret } from '@/lib/auth' import { readStagedOriginalFiles } from '@/lib/upload-staging' import { mkdirRecursive, moveFolder, uploadFile, findNextVersion, } from '@/lib/nextcloud' import { acquireUploadLock, releaseUploadLock } from '@/lib/upload-lock' export const runtime = 'nodejs' export const dynamic = 'force-dynamic' // --------------------------------------------------------------------------- // POST /api/upload/drive // // Upload **original** files to Nextcloud Drive. // // JSON body: // - stagingId // - action: "new" | "replace" // // Versioning logic: // VF/{folderName} <- latest version // V1/{folderName} <- first archive, V2/ second, etc. // // action="new" -> just mkdir + upload into VF/ // action="replace" -> archive VF -> Vx, then re-upload all files into VF/ // --------------------------------------------------------------------------- export async function POST(req: NextRequest) { // --- Auth --- const authError = validateUploadSecret(req) if (authError) return authError // --- Check Nextcloud config --- if (!process.env.NEXTCLOUD_URL || !process.env.NEXTCLOUD_SHARE_TOKEN) { return NextResponse.json( { success: false, error: 'Nextcloud non configure sur le serveur (NEXTCLOUD_URL, NEXTCLOUD_SHARE_TOKEN)' }, { status: 500 }, ) } // --- Parse staging request --- let folderName: string let parsedFiles: Awaited>['files'] let action: string try { const body = await req.json() const stagingId = body.stagingId if (!stagingId || typeof stagingId !== 'string') { throw new Error('stagingId manquant') } action = typeof body.action === 'string' ? body.action.trim() || 'new' : 'new' const staged = await readStagedOriginalFiles(stagingId) folderName = staged.folderName parsedFiles = staged.files } catch (err) { const message = err instanceof Error ? err.message : 'Erreur inconnue' return NextResponse.json({ success: false, error: message }, { status: 400 }) } if (!acquireUploadLock(folderName)) { return NextResponse.json( { success: false, error: 'Un upload est deja en cours pour ce dossier. Patientez quelques secondes.' }, { status: 409 }, ) } const basePath = process.env.NEXTCLOUD_BASE_PATH || 'Models' const vfFolderPath = `${basePath}/VF/${folderName}` try { if (action === 'replace') { // 1. Find the next available Vx const nextVersion = await findNextVersion(basePath, folderName) // 2. Ensure Vx/ exists await mkdirRecursive(`${basePath}/${nextVersion}`) // 3. Move VF/{folderName} -> Vx/{folderName} await moveFolder(vfFolderPath, `${basePath}/${nextVersion}/${folderName}`) // 4. Re-create VF/{folderName} await mkdirRecursive(vfFolderPath) } else { // action === 'new': just ensure VF/{folderName} exists await mkdirRecursive(vfFolderPath) } // --- Upload all original files --- for (const pf of parsedFiles) { const remotePath = `${vfFolderPath}/${pf.filename}` await uploadFile(remotePath, pf.buffer) } return NextResponse.json({ success: true, folderName, filesCount: parsedFiles.length, message: `${parsedFiles.length} fichier(s) envoye(s) sur le Drive.`, }) } catch (err) { const message = err instanceof Error ? err.message : 'Erreur Nextcloud inconnue' return NextResponse.json( { success: false, error: `Drive echoue: ${message}` }, { status: 500 }, ) } finally { releaseUploadLock(folderName) } }