aboutsummaryrefslogtreecommitdiff
path: root/src/api
diff options
context:
space:
mode:
authorPitu <[email protected]>2020-05-11 00:19:10 +0900
committerPitu <[email protected]>2020-05-11 00:19:10 +0900
commitb886fda0793b8a26de58cd462acf6676a0a8e7ed (patch)
tree07fcc32486b7654bf3ba173cef4061dc7cb6f12e /src/api
parentfix: remove uuid from user registration (diff)
downloadhost.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.js1
-rw-r--r--src/api/routes/albums/link/linkDELETE.js2
-rw-r--r--src/api/routes/files/filesAlbumsGET.js3
-rw-r--r--src/api/routes/files/uploadPOST.js286
-rw-r--r--src/api/routes/uploads/uploadPOST.js15
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 });