From 9a7560049a33e7586faa14942c06c0705d06ce6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sun, 29 Sep 2019 21:03:37 -0400 Subject: [PATCH] feat: bypass cropper for gifs --- public/src/client/account/edit.js | 3 ++- public/src/modules/pictureCropper.js | 21 +++++++++++++---- public/src/modules/uploader.js | 34 ++++++++++++++++------------ src/controllers/accounts/edit.js | 1 + src/user/picture.js | 21 +++++++++++++---- 5 files changed, 55 insertions(+), 25 deletions(-) diff --git a/public/src/client/account/edit.js b/public/src/client/account/edit.js index ccc293f03b..a546c71e6f 100644 --- a/public/src/client/account/edit.js +++ b/public/src/client/account/edit.js @@ -228,6 +228,7 @@ define('forum/account/edit', ['forum/account/header', 'translator', 'components' pictureCropper.show({ socketMethod: 'user.uploadCroppedPicture', + route: config.relative_path + '/api/user/' + ajaxify.data.userslug + '/uploadpicture', aspectRatio: 1 / 1, paramName: 'uid', paramValue: ajaxify.data.theirid, @@ -235,7 +236,7 @@ define('forum/account/edit', ['forum/account/header', 'translator', 'components' allowSkippingCrop: false, title: '[[user:upload_picture]]', description: '[[user:upload_a_picture]]', - accept: '.png,.jpg,.bmp', + accept: ajaxify.data.allowedProfileImageExtensios, }, function (url) { onUploadComplete(url); }); diff --git a/public/src/modules/pictureCropper.js b/public/src/modules/pictureCropper.js index 029b9ace31..40ed5ede89 100644 --- a/public/src/modules/pictureCropper.js +++ b/public/src/modules/pictureCropper.js @@ -18,6 +18,11 @@ define('pictureCropper', ['cropper'], function (Cropper) { uploadModal.remove(); }); + var uploadForm = uploadModal.find('#uploadForm'); + if (data.route) { + uploadForm.attr('action', data.route); + } + uploadModal.find('#fileUploadSubmitBtn').on('click', function () { $(this).addClass('disabled'); data.uploadModal = uploadModal; @@ -170,21 +175,27 @@ define('pictureCropper', ['cropper'], function (Cropper) { } var file = fileInput[0].files[0]; - var reader = new FileReader(); - var imageUrl; - var imageType = file.type; var fileSize = data.hasOwnProperty('fileSize') && data.fileSize !== undefined ? parseInt(data.fileSize, 10) : false; if (fileSize && file.size > fileSize * 1024) { return app.alertError('[[error:file-too-big, ' + fileSize + ']]'); } + + if (file.name.endsWith('.gif')) { + require(['uploader'], function (uploader) { + uploader.ajaxSubmit(data.uploadModal, callback); + }); + return; + } + + var reader = new FileReader(); reader.addEventListener('load', function () { - imageUrl = reader.result; + var imageUrl = reader.result; data.uploadModal.modal('hide'); module.handleImageCrop({ url: imageUrl, - imageType: imageType, + imageType: file.type, socketMethod: data.socketMethod, aspectRatio: data.aspectRatio, allowSkippingCrop: data.allowSkippingCrop, diff --git a/public/src/modules/uploader.js b/public/src/modules/uploader.js index fad6754257..9df3fe2dbd 100644 --- a/public/src/modules/uploader.js +++ b/public/src/modules/uploader.js @@ -42,34 +42,38 @@ define('uploader', ['translator', 'benchpress'], function (translator, Benchpres }; function onSubmit(uploadModal, fileSize, callback) { - function showAlert(type, message) { - module.hideAlerts(uploadModal); - if (type === 'error') { - uploadModal.find('#fileUploadSubmitBtn').removeClass('disabled'); - } - uploadModal.find('#alert-' + type).translateText(message).removeClass('hide'); - } - - showAlert('status', '[[uploads:uploading-file]]'); + showAlert(uploadModal, 'status', '[[uploads:uploading-file]]'); uploadModal.find('#upload-progress-bar').css('width', '0%'); uploadModal.find('#upload-progress-box').show().removeClass('hide'); var fileInput = uploadModal.find('#fileInput'); if (!fileInput.val()) { - return showAlert('error', '[[uploads:select-file-to-upload]]'); + return showAlert(uploadModal, 'error', '[[uploads:select-file-to-upload]]'); } if (!hasValidFileSize(fileInput[0], fileSize)) { - return showAlert('error', '[[error:file-too-big, ' + fileSize + ']]'); + return showAlert(uploadModal, 'error', '[[error:file-too-big, ' + fileSize + ']]'); + } + + module.ajaxSubmit(uploadModal, callback); + } + + function showAlert(uploadModal, type, message) { + module.hideAlerts(uploadModal); + if (type === 'error') { + uploadModal.find('#fileUploadSubmitBtn').removeClass('disabled'); } + uploadModal.find('#alert-' + type).translateText(message).removeClass('hide'); + } + module.ajaxSubmit = function (uploadModal, callback) { uploadModal.find('#uploadForm').ajaxSubmit({ headers: { 'x-csrf-token': config.csrf_token, }, error: function (xhr) { xhr = maybeParse(xhr); - showAlert('error', xhr.responseJSON ? (xhr.responseJSON.error || xhr.statusText) : 'error uploading, code : ' + xhr.status); + showAlert(uploadModal, 'error', xhr.responseJSON ? (xhr.responseJSON.error || xhr.statusText) : 'error uploading, code : ' + xhr.status); }, uploadProgress: function (event, position, total, percent) { uploadModal.find('#upload-progress-bar').css('width', percent + '%'); @@ -78,19 +82,19 @@ define('uploader', ['translator', 'benchpress'], function (translator, Benchpres response = maybeParse(response); if (response.error) { - return showAlert('error', response.error); + return showAlert(uploadModal, 'error', response.error); } callback(response[0].url); - showAlert('success', '[[uploads:upload-success]]'); + showAlert(uploadModal, 'success', '[[uploads:upload-success]]'); setTimeout(function () { module.hideAlerts(uploadModal); uploadModal.modal('hide'); }, 750); }, }); - } + }; function parseModal(tplVals, callback) { Benchpress.parse('partials/modals/upload_file_modal', tplVals, function (html) { diff --git a/src/controllers/accounts/edit.js b/src/controllers/accounts/edit.js index 4e13095e59..12124bbb9f 100644 --- a/src/controllers/accounts/edit.js +++ b/src/controllers/accounts/edit.js @@ -25,6 +25,7 @@ editController.get = async function (req, res, next) { userData.allowProfilePicture = !userData.isSelf || !!meta.config['reputation:disabled'] || userData.reputation >= meta.config['min:rep:profile-picture']; userData.allowCoverPicture = !userData.isSelf || !!meta.config['reputation:disabled'] || userData.reputation >= meta.config['min:rep:cover-picture']; userData.allowProfileImageUploads = meta.config.allowProfileImageUploads; + userData.allowedProfileImageExtensios = user.getAllowedProfileImageExtensions().map(ext => '.' + ext).join(', '); userData.allowMultipleBadges = meta.config.allowMultipleBadges === 1; userData.allowAccountDelete = meta.config.allowAccountDelete === 1; userData.allowWebsite = !userData.isSelf || !!meta.config['reputation:disabled'] || userData.reputation >= meta.config['min:rep:website']; diff --git a/src/user/picture.js b/src/user/picture.js index bc267c1875..6e6ee22afa 100644 --- a/src/user/picture.js +++ b/src/user/picture.js @@ -1,14 +1,27 @@ 'use strict'; const winston = require('winston'); +const mime = require('mime'); const db = require('../database'); const file = require('../file'); const image = require('../image'); const meta = require('../meta'); +const plugins = require('../plugins'); module.exports = function (User) { - const allowedTypes = ['image/png', 'image/jpeg', 'image/bmp']; + User.getAllowedProfileImageExtensions = function () { + return User.getAllowedImageTypes().map(type => mime.getExtension(type)); + }; + + User.getAllowedImageTypes = function () { + const allowedTypes = ['image/png', 'image/jpeg', 'image/bmp']; + if (plugins.hasListeners('filter:image.isFileTypeAllowed')) { + allowedTypes.push('image/gif'); + } + return allowedTypes; + }; + User.updateCoverPosition = async function (uid, position) { // Reject anything that isn't two percentages if (!/^[\d.]+%\s[\d.]+%$/.test(position)) { @@ -30,7 +43,7 @@ module.exports = function (User) { return await User.updateCoverPosition(data.uid, data.position); } - validateUpload(data, meta.config.maximumCoverImageSize); + validateUpload(data, meta.config.maximumCoverImageSize, ['image/png', 'image/jpeg', 'image/bmp']); picture.path = await getTempPath(data); @@ -63,7 +76,7 @@ module.exports = function (User) { throw new Error('[[error:profile-image-uploads-disabled]]'); } - validateUpload(data, meta.config.maximumProfileImageSize); + validateUpload(data, meta.config.maximumProfileImageSize, User.getAllowedImageTypes()); const extension = file.typeToExtension(getMimeType(data)); if (!extension) { @@ -92,7 +105,7 @@ module.exports = function (User) { } }; - function validateUpload(data, maxSize) { + function validateUpload(data, maxSize, allowedTypes) { if (!data.imageData && !data.file) { throw new Error('[[error:invalid-data]]'); }