From 980e8e84a6b6c3a19a0d87183d46dd38faeccce0 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 10 Mar 2014 17:26:04 +1100 Subject: [PATCH 1/2] Fixes: U4-4353 You are able to create duplicate content/media/member type's with the same alias --- .../Repositories/ContentTypeBaseRepository.cs | 26 ++++ .../DataTypeDefinitionRepository.cs | 12 ++ .../Repositories/RepositoryBase.cs | 30 +++- .../controls/ContentTypeControlNew.ascx | 3 +- .../controls/ContentTypeControlNew.ascx.cs | 1 + .../ContentTypeControlNew.ascx.designer.cs | 2 + src/Umbraco.Web.UI/umbraco/create/simple.ascx | 2 +- .../developer/DataTypes/editDatatype.aspx | 1 + src/Umbraco.Web/Umbraco.Web.csproj | 13 +- .../controls/ContentTypeControlNew.ascx.cs | 21 ++- .../umbraco/create/nodeType.ascx.cs | 35 ++--- .../umbraco/create/simple.ascx.cs | 2 +- .../developer/DataTypes/editDatatype.aspx | 27 ---- .../developer/DataTypes/editDatatype.aspx.cs | 140 ++++++++++++++---- .../DataTypes/editDatatype.aspx.designer.cs | 105 ------------- .../umbraco/settings/EditMediaType.aspx.cs | 19 --- .../datatype/DataTypeDefinition.cs | 27 +++- .../businesslogic/media/MediaType.cs | 4 +- 18 files changed, 245 insertions(+), 225 deletions(-) delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/developer/DataTypes/editDatatype.aspx delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/developer/DataTypes/editDatatype.aspx.designer.cs diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs index 5b761ad559..da259c1594 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Data; using System.Globalization; using System.Linq; using System.Threading.Tasks; @@ -11,6 +12,7 @@ using Umbraco.Core.Persistence.Caching; using Umbraco.Core.Persistence.Factories; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Persistence.Relators; +using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Persistence.UnitOfWork; namespace Umbraco.Core.Persistence.Repositories @@ -63,6 +65,17 @@ namespace Umbraco.Core.Persistence.Repositories protected void PersistNewBaseContentType(ContentTypeDto dto, IContentTypeComposition entity) { + //Cannot add a duplicate content type type + var exists = Database.ExecuteScalar(@"SELECT COUNT(*) FROM cmsContentType +INNER JOIN umbracoNode ON cmsContentType.nodeId = umbracoNode.id +WHERE cmsContentType." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("alias") + @"= @alias +AND umbracoNode.nodeObjectType = @objectType", + new { alias = entity.Alias, objectType = NodeObjectTypeId }); + if (exists > 0) + { + throw new DuplicateNameException("An item with the alias " + entity.Alias + " already exists"); + } + //Logic for setting Path, Level and SortOrder var parent = Database.First("WHERE id = @ParentId", new { ParentId = entity.ParentId }); int level = parent.Level + 1; @@ -165,6 +178,19 @@ namespace Umbraco.Core.Persistence.Repositories protected void PersistUpdatedBaseContentType(ContentTypeDto dto, IContentTypeComposition entity) { + + //Cannot update to a duplicate alias + var exists = Database.ExecuteScalar(@"SELECT COUNT(*) FROM cmsContentType +INNER JOIN umbracoNode ON cmsContentType.nodeId = umbracoNode.id +WHERE cmsContentType." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("alias") + @"= @alias +AND umbracoNode.nodeObjectType = @objectType +AND umbracoNode.id <> @id", + new { id = dto.NodeId, alias = entity.Alias, objectType = NodeObjectTypeId }); + if (exists > 0) + { + throw new DuplicateNameException("An item with the alias " + entity.Alias + " already exists"); + } + var propertyGroupFactory = new PropertyGroupFactory(entity.Id); var nodeDto = dto.NodeDto; diff --git a/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs b/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs index d8bfe62deb..3798bb53d9 100644 --- a/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs @@ -165,6 +165,18 @@ WHERE umbracoNode." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("te protected override void PersistUpdatedItem(IDataTypeDefinition entity) { + + //Cannot change to a duplicate alias + var exists = Database.ExecuteScalar(@"SELECT COUNT(*) FROM cmsDataType +INNER JOIN umbracoNode ON cmsDataType.nodeId = umbracoNode.id +WHERE umbracoNode." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("text") + @"= @name +AND umbracoNode.id <> @id", + new { id = entity.Id, name = entity.Name }); + if (exists > 0) + { + throw new DuplicateNameException("A data type with the name " + entity.Name + " already exists"); + } + //Updates Modified date and Version Guid ((DataTypeDefinition)entity).UpdatingEntity(); diff --git a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs index 05b8c84fd1..737ed7daef 100644 --- a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs @@ -220,8 +220,19 @@ namespace Umbraco.Core.Persistence.Repositories /// public virtual void PersistNewItem(IEntity entity) { - PersistNewItem((TEntity)entity); - _cache.Save(typeof(TEntity), entity); + try + { + PersistNewItem((TEntity)entity); + _cache.Save(typeof(TEntity), entity); + } + catch (Exception) + { + //if an exception is thrown we need to remove the entry from cache, this is ONLY a work around because of the way + // that we cache entities: http://issues.umbraco.org/issue/U4-4259 + _cache.Delete(typeof (TEntity), entity); + throw; + } + } /// @@ -230,8 +241,19 @@ namespace Umbraco.Core.Persistence.Repositories /// public virtual void PersistUpdatedItem(IEntity entity) { - PersistUpdatedItem((TEntity)entity); - _cache.Save(typeof(TEntity), entity); + try + { + PersistUpdatedItem((TEntity)entity); + _cache.Save(typeof(TEntity), entity); + } + catch (Exception) + { + //if an exception is thrown we need to remove the entry from cache, this is ONLY a work around because of the way + // that we cache entities: http://issues.umbraco.org/issue/U4-4259 + _cache.Delete(typeof (TEntity), entity); + throw; + } + } /// diff --git a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx index b803f94494..3bb2fad469 100644 --- a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx +++ b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx @@ -49,7 +49,8 @@ - + + diff --git a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.cs b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.cs index c3459b752e..28250d9fa4 100644 --- a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Web; +using System.Web.UI.WebControls; namespace Umbraco.Web.UI.Umbraco.Controls { diff --git a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.designer.cs b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.designer.cs index 582c67837d..c17c27becf 100644 --- a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.designer.cs +++ b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.designer.cs @@ -11,5 +11,7 @@ namespace Umbraco.Web.UI.Umbraco.Controls { public partial class ContentTypeControlNew { + + } } diff --git a/src/Umbraco.Web.UI/umbraco/create/simple.ascx b/src/Umbraco.Web.UI/umbraco/create/simple.ascx index 16ec4cdaad..04f63ecaff 100644 --- a/src/Umbraco.Web.UI/umbraco/create/simple.ascx +++ b/src/Umbraco.Web.UI/umbraco/create/simple.ascx @@ -6,7 +6,7 @@ public override void Save() { + //Cannot change to a duplicate alias + var exists = Database.ExecuteScalar(@"SELECT COUNT(*) FROM cmsDataType +INNER JOIN umbracoNode ON cmsDataType.nodeId = umbracoNode.id +WHERE umbracoNode." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("text") + @"= @name +AND umbracoNode.id <> @id", + new { id = this.Id, name = this.Text }); + if (exists > 0) + { + ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem( + string.Format("{0}{1}", CacheKeys.DataTypeCacheKey, this.Id)); + + throw new DuplicateNameException("A data type with the name " + this.Text + " already exists"); + } + + //this actually does the persisting. + base.Text = _text1; + OnSaving(EventArgs.Empty); } diff --git a/src/umbraco.cms/businesslogic/media/MediaType.cs b/src/umbraco.cms/businesslogic/media/MediaType.cs index c597774472..5f00c9388a 100644 --- a/src/umbraco.cms/businesslogic/media/MediaType.cs +++ b/src/umbraco.cms/businesslogic/media/MediaType.cs @@ -91,12 +91,12 @@ namespace umbraco.cms.businesslogic.media /// The name of the MediaType /// The new MediaType [Obsolete("Obsolete, Use Umbraco.Core.Models.MediaType and Umbraco.Core.Services.ContentTypeService.Save()", false)] - public static MediaType MakeNew(BusinessLogic.User u, string Text) + public static MediaType MakeNew(User u, string Text) { return MakeNew(u, Text, -1); } - internal static MediaType MakeNew(BusinessLogic.User u, string text, int parentId) + internal static MediaType MakeNew(User u, string text, int parentId) { var mediaType = new Umbraco.Core.Models.MediaType(parentId) { Name = text, Alias = text, CreatorId = u.Id, Thumbnail = "folder.png", Icon = "folder.gif" }; ApplicationContext.Current.Services.ContentTypeService.Save(mediaType, u.Id); From 3626d5b79d3c8a6a2dea801924150ecbea8e1632 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 10 Mar 2014 17:27:22 +1100 Subject: [PATCH 2/2] fixes unit tests --- .../Membership/UmbracoServiceMembershipProviderTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Tests/Membership/UmbracoServiceMembershipProviderTests.cs b/src/Umbraco.Tests/Membership/UmbracoServiceMembershipProviderTests.cs index 64305d6b1c..99ec6dbef2 100644 --- a/src/Umbraco.Tests/Membership/UmbracoServiceMembershipProviderTests.cs +++ b/src/Umbraco.Tests/Membership/UmbracoServiceMembershipProviderTests.cs @@ -95,7 +95,7 @@ namespace Umbraco.Tests.Membership mServiceMock.Setup(service => service.GetDefaultMemberType()).Returns("Member"); mServiceMock.Setup( service => service.CreateWithIdentity(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((string u, string e, string p, string m, bool b) => + .Callback((string u, string e, string p, string m) => { createdMember = new Member("test", e, u, p, memberType); }) @@ -126,7 +126,7 @@ namespace Umbraco.Tests.Membership mServiceMock.Setup(service => service.GetDefaultMemberType()).Returns("Member"); mServiceMock.Setup( service => service.CreateWithIdentity(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((string u, string e, string p, string m, bool b) => + .Callback((string u, string e, string p, string m) => { createdMember = new Member("test", e, u, p, memberType); }) @@ -159,7 +159,7 @@ namespace Umbraco.Tests.Membership mServiceMock.Setup(service => service.GetDefaultMemberType()).Returns("Member"); mServiceMock.Setup( service => service.CreateWithIdentity(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((string u, string e, string p, string m, bool b) => + .Callback((string u, string e, string p, string m) => { createdMember = new Member("test", e, u, p, memberType); })