From 6d50b46bd8fb8deae6b5b1c971292654f7aadcbf Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 23 Apr 2014 19:25:52 +0200 Subject: [PATCH 1/8] U4-4747,3027... - bugfix content type editor / aliases --- .../GenericProperty/genericProperty.js | 13 +++++++------ .../umbraco/controls/ContentTypeControlNew.ascx.cs | 4 ++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco_client/GenericProperty/genericProperty.js b/src/Umbraco.Web.UI/umbraco_client/GenericProperty/genericProperty.js index 780793f762..cb71b3d0bd 100644 --- a/src/Umbraco.Web.UI/umbraco_client/GenericProperty/genericProperty.js +++ b/src/Umbraco.Web.UI/umbraco_client/GenericProperty/genericProperty.js @@ -13,13 +13,14 @@ function expandCollapse(theId) { } } function duplicatePropertyNameAsSafeAlias(nameId, aliasId) { - var input = $('#' + aliasId); - - $('#' + nameId).keyup(function(event) { - var value = $(this).val(); - getSafeAlias(aliasId, value, false, function (alias) { - input.val(alias); + var inputName = $('#' + nameId); + var inputAlias = $('#' + aliasId); + inputName.on('input', function (event) { + getSafeAlias(inputAlias, inputName.val(), false, function (alias) { + inputAlias.val(alias); }); + }).on('blur', function (event) { + $(this).off('input'); }); } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs index 9138a470e8..0e4b20c268 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -834,7 +834,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); GenericProperty gpData = gp.GenricPropertyControl; if (string.IsNullOrEmpty(gpData.Name.Trim()) == false && string.IsNullOrEmpty(gpData.Alias.Trim()) == false) { - var propertyTypeAlias = Casing.SafeAliasWithForcingCheck(gpData.Alias.Trim()); + var propertyTypeAlias = gpData.Alias.ToSafeAlias(); if (contentTypeItem.PropertyTypeExists(propertyTypeAlias) == false) { //Find the DataTypeDefinition that the PropertyType should be based on @@ -891,7 +891,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); var propertyType = contentTypeItem.PropertyTypes.First(x => x.Alias == gpw.PropertyType.Alias); if (propertyType == null) continue; var dataTypeDefinition = ApplicationContext.Current.Services.DataTypeService.GetDataTypeDefinitionById(gpw.GenricPropertyControl.Type); - propertyType.Alias = gpw.GenricPropertyControl.Alias; + propertyType.Alias = gpw.GenricPropertyControl.Alias.ToSafeAlias(); propertyType.Name = gpw.GenricPropertyControl.Name; propertyType.Description = gpw.GenricPropertyControl.Description; propertyType.ValidationRegExp = gpw.GenricPropertyControl.Validation; From f46811ff67f8aeea8e7fdf85eee6b73da0139ee5 Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 24 Apr 2014 00:10:50 +0200 Subject: [PATCH 2/8] U4-3027 - fix content & property types alias casing --- src/Umbraco.Core/Models/ContentTypeBase.cs | 4 +++- src/Umbraco.Core/Models/PropertyType.cs | 3 ++- src/Umbraco.Core/Strings/CleanStringType.cs | 5 +++-- src/Umbraco.Web/WebServices/CoreStringsController.cs | 4 +++- .../umbraco/controls/ContentTypeControlNew.ascx.cs | 10 +++++++--- .../umbraco/create/nodetypeTasks.cs | 5 ++++- 6 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Core/Models/ContentTypeBase.cs b/src/Umbraco.Core/Models/ContentTypeBase.cs index 760c0e2116..da4cdcfd19 100644 --- a/src/Umbraco.Core/Models/ContentTypeBase.cs +++ b/src/Umbraco.Core/Models/ContentTypeBase.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Models.EntityBase; +using Umbraco.Core.Strings; namespace Umbraco.Core.Models { @@ -173,7 +174,8 @@ namespace Umbraco.Core.Models { SetPropertyValueAndDetectChanges(o => { - _alias = value.ToSafeAlias(); + //_alias = value.ToSafeAlias(); + _alias = value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase); return _alias; }, _alias, AliasSelector); } diff --git a/src/Umbraco.Core/Models/PropertyType.cs b/src/Umbraco.Core/Models/PropertyType.cs index 2168edba2f..f66a23d12c 100644 --- a/src/Umbraco.Core/Models/PropertyType.cs +++ b/src/Umbraco.Core/Models/PropertyType.cs @@ -4,6 +4,7 @@ using System.Runtime.Serialization; using System.Text.RegularExpressions; using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Persistence.Mappers; +using Umbraco.Core.Strings; namespace Umbraco.Core.Models { @@ -94,7 +95,7 @@ namespace Umbraco.Core.Models { SetPropertyValueAndDetectChanges(o => { - _alias = value; + _alias = value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase); return _alias; }, _alias, AliasSelector); } diff --git a/src/Umbraco.Core/Strings/CleanStringType.cs b/src/Umbraco.Core/Strings/CleanStringType.cs index 4c53be4cb8..ea9603ec6f 100644 --- a/src/Umbraco.Core/Strings/CleanStringType.cs +++ b/src/Umbraco.Core/Strings/CleanStringType.cs @@ -57,8 +57,9 @@ namespace Umbraco.Core.Strings /// /// Umbraco "safe alias" case. /// - /// This is for backward compatibility. Casing is unchanged within terms, - /// and is pascal otherwise. + /// Uppercases the first char of each term except for the first + /// char of the string, everything else including the first char of the + /// string is unchanged. UmbracoCase = 0x20, diff --git a/src/Umbraco.Web/WebServices/CoreStringsController.cs b/src/Umbraco.Web/WebServices/CoreStringsController.cs index 2d8c8e71ce..087caa4e50 100644 --- a/src/Umbraco.Web/WebServices/CoreStringsController.cs +++ b/src/Umbraco.Web/WebServices/CoreStringsController.cs @@ -20,9 +20,11 @@ namespace Umbraco.Web.WebServices [HttpGet] public JsonResult ToSafeAlias(string value) { + // always return a proper camel-cased alias + // when checking... javascript does a case-unsensitive comparison return value == null ? Json(new {error = "no value."}, JsonRequestBehavior.AllowGet) - : Json(new { alias = value.ToSafeAlias() }, JsonRequestBehavior.AllowGet); + : Json(new { alias = value.ToCleanString(CleanStringType.Alias | CleanStringType.CamelCase) }, JsonRequestBehavior.AllowGet); } [HttpGet] diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs index 0e4b20c268..3bffc3bbdc 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -17,6 +17,7 @@ using ClientDependency.Core; using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Strings; using Umbraco.Web.UI.Controls; using umbraco.BusinessLogic; using umbraco.cms.businesslogic; @@ -294,7 +295,7 @@ namespace umbraco.controls global::Umbraco.Web.UmbracoContext.Current = asyncState.UmbracoContext; _contentType.ContentTypeItem.Name = txtName.Text; - _contentType.ContentTypeItem.Alias = txtAlias.Text; + _contentType.ContentTypeItem.Alias = txtAlias.Text; // raw, contentType.Alias takes care of it _contentType.ContentTypeItem.Icon = ddlIcons.SelectedValue; _contentType.ContentTypeItem.Description = description.Text; _contentType.ContentTypeItem.Thumbnail = ddlThumbnails.SelectedValue; @@ -834,7 +835,9 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); GenericProperty gpData = gp.GenricPropertyControl; if (string.IsNullOrEmpty(gpData.Name.Trim()) == false && string.IsNullOrEmpty(gpData.Alias.Trim()) == false) { - var propertyTypeAlias = gpData.Alias.ToSafeAlias(); + // when creating a property don't do anything special, propertyType.Alias will take care of it + // don't enforce camel here because the user might have changed what the CoreStringsController returned + var propertyTypeAlias = gpData.Alias; if (contentTypeItem.PropertyTypeExists(propertyTypeAlias) == false) { //Find the DataTypeDefinition that the PropertyType should be based on @@ -891,7 +894,8 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); var propertyType = contentTypeItem.PropertyTypes.First(x => x.Alias == gpw.PropertyType.Alias); if (propertyType == null) continue; var dataTypeDefinition = ApplicationContext.Current.Services.DataTypeService.GetDataTypeDefinitionById(gpw.GenricPropertyControl.Type); - propertyType.Alias = gpw.GenricPropertyControl.Alias.ToSafeAlias(); + // when saving, respect user's casing, so do nothing here as propertyType takes care of it + propertyType.Alias = gpw.GenricPropertyControl.Alias; propertyType.Name = gpw.GenricPropertyControl.Name; propertyType.Description = gpw.GenricPropertyControl.Description; propertyType.ValidationRegExp = gpw.GenricPropertyControl.Validation; diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create/nodetypeTasks.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create/nodetypeTasks.cs index d47ca194ba..fa721596f0 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/create/nodetypeTasks.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/create/nodetypeTasks.cs @@ -5,6 +5,7 @@ using System.Web.Security; using Umbraco.Core; using Umbraco.Core.Models; using umbraco.BusinessLogic; +using Umbraco.Core.Strings; using umbraco.DataLayer; using umbraco.BasePages; using Umbraco.Core.IO; @@ -52,7 +53,9 @@ namespace umbraco ? new ContentType(-1) : new ContentType(ApplicationContext.Current.Services.ContentTypeService.GetContentType(parentId)); contentType.CreatorId = _userID; - contentType.Alias = Alias.Replace("'", "''"); + // when creating a content type, enforce PascalCase + // preserve separator because contentType.Alias will re-alias it + contentType.Alias = Alias.ToCleanString(CleanStringType.Alias | CleanStringType.PascalCase, ' '); contentType.Name = Alias.Replace("'", "''"); contentType.Icon = UmbracoSettings.IconPickerBehaviour == IconPickerBehaviour.HideFileDuplicates ? ".sprTreeFolder" From 437d1b759b23406b65a77b9f806136228651a899 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 24 Apr 2014 12:13:50 +1000 Subject: [PATCH 3/8] fix for: U4-4696. Macro personalized cache with custom membership provider not working --- src/Umbraco.Web/umbraco.presentation/macro.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web/umbraco.presentation/macro.cs b/src/Umbraco.Web/umbraco.presentation/macro.cs index 02b9f79466..8e4e52e1dc 100644 --- a/src/Umbraco.Web/umbraco.presentation/macro.cs +++ b/src/Umbraco.Web/umbraco.presentation/macro.cs @@ -228,8 +228,8 @@ namespace umbraco if (CacheByPersonalization) { - var currentMember = Member.GetCurrentMember(); - id.AppendFormat("m{0}-", currentMember == null ? 0 : currentMember.Id); + int currentMember = Member.CurrentMemberId(); + id.AppendFormat("m{0}-", currentMember); } foreach (var prop in model.Properties) @@ -537,7 +537,7 @@ namespace umbraco if (Model.CacheDuration > 0) { // do not add to cache if there's no member and it should cache by personalization - if (!Model.CacheByMember || (Model.CacheByMember && Member.GetCurrentMember() != null)) + if (!Model.CacheByMember || (Model.CacheByMember && Member.IsLoggedOn())) { if (macroControl != null) { From c32cae16dbaaaaea5631f3a3f55db2b88e168df1 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 24 Apr 2014 12:14:06 +1000 Subject: [PATCH 4/8] Fixes: U4-4696 Macro personalized cache with custom membership provider not working - for any membership provider regardless of provider user key type --- .../Security/MembershipProviderExtensions.cs | 6 ++++-- src/Umbraco.Web/umbraco.presentation/macro.cs | 13 +++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Core/Security/MembershipProviderExtensions.cs b/src/Umbraco.Core/Security/MembershipProviderExtensions.cs index 3e8fa1a568..68505e5669 100644 --- a/src/Umbraco.Core/Security/MembershipProviderExtensions.cs +++ b/src/Umbraco.Core/Security/MembershipProviderExtensions.cs @@ -65,7 +65,9 @@ namespace Umbraco.Core.Security public static MembershipUser GetCurrentUser(this MembershipProvider membershipProvider) { var username = membershipProvider.GetCurrentUserName(); - return membershipProvider.GetUser(username, true); + return username.IsNullOrWhiteSpace() + ? null + : membershipProvider.GetUser(username, true); } /// @@ -78,7 +80,7 @@ namespace Umbraco.Core.Security if (HostingEnvironment.IsHosted) { HttpContext current = HttpContext.Current; - if (current != null) + if (current != null && current.User != null && current.User.Identity != null) return current.User.Identity.Name; } IPrincipal currentPrincipal = Thread.CurrentPrincipal; diff --git a/src/Umbraco.Web/umbraco.presentation/macro.cs b/src/Umbraco.Web/umbraco.presentation/macro.cs index 8e4e52e1dc..cacf2a13e3 100644 --- a/src/Umbraco.Web/umbraco.presentation/macro.cs +++ b/src/Umbraco.Web/umbraco.presentation/macro.cs @@ -228,8 +228,17 @@ namespace umbraco if (CacheByPersonalization) { - int currentMember = Member.CurrentMemberId(); - id.AppendFormat("m{0}-", currentMember); + object memberId = 0; + if (HttpContext.Current.User.Identity.IsAuthenticated) + { + var provider = Umbraco.Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider(); + var member = Umbraco.Core.Security.MembershipProviderExtensions.GetCurrentUser(provider); + if (member != null) + { + memberId = member.ProviderUserKey ?? 0; + } + } + id.AppendFormat("m{0}-", memberId); } foreach (var prop in model.Properties) From 12170fd787c9ebe9fda65476cc05b6dcfb38d290 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 24 Apr 2014 14:23:17 +1000 Subject: [PATCH 5/8] fixes ysod overlay for ajax errors --- .../umbraco_client/Application/Extensions.js | 16 ++++++++++++++- .../Application/UmbracoClientManager.js | 20 +++++++++++++++++++ .../umbraco_client/modal/modal.js | 3 ++- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco_client/Application/Extensions.js b/src/Umbraco.Web.UI/umbraco_client/Application/Extensions.js index 04173f8749..66c97c4db7 100644 --- a/src/Umbraco.Web.UI/umbraco_client/Application/Extensions.js +++ b/src/Umbraco.Web.UI/umbraco_client/Application/Extensions.js @@ -256,7 +256,21 @@ contentType: 'application/json; charset=utf-8', error: function (x, t, e) { if (x.status.toString().startsWith("500")) { - $u.Sys.ApiMgr.getApp().handleAjaxException(x, t, e); + //show ysod overlay if we can + if (UmbClientMgr) { + var startIndex = x.responseText.indexOf(""); + var body = x.responseText.substring(startIndex, endIndex + 7); + var $div = $(body.replace("", "
").replace("", "
")); + $div.appendTo($(UmbClientMgr.mainWindow().document.getElementsByTagName("body")[0])); + UmbClientMgr.openModalWindowForContent($div, "ysod", true, 640, 640, null, null, null, function() { + //remove the $div + $div.closest(".umbModalBox").remove(); + }); + } + else { + alert("Unhandled exception occurred.\nStatus: " + x.status + "\nMessage: " + x.statusText + "\n\n" + x.responseText); + } } } }); diff --git a/src/Umbraco.Web.UI/umbraco_client/Application/UmbracoClientManager.js b/src/Umbraco.Web.UI/umbraco_client/Application/UmbracoClientManager.js index feeb02bf4f..6a3ac42c24 100644 --- a/src/Umbraco.Web.UI/umbraco_client/Application/UmbracoClientManager.js +++ b/src/Umbraco.Web.UI/umbraco_client/Application/UmbracoClientManager.js @@ -175,6 +175,26 @@ Umbraco.Sys.registerNamespace("Umbraco.Application"); } } }, + openModalWindowForContent: function (jQueryElement, name, showHeader, width, height, top, leftOffset, closeTriggers, onCloseCallback) { + //need to create the modal on the top window if the top window has a client manager, if not, create it on the current window + + //if this is the top window, or if the top window doesn't have a client manager, create the modal in this manager + if (window == this.mainWindow() || !this.mainWindow().UmbClientMgr) { + var m = new Umbraco.Controls.ModalWindow(); + this._modal.push(m); + m.show(jQueryElement, name, showHeader, width, height, top, leftOffset, closeTriggers, onCloseCallback); + } + else { + //if the main window has a client manager, then call the main window's open modal method whilst keeping the context of it's manager. + if (this.mainWindow().UmbClientMgr) { + this.mainWindow().UmbClientMgr.openModalWindowForContent.apply(this.mainWindow().UmbClientMgr, + [jQueryElement, name, showHeader, width, height, top, leftOffset, closeTriggers, onCloseCallback]); + } + else { + return; //exit recurse. + } + } + }, closeModalWindow: function(rVal) { /// /// will close the latest open modal window. diff --git a/src/Umbraco.Web.UI/umbraco_client/modal/modal.js b/src/Umbraco.Web.UI/umbraco_client/modal/modal.js index 597c95476f..c2c2812b0e 100644 --- a/src/Umbraco.Web.UI/umbraco_client/modal/modal.js +++ b/src/Umbraco.Web.UI/umbraco_client/modal/modal.js @@ -118,6 +118,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls"); /// The callback will receive one parameter with 2 properties: /// modalContent = the jQuery object for the popup window to query against /// outVal = the value passed to the close window method that was used to close the window (if it was specified) + /// /// The generated jquery object bound to the modal window @@ -355,7 +356,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls"); $.fn.jqmAddClose = function(e) { return hs(this, e, 'jqmHide'); }; $.fn.jqmAddTrigger = function(e) { return hs(this, e, 'jqmShow'); }; $.fn.jqmShow = function(t) { return this.each(function() { $.jqm.open(this._jqm, t); }); }; - $.fn.jqmHide = function(t) { return this.each(function() { $.jqm.close(this._jqm, t) }); }; + $.fn.jqmHide = function(t) { return this.each(function() { $.jqm.close(this._jqm, t); }); }; $.jqm = { hash: {}, From adf09d925f8360b5755c4a404495e684e147011a Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 24 Apr 2014 14:51:41 +1000 Subject: [PATCH 6/8] adds a comment --- src/Umbraco.Core/Models/PropertyType.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Models/PropertyType.cs b/src/Umbraco.Core/Models/PropertyType.cs index f66a23d12c..2b33119b73 100644 --- a/src/Umbraco.Core/Models/PropertyType.cs +++ b/src/Umbraco.Core/Models/PropertyType.cs @@ -389,7 +389,9 @@ namespace Umbraco.Core.Models } } - + + //TODO: We must ensure that the property value can actually be saved based on the specified database type + //TODO Add PropertyEditor validation when its relevant to introduce /*if (value is IEditorModel && DataTypeControlId != Guid.Empty) { From 61055380c5768be2e30ecb5f5760bf6b818fb153 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 24 Apr 2014 16:26:21 +1000 Subject: [PATCH 7/8] Ensures that member saving events don't get raised for normal member operations like validating and getting a user and flagging them as online. This fixes: U4-3451 Cache on Partial View refreshed, after member execute login --- .../Providers/UmbracoMembershipProvider.cs | 16 ++- .../businesslogic/member/Member.cs | 107 ++++-------------- .../members/UmbracoMembershipProvider.cs | 25 +++- 3 files changed, 56 insertions(+), 92 deletions(-) diff --git a/src/Umbraco.Web/Security/Providers/UmbracoMembershipProvider.cs b/src/Umbraco.Web/Security/Providers/UmbracoMembershipProvider.cs index d2f520b86d..8673cfc80b 100644 --- a/src/Umbraco.Web/Security/Providers/UmbracoMembershipProvider.cs +++ b/src/Umbraco.Web/Security/Providers/UmbracoMembershipProvider.cs @@ -330,7 +330,10 @@ namespace Umbraco.Web.Security.Providers { member.LastLoginDate = DateTime.Now; member.UpdateDate = DateTime.Now; - MemberService.Save(member); + //don't raise events for this! It just sets the member dates, if we do raise events this will + // cause all distributed cache to execute - which will clear out some caches we don't want. + // http://issues.umbraco.org/issue/U4-3451 + MemberService.Save(member, false); } return ConvertToMembershipUser(member); @@ -356,7 +359,10 @@ namespace Umbraco.Web.Security.Providers { member.LastLoginDate = DateTime.Now; member.UpdateDate = DateTime.Now; - MemberService.Save(member); + //don't raise events for this! It just sets the member dates, if we do raise events this will + // cause all distributed cache to execute - which will clear out some caches we don't want. + // http://issues.umbraco.org/issue/U4-3451 + MemberService.Save(member, false); } return ConvertToMembershipUser(member); @@ -530,7 +536,11 @@ namespace Umbraco.Web.Security.Providers member.LastLoginDate = DateTime.Now; } - MemberService.Save(member); + //don't raise events for this! It just sets the member dates, if we do raise events this will + // cause all distributed cache to execute - which will clear out some caches we don't want. + // http://issues.umbraco.org/issue/U4-3451 + MemberService.Save(member, false); + return authenticated; } diff --git a/src/umbraco.cms/businesslogic/member/Member.cs b/src/umbraco.cms/businesslogic/member/Member.cs index c0d102613e..8cd6675498 100644 --- a/src/umbraco.cms/businesslogic/member/Member.cs +++ b/src/umbraco.cms/businesslogic/member/Member.cs @@ -577,11 +577,11 @@ namespace umbraco.cms.businesslogic.member Version = MemberItem.Version; } - /// - /// Used to persist object changes to the database. In Version3.0 it's just a stub for future compatibility + /// Used to persist object changes to the database /// - public override void Save() + /// + public void Save(bool raiseEvents) { var provider = MembershipProviderExtensions.GetMembersMembershipProvider(); //Due to backwards compatibility with this API we need to check for duplicate emails here if required. @@ -595,17 +595,19 @@ namespace umbraco.cms.businesslogic.member } var e = new SaveEventArgs(); - FireBeforeSave(e); + if (raiseEvents) + { + FireBeforeSave(e); + } foreach (var property in GenericProperties) { MemberItem.SetValue(property.PropertyType.Alias, property.Value); } - if (!e.Cancel) + if (e.Cancel == false) { - - ApplicationContext.Current.Services.MemberService.Save(MemberItem); + ApplicationContext.Current.Services.MemberService.Save(MemberItem, raiseEvents); //base.VersionDate = MemberItem.UpdateDate; @@ -621,88 +623,19 @@ namespace umbraco.cms.businesslogic.member SavePreviewXml(generateXmlWithoutSaving(xd), Guid.NewGuid()); } - FireAfterSave(e); + if (raiseEvents) + { + FireAfterSave(e); + } } + } - //var e = new SaveEventArgs(); - //FireBeforeSave(e); - - //if (!e.Cancel) - //{ - // var db = ApplicationContext.Current.DatabaseContext.Database; - // using (var transaction = db.GetTransaction()) - // { - // foreach (var property in GenericProperties) - // { - // var poco = new PropertyDataDto - // { - // Id = property.Id, - // PropertyTypeId = property.PropertyType.Id, - // NodeId = Id, - // VersionId = property.VersionId - // }; - // if (property.Value != null) - // { - // string dbType = property.PropertyType.DataTypeDefinition.DbType; - // if (dbType.Equals("Integer")) - // { - // if (property.Value is bool || property.PropertyType.DataTypeDefinition.DataType.Id == new Guid("38b352c1-e9f8-4fd8-9324-9a2eab06d97a")) - // { - // poco.Integer = property.Value != null && string.IsNullOrEmpty(property.Value.ToString()) - // ? 0 - // : Convert.ToInt32(property.Value); - // } - // else - // { - // int value = 0; - // if (int.TryParse(property.Value.ToString(), out value)) - // { - // poco.Integer = value; - // } - // } - // } - // else if (dbType.Equals("Date")) - // { - // DateTime date; - - // if (DateTime.TryParse(property.Value.ToString(), out date)) - // poco.Date = date; - // } - // else if (dbType.Equals("Nvarchar")) - // { - // poco.VarChar = property.Value.ToString(); - // } - // else - // { - // poco.Text = property.Value.ToString(); - // } - // } - // bool isNew = db.IsNew(poco); - // if (isNew) - // { - // db.Insert(poco); - // } - // else - // { - // db.Update(poco); - // } - // } - // transaction.Complete(); - // } - - // // re-generate xml - // var xd = new XmlDocument(); - // XmlGenerate(xd); - - // // generate preview for blame history? - // if (UmbracoSettings.EnableGlobalPreviewStorage) - // { - // // Version as new guid to ensure different versions are generated as members are not versioned currently! - // SavePreviewXml(generateXmlWithoutSaving(xd), Guid.NewGuid()); - // } - - // FireAfterSave(e); - //} + /// + /// Used to persist object changes to the database. In Version3.0 it's just a stub for future compatibility + /// + public override void Save() + { + Save(true); } /// diff --git a/src/umbraco.providers/members/UmbracoMembershipProvider.cs b/src/umbraco.providers/members/UmbracoMembershipProvider.cs index ab3809db0a..f6a5ed6714 100644 --- a/src/umbraco.providers/members/UmbracoMembershipProvider.cs +++ b/src/umbraco.providers/members/UmbracoMembershipProvider.cs @@ -511,6 +511,11 @@ namespace umbraco.providers.members if (userIsOnline && LastLoginPropertyTypeAlias.IsNullOrWhiteSpace() == false) { UpdateMemberProperty(m, LastLoginPropertyTypeAlias, DateTime.Now); + + //don't raise events for this! It just sets the member dates, if we do raise events this will + // cause all distributed cache to execute - which will clear out some caches we don't want. + // http://issues.umbraco.org/issue/U4-3451 + m.Save(); } return ConvertToMembershipUser(m); @@ -533,6 +538,10 @@ namespace umbraco.providers.members if (userIsOnline && LastLoginPropertyTypeAlias.IsNullOrWhiteSpace() == false) { UpdateMemberProperty(m, LastLoginPropertyTypeAlias, DateTime.Now); + //don't raise events for this! It just sets the member dates, if we do raise events this will + // cause all distributed cache to execute - which will clear out some caches we don't want. + // http://issues.umbraco.org/issue/U4-3451 + m.Save(false); } return ConvertToMembershipUser(m); } @@ -543,6 +552,10 @@ namespace umbraco.providers.members if (userIsOnline && LastLoginPropertyTypeAlias.IsNullOrWhiteSpace() == false) { UpdateMemberProperty(m, LastLoginPropertyTypeAlias, DateTime.Now); + //don't raise events for this! It just sets the member dates, if we do raise events this will + // cause all distributed cache to execute - which will clear out some caches we don't want. + // http://issues.umbraco.org/issue/U4-3451 + m.Save(); } return ConvertToMembershipUser(m); } @@ -743,7 +756,11 @@ namespace umbraco.providers.members } // persist data - m.Save(); + + //don't raise events for this! It just sets the member dates, if we do raise events this will + // cause all distributed cache to execute - which will clear out some caches we don't want. + // http://issues.umbraco.org/issue/U4-3451 + m.Save(false); return true; } @@ -767,7 +784,11 @@ namespace umbraco.providers.members UpdateMemberProperty(m, LastLockedOutPropertyTypeAlias, DateTime.Now); LogHelper.Info("Member " + username + " is now locked out, max invalid password attempts exceeded"); } - m.Save(); + + //don't raise events for this! It just sets the member dates, if we do raise events this will + // cause all distributed cache to execute - which will clear out some caches we don't want. + // http://issues.umbraco.org/issue/U4-3451 + m.Save(false); } } From 2621b25fd34d541fa511cc08b3b1c3aa0d3b8231 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 24 Apr 2014 16:28:37 +1000 Subject: [PATCH 8/8] Ensures that member saving events don't get raised for normal member operations like validating and getting a user and flagging them as online. This fixes: U4-3451 Cache on Partial View refreshed, after member execute login --- src/umbraco.providers/members/UmbracoMembershipProvider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/umbraco.providers/members/UmbracoMembershipProvider.cs b/src/umbraco.providers/members/UmbracoMembershipProvider.cs index f6a5ed6714..dbefa53cc0 100644 --- a/src/umbraco.providers/members/UmbracoMembershipProvider.cs +++ b/src/umbraco.providers/members/UmbracoMembershipProvider.cs @@ -515,7 +515,7 @@ namespace umbraco.providers.members //don't raise events for this! It just sets the member dates, if we do raise events this will // cause all distributed cache to execute - which will clear out some caches we don't want. // http://issues.umbraco.org/issue/U4-3451 - m.Save(); + m.Save(false); } return ConvertToMembershipUser(m); @@ -555,7 +555,7 @@ namespace umbraco.providers.members //don't raise events for this! It just sets the member dates, if we do raise events this will // cause all distributed cache to execute - which will clear out some caches we don't want. // http://issues.umbraco.org/issue/U4-3451 - m.Save(); + m.Save(false); } return ConvertToMembershipUser(m); }