From 41c7e34059e91cfaa7c2a67e4c5f368e93b6c6c6 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Mon, 24 Jul 2023 08:17:58 +0000 Subject: [PATCH] V12: Dropzone should handle internal and external errors when uploading (#14579) * fix: for safety measure check that a file is truthy before trying to upload it * fix: push an error when file.$error is encountered to make sure it does not get uploaded * fix: mark file as done if it errors * format error messages * fix: check for maxFileSize before uploading pasted images in tinymce * remove the image from the DOM if any error is encountered * feat: add property to fileManager to get and format the maxFileSize * fix: make tinymce use fileManager to get maxFileSize * fix(image cropper): check for maxFileSize before setting file to upload * multiply by 1000 to get bytes --- .../upload/umbfiledropzone.directive.js | 11 +++++ .../upload/umbpropertyfileupload.directive.js | 18 +++++++-- .../common/services/filemanager.service.js | 11 +++++ .../src/common/services/tinymce.service.js | 40 +++++++++++++++---- .../components/upload/umb-file-dropzone.html | 2 +- 5 files changed, 71 insertions(+), 11 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js index fc84e53979..8c51763364 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js @@ -148,6 +148,17 @@ angular.module("umbraco.directives") */ function _upload(file) { + if (!file) { + return; + } + + if (file.$error) { + file.done = true; + scope.processed.push(file); + file.messages.push({type: "Error", header: "Error"}); + return; + } + scope.propertyAlias = scope.propertyAlias ? scope.propertyAlias : "umbracoFile"; scope.contentTypeAlias = scope.contentTypeAlias ? scope.contentTypeAlias : "umbracoAutoSelect"; diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbpropertyfileupload.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbpropertyfileupload.directive.js index 7de961bb34..eebdb7c223 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbpropertyfileupload.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbpropertyfileupload.directive.js @@ -7,8 +7,10 @@ * @param {any} fileManager * @param {any} mediaHelper * @param {any} angularHelper + * @param {any} $attrs + * @param {any} notificationsService */ - function umbPropertyFileUploadController($scope, $q, fileManager, mediaHelper, angularHelper, $attrs) { + function umbPropertyFileUploadController($scope, $q, fileManager, mediaHelper, angularHelper, $attrs, notificationsService) { //NOTE: this component supports multiple files, though currently the uploader does not but perhaps sometime in the future // we'd want it to, so i'll leave the multiple file support in place @@ -271,15 +273,25 @@ if (args.files && args.files.length > 0) { + const filesAllowed = []; + + for (let i = 0; i < args.files.length; i++) { + if (fileManager.maxFileSize && args.files[i].size > fileManager.maxFileSize) { + notificationsService.error(`File upload "${args.files[i].name}"`, `File size of ${args.files[i].size / 1000} KB exceeds the maximum allowed size of ${fileManager.maxFileSize / 1000} KB`); + } else { + filesAllowed.push(args.files[i]); + } + } + //set the files collection fileManager.setFiles({ propertyAlias: vm.propertyAlias, - files: args.files, + files: filesAllowed, culture: vm.culture, segment: vm.segment }); - updateModelFromSelectedFiles(args.files).then(function(newVal) { + updateModelFromSelectedFiles(filesAllowed).then(function(newVal) { angularHelper.safeApply($scope, function() { //pass in the file names and the model files diff --git a/src/Umbraco.Web.UI.Client/src/common/services/filemanager.service.js b/src/Umbraco.Web.UI.Client/src/common/services/filemanager.service.js index 38aee3fc4a..6b2bd3c295 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/filemanager.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/filemanager.service.js @@ -14,6 +14,17 @@ function fileManager($rootScope) { var mgr = { + /** + * @ngdoc property + * @name umbraco.services.fileManager#maxFileSize + * @propertyOf umbraco.services.fileManager + * @type {Number} + * @default 0 + * @description + * The max file size allowed to be uploaded to the server in bytes + */ + maxFileSize: parseInt(Umbraco.Sys.ServerVariables.umbracoSettings.maxFileSize ?? '0', 10) * 1000, + /** * @ngdoc function * @name umbraco.services.fileManager#setFiles diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js index 96b0681b8f..829b7d66a4 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js @@ -9,7 +9,7 @@ * @doc https://www.tiny.cloud/docs/tinymce/6/ */ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, stylesheetResource, macroResource, macroService, - $routeParams, umbRequestHelper, angularHelper, userService, editorService, entityResource, eventsService, localStorageService, mediaHelper) { + $routeParams, umbRequestHelper, angularHelper, userService, editorService, entityResource, eventsService, localStorageService, mediaHelper, fileManager) { //These are absolutely required in order for the macros to render inline //we put these as extended elements because they get merged on top of the normal allowed elements by tiny mce @@ -202,6 +202,17 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s function uploadImageHandler(blobInfo, progress) { return new Promise(function (resolve, reject) { + const blob = blobInfo.blob(); + + // if the file size is greater than the max file size, reject it + if (fileManager.maxFileSize > 0 && blob.size > fileManager.maxFileSize) { + reject({ + message: `The file size (${blob.size / 1000} KB) exceeded the maximum allowed size of ${fileManager.maxFileSize / 1000} KB.`, + remove: true + }); + return; + } + const xhr = new XMLHttpRequest(); xhr.open('POST', Umbraco.Sys.ServerVariables.umbracoUrls.tinyMceApiBaseUrl + 'UploadImage'); @@ -222,12 +233,18 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s }; xhr.onerror = function () { - reject('Image upload failed due to a XHR Transport error. Code: ' + xhr.status); + reject({ + message: 'Image upload failed due to a XHR Transport error. Code: ' + xhr.status, + remove: true + }); }; xhr.onload = function () { if (xhr.status < 200 || xhr.status >= 300) { - reject('HTTP Error: ' + xhr.status); + reject({ + message: 'HTTP Error: ' + xhr.status, + remove: true + }); return; } @@ -237,7 +254,10 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s data = data.split("\n"); if (!data.length > 1) { - reject('Unrecognized text string: ' + data); + reject({ + message: 'Unrecognized text string: ' + data, + remove: true + }); return; } @@ -246,12 +266,18 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s try { json = JSON.parse(data[1]); } catch (e) { - reject('Invalid JSON: ' + data + ' - ' + e.message); + reject({ + message: 'Invalid JSON: ' + data + ' - ' + e.message, + remove: true + }); return; } if (!json || typeof json.tmpLocation !== 'string') { - reject('Invalid JSON: ' + data); + reject({ + message: 'Invalid JSON: ' + data, + remove: true + }); return; } @@ -265,7 +291,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s }; const formData = new FormData(); - formData.append('file', blobInfo.blob(), blobInfo.blob().name); + formData.append('file', blob, blob.name); xhr.send(formData); }); diff --git a/src/Umbraco.Web.UI.Client/src/views/components/upload/umb-file-dropzone.html b/src/Umbraco.Web.UI.Client/src/views/components/upload/umb-file-dropzone.html index c90f3139a8..985eec7e99 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/upload/umb-file-dropzone.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/upload/umb-file-dropzone.html @@ -56,7 +56,7 @@
{{ file.name }} - {{message.header}}: {{message.message}} + {{::message.header}}: {{::message.message}} "{{maxFileSize}}"