mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 16:46:12 +01:00
fix: #7597, fix progress bar of cover/profile uploads
send big cover images in chunks
This commit is contained in:
@@ -106,14 +106,14 @@ define('pictureCropper', ['cropper'], function (Cropper) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cropperModal.find('#upload-progress-bar').css('width', '100%');
|
cropperModal.find('#upload-progress-bar').css('width', '0%');
|
||||||
cropperModal.find('#upload-progress-box').show().removeClass('hide');
|
cropperModal.find('#upload-progress-box').show().removeClass('hide');
|
||||||
|
|
||||||
var socketData = {};
|
socketUpload({
|
||||||
socketData[data.paramName] = data.paramValue;
|
data: data,
|
||||||
socketData.imageData = imageData;
|
imageData: imageData,
|
||||||
|
progressBarEl: cropperModal.find('#upload-progress-bar'),
|
||||||
socket.emit(data.socketMethod, socketData, function (err, imageData) {
|
}, function (err, result) {
|
||||||
if (err) {
|
if (err) {
|
||||||
cropperModal.find('#upload-progress-box').hide();
|
cropperModal.find('#upload-progress-box').hide();
|
||||||
cropperModal.find('.upload-btn').removeClass('disabled');
|
cropperModal.find('.upload-btn').removeClass('disabled');
|
||||||
@@ -121,7 +121,7 @@ define('pictureCropper', ['cropper'], function (Cropper) {
|
|||||||
return app.alertError(err.message);
|
return app.alertError(err.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(imageData.url);
|
callback(result.url);
|
||||||
cropperModal.modal('hide');
|
cropperModal.modal('hide');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -143,6 +143,36 @@ define('pictureCropper', ['cropper'], function (Cropper) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function socketUpload(params, callback) {
|
||||||
|
var socketData = {};
|
||||||
|
socketData[params.data.paramName] = params.data.paramValue;
|
||||||
|
socketData.method = params.data.socketMethod;
|
||||||
|
socketData.size = params.imageData.length;
|
||||||
|
socketData.progress = 0;
|
||||||
|
|
||||||
|
var chunkSize = 100000;
|
||||||
|
function doUpload() {
|
||||||
|
var chunk = params.imageData.slice(socketData.progress, socketData.progress + chunkSize);
|
||||||
|
socket.emit('uploads.upload', {
|
||||||
|
chunk: chunk,
|
||||||
|
params: socketData,
|
||||||
|
}, function (err, result) {
|
||||||
|
if (err) {
|
||||||
|
return app.alertError(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socketData.progress + chunkSize < socketData.size) {
|
||||||
|
socketData.progress += chunk.length;
|
||||||
|
params.progressBarEl.css('width', (socketData.progress / socketData.size * 100).toFixed(2) + '%');
|
||||||
|
return setTimeout(doUpload, 100);
|
||||||
|
}
|
||||||
|
params.progressBarEl.css('width', '100%');
|
||||||
|
callback(null, result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
doUpload();
|
||||||
|
}
|
||||||
|
|
||||||
function checkCORS(cropperTool, data) {
|
function checkCORS(cropperTool, data) {
|
||||||
var imageData;
|
var imageData;
|
||||||
try {
|
try {
|
||||||
@@ -177,7 +207,7 @@ define('pictureCropper', ['cropper'], function (Cropper) {
|
|||||||
var file = fileInput[0].files[0];
|
var file = fileInput[0].files[0];
|
||||||
var fileSize = data.hasOwnProperty('fileSize') && data.fileSize !== undefined ? parseInt(data.fileSize, 10) : false;
|
var fileSize = data.hasOwnProperty('fileSize') && data.fileSize !== undefined ? parseInt(data.fileSize, 10) : false;
|
||||||
if (fileSize && file.size > fileSize * 1024) {
|
if (fileSize && file.size > fileSize * 1024) {
|
||||||
return app.alertError('[[error:file-too-big, ' + fileSize + ']]');
|
return showAlert('error', '[[error:file-too-big, ' + fileSize + ']]');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file.name.endsWith('.gif')) {
|
if (file.name.endsWith('.gif')) {
|
||||||
|
|||||||
@@ -69,6 +69,14 @@ function onConnection(socket) {
|
|||||||
socket.on('*', function (payload) {
|
socket.on('*', function (payload) {
|
||||||
onMessage(socket, payload);
|
onMessage(socket, payload);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on('disconnect', function () {
|
||||||
|
onDisconnect(socket);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDisconnect(socket) {
|
||||||
|
require('./uploads').clear(socket.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onConnect(socket) {
|
function onConnect(socket) {
|
||||||
@@ -148,7 +156,8 @@ async function onMessage(socket, payload) {
|
|||||||
|
|
||||||
function requireModules() {
|
function requireModules() {
|
||||||
var modules = ['admin', 'categories', 'groups', 'meta', 'modules',
|
var modules = ['admin', 'categories', 'groups', 'meta', 'modules',
|
||||||
'notifications', 'plugins', 'posts', 'topics', 'user', 'blacklist', 'flags',
|
'notifications', 'plugins', 'posts', 'topics', 'user', 'blacklist',
|
||||||
|
'flags', 'uploads',
|
||||||
];
|
];
|
||||||
|
|
||||||
modules.forEach(function (module) {
|
modules.forEach(function (module) {
|
||||||
|
|||||||
52
src/socket.io/uploads.js
Normal file
52
src/socket.io/uploads.js
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const socketUser = require('./user');
|
||||||
|
const socketGroup = require('./groups');
|
||||||
|
const image = require('../image');
|
||||||
|
const meta = require('../meta');
|
||||||
|
|
||||||
|
const inProgress = {};
|
||||||
|
|
||||||
|
const uploads = module.exports;
|
||||||
|
|
||||||
|
uploads.upload = async function (socket, data) {
|
||||||
|
const methodToFunc = {
|
||||||
|
'user.uploadCroppedPicture': socketUser.uploadCroppedPicture,
|
||||||
|
'user.updateCover': socketUser.updateCover,
|
||||||
|
'groups.cover.update': socketGroup.cover.update,
|
||||||
|
};
|
||||||
|
if (!data || !data.chunk || !data.params || !data.params.method || !methodToFunc[data.params.method]) {
|
||||||
|
throw new Error('[[error:invalid-data]]');
|
||||||
|
}
|
||||||
|
|
||||||
|
inProgress[socket.id] = inProgress[socket.id] || {};
|
||||||
|
const socketUploads = inProgress[socket.id];
|
||||||
|
const method = data.params.method;
|
||||||
|
|
||||||
|
socketUploads[method] = socketUploads[method] || { imageData: '' };
|
||||||
|
socketUploads[method].imageData += data.chunk;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const maxSize = data.params.method === 'user.uploadCroppedPicture' ?
|
||||||
|
meta.config.maximumProfileImageSize : meta.config.maximumCoverImageSize;
|
||||||
|
const size = image.sizeFromBase64(socketUploads[method].imageData);
|
||||||
|
|
||||||
|
if (size > maxSize * 1024) {
|
||||||
|
throw new Error('[[error:file-too-big, ' + maxSize + ']]');
|
||||||
|
}
|
||||||
|
if (socketUploads[method].imageData.length < data.params.size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data.params.imageData = socketUploads[method].imageData;
|
||||||
|
const result = await methodToFunc[data.params.method](socket, data.params);
|
||||||
|
delete socketUploads[method];
|
||||||
|
return result;
|
||||||
|
} catch (err) {
|
||||||
|
delete inProgress[socket.id];
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
uploads.clear = function (sid) {
|
||||||
|
delete inProgress[sid];
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user