diff --git a/build/NuSpecs/UmbracoCms.Web.nuspec b/build/NuSpecs/UmbracoCms.Web.nuspec index e9bd8ca6ea..adf090c69b 100644 --- a/build/NuSpecs/UmbracoCms.Web.nuspec +++ b/build/NuSpecs/UmbracoCms.Web.nuspec @@ -25,7 +25,7 @@ - + diff --git a/src/Umbraco.Core/Manifest/ContentAppDefinitionConverter.cs b/src/Umbraco.Core/Manifest/ContentAppDefinitionConverter.cs deleted file mode 100644 index 87f104d90e..0000000000 --- a/src/Umbraco.Core/Manifest/ContentAppDefinitionConverter.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using Newtonsoft.Json.Linq; -using Umbraco.Core.Models.ContentEditing; -using Umbraco.Core.Serialization; - -namespace Umbraco.Core.Manifest -{ - /// - /// Implements a json read converter for . - /// - internal class ContentAppDefinitionConverter : JsonReadConverter - { - protected override IContentAppDefinition Create(Type objectType, string path, JObject jObject) - => new ManifestContentAppDefinition(); - } -} diff --git a/src/Umbraco.Core/Manifest/ManifestContentAppDefinition.cs b/src/Umbraco.Core/Manifest/ManifestContentAppDefinition.cs index d5f6c2b8c4..0667f11aab 100644 --- a/src/Umbraco.Core/Manifest/ManifestContentAppDefinition.cs +++ b/src/Umbraco.Core/Manifest/ManifestContentAppDefinition.cs @@ -31,11 +31,9 @@ namespace Umbraco.Core.Manifest /// Represents a content app definition, parsed from a manifest. /// [DataContract(Name = "appdef", Namespace = "")] - public class ManifestContentAppDefinition : IContentAppDefinition + public class ManifestContentAppDefinition { private string _view; - private ContentApp _app; - private ShowRule[] _showRules; /// /// Gets or sets the name of the content app. @@ -83,132 +81,5 @@ namespace Umbraco.Core.Manifest [DataMember(Name = "show")] public string[] Show { get; set; } = Array.Empty(); - /// - public ContentApp GetContentAppFor(object o, IEnumerable userGroups) - { - string partA, partB; - - switch (o) - { - case IContent content: - partA = "content"; - partB = content.ContentType.Alias; - break; - - case IMedia media: - partA = "media"; - partB = media.ContentType.Alias; - break; - - default: - return null; - } - - var rules = _showRules ?? (_showRules = ShowRule.Parse(Show).ToArray()); - var userGroupsList = userGroups.ToList(); - - var okRole = false; - var hasRole = false; - var okType = false; - var hasType = false; - - foreach (var rule in rules) - { - if (rule.PartA.InvariantEquals("role")) - { - // if roles have been ok-ed already, skip the rule - if (okRole) - continue; - - // remember we have role rules - hasRole = true; - - foreach (var group in userGroupsList) - { - // if the entry does not apply, skip - if (!rule.Matches("role", group.Alias)) - continue; - - // if the entry applies, - // if it's an exclude entry, exit, do not display the content app - if (!rule.Show) - return null; - - // else ok to display, remember roles are ok, break from userGroupsList - okRole = rule.Show; - break; - } - } - else // it is a type rule - { - // if type has been ok-ed already, skip the rule - if (okType) - continue; - - // remember we have type rules - hasType = true; - - // if the entry does not apply, skip it - if (!rule.Matches(partA, partB)) - continue; - - // if the entry applies, - // if it's an exclude entry, exit, do not display the content app - if (!rule.Show) - return null; - - // else ok to display, remember type rules are ok - okType = true; - } - } - - // if roles rules are specified but not ok, - // or if type roles are specified but not ok, - // cannot display the content app - if ((hasRole && !okRole) || (hasType && !okType)) - return null; - - // else - // content app can be displayed - return _app ?? (_app = new ContentApp - { - Alias = Alias, - Name = Name, - Icon = Icon, - View = View, - Weight = Weight - }); - } - - private class ShowRule - { - private static readonly Regex ShowRegex = new Regex("^([+-])?([a-z]+)/([a-z0-9_]+|\\*)$", RegexOptions.Compiled | RegexOptions.IgnoreCase); - - public bool Show { get; private set; } - public string PartA { get; private set; } - public string PartB { get; private set; } - - public bool Matches(string partA, string partB) - { - return (PartA == "*" || PartA.InvariantEquals(partA)) && (PartB == "*" || PartB.InvariantEquals(partB)); - } - - public static IEnumerable Parse(string[] rules) - { - foreach (var rule in rules) - { - var match = ShowRegex.Match(rule); - if (!match.Success) - throw new FormatException($"Illegal 'show' entry \"{rule}\" in manifest."); - - yield return new ShowRule - { - Show = match.Groups[1].Value != "-", - PartA = match.Groups[2].Value, - PartB = match.Groups[3].Value - }; - } - } - } } } diff --git a/src/Umbraco.Core/Manifest/ManifestContentAppFactory.cs b/src/Umbraco.Core/Manifest/ManifestContentAppFactory.cs new file mode 100644 index 0000000000..1c50a4b895 --- /dev/null +++ b/src/Umbraco.Core/Manifest/ManifestContentAppFactory.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using Umbraco.Core.Models; +using Umbraco.Core.Models.ContentEditing; +using Umbraco.Core.Models.Membership; + +namespace Umbraco.Core.Manifest +{ + // contentApps: [ + // { + // name: 'App Name', // required + // alias: 'appAlias', // required + // weight: 0, // optional, default is 0, use values between -99 and +99 + // icon: 'icon.app', // required + // view: 'path/view.htm', // required + // show: [ // optional, default is always show + // '-content/foo', // hide for content type 'foo' + // '+content/*', // show for all other content types + // '+media/*', // show for all media types + // '+role/admin' // show for admin users. Role based permissions will override others. + // ] + // }, + // ... + // ] + + /// + /// Represents a content app factory, for content apps parsed from the manifest. + /// + public class ManifestContentAppFactory : IContentAppFactory + { + private readonly ManifestContentAppDefinition _definition; + + public ManifestContentAppFactory(ManifestContentAppDefinition definition) + { + _definition = definition; + } + + private ContentApp _app; + private ShowRule[] _showRules; + + /// + public ContentApp GetContentAppFor(object o,IEnumerable userGroups) + { + string partA, partB; + + switch (o) + { + case IContent content: + partA = "content"; + partB = content.ContentType.Alias; + break; + + case IMedia media: + partA = "media"; + partB = media.ContentType.Alias; + break; + + default: + return null; + } + + var rules = _showRules ?? (_showRules = ShowRule.Parse(_definition.Show).ToArray()); + var userGroupsList = userGroups.ToList(); + + var okRole = false; + var hasRole = false; + var okType = false; + var hasType = false; + + foreach (var rule in rules) + { + if (rule.PartA.InvariantEquals("role")) + { + // if roles have been ok-ed already, skip the rule + if (okRole) + continue; + + // remember we have role rules + hasRole = true; + + foreach (var group in userGroupsList) + { + // if the entry does not apply, skip + if (!rule.Matches("role", group.Alias)) + continue; + + // if the entry applies, + // if it's an exclude entry, exit, do not display the content app + if (!rule.Show) + return null; + + // else ok to display, remember roles are ok, break from userGroupsList + okRole = rule.Show; + break; + } + } + else // it is a type rule + { + // if type has been ok-ed already, skip the rule + if (okType) + continue; + + // remember we have type rules + hasType = true; + + // if the entry does not apply, skip it + if (!rule.Matches(partA, partB)) + continue; + + // if the entry applies, + // if it's an exclude entry, exit, do not display the content app + if (!rule.Show) + return null; + + // else ok to display, remember type rules are ok + okType = true; + } + } + + // if roles rules are specified but not ok, + // or if type roles are specified but not ok, + // cannot display the content app + if ((hasRole && !okRole) || (hasType && !okType)) + return null; + + // else + // content app can be displayed + return _app ?? (_app = new ContentApp + { + Alias = _definition.Alias, + Name = _definition.Name, + Icon = _definition.Icon, + View = _definition.View, + Weight = _definition.Weight + }); + } + + private class ShowRule + { + private static readonly Regex ShowRegex = new Regex("^([+-])?([a-z]+)/([a-z0-9_]+|\\*)$", RegexOptions.Compiled | RegexOptions.IgnoreCase); + + public bool Show { get; private set; } + public string PartA { get; private set; } + public string PartB { get; private set; } + + public bool Matches(string partA, string partB) + { + return (PartA == "*" || PartA.InvariantEquals(partA)) && (PartB == "*" || PartB.InvariantEquals(partB)); + } + + public static IEnumerable Parse(string[] rules) + { + foreach (var rule in rules) + { + var match = ShowRegex.Match(rule); + if (!match.Success) + throw new FormatException($"Illegal 'show' entry \"{rule}\" in manifest."); + + yield return new ShowRule + { + Show = match.Groups[1].Value != "-", + PartA = match.Groups[2].Value, + PartB = match.Groups[3].Value + }; + } + } + } + } +} diff --git a/src/Umbraco.Core/Manifest/ManifestParser.cs b/src/Umbraco.Core/Manifest/ManifestParser.cs index fe021fae5b..59753df66a 100644 --- a/src/Umbraco.Core/Manifest/ManifestParser.cs +++ b/src/Umbraco.Core/Manifest/ManifestParser.cs @@ -99,7 +99,7 @@ namespace Umbraco.Core.Manifest var propertyEditors = new List(); var parameterEditors = new List(); var gridEditors = new List(); - var contentApps = new List(); + var contentApps = new List(); var dashboards = new List(); foreach (var manifest in manifests) @@ -153,7 +153,6 @@ namespace Umbraco.Core.Manifest var manifest = JsonConvert.DeserializeObject(text, new DataEditorConverter(_logger), new ValueValidatorConverter(_validators), - new ContentAppDefinitionConverter(), new DashboardAccessRuleConverter()); // scripts and stylesheets are raw string, must process here diff --git a/src/Umbraco.Core/Manifest/PackageManifest.cs b/src/Umbraco.Core/Manifest/PackageManifest.cs index 95a5c01b6a..cd806ac847 100644 --- a/src/Umbraco.Core/Manifest/PackageManifest.cs +++ b/src/Umbraco.Core/Manifest/PackageManifest.cs @@ -26,7 +26,7 @@ namespace Umbraco.Core.Manifest public GridEditor[] GridEditors { get; set; } = Array.Empty(); [JsonProperty("contentApps")] - public IContentAppDefinition[] ContentApps { get; set; } = Array.Empty(); + public ManifestContentAppDefinition[] ContentApps { get; set; } = Array.Empty(); [JsonProperty("dashboards")] public ManifestDashboardDefinition[] Dashboards { get; set; } = Array.Empty(); diff --git a/src/Umbraco.Core/Models/ContentEditing/IContentAppDefinition.cs b/src/Umbraco.Core/Models/ContentEditing/IContentAppFactory.cs similarity index 89% rename from src/Umbraco.Core/Models/ContentEditing/IContentAppDefinition.cs rename to src/Umbraco.Core/Models/ContentEditing/IContentAppFactory.cs index af83c5a2f5..6b8d90d418 100644 --- a/src/Umbraco.Core/Models/ContentEditing/IContentAppDefinition.cs +++ b/src/Umbraco.Core/Models/ContentEditing/IContentAppFactory.cs @@ -3,11 +3,10 @@ using Umbraco.Core.Models.Membership; namespace Umbraco.Core.Models.ContentEditing { - /// - /// Represents a content app definition. + /// Represents a content app factory. /// - public interface IContentAppDefinition + public interface IContentAppFactory { /// /// Gets the content app for an object. diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 98aad7ec3c..d2ec86178b 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -346,9 +346,9 @@ - + @@ -393,7 +393,7 @@ - + diff --git a/src/Umbraco.Tests/Manifest/ManifestContentAppTests.cs b/src/Umbraco.Tests/Manifest/ManifestContentAppTests.cs index eed0919149..016eb4113a 100644 --- a/src/Umbraco.Tests/Manifest/ManifestContentAppTests.cs +++ b/src/Umbraco.Tests/Manifest/ManifestContentAppTests.cs @@ -67,7 +67,8 @@ namespace Umbraco.Tests.Manifest private void AssertDefinition(object source, bool expected, string[] show, IReadOnlyUserGroup[] groups) { var definition = JsonConvert.DeserializeObject("{" + (show.Length == 0 ? "" : " \"show\": [" + string.Join(",", show.Select(x => "\"" + x + "\"")) + "] ") + "}"); - var app = definition.GetContentAppFor(source, groups); + var factory = new ManifestContentAppFactory(definition); + var app = factory.GetContentAppFor(source, groups); if (expected) Assert.IsNotNull(app); else diff --git a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs index e357d9b4be..419819b79d 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs @@ -109,6 +109,7 @@ namespace Umbraco.Tests.PublishedContent } [Test] + [Ignore("No point testing with Examine, should refactor this test.")] public void Ensure_Children_Sorted_With_Examine() { var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetInstance(), IndexInitializer.GetMockMediaService()); @@ -136,6 +137,7 @@ namespace Umbraco.Tests.PublishedContent } [Test] + [Ignore("No point testing with Examine, should refactor this test.")] public void Do_Not_Find_In_Recycle_Bin() { var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetInstance(), IndexInitializer.GetMockMediaService()); @@ -183,6 +185,7 @@ namespace Umbraco.Tests.PublishedContent } [Test] + [Ignore("No point testing with Examine, should refactor this test.")] public void Children_With_Examine() { var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetInstance(), IndexInitializer.GetMockMediaService()); @@ -210,6 +213,7 @@ namespace Umbraco.Tests.PublishedContent } [Test] + [Ignore("No point testing with Examine, should refactor this test.")] public void Descendants_With_Examine() { var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetInstance(), IndexInitializer.GetMockMediaService()); @@ -237,6 +241,7 @@ namespace Umbraco.Tests.PublishedContent } [Test] + [Ignore("No point testing with Examine, should refactor this test.")] public void DescendantsOrSelf_With_Examine() { var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetInstance(), IndexInitializer.GetMockMediaService()); @@ -264,6 +269,7 @@ namespace Umbraco.Tests.PublishedContent } [Test] + [Ignore("No point testing with Examine, should refactor this test.")] public void Ancestors_With_Examine() { var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetInstance(), IndexInitializer.GetMockMediaService()); @@ -289,6 +295,7 @@ namespace Umbraco.Tests.PublishedContent } [Test] + [Ignore("No point testing with Examine, should refactor this test.")] public void AncestorsOrSelf_With_Examine() { var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetInstance(), IndexInitializer.GetMockMediaService()); diff --git a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs index 7758b570e7..5f4b9dd21f 100644 --- a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs +++ b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs @@ -153,11 +153,8 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting var membershipHelper = new MembershipHelper(new TestUmbracoContextAccessor(umbCtx), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), null, Mock.Of(), Mock.Of()); - var mockedTypedContent = Mock.Of(); - var umbHelper = new UmbracoHelper(umbCtx, Mock.Of(), - mockedTypedContent, Mock.Of(), Mock.Of(), Mock.Of(), diff --git a/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs b/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs index bace084313..1b99479dea 100644 --- a/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs +++ b/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs @@ -62,7 +62,6 @@ namespace Umbraco.Tests.Testing.TestingTests // ReSharper disable once UnusedVariable var helper = new UmbracoHelper(umbracoContext, Mock.Of(), - Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index 72da9e9ef2..ff9318e63f 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -232,7 +232,7 @@ namespace Umbraco.Tests.Testing Composition.RegisterUnique(); // register empty content apps collection - Composition.WithCollectionBuilder(); + Composition.WithCollectionBuilder(); } protected virtual void ComposeAutoMapper(bool configure) diff --git a/src/Umbraco.Tests/UmbracoExamine/IndexTest.cs b/src/Umbraco.Tests/UmbracoExamine/IndexTest.cs index 15ed76f155..07a2eb467a 100644 --- a/src/Umbraco.Tests/UmbracoExamine/IndexTest.cs +++ b/src/Umbraco.Tests/UmbracoExamine/IndexTest.cs @@ -185,21 +185,21 @@ namespace Umbraco.Tests.UmbracoExamine [Test] public void Index_Move_Media_From_Non_Indexable_To_Indexable_ParentID() { + // create a validator with + // publishedValuesOnly false + // parentId 1116 (only content under that parent will be indexed) + var validator = new ContentValueSetValidator(false, 1116); using (var luceneDir = new RandomIdRamDirectory()) - using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, - //make parent id 1116 - validator: new ContentValueSetValidator(false, 1116))) + using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, validator: validator)) using (indexer.ProcessNonAsync()) { var searcher = indexer.GetSearcher(); //get a node from the data repo (this one exists underneath 2222) var node = _mediaService.GetLatestMediaByXpath("//*[string-length(@id)>0 and number(@id)>0]") - .Root - .Elements() - .Where(x => (int)x.Attribute("id") == 2112) - .First(); + .Root.Elements() + .First(x => (int) x.Attribute("id") == 2112); var currPath = (string)node.Attribute("path"); //should be : -1,1111,2222,2112 Assert.AreEqual("-1,1111,2222,2112", currPath); @@ -228,20 +228,21 @@ namespace Umbraco.Tests.UmbracoExamine [Test] public void Index_Move_Media_To_Non_Indexable_ParentID() { + // create a validator with + // publishedValuesOnly false + // parentId 2222 (only content under that parent will be indexed) + var validator = new ContentValueSetValidator(false, 2222); + using (var luceneDir = new RandomIdRamDirectory()) - using (var indexer1 = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, - //make parent id 2222 - validator: new ContentValueSetValidator(false, 2222))) + using (var indexer1 = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, luceneDir, validator: validator)) using (indexer1.ProcessNonAsync()) { var searcher = indexer1.GetSearcher(); //get a node from the data repo (this one exists underneath 2222) var node = _mediaService.GetLatestMediaByXpath("//*[string-length(@id)>0 and number(@id)>0]") - .Root - .Elements() - .Where(x => (int)x.Attribute("id") == 2112) - .First(); + .Root.Elements() + .First(x => (int) x.Attribute("id") == 2112); var currPath = (string)node.Attribute("path"); //should be : -1,1111,2222,2112 Assert.AreEqual("-1,1111,2222,2112", currPath); @@ -249,8 +250,6 @@ namespace Umbraco.Tests.UmbracoExamine //ensure it's indexed indexer1.IndexItem(node.ConvertToValueSet(IndexTypes.Media)); - - //it will exist because it exists under 2222 var results = searcher.Search(searcher.CreateCriteria().Id(2112).Compile()); Assert.AreEqual(1, results.Count()); @@ -262,8 +261,6 @@ namespace Umbraco.Tests.UmbracoExamine //now reindex the node, this should first delete it and then NOT add it because of the parent id constraint indexer1.IndexItems(new[] { node.ConvertToValueSet(IndexTypes.Media) }); - - //now ensure it's deleted results = searcher.Search(searcher.CreateCriteria().Id(2112).Compile()); Assert.AreEqual(0, results.Count()); diff --git a/src/Umbraco.Tests/Web/Controllers/ContentControllerTests.cs b/src/Umbraco.Tests/Web/Controllers/ContentControllerTests.cs index ec97b92c8e..f16863795b 100644 --- a/src/Umbraco.Tests/Web/Controllers/ContentControllerTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/ContentControllerTests.cs @@ -211,9 +211,8 @@ namespace Umbraco.Tests.Web.Controllers var contentServiceMock = Mock.Get(Current.Services.ContentService); contentServiceMock.Setup(x => x.GetById(123)).Returns(() => null); //do not find it - var publishedSnapshot = Mock.Of(); var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); - var usersController = new ContentController(publishedSnapshot, propertyEditorCollection); + var usersController = new ContentController(propertyEditorCollection); return usersController; } @@ -238,9 +237,8 @@ namespace Umbraco.Tests.Web.Controllers var contentServiceMock = Mock.Get(Current.Services.ContentService); contentServiceMock.Setup(x => x.GetById(123)).Returns(() => GetMockedContent()); - var publishedSnapshot = Mock.Of(); var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); - var usersController = new ContentController(publishedSnapshot, propertyEditorCollection); + var usersController = new ContentController(propertyEditorCollection); return usersController; } @@ -270,9 +268,8 @@ namespace Umbraco.Tests.Web.Controllers var contentServiceMock = Mock.Get(Current.Services.ContentService); contentServiceMock.Setup(x => x.GetById(123)).Returns(() => GetMockedContent()); - var publishedSnapshot = Mock.Of(); var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); - var usersController = new ContentController(publishedSnapshot, propertyEditorCollection); + var usersController = new ContentController(propertyEditorCollection); return usersController; } @@ -308,9 +305,8 @@ namespace Umbraco.Tests.Web.Controllers contentServiceMock.Setup(x => x.Save(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new OperationResult(OperationResultType.Success, new Core.Events.EventMessages())); //success - var publishedSnapshot = Mock.Of(); var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); - var usersController = new ContentController(publishedSnapshot, propertyEditorCollection); + var usersController = new ContentController(propertyEditorCollection); return usersController; } @@ -340,9 +336,8 @@ namespace Umbraco.Tests.Web.Controllers contentServiceMock.Setup(x => x.Save(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new OperationResult(OperationResultType.Success, new Core.Events.EventMessages())); //success - var publishedSnapshot = Mock.Of(); var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); - var usersController = new ContentController(publishedSnapshot, propertyEditorCollection); + var usersController = new ContentController(propertyEditorCollection); return usersController; } @@ -376,9 +371,8 @@ namespace Umbraco.Tests.Web.Controllers contentServiceMock.Setup(x => x.Save(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new OperationResult(OperationResultType.Success, new Core.Events.EventMessages())); //success - var publishedSnapshot = Mock.Of(); var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); - var usersController = new ContentController(publishedSnapshot, propertyEditorCollection); + var usersController = new ContentController(propertyEditorCollection); return usersController; } diff --git a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs index e4dc2cc85f..f833e39d5a 100644 --- a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs @@ -104,6 +104,13 @@ namespace Umbraco.Tests.Web.Mvc { var publishedSnapshot = new Mock(); publishedSnapshot.Setup(x => x.Members).Returns(Mock.Of()); + var contentCache = new Mock(); + var content = new Mock(); + content.Setup(x => x.Id).Returns(2); + contentCache.Setup(x => x.GetById(It.IsAny())).Returns(content.Object); + var mediaCache = new Mock(); + publishedSnapshot.Setup(x => x.Content).Returns(contentCache.Object); + publishedSnapshot.Setup(x => x.Media).Returns(mediaCache.Object); var publishedSnapshotService = new Mock(); publishedSnapshotService.Setup(x => x.CreatePublishedSnapshot(It.IsAny())).Returns(publishedSnapshot.Object); var globalSettings = TestObjects.GetGlobalSettings(); @@ -122,9 +129,6 @@ namespace Umbraco.Tests.Web.Mvc var helper = new UmbracoHelper( umbracoContext, Mock.Of(), - Mock.Of(query => query.Content(It.IsAny()) == - //return mock of IPublishedContent for any call to GetById - Mock.Of(content => content.Id == 2)), Mock.Of(), Mock.Of(), Mock.Of(), diff --git a/src/Umbraco.Web/CompositionExtensions.cs b/src/Umbraco.Web/CompositionExtensions.cs index 72e1d1ddbe..5adae22b4a 100644 --- a/src/Umbraco.Web/CompositionExtensions.cs +++ b/src/Umbraco.Web/CompositionExtensions.cs @@ -36,8 +36,8 @@ namespace Umbraco.Core.Components /// /// The composition. /// - public static ContentAppDefinitionCollectionBuilder ContentApps(this Composition composition) - => composition.WithCollectionBuilder(); + public static ContentAppFactoryCollectionBuilder ContentApps(this Composition composition) + => composition.WithCollectionBuilder(); /// /// Gets the content finders collection builder. diff --git a/src/Umbraco.Web/ContentApps/ContentAppDefinitionCollection.cs b/src/Umbraco.Web/ContentApps/ContentAppFactoryCollection.cs similarity index 80% rename from src/Umbraco.Web/ContentApps/ContentAppDefinitionCollection.cs rename to src/Umbraco.Web/ContentApps/ContentAppFactoryCollection.cs index 8b33fd1447..07987aea3e 100644 --- a/src/Umbraco.Web/ContentApps/ContentAppDefinitionCollection.cs +++ b/src/Umbraco.Web/ContentApps/ContentAppFactoryCollection.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using Umbraco.Core; using Umbraco.Core.Composing; @@ -9,11 +8,11 @@ using Umbraco.Core.Models.Membership; namespace Umbraco.Web.ContentApps { - public class ContentAppDefinitionCollection : BuilderCollectionBase + public class ContentAppFactoryCollection : BuilderCollectionBase { private readonly ILogger _logger; - public ContentAppDefinitionCollection(IEnumerable items, ILogger logger) + public ContentAppFactoryCollection(IEnumerable items, ILogger logger) : base(items) { _logger = logger; @@ -32,6 +31,7 @@ namespace Umbraco.Web.ContentApps public IEnumerable GetContentAppsFor(object o, IEnumerable userGroups=null) { var roles = GetCurrentUserGroups(); + var apps = this.Select(x => x.GetContentAppFor(o, roles)).WhereNotNull().OrderBy(x => x.Weight).ToList(); var aliases = new HashSet(); @@ -50,7 +50,7 @@ namespace Umbraco.Web.ContentApps // dying is not user-friendly, so let's write to log instead, and wish people read logs... //throw new InvalidOperationException($"Duplicate content app aliases found: {string.Join(",", dups)}"); - _logger.Warn("Duplicate content app aliases found: {DuplicateAliases}", string.Join(",", dups)); + _logger.Warn("Duplicate content app aliases found: {DuplicateAliases}", string.Join(",", dups)); } return apps; diff --git a/src/Umbraco.Web/ContentApps/ContentAppDefinitionCollectionBuilder.cs b/src/Umbraco.Web/ContentApps/ContentAppFactoryCollectionBuilder.cs similarity index 61% rename from src/Umbraco.Web/ContentApps/ContentAppDefinitionCollectionBuilder.cs rename to src/Umbraco.Web/ContentApps/ContentAppFactoryCollectionBuilder.cs index 5299fe7152..2f35e77a7c 100644 --- a/src/Umbraco.Web/ContentApps/ContentAppDefinitionCollectionBuilder.cs +++ b/src/Umbraco.Web/ContentApps/ContentAppFactoryCollectionBuilder.cs @@ -7,27 +7,27 @@ using Umbraco.Core.Models.ContentEditing; namespace Umbraco.Web.ContentApps { - public class ContentAppDefinitionCollectionBuilder : OrderedCollectionBuilderBase + public class ContentAppFactoryCollectionBuilder : OrderedCollectionBuilderBase { - protected override ContentAppDefinitionCollectionBuilder This => this; + protected override ContentAppFactoryCollectionBuilder This => this; // need to inject dependencies in the collection, so override creation - public override ContentAppDefinitionCollection CreateCollection(IFactory factory) + public override ContentAppFactoryCollection CreateCollection(IFactory factory) { // get the logger just-in-time - see note below for manifest parser var logger = factory.GetInstance(); - return new ContentAppDefinitionCollection(CreateItems(factory), logger); + return new ContentAppFactoryCollection(CreateItems(factory), logger); } - protected override IEnumerable CreateItems(IFactory factory) + protected override IEnumerable CreateItems(IFactory factory) { // get the manifest parser just-in-time - injecting it in the ctor would mean that // simply getting the builder in order to configure the collection, would require // its dependencies too, and that can create cycles or other oddities var manifestParser = factory.GetInstance(); - return base.CreateItems(factory).Concat(manifestParser.Manifest.ContentApps); + return base.CreateItems(factory).Concat(manifestParser.Manifest.ContentApps.Select(x => new ManifestContentAppFactory(x))); } } } diff --git a/src/Umbraco.Web/ContentApps/ContentEditorContentAppDefinition.cs b/src/Umbraco.Web/ContentApps/ContentEditorContentAppFactory.cs similarity index 95% rename from src/Umbraco.Web/ContentApps/ContentEditorContentAppDefinition.cs rename to src/Umbraco.Web/ContentApps/ContentEditorContentAppFactory.cs index d54d1a44d4..b1d5d373c0 100644 --- a/src/Umbraco.Web/ContentApps/ContentEditorContentAppDefinition.cs +++ b/src/Umbraco.Web/ContentApps/ContentEditorContentAppFactory.cs @@ -6,7 +6,7 @@ using Umbraco.Core.Models.Membership; namespace Umbraco.Web.ContentApps { - internal class ContentEditorContentAppDefinition : IContentAppDefinition + internal class ContentEditorContentAppFactory : IContentAppFactory { // see note on ContentApp private const int Weight = -100; diff --git a/src/Umbraco.Web/ContentApps/ContentInfoContentAppDefinition.cs b/src/Umbraco.Web/ContentApps/ContentInfoContentAppFactory.cs similarity index 95% rename from src/Umbraco.Web/ContentApps/ContentInfoContentAppDefinition.cs rename to src/Umbraco.Web/ContentApps/ContentInfoContentAppFactory.cs index de490439ba..49be194349 100644 --- a/src/Umbraco.Web/ContentApps/ContentInfoContentAppDefinition.cs +++ b/src/Umbraco.Web/ContentApps/ContentInfoContentAppFactory.cs @@ -6,7 +6,7 @@ using Umbraco.Core.Models.Membership; namespace Umbraco.Web.ContentApps { - public class ContentInfoContentAppDefinition : IContentAppDefinition + public class ContentInfoContentAppFactory : IContentAppFactory { // see note on ContentApp private const int Weight = +100; diff --git a/src/Umbraco.Web/ContentApps/ListViewContentAppDefinition.cs b/src/Umbraco.Web/ContentApps/ListViewContentAppFactory.cs similarity index 96% rename from src/Umbraco.Web/ContentApps/ListViewContentAppDefinition.cs rename to src/Umbraco.Web/ContentApps/ListViewContentAppFactory.cs index 0e4c7a04b8..7421a55907 100644 --- a/src/Umbraco.Web/ContentApps/ListViewContentAppDefinition.cs +++ b/src/Umbraco.Web/ContentApps/ListViewContentAppFactory.cs @@ -9,7 +9,7 @@ using Umbraco.Web.Models.ContentEditing; namespace Umbraco.Web.ContentApps { - internal class ListViewContentAppDefinition : IContentAppDefinition + internal class ListViewContentAppFactory : IContentAppFactory { // see note on ContentApp private const int Weight = -666; @@ -17,7 +17,7 @@ namespace Umbraco.Web.ContentApps private readonly IDataTypeService _dataTypeService; private readonly PropertyEditorCollection _propertyEditors; - public ListViewContentAppDefinition(IDataTypeService dataTypeService, PropertyEditorCollection propertyEditors) + public ListViewContentAppFactory(IDataTypeService dataTypeService, PropertyEditorCollection propertyEditors) { _dataTypeService = dataTypeService; _propertyEditors = propertyEditors; diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index e330df1c45..832103009a 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.IO; using System.Linq; using System.Net; @@ -9,7 +8,6 @@ using System.Text; using System.Web.Http; using System.Web.Http.Controllers; using System.Web.Http.ModelBinding; -using System.Web.Http.ValueProviders; using AutoMapper; using Umbraco.Core; using Umbraco.Core.Logging; @@ -23,16 +21,11 @@ using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; using Umbraco.Web.WebApi.Filters; using Umbraco.Core.Persistence.Querying; -using Umbraco.Web.PublishedCache; using Umbraco.Core.Events; using Umbraco.Core.Models.ContentEditing; using Umbraco.Core.Models.Validation; using Umbraco.Web.Composing; -using Umbraco.Web.Models; -using Umbraco.Web.WebServices; - using Constants = Umbraco.Core.Constants; -using Language = Umbraco.Web.Models.ContentEditing.Language; using Umbraco.Core.PropertyEditors; using Umbraco.Web.Actions; using Umbraco.Web.ContentApps; @@ -55,16 +48,13 @@ namespace Umbraco.Web.Editors [ContentControllerConfiguration] public class ContentController : ContentControllerBase { - private readonly IPublishedSnapshotService _publishedSnapshotService; private readonly PropertyEditorCollection _propertyEditors; private readonly Lazy> _allLangs; public object Domains { get; private set; } - public ContentController(IPublishedSnapshotService publishedSnapshotService, PropertyEditorCollection propertyEditors) + public ContentController(PropertyEditorCollection propertyEditors) { - if (publishedSnapshotService == null) throw new ArgumentNullException(nameof(publishedSnapshotService)); - _publishedSnapshotService = publishedSnapshotService; _propertyEditors = propertyEditors ?? throw new ArgumentNullException(nameof(propertyEditors)); _allLangs = new Lazy>(() => Services.LocalizationService.GetAllLanguages().ToDictionary(x => x.IsoCode, x => x, StringComparer.InvariantCultureIgnoreCase)); } @@ -234,7 +224,7 @@ namespace Umbraco.Web.Editors public ContentItemDisplay GetRecycleBin() { var apps = new List(); - apps.Add(ListViewContentAppDefinition.CreateContentApp(Services.DataTypeService, _propertyEditors, "recycleBin", "content", Core.Constants.DataTypes.DefaultMembersListView)); + apps.Add(ListViewContentAppFactory.CreateContentApp(Services.DataTypeService, _propertyEditors, "recycleBin", "content", Core.Constants.DataTypes.DefaultMembersListView)); apps[0].Active = true; var display = new ContentItemDisplay { @@ -352,7 +342,7 @@ namespace Umbraco.Web.Editors /// Gets an empty content item for the /// /// - /// + /// [OutgoingEditorModelEvent] public ContentItemDisplay GetEmpty(string contentTypeAlias, int parentId) { @@ -1083,7 +1073,7 @@ namespace Umbraco.Web.Editors ActionPublish.ActionLetter) == ContentPermissionsHelper.ContentAccess.Denied)) { denied.Add(c); - } + } } } noAccess = denied; @@ -1241,11 +1231,11 @@ namespace Umbraco.Web.Editors //Check if a mandatory language is missing from being published var mandatoryVariant = cultureVariants.First(x => x.Culture.InvariantEquals(culture)); - + var isPublished = contentItem.PersistedContent.Published && contentItem.PersistedContent.IsCulturePublished(culture); result.Add((mandatoryVariant, isPublished)); - var isPublishing = isPublished ? true : publishingCheck(mandatoryVariant); + var isPublishing = isPublished ? true : publishingCheck(mandatoryVariant); if (isPublished || isPublishing) continue; @@ -1880,7 +1870,7 @@ namespace Umbraco.Web.Editors case PublishResultType.SuccessPublish: case PublishResultType.SuccessPublishCulture: //these 2 belong to a single group - return PublishResultType.SuccessPublish; + return PublishResultType.SuccessPublish; case PublishResultType.FailedPublishAwaitingRelease: case PublishResultType.FailedPublishCultureAwaitingRelease: //these 2 belong to a single group @@ -1903,7 +1893,7 @@ namespace Umbraco.Web.Editors }); foreach (var status in statusGroup) - { + { switch (status.Key) { case PublishResultType.SuccessPublishAlready: diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index 9aebc11dc6..dd224dc551 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -99,7 +99,7 @@ namespace Umbraco.Web.Editors public MediaItemDisplay GetRecycleBin() { var apps = new List(); - apps.Add(ListViewContentAppDefinition.CreateContentApp(Services.DataTypeService, _propertyEditors, "recycleBin", "media", Core.Constants.DataTypes.DefaultMediaListView)); + apps.Add(ListViewContentAppFactory.CreateContentApp(Services.DataTypeService, _propertyEditors, "recycleBin", "media", Core.Constants.DataTypes.DefaultMediaListView)); apps[0].Active = true; var display = new MediaItemDisplay { diff --git a/src/Umbraco.Web/Editors/MemberController.cs b/src/Umbraco.Web/Editors/MemberController.cs index 6117db8857..ae02645afa 100644 --- a/src/Umbraco.Web/Editors/MemberController.cs +++ b/src/Umbraco.Web/Editors/MemberController.cs @@ -139,7 +139,7 @@ namespace Umbraco.Web.Editors var name = foundType != null ? foundType.Name : listName; var apps = new List(); - apps.Add(ListViewContentAppDefinition.CreateContentApp(Services.DataTypeService, _propertyEditors, listName, "member", Core.Constants.DataTypes.DefaultMembersListView)); + apps.Add(ListViewContentAppFactory.CreateContentApp(Services.DataTypeService, _propertyEditors, listName, "member", Core.Constants.DataTypes.DefaultMembersListView)); apps[0].Active = true; var display = new MemberListDisplay diff --git a/src/Umbraco.Web/Models/Mapping/ContentAppResolver.cs b/src/Umbraco.Web/Models/Mapping/ContentAppResolver.cs index a199c7e60e..ee3e991f89 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentAppResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentAppResolver.cs @@ -11,9 +11,9 @@ namespace Umbraco.Web.Models.Mapping // maps ContentApps when mapping IContent to ContentItemDisplay internal class ContentAppResolver : IValueResolver> { - private readonly ContentAppDefinitionCollection _contentAppDefinitions; + private readonly ContentAppFactoryCollection _contentAppDefinitions; - public ContentAppResolver(ContentAppDefinitionCollection contentAppDefinitions) + public ContentAppResolver(ContentAppFactoryCollection contentAppDefinitions) { _contentAppDefinitions = contentAppDefinitions; } diff --git a/src/Umbraco.Web/Models/Mapping/MediaAppResolver.cs b/src/Umbraco.Web/Models/Mapping/MediaAppResolver.cs index caaaacc5f2..2e3afac549 100644 --- a/src/Umbraco.Web/Models/Mapping/MediaAppResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/MediaAppResolver.cs @@ -11,9 +11,9 @@ namespace Umbraco.Web.Models.Mapping // maps ContentApps when mapping IMedia to MediaItemDisplay internal class MediaAppResolver : IValueResolver> { - private readonly ContentAppDefinitionCollection _contentAppDefinitions; + private readonly ContentAppFactoryCollection _contentAppDefinitions; - public MediaAppResolver(ContentAppDefinitionCollection contentAppDefinitions) + public MediaAppResolver(ContentAppFactoryCollection contentAppDefinitions) { _contentAppDefinitions = contentAppDefinitions; } diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs b/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs index 68e1e89ea2..da07096b75 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs @@ -205,10 +205,10 @@ namespace Umbraco.Web.Runtime composition.RegisterUnique(); // register known content apps - composition.WithCollectionBuilder() - .Append() - .Append() - .Append(); + composition.WithCollectionBuilder() + .Append() + .Append() + .Append(); } internal void Initialize( diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index de8bbf8e0c..99121970c7 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -113,6 +113,7 @@ + @@ -158,11 +159,10 @@ - - - - - + + + + diff --git a/src/Umbraco.Web/UmbracoHelper.cs b/src/Umbraco.Web/UmbracoHelper.cs index 58e88c4bab..d274ca2f44 100644 --- a/src/Umbraco.Web/UmbracoHelper.cs +++ b/src/Umbraco.Web/UmbracoHelper.cs @@ -10,7 +10,6 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; using Umbraco.Core.Xml; -using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Web.Routing; using Umbraco.Web.Security; @@ -29,7 +28,6 @@ namespace Umbraco.Web private readonly UmbracoContext _umbracoContext; private readonly IPublishedContent _currentPage; - private readonly IPublishedContentQuery _iQuery; private readonly ServiceContext _services; private IUmbracoComponentRenderer _componentRenderer; @@ -45,22 +43,18 @@ namespace Umbraco.Web /// /// For tests. internal UmbracoHelper(UmbracoContext umbracoContext, IPublishedContent content, - IPublishedContentQuery query, ITagQuery tagQuery, ICultureDictionary cultureDictionary, IUmbracoComponentRenderer componentRenderer, MembershipHelper membershipHelper, ServiceContext services) { - if (tagQuery == null) throw new ArgumentNullException(nameof(tagQuery)); - _umbracoContext = umbracoContext ?? throw new ArgumentNullException(nameof(umbracoContext)); - _tag = new TagQuery(tagQuery); + _tag = tagQuery ?? throw new ArgumentNullException(nameof(tagQuery)); _cultureDictionary = cultureDictionary ?? throw new ArgumentNullException(nameof(cultureDictionary)); _componentRenderer = componentRenderer ?? throw new ArgumentNullException(nameof(componentRenderer)); _membershipHelper = membershipHelper ?? throw new ArgumentNullException(nameof(membershipHelper)); _currentPage = content ?? throw new ArgumentNullException(nameof(content)); - _iQuery = query ?? throw new ArgumentNullException(nameof(query)); _services = services ?? throw new ArgumentNullException(nameof(services)); } @@ -106,15 +100,13 @@ namespace Umbraco.Web /// Gets the tag context. /// public ITagQuery TagQuery => _tag ?? - (_tag = new TagQuery(_services.TagService, _iQuery ?? ContentQuery)); + (_tag = new TagQuery(_services.TagService, ContentQuery)); /// /// Gets the query context. /// public IPublishedContentQuery ContentQuery => _query ?? - (_query = _iQuery != null - ? new PublishedContentQuery(_iQuery) - : new PublishedContentQuery(UmbracoContext.ContentCache, UmbracoContext.MediaCache)); + (_query = new PublishedContentQuery(UmbracoContext.ContentCache, UmbracoContext.MediaCache)); /// /// Gets the Umbraco context.