From feb1892e9e89f823d265712c49b5dde555aaf43d Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 22 Jul 2013 18:16:50 +1000 Subject: [PATCH] Gets notification msgs on the server side to be displayed. Fixes property existence checking... was checking on id before but that is incorrect, needs to be on alias since a new property id is gen'd on each save and we're not re-wiring them back up. Fixes YSOD messaging for content as well. Changes the ModelState to modelState to be consistent in js. --- .../common/services/notifications.service.js | 50 +++++++++++++++++- .../src/common/services/util.service.js | 51 +++++++++++-------- .../src/views/common/dialogs/ysod.html | 2 +- .../views/content/contentedit.controller.js | 4 +- .../services/content-editing-helper.spec.js | 2 +- src/Umbraco.Web/Editors/ContentController.cs | 2 +- .../ContentEditing/ContentItemDisplay.cs | 2 +- .../ContentEditing/ContentPropertyBasic.cs | 17 ------- src/Umbraco.Web/UI/SpeechBubbleIcon.cs | 10 ++-- .../Filters/ContentItemValidationHelper.cs | 14 +++-- 10 files changed, 97 insertions(+), 57 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/notifications.service.js b/src/Umbraco.Web.UI.Client/src/common/services/notifications.service.js index e90ff8a244..0456612104 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/notifications.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/notifications.service.js @@ -42,7 +42,55 @@ angular.module('umbraco.services') } return { - /** + + /** + * @ngdoc method + * @name umbraco.services.notificationsService#showNotification + * @methodOf umbraco.services.notificationsService + * + * @description + * Shows a notification based on the object passed in, normally used to render notifications sent back from the server + * + * @returns {Object} args notification object + */ + showNotification: function(args) { + if (!args) { + throw "args cannot be null"; + } + if (!args.type) { + throw "args.type cannot be null"; + } + if (!args.header) { + throw "args.header cannot be null"; + } + if (!args.message) { + throw "args.message cannot be null"; + } + switch(args.type) { + case 0: + //save + this.success(args.header, args.message); + break; + case 1: + //info + this.success(args.header, args.message); + break; + case 2: + //error + this.error(args.header, args.message); + break; + case 3: + //success + this.success(args.header, args.message); + break; + case 4: + //warning + this.warning(args.header, args.message); + break; + } + }, + + /** * @ngdoc method * @name umbraco.services.notificationsService#success * @methodOf umbraco.services.notificationsService diff --git a/src/Umbraco.Web.UI.Client/src/common/services/util.service.js b/src/Umbraco.Web.UI.Client/src/common/services/util.service.js index e760873c72..32f97895b4 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/util.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/util.service.js @@ -441,12 +441,24 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ function (data, status, headers, config) { //failure callback - deferred.reject({ - data: data, - status: status, - headers: headers, - config: config - }); + //when there's a 500 (unhandled) error show a YSOD overlay if debugging is enabled. + if (status >= 500 && status < 600 && Umbraco.Sys.ServerVariables["isDebuggingEnabled"] === true) { + + dialogService.ysodDialog({ + errorMsg: 'An error occurred', + data: data + }); + } + else { + + //return an error object including the error message for UI + deferred.reject({ + errorMsg: 'An error occurred', + data: data, + status: status + }); + } + }); return deferred.promise; @@ -675,7 +687,7 @@ angular.module('umbraco.services').factory('iconHelper', iconHelper); * @name umbraco.services.contentEditingHelper * @description A helper service for content controllers when editing/creating/saving content. **/ -function contentEditingHelper($location, $routeParams, notificationsService, serverValidationManager) { +function contentEditingHelper($location, $routeParams, notificationsService, serverValidationManager, dialogService) { return { @@ -742,7 +754,7 @@ function contentEditingHelper($location, $routeParams, notificationsService, ser * @function * * @description - * A function to handle the validation (ModelState) errors collection which will happen on a 403 error indicating validation errors + * A function to handle the validation (modelState) errors collection which will happen on a 403 error indicating validation errors * It's worth noting that when a 403 occurs, the data is still saved just never published, though this depends on if the entity is a new * entity and whether or not the data fulfils the absolute basic requirements like having a mandatory Name. */ @@ -806,11 +818,11 @@ function contentEditingHelper($location, $routeParams, notificationsService, ser //Or, some strange server error if (err.status === 403) { //now we need to look through all the validation errors - if (err.data && (err.data.ModelState)) { + if (err.data && (err.data.modelState)) { - this.handleValidationErrors(err.data, err.data.ModelState); + this.handleValidationErrors(err.data, err.data.modelState); - if (!this.redirectToCreatedContent(err.data.id, err.data.ModelState)) { + if (!this.redirectToCreatedContent(err.data.id, err.data.modelState)) { //we are not redirecting because this is not new content, it is existing content. In this case // we need to detect what properties have changed and re-bind them with the server data. Then we need // to re-bind any server validation errors after the digest takes place. @@ -821,14 +833,12 @@ function contentEditingHelper($location, $routeParams, notificationsService, ser //indicates we've handled the server result return true; } - else { - //TODO: Implement an overlay showing the full YSOD like we had in v5 - notificationsService.error("Server error", err); + else { + dialogService.ysodDialog(err); } } else { - //TODO: Implement an overlay showing the full YSOD like we had in v5 - notificationsService.error("Validation failed", err); + dialogService.ysodDialog(err); } return false; @@ -859,14 +869,11 @@ function contentEditingHelper($location, $routeParams, notificationsService, ser if (!args.newContent) { throw "args.newContent cannot be null"; } - if (!args.notifyHeader) { - throw "args.notifyHeader cannot be null"; - } - if (!args.notifyMsg) { - throw "args.notifyMsg cannot be null"; + + for (var i = 0; i < args.newContent.notifications.length;i++) { + notificationsService.showNotification(args.newContent.notifications[i]); } - notificationsService.success(args.notifyHeader, args.notifyMsg); args.scope.$broadcast("saved", { scope: args.scope }); if (!this.redirectToCreatedContent(args.scope.content.id)) { //we are not redirecting because this is not new content, it is existing content. In this case diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/ysod.html b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/ysod.html index 2ad93bb30a..a096546090 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/ysod.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/ysod.html @@ -4,7 +4,7 @@

{{error.errorMsg}}


-

{{error.data.ExceptionMessage}}

+

{{error.data.ExceptionMessage || error.data.Message}}

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
diff --git a/src/Umbraco.Web.UI.Client/src/views/content/contentedit.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/contentedit.controller.js index bc7fc67cde..9bbc78d338 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/contentedit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/contentedit.controller.js @@ -62,9 +62,7 @@ function ContentEditController($scope, $routeParams, $location, contentResource, .then(function (data) { contentEditingHelper.handleSuccessfulSave({ scope: $scope, - newContent: data, - notifyHeader: "Published", - notifyMsg: "Content has been saved and published" + newContent: data }); }, function (err) { contentEditingHelper.handleSaveError(err, $scope); diff --git a/src/Umbraco.Web.UI.Client/test/unit/common/services/content-editing-helper.spec.js b/src/Umbraco.Web.UI.Client/test/unit/common/services/content-editing-helper.spec.js index 8b35033e2a..dee7d6dfcf 100644 --- a/src/Umbraco.Web.UI.Client/test/unit/common/services/content-editing-helper.spec.js +++ b/src/Umbraco.Web.UI.Client/test/unit/common/services/content-editing-helper.spec.js @@ -22,7 +22,7 @@ describe('contentEditingHelper tests', function () { data: content, status: 403 }; - err.data.ModelState = {}; + err.data.modelState = {}; //act var handled = contentEditingHelper.handleSaveError(err, {content: content}); diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index 6a8807e886..be8cff37e7 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -184,7 +184,7 @@ namespace Umbraco.Web.Editors } else { - //publish the item + //publish the item and check if it worked, if not we will show a diff msg below isPublishSuccess = Services.ContentService.SaveAndPublish(contentItem.PersistedContent); } diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs index b179072677..4e4f403760 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs @@ -32,7 +32,7 @@ namespace Umbraco.Web.Models.ContentEditing /// still save the item but it cannot be published. So we need a way of returning validation errors as well as the /// updated model. /// - [DataMember(Name = "ModelState")] + [DataMember(Name = "modelState")] public IDictionary Errors { get; set; } /// diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyBasic.cs b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyBasic.cs index f439eadf79..237d75939c 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyBasic.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyBasic.cs @@ -20,22 +20,5 @@ namespace Umbraco.Web.Models.ContentEditing [Required(AllowEmptyStrings = false)] public string Alias { get; set; } - protected bool Equals(ContentPropertyBasic other) - { - return Id == other.Id; - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - var other = obj as ContentPropertyBasic; - return other != null && Equals(other); - } - - public override int GetHashCode() - { - return Id; - } } } \ No newline at end of file diff --git a/src/Umbraco.Web/UI/SpeechBubbleIcon.cs b/src/Umbraco.Web/UI/SpeechBubbleIcon.cs index ae76f48cfe..2dd0d4946a 100644 --- a/src/Umbraco.Web/UI/SpeechBubbleIcon.cs +++ b/src/Umbraco.Web/UI/SpeechBubbleIcon.cs @@ -10,22 +10,22 @@ namespace Umbraco.Web.UI /// /// Save icon /// - Save, + Save = 0, /// /// Info icon /// - Info, + Info = 1, /// /// Error icon /// - Error, + Error = 2, /// /// Success icon /// - Success, + Success = 3, /// /// Warning icon /// - Warning + Warning = 4 } } diff --git a/src/Umbraco.Web/WebApi/Filters/ContentItemValidationHelper.cs b/src/Umbraco.Web/WebApi/Filters/ContentItemValidationHelper.cs index ff85558cad..d819dd9d17 100644 --- a/src/Umbraco.Web/WebApi/Filters/ContentItemValidationHelper.cs +++ b/src/Umbraco.Web/WebApi/Filters/ContentItemValidationHelper.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http.Controllers; @@ -80,16 +81,19 @@ namespace Umbraco.Web.WebApi.Filters /// private bool ValidateProperties(ContentItemBasic postedItem, HttpActionContext actionContext) { + //ensure the property actually exists in our server side properties + //var propertyAliases = postedItem.ContentDto.Properties.Select(x => x.Alias).ToArray(); + foreach (var p in postedItem.Properties) { - //ensure the property actually exists in our server side properties - if (postedItem.ContentDto.Properties.Contains(p) == false) + //if (propertyAliases.Contains(p.Alias) == false) + if (postedItem.PersistedContent.Properties[p.Alias] == null) { //TODO: Do we return errors here ? If someone deletes a property whilst their editing then should we just //save the property data that remains? Or inform them they need to reload... not sure. This problem exists currently too i think. - var message = string.Format("property with id: {0} was not found", p.Id); - actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, message); + var message = string.Format("property with alias: {0} was not found", p.Alias); + actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, new InvalidOperationException(message)); return false; } }