aboutsummaryrefslogtreecommitdiff
path: root/src/api/routes/files
diff options
context:
space:
mode:
authorPitu <[email protected]>2018-09-19 04:45:50 -0300
committerPitu <[email protected]>2018-09-19 04:45:50 -0300
commit430af8306b1ab17e59a6dabf8f65ab816d28695d (patch)
tree975814e80919cc7b8c5d820080a30def32a371ea /src/api/routes/files
parentSome adjustements to public album view (diff)
downloadhost.fuwn.me-430af8306b1ab17e59a6dabf8f65ab816d28695d.tar.xz
host.fuwn.me-430af8306b1ab17e59a6dabf8f65ab816d28695d.zip
Switch to Nuxt.js
Diffstat (limited to 'src/api/routes/files')
-rw-r--r--src/api/routes/files/uploadPOST_Multer.js.bak380
1 files changed, 380 insertions, 0 deletions
diff --git a/src/api/routes/files/uploadPOST_Multer.js.bak b/src/api/routes/files/uploadPOST_Multer.js.bak
new file mode 100644
index 0000000..d6e6436
--- /dev/null
+++ b/src/api/routes/files/uploadPOST_Multer.js.bak
@@ -0,0 +1,380 @@
+const Route = require('../../structures/Route');
+const config = require('../../../../config');
+const path = require('path');
+const multer = require('multer');
+const Util = require('../../utils/Util');
+const db = require('knex')(config.server.database);
+const moment = require('moment');
+const log = require('../../utils/Log');
+const jetpack = require('fs-jetpack');
+const Busboy = require('busboy');
+const fs = require('fs');
+// WE SHOULD ALSO STRIP EXIF UNLESS THE USER SPECIFIED THEY WANT IT.
+// https://github.com/WeebDev/lolisafe/issues/110
+class uploadPOST extends Route {
+ constructor() {
+ super('/upload', 'post', { bypassAuth: true });
+ }
+
+ async run(req, res) {
+ const user = Util.isAuthorized(req);
+ if (!user && !config.uploads.allowAnonymousUploads) return res.status(401).json({ message: 'Not authorized to use this resource' });
+
+ /*
+ const albumId = req.body.albumId || req.headers.albumId;
+ if (this.albumId && !this.user) return res.status(401).json({ message: 'Only registered users can upload files to an album' });
+ if (this.albumId && this.user) {
+ const album = await db.table('albums').where({ id: this.albumId, userId: this.user.id }).first();
+ if (!album) return res.status(401).json({ message: 'Album doesn\'t exist or it doesn\'t belong to the user' });
+ }
+ */
+ return this.uploadFile(req, res, user);
+ }
+
+ async processFile(req, res, user, file) {
+ /*
+ Check if the user is trying to upload to an album
+ */
+ const albumId = req.body.albumId || req.headers.albumId;
+ if (albumId && !user) return res.status(401).json({ message: 'Only registered users can upload files to an album' });
+ if (albumId && user) {
+ const album = await db.table('albums').where({ id: albumId, userId: user.id }).first();
+ if (!album) return res.status(401).json({ message: 'Album doesn\'t exist or it doesn\'t belong to the user' });
+ }
+
+ let upload = file.data;
+ /*
+ If it's a chunked upload but this is not the last part of the chunk, just green light.
+ Otherwise, put the file together and process it
+ */
+ if (file.body.uuid) {
+ if (file.body.chunkindex < file.body.totalchunkcount - 1) { // eslint-disable-line no-lonely-if
+ /*
+ We got a chunk that is not the last part, send smoke signal that we received it.
+ */
+ return res.json({ message: 'Successfully uploaded chunk' });
+ } else {
+ /*
+ Seems we finally got the last part of a chunk upload
+ */
+ const uploadsDir = path.join(__dirname, '..', '..', '..', '..', config.uploads.uploadFolder);
+ const chunkedFileDir = path.join(__dirname, '..', '..', '..', '..', config.uploads.uploadFolder, 'chunks', file.body.uuid);
+ const chunkFiles = await jetpack.findAsync(chunkedFileDir, { matching: '*' });
+ const originalname = chunkFiles[0].substring(0, chunkFiles[0].lastIndexOf('.'));
+
+ const tempFile = {
+ filename: Util.getUniqueFilename(originalname),
+ originalname,
+ size: file.body.totalfilesize
+ };
+
+ for (const chunkFile of chunkFiles) {
+ try {
+ const data = await jetpack.readAsync(chunkFile, 'buffer'); // eslint-disable-line no-await-in-loop
+ await jetpack.appendAsync(path.join(uploadsDir, tempFile.filename), data); // eslint-disable-line no-await-in-loop
+ } catch (error) {
+ console.error(error);
+ }
+ }
+ upload = tempFile;
+ }
+ }
+
+ console.log(upload);
+ const hash = await Util.getFileHash(upload.filename); // eslint-disable-line no-await-in-loop
+ const exists = await db.table('files') // eslint-disable-line no-await-in-loop
+ .where(function() {
+ if (!user) this.whereNull('userId'); // eslint-disable-line no-invalid-this
+ else this.where('userId', user.id); // eslint-disable-line no-invalid-this
+ })
+ .where({
+ hash,
+ size: upload.size
+ })
+ .first();
+
+ if (exists) {
+ res.json({
+ message: 'Successfully uploaded file',
+ name: exists.name,
+ size: exists.size,
+ url: `${config.filesServeLocation}/${exists.name}`
+ });
+
+ return Util.deleteFile(upload.filename);
+ }
+
+ const now = moment.utc().toDate();
+ try {
+ await db.table('files').insert({
+ userId: user ? user.id : null,
+ name: upload.filename,
+ original: upload.originalname,
+ type: upload.mimetype || '',
+ size: upload.size,
+ hash,
+ ip: req.ip,
+ albumId: albumId ? albumId : null,
+ createdAt: now,
+ editedAt: now
+ });
+ } catch (error) {
+ log.error('There was an error saving the file to the database');
+ console.log(error);
+ return res.status(500).json({ message: 'There was an error uploading the file.' });
+ }
+
+ res.json({
+ message: 'Successfully uploaded file',
+ name: upload.filename,
+ size: upload.size,
+ url: `${config.filesServeLocation}/${upload.filename}`
+ });
+
+ if (albumId) {
+ try {
+ db.table('albums').where('id', albumId).update('editedAt', now);
+ } catch (error) {
+ log.error('There was an error updating editedAt on an album');
+ console.error(error);
+ }
+ }
+
+ // return Util.generateThumbnail(file.filename);
+ }
+
+ uploadFile(req, res, user) {
+ const busboy = new Busboy({
+ headers: req.headers,
+ limits: {
+ fileSize: config.uploads.uploadMaxSize * (1000 * 1000),
+ files: 1
+ }
+ });
+
+ const fileToUpload = {
+ data: {},
+ body: {}
+ };
+
+ /*
+ Note: For this to work on every case, whoever is uploading a chunk
+ should really send the body first and the file last. Otherwise lolisafe
+ may not catch the field on time and the chunk may end up being saved
+ as a standalone file, completely broken.
+ */
+ busboy.on('field', (fieldname, val) => {
+ if (/^dz/.test(fieldname)) {
+ fileToUpload.body[fieldname.substring(2)] = val;
+ } else {
+ fileToUpload.body[fieldname] = val;
+ }
+ });
+
+ /*
+ Hey ther's a file! Let's upload it.
+ */
+ busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
+ let name, saveTo;
+
+ /*
+ Let check whether the file is part of a chunk upload or if it's a standalone one.
+ If the former, we should store them separately and join all the pieces after we
+ receive the last one.
+ */
+ if (!fileToUpload.body.uuid) {
+ name = Util.getUniqueFilename(filename);
+ if (!name) return res.status(500).json({ message: 'There was a problem allocating a filename for your upload' });
+ saveTo = path.join(__dirname, '..', '..', '..', '..', config.uploads.uploadFolder, name);
+ } else {
+ name = `${filename}.${fileToUpload.body.chunkindex}`;
+ const chunkDir = path.join(__dirname, '..', '..', '..', '..', config.uploads.uploadFolder, 'chunks', fileToUpload.body.uuid);
+ jetpack.dir(chunkDir);
+ saveTo = path.join(__dirname, '..', '..', '..', '..', config.uploads.uploadFolder, 'chunks', fileToUpload.body.uuid, name);
+ }
+
+ /*
+ Let's save some metadata for the db.
+ */
+ fileToUpload.data = { filename: name, originalname: filename, encoding, mimetype };
+ const stream = fs.createWriteStream(saveTo);
+
+ file.on('data', data => {
+ fileToUpload.data.size = data.length;
+ });
+
+ /*
+ The file that is being uploaded is bigger than the limit specified on the config file
+ and thus we should close the stream and delete the file.
+ */
+ file.on('limit', () => {
+ file.unpipe(stream);
+ stream.end();
+ jetpack.removeAsync(saveTo);
+ res.status(400).json({ message: 'The file is too big.' });
+ });
+
+ file.pipe(stream);
+ });
+
+ busboy.on('error', err => {
+ log.error('There was an error uploading a file');
+ console.error(err);
+ return res.status(500).json({ message: 'There was an error uploading the file.' });
+ });
+
+ busboy.on('finish', () => this.processFile(req, res, user, fileToUpload));
+ req.pipe(busboy);
+
+ // return req.pipe(busboy);
+
+ /*
+ return upload(this.req, this.res, async err => {
+ if (err) {
+ log.error('There was an error uploading a file');
+ console.error(err);
+ return this.res.status(500).json({ message: 'There was an error uploading the file.' });
+ }
+
+ log.info('---');
+ console.log(this.req.file);
+ log.info('---');
+
+ let file = this.req.file;
+ if (this.req.body.uuid) {
+ // If it's a chunked upload but this is not the last part of the chunk, just green light.
+ // Otherwise, put the file together and process it
+ if (this.req.body.chunkindex < this.req.body.totalchunkcount - 1) { // eslint-disable-line no-lonely-if
+ log.info('Hey this is a chunk, sweet.');
+ return this.res.json({ message: 'Successfully uploaded chunk' });
+ } else {
+ log.info('Hey this is the last part of a chunk, sweet.');
+
+ const uploadsDir = path.join(__dirname, '..', '..', '..', '..', config.uploads.uploadFolder);
+ const chunkedFileDir = path.join(__dirname, '..', '..', '..', '..', config.uploads.uploadFolder, 'chunks', this.req.body.uuid);
+ const chunkFiles = await jetpack.findAsync(chunkedFileDir, { matching: '*' });
+ const originalname = chunkFiles[0].substring(0, chunkFiles[0].lastIndexOf('.'));
+
+ const tempFile = {
+ filename: Util.getUniqueFilename(originalname),
+ originalname,
+ size: this.req.body.totalfilesize
+ };
+
+ for (const chunkFile of chunkFiles) {
+ try {
+ const data = await jetpack.readAsync(chunkFile, 'buffer'); // eslint-disable-line no-await-in-loop
+ await jetpack.appendAsync(path.join(uploadsDir, tempFile.filename), data); // eslint-disable-line no-await-in-loop
+ } catch (error) {
+ console.error(error);
+ }
+ }
+ file = tempFile;
+ }
+ }
+
+ const { user } = this;
+ // console.log(file);
+ if (!file.filename) return log.error('This file doesnt have a filename!');
+ // console.log(file);
+ const hash = await Util.getFileHash(file.filename); // eslint-disable-line no-await-in-loop
+ const exists = await db.table('files') // eslint-disable-line no-await-in-loop
+ .where(function() {
+ if (!user) this.whereNull('userId'); // eslint-disable-line no-invalid-this
+ else this.where('userId', user.id); // eslint-disable-line no-invalid-this
+ })
+ .where({
+ hash,
+ size: file.size
+ })
+ .first();
+
+ if (exists) {
+ this.res.json({
+ message: 'Successfully uploaded file',
+ name: exists.name,
+ size: exists.size,
+ url: `${config.filesServeLocation}/${exists.name}`
+ });
+
+ return Util.deleteFile(file.filename);
+ }
+
+ const now = moment.utc().toDate();
+ try {
+ await db.table('files').insert({
+ userId: this.user ? this.user.id : null,
+ name: file.filename,
+ original: file.originalname,
+ type: file.mimetype || '',
+ size: file.size,
+ hash,
+ ip: this.req.ip,
+ albumId: this.albumId ? this.albumId : null,
+ createdAt: now,
+ editedAt: now
+ });
+ } catch (error) {
+ log.error('There was an error saving the file to the database');
+ console.log(error);
+ return this.res.status(500).json({ message: 'There was an error uploading the file.' });
+ }
+
+ this.res.json({
+ message: 'Successfully uploaded file',
+ name: file.filename,
+ size: file.size,
+ url: `${config.filesServeLocation}/${file.filename}`
+ });
+
+ if (this.albumId) {
+ try {
+ db.table('albums').where('id', this.albumId).update('editedAt', now);
+ } catch (error) {
+ log.error('There was an error updating editedAt on an album');
+ console.error(error);
+ }
+ }
+
+ // return Util.generateThumbnail(file.filename);
+ });
+ */
+ }
+}
+
+/*
+const upload = multer({
+ limits: config.uploads.uploadMaxSize,
+ fileFilter(req, file, cb) {
+ const ext = path.extname(file.originalname).toLowerCase();
+ if (Util.isExtensionBlocked(ext)) return cb('This file extension is not allowed');
+
+ // Remove those pesky dz prefixes. Thanks to BobbyWibowo.
+ for (const key in req.body) {
+ if (!/^dz/.test(key)) continue;
+ req.body[key.replace(/^dz/, '')] = req.body[key];
+ delete req.body[key];
+ }
+
+ return cb(null, true);
+ },
+ storage: multer.diskStorage({
+ destination(req, file, cb) {
+ if (!req.body.uuid) return cb(null, path.join(__dirname, '..', '..', '..', '..', config.uploads.uploadFolder));
+ // Hey, we have chunks
+
+ const chunkDir = path.join(__dirname, '..', '..', '..', '..', config.uploads.uploadFolder, 'chunks', req.body.uuid);
+ jetpack.dir(chunkDir);
+ return cb(null, chunkDir);
+ return cb(null, path.join(__dirname, '..', '..', '..', '..', config.uploads.uploadFolder));
+ },
+ filename(req, file, cb) {
+ // if (req.body.uuid) return cb(null, `${file.originalname}.${req.body.chunkindex}`);
+ const filename = Util.getUniqueFilename(file.originalname);
+ // if (!filename) return cb('Could not allocate a unique file name');
+ return cb(null, filename);
+ }
+ })
+}).single('file');
+*/
+module.exports = uploadPOST;