diff --git a/src/Umbraco.Core/Models/PublicAccessEntry.cs b/src/Umbraco.Core/Models/PublicAccessEntry.cs index 1ed15a8fb4..5989f885cb 100644 --- a/src/Umbraco.Core/Models/PublicAccessEntry.cs +++ b/src/Umbraco.Core/Models/PublicAccessEntry.cs @@ -110,6 +110,12 @@ namespace Umbraco.Core.Models _ruleCollection.Clear(); } + + internal void ClearRemovedRules() + { + _removedRules.Clear(); + } + [DataMember] public int LoginNodeId { diff --git a/src/Umbraco.Core/Persistence/Repositories/PublicAccessRepository.cs b/src/Umbraco.Core/Persistence/Repositories/PublicAccessRepository.cs index 4ed29abd13..32a9d384af 100644 --- a/src/Umbraco.Core/Persistence/Repositories/PublicAccessRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/PublicAccessRepository.cs @@ -44,10 +44,9 @@ namespace Umbraco.Core.Persistence.Repositories { sql.Where("umbracoAccess.id IN (@ids)", new { ids = ids }); } - - sql.OrderBy(x => x.NodeId, SqlSyntax); - + var factory = new PublicAccessEntryFactory(); + //MUST be ordered by this GUID ID for the AccessRulesRelator to work var dtos = Database.Fetch(new AccessRulesRelator().Map, sql); return dtos.Select(factory.BuildEntity); } @@ -59,6 +58,7 @@ namespace Umbraco.Core.Persistence.Repositories var sql = translator.Translate(); var factory = new PublicAccessEntryFactory(); + //MUST be ordered by this GUID ID for the AccessRulesRelator to work var dtos = Database.Fetch(new AccessRulesRelator().Map, sql); return dtos.Select(factory.BuildEntity); } @@ -70,7 +70,8 @@ namespace Umbraco.Core.Persistence.Repositories .From(SqlSyntax) .LeftJoin(SqlSyntax) .On(SqlSyntax, left => left.Id, right => right.AccessId) - .OrderBy(new string[] { "umbracoAccess.id" }); + //MUST be ordered by this GUID ID for the AccessRulesRelator to work + .OrderBy(dto => dto.Id, SqlSyntax); return sql; } @@ -111,6 +112,11 @@ namespace Umbraco.Core.Persistence.Repositories { rule.AccessId = entity.Key; Database.Insert(rule); + //update the id so HasEntity is correct + var entityRule = entity.Rules.First(x => x.Key == rule.Id); + entityRule.Id = entityRule.Key.GetHashCode(); + //double make sure that this is set since it is possible to add rules via ctor without AddRule + entityRule.AccessEntryId = entity.Key; } entity.ResetDirtyProperties(); @@ -131,7 +137,7 @@ namespace Umbraco.Core.Persistence.Repositories { if (rule.HasIdentity) { - var count = Database.Update(dto.Rules.Single(x => x.Id == rule.Key)); + var count = Database.Update(dto.Rules.First(x => x.Id == rule.Key)); if (count == 0) { throw new InvalidOperationException("No rows were updated for the access rule"); @@ -157,6 +163,8 @@ namespace Umbraco.Core.Persistence.Repositories Database.Delete("WHERE id=@Id", new {Id = removedRule}); } + entity.ClearRemovedRules(); + entity.ResetDirtyProperties(); } diff --git a/src/Umbraco.Tests/Persistence/Repositories/PublicAccessRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/PublicAccessRepositoryTest.cs index 4fa212f9bc..00a508dee9 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/PublicAccessRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/PublicAccessRepositoryTest.cs @@ -154,36 +154,61 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Get_All() { - var content = CreateTestData(3).ToArray(); + var content = CreateTestData(30).ToArray(); var provider = new PetaPocoUnitOfWorkProvider(Logger); var unitOfWork = provider.GetUnitOfWork(); using (var repo = new PublicAccessRepository(unitOfWork, CacheHelper, Logger, SqlSyntax)) - { - var entry1 = new PublicAccessEntry(content[0], content[1], content[2], new[] + { + var allEntries = new List(); + for (int i = 0; i < 10; i++) { - new PublicAccessRule + var rules = new List(); + for (int j = 0; j < 50; j++) { - RuleValue = "test", - RuleType = "RoleName" - }, - }); - repo.AddOrUpdate(entry1); + rules.Add(new PublicAccessRule + { + RuleValue = "test" + j, + RuleType = "RoleName" + j + }); + } + var entry1 = new PublicAccessEntry(content[i], content[i+1], content[i+2], rules); + repo.AddOrUpdate(entry1); + unitOfWork.Commit(); + allEntries.Add(entry1); + } - var entry2 = new PublicAccessEntry(content[1], content[0], content[2], new[] + //now remove a few rules from a few of the items and then add some more, this will put things 'out of order' which + //we need to verify our sort order is working for the relator + for (int i = 0; i < allEntries.Count; i++) { - new PublicAccessRule + //all the even ones + if (i % 2 == 0) { - RuleValue = "test", - RuleType = "RoleName" - }, - }); - repo.AddOrUpdate(entry2); - - unitOfWork.Commit(); + var rules = allEntries[i].Rules.ToArray(); + for (int j = 0; j < rules.Length; j++) + { + //all the even ones + if (j % 2 == 0) + { + allEntries[i].RemoveRule(rules[j]); + } + } + allEntries[i].AddRule("newrule" + i, "newrule" + i); + repo.AddOrUpdate(allEntries[i]); + unitOfWork.Commit(); + } + } var found = repo.GetAll().ToArray(); - Assert.AreEqual(2, found.Count()); + Assert.AreEqual(10, found.Length); + + foreach (var publicAccessEntry in found) + { + var matched = allEntries.First(x => x.Key == publicAccessEntry.Key); + + Assert.AreEqual(matched.Rules.Count(), publicAccessEntry.Rules.Count()); + } } }