diff --git a/src/Umbraco.Core/Manifest/ContentAppDefinitionConverter.cs b/src/Umbraco.Core/Manifest/ContentAppDefinitionConverter.cs
index 87f104d90e..dd167e06df 100644
--- a/src/Umbraco.Core/Manifest/ContentAppDefinitionConverter.cs
+++ b/src/Umbraco.Core/Manifest/ContentAppDefinitionConverter.cs
@@ -6,11 +6,11 @@ using Umbraco.Core.Serialization;
namespace Umbraco.Core.Manifest
{
///
- /// Implements a json read converter for .
+ /// Implements a json read converter for .
///
- internal class ContentAppDefinitionConverter : JsonReadConverter
+ internal class ContentAppDefinitionConverter : JsonReadConverter
{
- protected override IContentAppDefinition Create(Type objectType, string path, JObject jObject)
+ protected override ManifestContentAppDefinition 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..b44d31f0a5
--- /dev/null
+++ b/src/Umbraco.Core/Manifest/ManifestContentAppFactory.cs
@@ -0,0 +1,172 @@
+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 definition, parsed from a 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..2d6ec93e14 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)
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 92%
rename from src/Umbraco.Core/Models/ContentEditing/IContentAppDefinition.cs
rename to src/Umbraco.Core/Models/ContentEditing/IContentAppFactory.cs
index af83c5a2f5..144f1c4f84 100644
--- a/src/Umbraco.Core/Models/ContentEditing/IContentAppDefinition.cs
+++ b/src/Umbraco.Core/Models/ContentEditing/IContentAppFactory.cs
@@ -1,13 +1,15 @@
using System.Collections.Generic;
+using Umbraco.Core.Manifest;
using Umbraco.Core.Models.Membership;
namespace Umbraco.Core.Models.ContentEditing
{
+
///
/// Represents a content app definition.
///
- 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 047f3f8cdd..c2b16f590a 100755
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -336,6 +336,7 @@
+
@@ -380,7 +381,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.Web/ContentApps/ContentAppDefinitionCollection.cs b/src/Umbraco.Web/ContentApps/ContentAppDefinitionCollection.cs
index 8b33fd1447..1d94c3f381 100644
--- a/src/Umbraco.Web/ContentApps/ContentAppDefinitionCollection.cs
+++ b/src/Umbraco.Web/ContentApps/ContentAppDefinitionCollection.cs
@@ -5,15 +5,17 @@ using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Models.ContentEditing;
using Umbraco.Core.Logging;
+using Umbraco.Core.Manifest;
using Umbraco.Core.Models.Membership;
namespace Umbraco.Web.ContentApps
{
- public class ContentAppDefinitionCollection : BuilderCollectionBase
+ public class ContentAppDefinitionCollection : BuilderCollectionBase
{
private readonly ILogger _logger;
+ private readonly IContentAppFactory _factory;
- public ContentAppDefinitionCollection(IEnumerable items, ILogger logger)
+ public ContentAppDefinitionCollection(IEnumerable items, ILogger logger)
: base(items)
{
_logger = logger;
@@ -32,7 +34,10 @@ 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 apps = Enumerable.Empty();// this.Select(x => x.GetContentAppFor(o, roles)).WhereNotNull().OrderBy(x => x.Weight).ToList();
+
var aliases = new HashSet();
List dups = null;
diff --git a/src/Umbraco.Web/ContentApps/ContentAppDefinitionCollectionBuilder.cs b/src/Umbraco.Web/ContentApps/ContentAppDefinitionCollectionBuilder.cs
index 267dd2d0e7..744785bacd 100644
--- a/src/Umbraco.Web/ContentApps/ContentAppDefinitionCollectionBuilder.cs
+++ b/src/Umbraco.Web/ContentApps/ContentAppDefinitionCollectionBuilder.cs
@@ -5,14 +5,16 @@ using Umbraco.Core.Composing;
using Umbraco.Core.Logging;
using Umbraco.Core.Manifest;
using Umbraco.Core.Models.ContentEditing;
+using Umbraco.Core.Services;
namespace Umbraco.Web.ContentApps
{
- public class ContentAppDefinitionCollectionBuilder : OrderedCollectionBuilderBase
+ public class ContentAppDefinitionCollectionBuilder : OrderedCollectionBuilderBase
{
public ContentAppDefinitionCollectionBuilder(IServiceContainer container)
: base(container)
- { }
+ {
+ }
protected override ContentAppDefinitionCollectionBuilder This => this;
@@ -25,14 +27,14 @@ namespace Umbraco.Web.ContentApps
return new ContentAppDefinitionCollection(CreateItems(), logger);
}
- protected override IEnumerable CreateItems(params object[] args)
+ protected override IEnumerable CreateItems(params object[] args)
{
// 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 = Container.GetInstance();
- return base.CreateItems(args).Concat(manifestParser.Manifest.ContentApps);
+ return base.CreateItems(args).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 53ecddd015..1e7e24e903 100644
--- a/src/Umbraco.Web/Editors/ContentController.cs
+++ b/src/Umbraco.Web/Editors/ContentController.cs
@@ -234,7 +234,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
{
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/Runtime/WebRuntimeComponent.cs b/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs
index 97cebdb076..421b807c26 100644
--- a/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs
+++ b/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs
@@ -207,9 +207,9 @@ namespace Umbraco.Web.Runtime
// register known content apps
composition.Container.RegisterCollectionBuilder()
- .Append()
- .Append()
- .Append();
+ .Append()
+ .Append()
+ .Append();
}
internal void Initialize(
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index c17536ab4d..371b34d71d 100755
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -110,6 +110,7 @@
+
@@ -155,9 +156,8 @@
-
-
-
+
+