From 2477500045e070822bb56d49b706bd46079e8984 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Fri, 28 Jun 2013 13:27:23 +0200 Subject: [PATCH 1/2] Fixes #U4-2414 and removes internal usage of action handlers Yay! --- .../Persistence/Factories/PropertyFactory.cs | 5 +- .../Repositories/ContentRepository.cs | 84 +++++++++++++++++++ .../ActionHandlers/umbEnsureUniqueName.cs | 5 +- src/umbraco.cms/Actions/IActionHandler.cs | 8 +- .../businesslogic/member/Member.cs | 6 +- 5 files changed, 95 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs b/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs index ef71c020b7..5ed8faf3b6 100644 --- a/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs @@ -70,8 +70,9 @@ namespace Umbraco.Core.Persistence.Factories { if (property.Value is bool || property.PropertyType.DataTypeId == new Guid("38b352c1-e9f8-4fd8-9324-9a2eab06d97a")) { - int val = Convert.ToInt32(property.Value); - dto.Integer = val; + dto.Integer = property.Value != null && string.IsNullOrEmpty(property.Value.ToString()) + ? 0 + : Convert.ToInt32(property.Value); } else { diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs index 5d25ed2504..132105ad6a 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs @@ -27,6 +27,8 @@ namespace Umbraco.Core.Persistence.Repositories { _contentTypeRepository = contentTypeRepository; _templateRepository = templateRepository; + + EnsureUniqueNaming = true; } public ContentRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository) @@ -34,8 +36,12 @@ namespace Umbraco.Core.Persistence.Repositories { _contentTypeRepository = contentTypeRepository; _templateRepository = templateRepository; + + EnsureUniqueNaming = true; } + public bool EnsureUniqueNaming { get; set; } + #region Overrides of RepositoryBase protected override IContent PerformGet(int id) @@ -180,6 +186,9 @@ namespace Umbraco.Core.Persistence.Repositories { ((Content)entity).AddingEntity(); + //Ensure unique name on the same level + entity.Name = EnsureUniqueNodeName(entity.ParentId, entity.Name); + var factory = new ContentFactory(NodeObjectTypeId, entity.Id); var dto = factory.BuildDto(entity); @@ -260,6 +269,9 @@ namespace Umbraco.Core.Persistence.Repositories entity.UpdateDate = DateTime.Now; } + //Ensure unique name on the same level + entity.Name = EnsureUniqueNodeName(entity.ParentId, entity.Name, entity.Id); + //Look up parent to get and set the correct Path and update SortOrder if ParentId has changed if (((ICanBeDirty)entity).IsPropertyDirty("ParentId")) { @@ -487,5 +499,77 @@ namespace Umbraco.Core.Persistence.Repositories return new PropertyCollection(properties); } + + private string EnsureUniqueNodeName(int parentId, string nodeName, int id = 0) + { + if (EnsureUniqueNaming == false) + return nodeName; + + var sql = new Sql(); + sql.Select("*") + .From() + .Where(x => x.ParentId == parentId && x.Text.StartsWith(nodeName)); + + int uniqueNumber = 1; + var currentName = nodeName; + + var dtos = Database.Fetch(sql); + if (dtos.Any()) + { + var results = dtos.OrderBy(x => x.Text, new SimilarNodeNameComparer()); + foreach (var dto in results) + { + if(id != 0 && id == dto.NodeId) continue; + + if (dto.Text.ToLowerInvariant().Equals(currentName.ToLowerInvariant())) + { + currentName = nodeName + string.Format(" ({0})", uniqueNumber); + uniqueNumber++; + } + } + } + + return currentName; + } + + /// + /// Comparer that takes into account the duplicate index of a node name + /// This is needed as a normal alphabetic sort would go Page (1), Page (10), Page (2) etc. + /// + private class SimilarNodeNameComparer : IComparer + { + public int Compare(string x, string y) + { + if (x.LastIndexOf(')') == x.Length - 1 && y.LastIndexOf(')') == y.Length - 1) + { + if (x.ToLower().Substring(0, x.LastIndexOf('(')) == y.ToLower().Substring(0, y.LastIndexOf('('))) + { + int xDuplicateIndex = ExtractDuplicateIndex(x); + int yDuplicateIndex = ExtractDuplicateIndex(y); + + if (xDuplicateIndex != 0 && yDuplicateIndex != 0) + { + return xDuplicateIndex.CompareTo(yDuplicateIndex); + } + } + } + return String.Compare(x.ToLower(), y.ToLower(), StringComparison.Ordinal); + } + + private int ExtractDuplicateIndex(string text) + { + int index = 0; + + if (text.LastIndexOf('(') != -1 && text.LastIndexOf('(') < text.Length - 2) + { + int startPos = text.LastIndexOf('(') + 1; + int length = text.Length - 1 - startPos; + + int.TryParse(text.Substring(startPos, length), out index); + } + + return index; + } + } } } \ No newline at end of file diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/ActionHandlers/umbEnsureUniqueName.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/ActionHandlers/umbEnsureUniqueName.cs index 4c57614846..baacbff4f6 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/ActionHandlers/umbEnsureUniqueName.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/ActionHandlers/umbEnsureUniqueName.cs @@ -12,7 +12,8 @@ namespace umbraco.ActionHandlers /// It ensures that new content nodes gets a unique name, and thereby avoiding conflictiong URLs. /// It can be disabled in the umbracoSettings.config file. /// - public class umbEnsureUniqueName : umbraco.BusinessLogic.Actions.IActionHandler + [Obsolete("This handler is no longer used")] + public class umbEnsureUniqueName : IActionHandler { public umbEnsureUniqueName() { @@ -82,7 +83,7 @@ namespace umbraco.ActionHandlers /// public interfaces.IAction[] ReturnActions() { - interfaces.IAction[] _retVal = { ActionNew.Instance }; + interfaces.IAction[] _retVal = { }; return _retVal; } diff --git a/src/umbraco.cms/Actions/IActionHandler.cs b/src/umbraco.cms/Actions/IActionHandler.cs index 7e28b7bd78..cc4fecd51c 100644 --- a/src/umbraco.cms/Actions/IActionHandler.cs +++ b/src/umbraco.cms/Actions/IActionHandler.cs @@ -1,12 +1,5 @@ using System; -using System.Collections; -using System.Collections.Generic; -using System.Web; -using System.Reflection; -using umbraco.BasePages; -using umbraco.BusinessLogic.Utils; using umbraco.cms.businesslogic.web; -using umbraco.cms.businesslogic.workflow; using umbraco.interfaces; namespace umbraco.BusinessLogic.Actions @@ -20,6 +13,7 @@ namespace umbraco.BusinessLogic.Actions /// /// /// + [Obsolete("Legacy! Use events instead")] public interface IActionHandler { bool Execute(Document documentObject, IAction action); diff --git a/src/umbraco.cms/businesslogic/member/Member.cs b/src/umbraco.cms/businesslogic/member/Member.cs index c4a85f50b9..c6e8d5dfd6 100644 --- a/src/umbraco.cms/businesslogic/member/Member.cs +++ b/src/umbraco.cms/businesslogic/member/Member.cs @@ -637,8 +637,10 @@ namespace umbraco.cms.businesslogic.member { if (property.Value is bool || property.PropertyType.DataTypeDefinition.DataType.Id == new Guid("38b352c1-e9f8-4fd8-9324-9a2eab06d97a")) { - int val = Convert.ToInt32(property.Value); - poco.Integer = val; + poco.Integer = property.Value != null && + string.IsNullOrEmpty(property.Value.ToString()) + ? 0 + : Convert.ToInt32(property.Value); } else { From f809dec87452453c8760fa5873b6ec2361258c8e Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Fri, 28 Jun 2013 13:28:03 +0200 Subject: [PATCH 2/2] Updating repository factory to inject unique name setting into ContentRepository --- src/Umbraco.Core/Persistence/RepositoryFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Persistence/RepositoryFactory.cs b/src/Umbraco.Core/Persistence/RepositoryFactory.cs index 6b7b46ccc7..3aa5f0294f 100644 --- a/src/Umbraco.Core/Persistence/RepositoryFactory.cs +++ b/src/Umbraco.Core/Persistence/RepositoryFactory.cs @@ -30,7 +30,7 @@ namespace Umbraco.Core.Persistence uow, RuntimeCacheProvider.Current, CreateContentTypeRepository(uow), - CreateTemplateRepository(uow)); + CreateTemplateRepository(uow)) { EnsureUniqueNaming = Umbraco.Core.Configuration.UmbracoSettings.EnsureUniqueNaming }; } public virtual IContentTypeRepository CreateContentTypeRepository(IDatabaseUnitOfWork uow)