diff options
| author | Pitu <[email protected]> | 2020-05-11 00:19:10 +0900 |
|---|---|---|
| committer | Pitu <[email protected]> | 2020-05-11 00:19:10 +0900 |
| commit | b886fda0793b8a26de58cd462acf6676a0a8e7ed (patch) | |
| tree | 07fcc32486b7654bf3ba173cef4061dc7cb6f12e /src/api | |
| parent | fix: remove uuid from user registration (diff) | |
| download | host.fuwn.me-b886fda0793b8a26de58cd462acf6676a0a8e7ed.tar.xz host.fuwn.me-b886fda0793b8a26de58cd462acf6676a0a8e7ed.zip | |
chore: cleanup and todo
Diffstat (limited to 'src/api')
| -rw-r--r-- | src/api/routes/admin/fileGET.js (renamed from src/api/routes/files/fileGET.js) | 0 | ||||
| -rw-r--r-- | src/api/routes/albums/albumZipGET.js | 1 | ||||
| -rw-r--r-- | src/api/routes/albums/link/linkDELETE.js | 2 | ||||
| -rw-r--r-- | src/api/routes/files/filesAlbumsGET.js | 3 | ||||
| -rw-r--r-- | src/api/routes/files/uploadPOST.js | 286 | ||||
| -rw-r--r-- | src/api/routes/uploads/uploadPOST.js | 15 |
6 files changed, 19 insertions, 288 deletions
diff --git a/src/api/routes/files/fileGET.js b/src/api/routes/admin/fileGET.js index 3bb8da4..3bb8da4 100644 --- a/src/api/routes/files/fileGET.js +++ b/src/api/routes/admin/fileGET.js diff --git a/src/api/routes/albums/albumZipGET.js b/src/api/routes/albums/albumZipGET.js index d1d3e16..a6ef6fd 100644 --- a/src/api/routes/albums/albumZipGET.js +++ b/src/api/routes/albums/albumZipGET.js @@ -13,6 +13,7 @@ class albumGET extends Route { const { identifier } = req.params; if (!identifier) return res.status(400).json({ message: 'Invalid identifier supplied' }); + // TODO: Do we really want to let anyone create a zip of an album? /* Make sure it exists and it's enabled */ diff --git a/src/api/routes/albums/link/linkDELETE.js b/src/api/routes/albums/link/linkDELETE.js index 904687f..23db411 100644 --- a/src/api/routes/albums/link/linkDELETE.js +++ b/src/api/routes/albums/link/linkDELETE.js @@ -15,8 +15,6 @@ class linkDELETE extends Route { .where({ identifier, userId: user.id }) .first(); - dump(link); - if (!link) return res.status(400).json({ message: 'Identifier doesn\'t exist' }); await db.table('links') diff --git a/src/api/routes/files/filesAlbumsGET.js b/src/api/routes/files/filesAlbumsGET.js index c834658..7f1190c 100644 --- a/src/api/routes/files/filesAlbumsGET.js +++ b/src/api/routes/files/filesAlbumsGET.js @@ -9,6 +9,9 @@ class filesGET extends Route { const { id } = req.params; if (!id) return res.status(400).json({ message: 'Invalid file ID supplied' }); + const file = await db.table('files').where({ id, userId: user.id }).first(); + if (!file) return res.status(400).json({ message: 'The file doesn\'t exist or doesn\'t belong to the user' }); + let albums = []; let albumFiles = await db.table('albumsFiles') .where('fileId', id) diff --git a/src/api/routes/files/uploadPOST.js b/src/api/routes/files/uploadPOST.js deleted file mode 100644 index 6996a6e..0000000 --- a/src/api/routes/files/uploadPOST.js +++ /dev/null @@ -1,286 +0,0 @@ -const Route = require('../../structures/Route'); -const path = require('path'); -const Util = require('../../utils/Util'); -const moment = require('moment'); -const log = require('../../utils/Log'); -const jetpack = require('fs-jetpack'); -const Busboy = require('busboy'); -const fs = require('fs'); -/* - TODO: If source has transparency generate a png thumbnail, otherwise a jpg. - TODO: If source is a gif, generate a thumb of the first frame and play the gif on hover. - TODO: If source is a video, generate a thumb of the first frame and save the video length. - - TODO: Think if its worth making a folder with the user uuid in uploads/ and upload the pictures there so that this way at least not every single file will be in 1 directory -*/ - -class uploadPOST extends Route { - constructor() { - super('/upload.....', 'post', { bypassAuth: true }); - } - - run(req, res) { - return res.status(201).send(); - - /* - const user = await Util.isAuthorized(req); - if (!user && process.env.PUBLIC_MODE == 'false') return res.status(401).json({ message: 'Not authorized to use this resource' }); - return this.uploadFile(req, res, db, user); - */ - } - - async processFile(req, res, db, 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' }); - } - - /* - if (!albumId) log.info('Incoming file'); - else log.info(`Incoming file for album ${albumId}`); - */ - - 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' }); - } - /* - Seems we finally got the last part of a chunk upload - */ - const uploadsDir = path.join(__dirname, '..', '..', '..', '..', process.env.UPLOAD_FOLDER); - const chunkedFileDir = path.join(__dirname, '..', '..', '..', '..', process.env.UPLOAD_FOLDER, 'chunks', file.body.uuid); - const chunkFiles = await jetpack.findAsync(chunkedFileDir, { matching: '*' }); - const originalname = Util.getFilenameFromPath(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) { - log.error(error); - } - } - - try { - await jetpack.removeAsync(chunkedFileDir); - } catch (error) { - log.error(error); - } - - upload = tempFile; - } - - /* - 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. - */ - 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 }) - .first(); - - if (exists) { - res.json({ - message: 'Successfully uploaded file BUT IT EXISTED ALREADY', - name: exists.name, - size: exists.size, - url: `${process.env.DOMAIN}/${exists.name}`, - deleteUrl: `${process.env.DOMAIN}/api/file/${exists.id}` - }); - - return Util.deleteFile(upload.filename); - } - - /* - The file doesn't appear to exist yet for this user, so let's - store the details on the database. - */ - const now = moment.utc().toDate(); - let insertedId = null; - try { - /* - This is so fucking dumb - */ - if (process.env.DB_CLIENT === 'sqlite3') { - insertedId = 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, - createdAt: now, - editedAt: now - }); - } else { - insertedId = 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, - createdAt: now, - editedAt: now - }, 'id'); - } - } catch (error) { - log.error('There was an error saving the file to the database'); - log.error(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: `${process.env.DOMAIN}/${upload.filename}`, - 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) { - log.error('There was an error updating editedAt on an album'); - log.error(error); - } - } - - /* - Generate those thumbnails - */ - return Util.generateThumbnails(upload.filename); - } - - uploadFile(req, res, db, user) { - const busboy = new Busboy({ - headers: req.headers, - limits: { - fileSize: parseInt(process.env.MAX_SIZE, 10) * (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; - let 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. - */ - const ext = path.extname(filename).toLowerCase(); - if (Util.isExtensionBlocked(ext)) return res.status(400).json({ message: 'This extension is not allowed.' }); - - if (fileToUpload.body.uuid) { - name = `${filename}.${fileToUpload.body.chunkindex}`; - const chunkDir = path.join(__dirname, '..', '..', '..', '..', process.env.UPLOAD_FOLDER, 'chunks', fileToUpload.body.uuid); - jetpack.dir(chunkDir); - saveTo = path.join(__dirname, '..', '..', '..', '..', process.env.UPLOAD_FOLDER, 'chunks', fileToUpload.body.uuid, name); - } else { - 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, '..', '..', '..', '..', process.env.UPLOAD_FOLDER, 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); - return res.status(400).json({ message: 'The file is too big.' }); - }); - - file.on('error', err => { - log.error('There was an error uploading a file'); - log.error(err); - return res.status(500).json({ message: 'There was an error uploading the file.' }); - }); - - /* - TODO: Does this even work?? - */ - return file.pipe(stream); - }); - - busboy.on('error', err => { - log.error('There was an error uploading a file'); - log.error(err); - return res.status(500).json({ message: 'There was an error uploading the file.' }); - }); - - busboy.on('finish', () => this.processFile(req, res, db, user, fileToUpload)); - req.pipe(busboy); - } -} - -module.exports = uploadPOST; diff --git a/src/api/routes/uploads/uploadPOST.js b/src/api/routes/uploads/uploadPOST.js index d35b9fc..d611175 100644 --- a/src/api/routes/uploads/uploadPOST.js +++ b/src/api/routes/uploads/uploadPOST.js @@ -11,6 +11,7 @@ const upload = multer({ files: 1 }, fileFilter: (req, file, cb) => { + // TODO: Enable blacklisting of files/extensions /* if (options.blacklist.mimes.includes(file.mimetype)) { return cb(new Error(`${file.mimetype} is a blacklisted filetype.`)); @@ -22,6 +23,20 @@ const upload = multer({ } }).array('files[]'); +/* + TODO: If source has transparency generate a png thumbnail, otherwise a jpg. + TODO: If source is a gif, generate a thumb of the first frame and play the gif on hover on the frontend. + TODO: If source is a video, generate a thumb of the first frame and save the video length to the file? + Another possible solution would be to play a gif on hover that grabs a few chunks like youtube. + + TODO: Think if its worth making a folder with the user uuid in uploads/ and upload the pictures there so + that this way at least not every single file will be in 1 directory + + - Addendum to this: Now that the default behaviour is to serve files with node, we can actually pull this off. Before this, having files in + subfolders meant messing with nginx and the paths, but now it should be fairly easy to re-arrange the folder structure with express.static + I see great value in this, open to suggestions. +*/ + class uploadPOST extends Route { constructor() { super('/upload', 'post', { bypassAuth: true }); |