diff --git a/server/controllers/MiscController.js b/server/controllers/MiscController.js index 591f8ccf2..26a3d9f61 100644 --- a/server/controllers/MiscController.js +++ b/server/controllers/MiscController.js @@ -99,6 +99,57 @@ class MiscController { res.sendStatus(200) } + /** + * POST: /api/upload/chunk + * Handle chunked upload + * + * @param {RequestWithUser} req + * @param {Response} res + */ + async handleChunkUpload(req, res) { + if (!req.user.canUpload) { + Logger.warn(`User "${req.user.username}" attempted to upload without permission`) + return res.sendStatus(403) + } + if (!req.files || !Object.values(req.files).length) { + Logger.error('Invalid request, no files') + return res.sendStatus(400) + } + + const { fileId, chunkIndex, totalChunks, filename, library: libraryId, folder: folderId, title, author, series } = req.body + + if (!fileId || chunkIndex === undefined || !totalChunks || !filename || !libraryId || !folderId || !title) { + return res.status(400).send('Invalid request body for chunk upload') + } + + const library = await Database.libraryModel.findByIdWithFolders(libraryId) + if (!library) { + return res.status(404).send('Library not found') + } + if (!req.user.checkCanAccessLibrary(library.id)) { + Logger.error(`[MiscController] User "${req.user.username}" attempting to upload to library "${library.id}" without access`) + return res.sendStatus(403) + } + + const tmpDir = Path.join(global.MetadataPath, 'tmp', 'uploads', fileId) + await fs.ensureDir(tmpDir) + + const file = Object.values(req.files)[0] + const chunkPath = Path.join(tmpDir, `${fileId}_${chunkIndex}`) + + try { + await file.mv(chunkPath) + + // If this is the last chunk, we trigger reassembly. + // To keep the commit scoped to "Temporary Storage", we will return success here for now + // and implement the reassembly in Commit 2. + res.sendStatus(200) + } catch (error) { + Logger.error(`Failed to move chunk ${chunkIndex} for file ${fileId}`, error) + return res.status(500).send('Failed to save chunk') + } + } + /** * GET: /api/tasks * Get tasks for task manager diff --git a/server/routers/ApiRouter.js b/server/routers/ApiRouter.js index e89b364f3..95de5c957 100644 --- a/server/routers/ApiRouter.js +++ b/server/routers/ApiRouter.js @@ -339,6 +339,7 @@ class ApiRouter { // Misc Routes // this.router.post('/upload', MiscController.handleUpload.bind(this)) + this.router.post('/upload/chunk', MiscController.handleChunkUpload.bind(this)) this.router.get('/tasks', MiscController.getTasks.bind(this)) this.router.patch('/settings', MiscController.updateServerSettings.bind(this)) this.router.patch('/sorting-prefixes', MiscController.updateSortingPrefixes.bind(this))