From edf70388487a4dec7985148c5163986a73cf314e Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Tue, 20 Mar 2018 15:00:09 +0100 Subject: [PATCH 1/6] U4-11020 Deleting a member group that is part of a Public Access feature, from the system, does not also remove the corresponding rows from the umbracoAccessRule table. --- .../umbraco/create/MemberGroupTasks.cs | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create/MemberGroupTasks.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create/MemberGroupTasks.cs index 42f8419723..85f6906e36 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/create/MemberGroupTasks.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/create/MemberGroupTasks.cs @@ -1,5 +1,6 @@ using System; using System.Data; +using System.Linq; using System.Web.Security; using Umbraco.Web.UI; using umbraco.BusinessLogic; @@ -7,6 +8,8 @@ using umbraco.DataLayer; using umbraco.BasePages; using Umbraco.Core.IO; using umbraco.cms.businesslogic.member; +using Umbraco.Core; +using Umbraco.Web; namespace umbraco { @@ -21,13 +24,32 @@ namespace umbraco public override bool PerformDelete() { + var roleDeleted = false; + // only built-in roles can be deleted if (Member.IsUsingUmbracoRoles()) { MemberGroup.GetByName(Alias).delete(); - return true; + roleDeleted = true; } - return false; + + // Need to delete the member group from any content item that has it assigned in public access settings + var publicAccessService = UmbracoContext.Current.Application.Services.PublicAccessService; + var allPublicAccessRules = publicAccessService.GetAll(); + + // Find only rules which have the current role name (alias) assigned to them + var rulesWithDeletedRoles = allPublicAccessRules.Where(x => x.Rules.Any(r => r.RuleValue == Alias)); + + var contentService = UmbracoContext.Current.Application.Services.ContentService; + foreach (var publicAccessEntry in rulesWithDeletedRoles) + { + var contentItem = contentService.GetById(publicAccessEntry.ProtectedNodeId); + var rulesToDelete = publicAccessEntry.Rules.ToList(); + foreach (var rule in rulesToDelete) + publicAccessService.RemoveRule(contentItem, rule.RuleType, rule.RuleValue); + } + + return roleDeleted; } private string _returnUrl = ""; From 0d2df4de811fbbd5760e0ef70adf0abcf8da326c Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 21 Mar 2018 10:22:08 +0100 Subject: [PATCH 2/6] Some cleanup --- .../umbraco/create/MemberGroupTasks.cs | 25 +++++-------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create/MemberGroupTasks.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create/MemberGroupTasks.cs index 85f6906e36..14fd55ee98 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/create/MemberGroupTasks.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/create/MemberGroupTasks.cs @@ -1,24 +1,17 @@ -using System; -using System.Data; using System.Linq; using System.Web.Security; -using Umbraco.Web.UI; using umbraco.BusinessLogic; -using umbraco.DataLayer; -using umbraco.BasePages; -using Umbraco.Core.IO; using umbraco.cms.businesslogic.member; -using Umbraco.Core; -using Umbraco.Web; +using Umbraco.Web.UI; -namespace umbraco +namespace Umbraco.Web.umbraco.presentation.umbraco.create { public class MemberGroupTasks : LegacyDialogTask { public override bool PerformSave() { Roles.CreateRole(Alias); - _returnUrl = string.Format("members/EditMemberGroup.aspx?id={0}", System.Web.HttpContext.Current.Server.UrlEncode(Alias)); + _returnUrl = $"members/EditMemberGroup.aspx?id={System.Web.HttpContext.Current.Server.UrlEncode(Alias)}"; return true; } @@ -29,7 +22,7 @@ namespace umbraco // only built-in roles can be deleted if (Member.IsUsingUmbracoRoles()) { - MemberGroup.GetByName(Alias).delete(); + Roles.DeleteRole(Alias); roleDeleted = true; } @@ -54,14 +47,8 @@ namespace umbraco private string _returnUrl = ""; - public override string ReturnUrl - { - get { return _returnUrl; } - } + public override string ReturnUrl => _returnUrl; - public override string AssignedApp - { - get { return DefaultApps.member.ToString(); } - } + public override string AssignedApp => DefaultApps.member.ToString(); } } From 97d7e3db8424a650386486dce08764da2fe45cba Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 21 Mar 2018 10:46:42 +0100 Subject: [PATCH 3/6] Forgot add the new namespace --- src/Umbraco.Tests/UI/LegacyDialogTests.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Umbraco.Tests/UI/LegacyDialogTests.cs b/src/Umbraco.Tests/UI/LegacyDialogTests.cs index e7749cf80b..304f8256b8 100644 --- a/src/Umbraco.Tests/UI/LegacyDialogTests.cs +++ b/src/Umbraco.Tests/UI/LegacyDialogTests.cs @@ -1,13 +1,11 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using NUnit.Framework; using Umbraco.Core; using Umbraco.Web.UI; using umbraco; using umbraco.BusinessLogic; using umbraco.interfaces; +using Umbraco.Web.umbraco.presentation.umbraco.create; namespace Umbraco.Tests.UI { From 3c4f052a278442eb18a7e75000b6bd4976725fb9 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 21 Mar 2018 13:45:44 +0100 Subject: [PATCH 4/6] Moved some code around based on feedback --- .../umbraco.presentation/umbraco/create/MemberGroupTasks.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create/MemberGroupTasks.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create/MemberGroupTasks.cs index 14fd55ee98..905aa42ca3 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/create/MemberGroupTasks.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/create/MemberGroupTasks.cs @@ -22,8 +22,7 @@ namespace Umbraco.Web.umbraco.presentation.umbraco.create // only built-in roles can be deleted if (Member.IsUsingUmbracoRoles()) { - Roles.DeleteRole(Alias); - roleDeleted = true; + roleDeleted = Roles.DeleteRole(Alias); } // Need to delete the member group from any content item that has it assigned in public access settings From 014ac98d0beb79e08435e3dcf3a1323d54b8804d Mon Sep 17 00:00:00 2001 From: Lee Kelleher Date: Wed, 21 Mar 2018 18:08:24 +0000 Subject: [PATCH 5/6] U4-11052 - Enabled IntegerValueConverter to handle `Int64` source values (#2500) * Enabled IntegerValueConverter to handle `Int64` source values --- .../ValueConverters/IntegerValueConverter.cs | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/IntegerValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/IntegerValueConverter.cs index 34b1ebffb1..20ab244de5 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/IntegerValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/IntegerValueConverter.cs @@ -1,4 +1,5 @@ -using Umbraco.Core.Models.PublishedContent; +using System; +using Umbraco.Core.Models.PublishedContent; namespace Umbraco.Core.PropertyEditors.ValueConverters { @@ -14,19 +15,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview) { - if (source == null) return 0; - - // in XML an integer is a string - var sourceString = source as string; - if (sourceString != null) - { - int i; - return (int.TryParse(sourceString, out i)) ? i : 0; - } - - // in the database an integer is an integer - // default value is zero - return (source is int) ? source : 0; + return source.TryConvertTo().Result; } } } From b4a0dadee94bc1e5991b784d57e5e6dd6159bde3 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 21 Mar 2018 19:52:56 +0100 Subject: [PATCH 6/6] Re-apply the nice C# syntax James provided --- src/Umbraco.Core/ObjectExtensions.cs | 84 ++++++++++------------------ 1 file changed, 28 insertions(+), 56 deletions(-) diff --git a/src/Umbraco.Core/ObjectExtensions.cs b/src/Umbraco.Core/ObjectExtensions.cs index 185a75fac9..479e425c99 100644 --- a/src/Umbraco.Core/ObjectExtensions.cs +++ b/src/Umbraco.Core/ObjectExtensions.cs @@ -140,8 +140,7 @@ namespace Umbraco.Core if (underlying != null) { // Special case for empty strings for bools/dates which should return null if an empty string. - var inputString = input as string; - if (inputString != null) + if (input is string inputString) { //TODO: Why the check against only bool/date when a string is null/empty? In what scenario can we convert to another type when the string is null or empty other than just being null? if (string.IsNullOrEmpty(inputString) && (underlying == typeof(DateTime) || underlying == typeof(bool))) @@ -168,8 +167,7 @@ namespace Umbraco.Core { // target is not a generic type - var inputString = input as string; - if (inputString != null) + if (input is string inputString) { // Try convert from string, returns an Attempt if the string could be // processed (either succeeded or failed), else null if we need to try @@ -218,8 +216,7 @@ namespace Umbraco.Core } // Re-check convertables since we altered the input through recursion - var convertible2 = input as IConvertible; - if (convertible2 != null) + if (input is IConvertible convertible2) { return Attempt.Succeed(Convert.ChangeType(convertible2, target)); } @@ -277,8 +274,7 @@ namespace Umbraco.Core { if (target == typeof(int)) { - int value; - if (int.TryParse(input, out value)) + if (int.TryParse(input, out var value)) { return Attempt.Succeed(value); } @@ -286,30 +282,26 @@ namespace Umbraco.Core // Because decimal 100.01m will happily convert to integer 100, it // makes sense that string "100.01" *also* converts to integer 100. var input2 = NormalizeNumberDecimalSeparator(input); - decimal value2; - return Attempt.SucceedIf(decimal.TryParse(input2, out value2), Convert.ToInt32(value2)); + return Attempt.SucceedIf(decimal.TryParse(input2, out var value2), Convert.ToInt32(value2)); } if (target == typeof(long)) { - long value; - if (long.TryParse(input, out value)) + if (long.TryParse(input, out var value)) { return Attempt.Succeed(value); } // Same as int var input2 = NormalizeNumberDecimalSeparator(input); - decimal value2; - return Attempt.SucceedIf(decimal.TryParse(input2, out value2), Convert.ToInt64(value2)); + return Attempt.SucceedIf(decimal.TryParse(input2, out var value2), Convert.ToInt64(value2)); } // TODO: Should we do the decimal trick for short, byte, unsigned? if (target == typeof(bool)) { - bool value; - if (bool.TryParse(input, out value)) + if (bool.TryParse(input, out var value)) { return Attempt.Succeed(value); } @@ -322,53 +314,42 @@ namespace Umbraco.Core switch (Type.GetTypeCode(target)) { case TypeCode.Int16: - short value; - return Attempt.SucceedIf(short.TryParse(input, out value), value); + return Attempt.SucceedIf(short.TryParse(input, out var value), value); case TypeCode.Double: var input2 = NormalizeNumberDecimalSeparator(input); - double valueD; - return Attempt.SucceedIf(double.TryParse(input2, out valueD), valueD); + return Attempt.SucceedIf(double.TryParse(input2, out var valueD), valueD); case TypeCode.Single: var input3 = NormalizeNumberDecimalSeparator(input); - float valueF; - return Attempt.SucceedIf(float.TryParse(input3, out valueF), valueF); + return Attempt.SucceedIf(float.TryParse(input3, out var valueF), valueF); case TypeCode.Char: - char valueC; - return Attempt.SucceedIf(char.TryParse(input, out valueC), valueC); + return Attempt.SucceedIf(char.TryParse(input, out var valueC), valueC); case TypeCode.Byte: - byte valueB; - return Attempt.SucceedIf(byte.TryParse(input, out valueB), valueB); + return Attempt.SucceedIf(byte.TryParse(input, out var valueB), valueB); case TypeCode.SByte: - sbyte valueSb; - return Attempt.SucceedIf(sbyte.TryParse(input, out valueSb), valueSb); + return Attempt.SucceedIf(sbyte.TryParse(input, out var valueSb), valueSb); case TypeCode.UInt32: - uint valueU; - return Attempt.SucceedIf(uint.TryParse(input, out valueU), valueU); + return Attempt.SucceedIf(uint.TryParse(input, out var valueU), valueU); case TypeCode.UInt16: - ushort valueUs; - return Attempt.SucceedIf(ushort.TryParse(input, out valueUs), valueUs); + return Attempt.SucceedIf(ushort.TryParse(input, out var valueUs), valueUs); case TypeCode.UInt64: - ulong valueUl; - return Attempt.SucceedIf(ulong.TryParse(input, out valueUl), valueUl); + return Attempt.SucceedIf(ulong.TryParse(input, out var valueUl), valueUl); } } else if (target == typeof(Guid)) { - Guid value; - return Attempt.SucceedIf(Guid.TryParse(input, out value), value); + return Attempt.SucceedIf(Guid.TryParse(input, out var value), value); } else if (target == typeof(DateTime)) { - DateTime value; - if (DateTime.TryParse(input, out value)) + if (DateTime.TryParse(input, out var value)) { switch (value.Kind) { @@ -388,24 +369,20 @@ namespace Umbraco.Core } else if (target == typeof(DateTimeOffset)) { - DateTimeOffset value; - return Attempt.SucceedIf(DateTimeOffset.TryParse(input, out value), value); + return Attempt.SucceedIf(DateTimeOffset.TryParse(input, out var value), value); } else if (target == typeof(TimeSpan)) { - TimeSpan value; - return Attempt.SucceedIf(TimeSpan.TryParse(input, out value), value); + return Attempt.SucceedIf(TimeSpan.TryParse(input, out var value), value); } else if (target == typeof(decimal)) { var input2 = NormalizeNumberDecimalSeparator(input); - decimal value; - return Attempt.SucceedIf(decimal.TryParse(input2, out value), value); + return Attempt.SucceedIf(decimal.TryParse(input2, out var value), value); } else if (input != null && target == typeof(Version)) { - Version value; - return Attempt.SucceedIf(Version.TryParse(input, out value), value); + return Attempt.SucceedIf(Version.TryParse(input, out var value), value); } // E_NOTIMPL IPAddress, BigInteger @@ -690,8 +667,7 @@ namespace Umbraco.Core { var key = new CompositeTypeTypeKey(source, target); - TypeConverter typeConverter; - if (InputTypeConverterCache.TryGetValue(key, out typeConverter)) + if (InputTypeConverterCache.TryGetValue(key, out TypeConverter typeConverter)) { return typeConverter; } @@ -711,8 +687,7 @@ namespace Umbraco.Core { var key = new CompositeTypeTypeKey(source, target); - TypeConverter typeConverter; - if (DestinationTypeConverterCache.TryGetValue(key, out typeConverter)) + if (DestinationTypeConverterCache.TryGetValue(key, out TypeConverter typeConverter)) { return typeConverter; } @@ -730,8 +705,7 @@ namespace Umbraco.Core [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Type GetCachedGenericNullableType(Type type) { - Type underlyingType; - if (NullableGenericCache.TryGetValue(type, out underlyingType)) + if (NullableGenericCache.TryGetValue(type, out Type underlyingType)) { return underlyingType; } @@ -750,8 +724,7 @@ namespace Umbraco.Core private static bool GetCachedCanAssign(object input, Type source, Type target) { var key = new CompositeTypeTypeKey(source, target); - bool canConvert; - if (AssignableTypeCache.TryGetValue(key, out canConvert)) + if (AssignableTypeCache.TryGetValue(key, out bool canConvert)) { return canConvert; } @@ -770,8 +743,7 @@ namespace Umbraco.Core [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool GetCachedCanConvertToBoolean(Type type) { - bool result; - if (BoolConvertCache.TryGetValue(type, out result)) + if (BoolConvertCache.TryGetValue(type, out bool result)) { return result; }