diff options
| author | Pitu <[email protected]> | 2018-09-19 04:45:50 -0300 |
|---|---|---|
| committer | Pitu <[email protected]> | 2018-09-19 04:45:50 -0300 |
| commit | 430af8306b1ab17e59a6dabf8f65ab816d28695d (patch) | |
| tree | 975814e80919cc7b8c5d820080a30def32a371ea /src/api/routes/files | |
| parent | Some adjustements to public album view (diff) | |
| download | host.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.bak | 380 |
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; |