V10: Dropzone should handle internal and external errors when uploading (#14578)
* fix: mark files that result in error as processed * 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: remove header from error messages since it is not being used anyway * fix: check for maxFileSize before uploading pasted images in tinymce * use stored blob variable * 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 --------- Co-authored-by: Elitsa <elm@umbraco.dk>
This commit is contained in:
@@ -31,7 +31,7 @@ angular.module("umbraco.directives")
|
||||
propertyAlias: '@',
|
||||
accept: '@',
|
||||
maxFileSize: '@',
|
||||
|
||||
|
||||
compact: '@',
|
||||
hideDropzone: '@',
|
||||
acceptedMediatypes: '=',
|
||||
@@ -87,7 +87,7 @@ angular.module("umbraco.directives")
|
||||
// Add the processed length, as we might be uploading in stages
|
||||
scope.totalQueued = scope.queue.length + scope.processed.length;
|
||||
|
||||
_processQueueItems();
|
||||
_processQueueItems();
|
||||
}
|
||||
|
||||
function _processQueueItems() {
|
||||
@@ -115,6 +115,18 @@ angular.module("umbraco.directives")
|
||||
|
||||
function _upload(file) {
|
||||
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.$error) {
|
||||
scope.processed.push(file);
|
||||
scope.currentFile = undefined;
|
||||
file.messages.push({type: "Error"});
|
||||
_processQueueItems();
|
||||
return;
|
||||
}
|
||||
|
||||
scope.propertyAlias = scope.propertyAlias ? scope.propertyAlias : "umbracoFile";
|
||||
scope.contentTypeAlias = scope.contentTypeAlias ? scope.contentTypeAlias : "Image";
|
||||
|
||||
@@ -158,11 +170,22 @@ angular.module("umbraco.directives")
|
||||
} else if (evt && typeof evt === "string") {
|
||||
file.messages.push({message: evt, type: "Error"});
|
||||
}
|
||||
// If file not found, server will return a 404 and display this message
|
||||
if (status === 404) {
|
||||
file.messages.push({message: "File not found", type: "Error"});
|
||||
|
||||
// If there were no errors with the request, but the status code was 404, we'll add a custom message
|
||||
// or a generic message for all other status codes.
|
||||
if (!file.messages.length) {
|
||||
if (status === 404) {
|
||||
file.messages.push({message: "File not found", type: "Error"});
|
||||
} else {
|
||||
file.messages.push({message: "Error uploading file", type: "Error"});
|
||||
}
|
||||
}
|
||||
|
||||
// The file has been processed, even though it resulted in an error, so we add it to the processed queue
|
||||
scope.processed.push(file);
|
||||
scope.currentFile = undefined;
|
||||
|
||||
// Return to queue processing
|
||||
_processQueueItems();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* A service containing all logic for all of the Umbraco TinyMCE plugins
|
||||
*/
|
||||
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
|
||||
@@ -222,6 +222,14 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
}
|
||||
|
||||
function uploadImageHandler(blobInfo, success, failure, progress){
|
||||
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) {
|
||||
failure(`The file size (${blob.size / 1000} KB) exceeded the maximum allowed size of ${fileManager.maxFileSize / 1000} KB.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', Umbraco.Sys.ServerVariables.umbracoUrls.tinyMceApiBaseUrl + 'UploadImage');
|
||||
|
||||
@@ -285,7 +293,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);
|
||||
}
|
||||
@@ -727,11 +735,11 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
};
|
||||
var newImage = editor.dom.createHTML('img', data);
|
||||
var parentElement = editor.selection.getNode().parentElement;
|
||||
|
||||
|
||||
if (img.caption) {
|
||||
var figCaption = editor.dom.createHTML('figcaption', {}, img.caption);
|
||||
var combined = newImage + figCaption;
|
||||
|
||||
|
||||
if (parentElement.nodeName !== 'FIGURE') {
|
||||
var fragment = editor.dom.createHTML('figure', {}, combined);
|
||||
editor.selection.setContent(fragment);
|
||||
@@ -749,7 +757,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
editor.selection.setContent(newImage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Using settimeout to wait for a DoM-render, so we can find the new element by ID.
|
||||
$timeout(function () {
|
||||
|
||||
@@ -770,7 +778,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1454,7 +1462,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
// Then we need to add an event listener to the editor
|
||||
// That will update native browser drag & drop events
|
||||
// To update the icon to show you can NOT drop something into the editor
|
||||
|
||||
|
||||
var toolbarItems = args.editor.settings.toolbar === false ? [] : args.editor.settings.toolbar.split(" ");
|
||||
if(isMediaPickerEnabled(toolbarItems) === false){
|
||||
// Wire up the event listener
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<ul class="file-list" ng-show="queue.length > 0 || processed.length > 0 || filesHolder.length > 0">
|
||||
|
||||
|
||||
<li class="file" ng-if="totalMessages > 1">
|
||||
<li class="file" ng-if="totalMessages > 1">
|
||||
<div class="file-description">
|
||||
<!-- Okay all -->
|
||||
<button class="btn btn-primary ok-all" type="button" ng-click="dismissAllMessages()">
|
||||
@@ -56,7 +56,7 @@
|
||||
<div>
|
||||
<span>{{ file.name }}</span>
|
||||
<span ng-if="file.messages.length > 0 || file.$error" class="file-messages">
|
||||
<span class="errorMessage color-red" ng-repeat="message in file.messages">{{message.header}}: {{message.message}}</span>
|
||||
<span class="errorMessage color-red" ng-repeat="message in ::file.messages">{{::message.message}}</span>
|
||||
<span ng-if="file.$error === 'pattern'" class="errorMessage color-red"><localize key="media_disallowedFileType"></localize></span>
|
||||
<span ng-if="file.$error === 'maxSize'" class="errorMessage color-red"><localize key="media_maxFileSize"></localize> "{{maxFileSize}}"</span>
|
||||
</span>
|
||||
@@ -84,7 +84,7 @@
|
||||
<li class="file" ng-repeat="file in queue track by file.key">
|
||||
<div class="file-description">{{ file.name }}</div>
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
</ng-form>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user