aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPitu <[email protected]>2019-10-12 18:18:32 +0900
committerPitu <[email protected]>2019-10-12 18:18:32 +0900
commit2695d192ba253219f41dce259cc53070058cad91 (patch)
tree1d35db90ce66cddc3a587a9c3726c4b1514bb9e0 /src
parentfeature: save uploaded files to album if specified (diff)
downloadhost.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.js134
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