Merge pull request #230 from WeebDev/fix/chunk-uploads

Fix/chunk uploads
This commit is contained in:
Kana 2020-12-27 04:49:38 +09:00 committed by GitHub
commit 35c14c2242
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 108 additions and 78 deletions

View File

@ -12,7 +12,10 @@ class uploadPOST extends Route {
}); });
} }
async run(req, res) { async run(req, res, db) {
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' });
const filename = Util.getUniqueFilename(randomstring.generate(32)); const filename = Util.getUniqueFilename(randomstring.generate(32));
// console.log('Files', req.body.files); // console.log('Files', req.body.files);
const info = { const info = {
@ -40,6 +43,7 @@ class uploadPOST extends Route {
// Save some data // Save some data
info.name = `${filename}${ext || ''}`; info.name = `${filename}${ext || ''}`;
info.url += `${filename}${ext || ''}`; info.url += `${filename}${ext || ''}`;
info.data = chunk;
for (let i = 0; i < chunkDir.length; i++) { for (let i = 0; i < chunkDir.length; i++) {
const dir = path.join(__dirname, const dir = path.join(__dirname,
@ -54,15 +58,40 @@ class uploadPOST extends Route {
await jetpack.removeAsync(chunkOutput); await jetpack.removeAsync(chunkOutput);
} }
/*
If a file with the same hash and user is found, delete this
uploaded copy and return a link to the original
*/
info.hash = await Util.getFileHash(info.name);
let existingFile = await Util.checkIfFileExists(db, user, info.hash);
if (existingFile) {
existingFile = Util.constructFilePublicLink(existingFile);
res.json({
message: 'Successfully uploaded the file.',
name: existingFile.name,
hash: existingFile.hash,
size: existingFile.size,
url: `${process.env.DOMAIN}/${existingFile.name}`,
deleteUrl: `${process.env.DOMAIN}/api/file/${existingFile.id}`,
repeated: true
});
return Util.deleteFile(info.name);
}
// Otherwise generate thumbs and do the rest
Util.generateThumbnails(info.name);
const insertedId = await Util.saveFileToDatabase(req, res, user, db, info, {
originalname: info.data.original, mimetype: info.data.type
});
if (!insertedId) return res.status(500).json({ message: 'There was an error saving the file.' });
info.deleteUrl = `${process.env.DOMAIN}/api/file/${insertedId[0]}`;
Util.saveFileToAlbum(db, req.headers.albumid, insertedId);
delete info.chunk;
return res.status(201).send({ return res.status(201).send({
message: 'Sucessfully merged the chunk(s).', message: 'Sucessfully merged the chunk(s).',
...info ...info
/*
name: `${filename}${ext || ''}`,
size: exists.size,
url: `${process.env.DOMAIN}/${exists.name}`,
deleteUrl: `${process.env.DOMAIN}/api/file/${exists.id}`
*/
}); });
} }
} }

View File

@ -79,7 +79,7 @@ class uploadPOST extends Route {
For this we need to wait until we have a filename so that we can delete the uploaded 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); const exists = await Util.checkIfFileExists(db, user, hash);
if (exists) return this.fileExists(res, exists, filename); if (exists) return this.fileExists(res, exists, filename);
if (remappedKeys && remappedKeys.uuid) { if (remappedKeys && remappedKeys.uuid) {
@ -106,7 +106,7 @@ class uploadPOST extends Route {
if (!remappedKeys || !remappedKeys.uuid) { if (!remappedKeys || !remappedKeys.uuid) {
Util.generateThumbnails(uploadedFile.name); Util.generateThumbnails(uploadedFile.name);
insertedId = await this.saveFileToDatabase(req, res, user, db, uploadedFile, file); insertedId = await Util.saveFileToDatabase(req, res, user, db, uploadedFile, file);
if (!insertedId) return res.status(500).json({ message: 'There was an error saving the 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]}`; uploadedFile.deleteUrl = `${process.env.DOMAIN}/api/file/${insertedId[0]}`;
@ -114,7 +114,7 @@ class uploadPOST extends Route {
If the upload had an album specified we make sure to create the relation If the upload had an album specified we make sure to create the relation
and update the according timestamps.. and update the according timestamps..
*/ */
this.saveFileToAlbum(db, albumId, insertedId); Util.saveFileToAlbum(db, albumId, insertedId);
} }
uploadedFile = Util.constructFilePublicLink(uploadedFile); uploadedFile = Util.constructFilePublicLink(uploadedFile);
@ -140,73 +140,6 @@ class uploadPOST extends Route {
return Util.deleteFile(filename); 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
*/
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: file.name,
original: originalFile.originalname,
type: originalFile.mimetype || '',
size: file.size,
hash: file.hash,
ip: req.ip,
createdAt: now,
editedAt: now
});
} else {
insertedId = await db.table('files').insert({
userId: user ? user.id : null,
name: file.name,
original: originalFile.originalname,
type: originalFile.mimetype || '',
size: file.size,
hash: file.hash,
ip: req.ip,
createdAt: now,
editedAt: now
}, 'id');
}
return insertedId;
} catch (error) {
console.error('There was an error saving the file to the database');
console.error(error);
return null;
// return res.status(500).json({ message: 'There was an error uploading the file.' });
}
}
_remapKeys(body) { _remapKeys(body) {
const keys = Object.keys(body); const keys = Object.keys(body);
if (keys.length) { if (keys.length) {
@ -217,7 +150,6 @@ class uploadPOST extends Route {
} }
return body; return body;
} }
return keys;
} }
} }

View File

@ -108,6 +108,17 @@ class Util {
return hash; return hash;
} }
static 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;
}
static getFilenameFromPath(fullPath) { static getFilenameFromPath(fullPath) {
return fullPath.replace(/^.*[\\\/]/, ''); // eslint-disable-line no-useless-escape return fullPath.replace(/^.*[\\\/]/, ''); // eslint-disable-line no-useless-escape
} }
@ -226,6 +237,60 @@ class Util {
} }
static generateThumbnails = ThumbUtil.generateThumbnails; static generateThumbnails = ThumbUtil.generateThumbnails;
static async saveFileToDatabase(req, res, user, db, file, originalFile) {
/*
Save the upload information to 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: file.name,
original: originalFile.originalname,
type: originalFile.mimetype || '',
size: file.size,
hash: file.hash,
ip: req.ip,
createdAt: now,
editedAt: now
});
} else {
insertedId = await db.table('files').insert({
userId: user ? user.id : null,
name: file.name,
original: originalFile.originalname,
type: originalFile.mimetype || '',
size: file.size,
hash: file.hash,
ip: req.ip,
createdAt: now,
editedAt: now
}, 'id');
}
return insertedId;
} catch (error) {
console.error('There was an error saving the file to the database');
console.error(error);
return null;
}
}
static 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);
}
}
} }
module.exports = Util; module.exports = Util;

View File

@ -184,6 +184,10 @@ export default {
type: file.type, type: file.type,
count: file.upload.totalChunkCount count: file.upload.totalChunkCount
}] }]
}, {
headers: {
albumId: this.selectedAlbum ? this.selectedAlbum : null
}
}); });
this.processResult(file, data); this.processResult(file, data);