diff options
| author | Pitu <[email protected]> | 2019-10-12 18:18:32 +0900 |
|---|---|---|
| committer | Pitu <[email protected]> | 2019-10-12 18:18:32 +0900 |
| commit | 2695d192ba253219f41dce259cc53070058cad91 (patch) | |
| tree | 1d35db90ce66cddc3a587a9c3726c4b1514bb9e0 /src | |
| parent | feature: save uploaded files to album if specified (diff) | |
| download | host.fuwn.me-2695d192ba253219f41dce259cc53070058cad91.tar.xz host.fuwn.me-2695d192ba253219f41dce259cc53070058cad91.zip | |
feature: prevent duplicated files
- If the user uploads a file that already exists under their account, it will return the previous url
- If an anonymous user uploads a file and already exists previously from another anon, return that url
- Files are unique per account since they can be deleted, anonymous files can't
Diffstat (limited to 'src')
| -rw-r--r-- | src/api/routes/uploads/uploadPOST.js | 134 |
1 files changed, 87 insertions, 47 deletions
diff --git a/src/api/routes/uploads/uploadPOST.js b/src/api/routes/uploads/uploadPOST.js index 3411abc..d35b9fc 100644 --- a/src/api/routes/uploads/uploadPOST.js +++ b/src/api/routes/uploads/uploadPOST.js @@ -42,63 +42,66 @@ class uploadPOST extends Route { if (err) console.error(err.message); let uploadedFile = {}; - let originalFile; let insertedId; - const now = moment.utc().toDate(); const remappedKeys = this._remapKeys(req.body); - for (const file of req.files) { - originalFile = file; - const ext = path.extname(file.originalname); - const hash = Util.generateFileHash(file.buffer); - const filename = Util.getUniqueFilename(file.originalname); - if (remappedKeys && remappedKeys.uuid) { - const chunkOutput = path.join(__dirname, - '..', - '..', - '..', - '..', - process.env.UPLOAD_FOLDER, - 'chunks', - remappedKeys.uuid, - `${remappedKeys.chunkindex.padStart(3, 0)}${ext || ''}`); - await jetpack.writeAsync(chunkOutput, file.buffer); - } else { - const output = path.join(__dirname, - '..', - '..', - '..', - '..', - process.env.UPLOAD_FOLDER, - filename); - await jetpack.writeAsync(output, file.buffer); - uploadedFile = { - name: filename, - hash, - size: file.buffer.length, - url: filename - }; - } + const file = req.files[0]; + + const ext = path.extname(file.originalname); + const hash = Util.generateFileHash(file.buffer); + + const filename = Util.getUniqueFilename(file.originalname); + + /* + First let's get the hash of the file. This will be useful to check if the file + has already been upload by either the user or an anonymous user. + In case this is true, instead of uploading it again we retrieve the url + of the file that is already saved and thus don't store extra copies of the same file. + + For this we need to wait until we have a filename so that we can delete the uploaded file. + */ + const exists = await this.checkIfFileExists(db, user, hash); + if (exists) return this.fileExists(res, exists, filename); + + if (remappedKeys && remappedKeys.uuid) { + const chunkOutput = path.join(__dirname, + '..', + '..', + '..', + '..', + process.env.UPLOAD_FOLDER, + 'chunks', + remappedKeys.uuid, + `${remappedKeys.chunkindex.padStart(3, 0)}${ext || ''}`); + await jetpack.writeAsync(chunkOutput, file.buffer); + } else { + const output = path.join(__dirname, + '..', + '..', + '..', + '..', + process.env.UPLOAD_FOLDER, + filename); + await jetpack.writeAsync(output, file.buffer); + uploadedFile = { + name: filename, + hash, + size: file.buffer.length, + url: filename + }; } if (!remappedKeys || !remappedKeys.uuid) { Util.generateThumbnails(uploadedFile.name); - insertedId = await this.saveFileToDatabase(req, res, user, db, uploadedFile, originalFile); + insertedId = await this.saveFileToDatabase(req, res, user, db, uploadedFile, file); if (!insertedId) return res.status(500).json({ message: 'There was an error saving the file.' }); uploadedFile.deleteUrl = `${process.env.DOMAIN}/api/file/${insertedId[0]}`; - } - /* - If the upload had an album specified we make sure to create the relation - and update the according timestamps.. - */ - if (albumId) { - try { - await db.table('albumsFiles').insert({ albumId, fileId: insertedId[0] }); - await db.table('albums').where('id', albumId).update('editedAt', now); - } catch (error) { - console.error(error); - } + /* + If the upload had an album specified we make sure to create the relation + and update the according timestamps.. + */ + this.saveFileToAlbum(db, albumId, insertedId); } return res.status(201).send({ @@ -108,6 +111,43 @@ class uploadPOST extends Route { }); } + fileExists(res, exists, filename) { + res.json({ + message: 'Successfully uploaded the file.', + name: exists.name, + hash: exists.hash, + size: exists.size, + url: `${process.env.DOMAIN}/${exists.name}`, + deleteUrl: `${process.env.DOMAIN}/api/file/${exists.id}`, + repeated: true + }); + + return Util.deleteFile(filename); + } + + async checkIfFileExists(db, user, hash) { + const exists = await db.table('files') + .where(function() { // eslint-disable-line func-names + if (user) this.where('userId', user.id); + else this.whereNull('userId'); + }) + .where({ hash }) + .first(); + return exists; + } + + async saveFileToAlbum(db, albumId, insertedId) { + if (!albumId) return; + + const now = moment.utc().toDate(); + try { + await db.table('albumsFiles').insert({ albumId, fileId: insertedId[0] }); + await db.table('albums').where('id', albumId).update('editedAt', now); + } catch (error) { + console.error(error); + } + } + async saveFileToDatabase(req, res, user, db, file, originalFile) { /* Save the upload information to the database |