diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.controller.js
index 8d21234aee..9d3a8a87e5 100644
--- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.controller.js
@@ -32,7 +32,10 @@
}
function hasAnyData(variant) {
- var result = variant.isDirty != null || (variant.name != null && variant.name.length > 0);
+ if(variant.name == null || variant.name.length === 0) {
+ return false;
+ }
+ var result = variant.isDirty != null;
if(result) return true;
diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
index 045c56764a..f05a7b4eed 100644
--- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
+++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
@@ -105,7 +105,7 @@
- 8.0.0-alpha.33
+ 8.0.0-alpha.34
@@ -212,6 +212,8 @@
Dashboard.config
Designer
+
+ feedProxy.config
@@ -308,6 +310,7 @@
Designer
+
Designer
diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml
index 2e63acd3c3..3dcbfcded2 100644
--- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml
+++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml
@@ -2016,4 +2016,16 @@ To manage your website, simply open the Umbraco back office and start adding con
Relation Type
Relations
+
+ Getting Started
+ Redirect URL Management
+ Content
+ Welcome
+ Examine Management
+ Published Status
+ Models Builder
+ Health Check
+ Getting Started
+ Install Umbraco Forms
+ >
diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml
index 86484b1393..8c8a405e29 100644
--- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml
+++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml
@@ -2049,4 +2049,16 @@ To manage your website, simply open the Umbraco back office and start adding con
Relation Type
Relations
+
+ Getting Started
+ Redirect URL Management
+ Content
+ Welcome
+ Examine Management
+ Published Status
+ Models Builder
+ Health Check
+ Getting Started
+ Install Umbraco Forms
+
diff --git a/src/Umbraco.Web.UI/config/Dashboard.Release.config b/src/Umbraco.Web.UI/config/Dashboard.Release.config
deleted file mode 100644
index fec6ab34ae..0000000000
--- a/src/Umbraco.Web.UI/config/Dashboard.Release.config
+++ /dev/null
@@ -1,107 +0,0 @@
-
-
-
-
-
- settings
-
-
-
- views/dashboard/settings/settingsdashboardintro.html
-
-
-
-
- views/dashboard/settings/examinemanagement.html
-
-
-
-
- views/dashboard/settings/publishedstatus.html
-
-
-
-
-
-
- forms
-
-
-
- views/dashboard/forms/formsdashboardintro.html
-
-
-
-
-
-
- media
-
-
-
- views/dashboard/media/mediafolderbrowser.html
-
-
-
-
-
-
- translator
-
-
- content
-
-
-
- admin
-
-
-
- views/dashboard/default/startupdashboardintro.html
-
-
-
-
-
-
- member
-
-
-
- views/dashboard/members/membersdashboardvideos.html
-
-
-
-
-
-
- settings
-
-
-
- /App_Plugins/ModelsBuilder/modelsbuilder.htm
-
-
-
-
-
-
- settings
-
-
-
- views/dashboard/settings/healthcheck.html
-
-
-
-
-
- content
-
-
-
- views/dashboard/content/redirecturls.html
-
-
-
-
diff --git a/src/Umbraco.Web.UI/config/Dashboard.config b/src/Umbraco.Web.UI/config/Dashboard.config
deleted file mode 100644
index fec6ab34ae..0000000000
--- a/src/Umbraco.Web.UI/config/Dashboard.config
+++ /dev/null
@@ -1,107 +0,0 @@
-
-
-
-
-
- settings
-
-
-
- views/dashboard/settings/settingsdashboardintro.html
-
-
-
-
- views/dashboard/settings/examinemanagement.html
-
-
-
-
- views/dashboard/settings/publishedstatus.html
-
-
-
-
-
-
- forms
-
-
-
- views/dashboard/forms/formsdashboardintro.html
-
-
-
-
-
-
- media
-
-
-
- views/dashboard/media/mediafolderbrowser.html
-
-
-
-
-
-
- translator
-
-
- content
-
-
-
- admin
-
-
-
- views/dashboard/default/startupdashboardintro.html
-
-
-
-
-
-
- member
-
-
-
- views/dashboard/members/membersdashboardvideos.html
-
-
-
-
-
-
- settings
-
-
-
- /App_Plugins/ModelsBuilder/modelsbuilder.htm
-
-
-
-
-
-
- settings
-
-
-
- views/dashboard/settings/healthcheck.html
-
-
-
-
-
- content
-
-
-
- views/dashboard/content/redirecturls.html
-
-
-
-
diff --git a/src/Umbraco.Web.UI/web.Template.config b/src/Umbraco.Web.UI/web.Template.config
index 2371282a14..e7399f600b 100644
--- a/src/Umbraco.Web.UI/web.Template.config
+++ b/src/Umbraco.Web.UI/web.Template.config
@@ -14,7 +14,6 @@
-
@@ -28,7 +27,6 @@
-
diff --git a/src/Umbraco.Web/CompositionExtensions.cs b/src/Umbraco.Web/CompositionExtensions.cs
index 246127b312..783c991ab4 100644
--- a/src/Umbraco.Web/CompositionExtensions.cs
+++ b/src/Umbraco.Web/CompositionExtensions.cs
@@ -10,6 +10,7 @@ using Umbraco.Web.Routing;
using Umbraco.Web.ContentApps;
using Umbraco.Web.Tour;
using Umbraco.Web.Trees;
+using Umbraco.Web.Dashboards;
// the namespace here is intentional - although defined in Umbraco.Web assembly,
// this class should be visible when using Umbraco.Core.Components, alongside
@@ -92,6 +93,13 @@ namespace Umbraco.Core.Components
public static BackOfficeSectionCollectionBuilder Sections(this Composition composition)
=> composition.WithCollectionBuilder();
+ ///
+ /// Gets the backoffice dashboards collection builder.
+ ///
+ /// The composition.
+ public static DashboardCollectionBuilder Dashboards(this Composition composition)
+ => composition.WithCollectionBuilder();
+
#endregion
#region Uniques
diff --git a/src/Umbraco.Web/Dashboards/ContentDashboard.cs b/src/Umbraco.Web/Dashboards/ContentDashboard.cs
new file mode 100644
index 0000000000..0cd96f738c
--- /dev/null
+++ b/src/Umbraco.Web/Dashboards/ContentDashboard.cs
@@ -0,0 +1,29 @@
+using Umbraco.Core;
+using Umbraco.Core.Composing;
+using Umbraco.Core.Dashboards;
+
+namespace Umbraco.Web.Dashboards
+{
+ [Weight(10)]
+ public class ContentDashboard : IDashboard
+ {
+ public string Alias => "contentIntro";
+
+ public string[] Sections => new [] { "content" };
+
+ public string View => "views/dashboard/default/startupdashboardintro.html";
+
+ public IAccessRule[] AccessRules
+ {
+ get
+ {
+ var rules = new IAccessRule[]
+ {
+ new AccessRule {Type = AccessRuleType.Deny, Value = Constants.Security.TranslatorGroupAlias},
+ new AccessRule {Type = AccessRuleType.Grant, Value = Constants.Security.AdminGroupAlias}
+ };
+ return rules;
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Web/Dashboards/DashboardCollection.cs b/src/Umbraco.Web/Dashboards/DashboardCollection.cs
new file mode 100644
index 0000000000..616a2cc8cc
--- /dev/null
+++ b/src/Umbraco.Web/Dashboards/DashboardCollection.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+using Umbraco.Core.Composing;
+using Umbraco.Core.Dashboards;
+
+namespace Umbraco.Web.Dashboards
+{
+ public class DashboardCollection : BuilderCollectionBase
+ {
+ public DashboardCollection(IEnumerable items)
+ : base(items)
+ { }
+ }
+}
diff --git a/src/Umbraco.Web/Dashboards/DashboardCollectionBuilder.cs b/src/Umbraco.Web/Dashboards/DashboardCollectionBuilder.cs
new file mode 100644
index 0000000000..36a417e957
--- /dev/null
+++ b/src/Umbraco.Web/Dashboards/DashboardCollectionBuilder.cs
@@ -0,0 +1,46 @@
+using System.Collections.Generic;
+using System.Linq;
+using Umbraco.Core;
+using Umbraco.Core.Composing;
+using Umbraco.Core.Dashboards;
+using Umbraco.Core.Manifest;
+
+namespace Umbraco.Web.Dashboards
+{
+ public class DashboardCollectionBuilder : WeightedCollectionBuilderBase
+ {
+ protected override DashboardCollectionBuilder This => this;
+
+ 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();
+
+ var dashboardSections = Merge(base.CreateItems(factory), manifestParser.Manifest.Dashboards);
+
+ return dashboardSections;
+ }
+
+ private IEnumerable Merge(IEnumerable dashboardsFromCode, IReadOnlyList dashboardFromManifest)
+ {
+ return dashboardsFromCode.Concat(dashboardFromManifest)
+ .Where(x => !string.IsNullOrEmpty(x.Alias))
+ .OrderBy(GetWeight);
+ }
+
+ private int GetWeight(IDashboard dashboard)
+ {
+ switch (dashboard)
+ {
+ case ManifestDashboard manifestDashboardDefinition:
+ return manifestDashboardDefinition.Weight;
+
+ default:
+ var weightAttribute = dashboard.GetType().GetCustomAttribute(false);
+ return weightAttribute?.Weight ?? DefaultWeight;
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Web/Dashboards/ExamineDashboard.cs b/src/Umbraco.Web/Dashboards/ExamineDashboard.cs
new file mode 100644
index 0000000000..47cf97ca3b
--- /dev/null
+++ b/src/Umbraco.Web/Dashboards/ExamineDashboard.cs
@@ -0,0 +1,20 @@
+using System;
+using Umbraco.Core.Composing;
+using Umbraco.Core.Dashboards;
+
+namespace Umbraco.Web.Dashboards
+{
+ [Weight(20)]
+ public class ExamineDashboard : IDashboard
+ {
+ public string Alias => "settingsExamine";
+
+ public string[] Sections => new [] { "settings" };
+
+ public string View => "views/dashboard/settings/examinemanagement.html";
+
+ public IAccessRule[] AccessRules => Array.Empty();
+ }
+
+
+}
diff --git a/src/Umbraco.Web/Dashboards/FormsDashboard.cs b/src/Umbraco.Web/Dashboards/FormsDashboard.cs
new file mode 100644
index 0000000000..a3e1123369
--- /dev/null
+++ b/src/Umbraco.Web/Dashboards/FormsDashboard.cs
@@ -0,0 +1,18 @@
+using System;
+using Umbraco.Core.Composing;
+using Umbraco.Core.Dashboards;
+
+namespace Umbraco.Web.Dashboards
+{
+ [Weight(10)]
+ public class FormsDashboard : IDashboard
+ {
+ public string Alias => "formsInstall";
+
+ public string[] Sections => new [] { "forms" };
+
+ public string View => "views/dashboard/forms/formsdashboardintro.html";
+
+ public IAccessRule[] AccessRules => Array.Empty();
+ }
+}
diff --git a/src/Umbraco.Web/Dashboards/HealthCheckDashboard.cs b/src/Umbraco.Web/Dashboards/HealthCheckDashboard.cs
new file mode 100644
index 0000000000..746dd04439
--- /dev/null
+++ b/src/Umbraco.Web/Dashboards/HealthCheckDashboard.cs
@@ -0,0 +1,20 @@
+using System;
+using Umbraco.Core.Composing;
+using Umbraco.Core.Dashboards;
+
+namespace Umbraco.Web.Dashboards
+{
+ [Weight(50)]
+ public class HealthCheckDashboard : IDashboard
+ {
+ public string Alias => "settingsHealthCheck";
+
+ public string[] Sections => new [] { "settings" };
+
+ public string View => "views/dashboard/settings/healthcheck.html";
+
+ public IAccessRule[] AccessRules => Array.Empty();
+ }
+
+
+}
diff --git a/src/Umbraco.Web/Dashboards/MediaDashboard.cs b/src/Umbraco.Web/Dashboards/MediaDashboard.cs
new file mode 100644
index 0000000000..c97ae298f3
--- /dev/null
+++ b/src/Umbraco.Web/Dashboards/MediaDashboard.cs
@@ -0,0 +1,18 @@
+using System;
+using Umbraco.Core.Composing;
+using Umbraco.Core.Dashboards;
+
+namespace Umbraco.Web.Dashboards
+{
+ [Weight(10)]
+ public class MediaDashboard : IDashboard
+ {
+ public string Alias => "mediaFolderBrowser";
+
+ public string[] Sections => new [] { "media" };
+
+ public string View => "views/dashboard/media/mediafolderbrowser.html";
+
+ public IAccessRule[] AccessRules => Array.Empty();
+ }
+}
diff --git a/src/Umbraco.Web/Dashboards/MembersDashboard.cs b/src/Umbraco.Web/Dashboards/MembersDashboard.cs
new file mode 100644
index 0000000000..473722dce1
--- /dev/null
+++ b/src/Umbraco.Web/Dashboards/MembersDashboard.cs
@@ -0,0 +1,18 @@
+using System;
+using Umbraco.Core.Composing;
+using Umbraco.Core.Dashboards;
+
+namespace Umbraco.Web.Dashboards
+{
+ [Weight(10)]
+ public class MembersDashboard : IDashboard
+ {
+ public string Alias => "memberIntro";
+
+ public string[] Sections => new [] { "member" };
+
+ public string View => "views/dashboard/members/membersdashboardvideos.html";
+
+ public IAccessRule[] AccessRules => Array.Empty();
+ }
+}
diff --git a/src/Umbraco.Web/Dashboards/ModelsBuilderDashboard.cs b/src/Umbraco.Web/Dashboards/ModelsBuilderDashboard.cs
new file mode 100644
index 0000000000..44bc00cb6f
--- /dev/null
+++ b/src/Umbraco.Web/Dashboards/ModelsBuilderDashboard.cs
@@ -0,0 +1,20 @@
+using System;
+using Umbraco.Core.Composing;
+using Umbraco.Core.Dashboards;
+
+namespace Umbraco.Web.Dashboards
+{
+ [Weight(40)]
+ public class ModelsBuilderDashboard : IDashboard
+ {
+ public string Alias => "settingsModelsBuilder";
+
+ public string[] Sections => new [] { "settings" };
+
+ public string View => "/App_Plugins/ModelsBuilder/modelsbuilder.htm";
+
+ public IAccessRule[] AccessRules => Array.Empty();
+ }
+
+
+}
diff --git a/src/Umbraco.Web/Dashboards/PublishedStatusDashboard.cs b/src/Umbraco.Web/Dashboards/PublishedStatusDashboard.cs
new file mode 100644
index 0000000000..66faa20b55
--- /dev/null
+++ b/src/Umbraco.Web/Dashboards/PublishedStatusDashboard.cs
@@ -0,0 +1,20 @@
+using System;
+using Umbraco.Core.Composing;
+using Umbraco.Core.Dashboards;
+
+namespace Umbraco.Web.Dashboards
+{
+ [Weight(30)]
+ public class PublishedStatusDashboard : IDashboard
+ {
+ public string Alias => "settingsPublishedStatus";
+
+ public string[] Sections => new [] { "settings" };
+
+ public string View => "views/dashboard/settings/publishedstatus.html";
+
+ public IAccessRule[] AccessRules => Array.Empty();
+ }
+
+
+}
diff --git a/src/Umbraco.Web/Dashboards/RedirectUrlDashboard.cs b/src/Umbraco.Web/Dashboards/RedirectUrlDashboard.cs
new file mode 100644
index 0000000000..f538cbc122
--- /dev/null
+++ b/src/Umbraco.Web/Dashboards/RedirectUrlDashboard.cs
@@ -0,0 +1,18 @@
+using System;
+using Umbraco.Core.Composing;
+using Umbraco.Core.Dashboards;
+
+namespace Umbraco.Web.Dashboards
+{
+ [Weight(20)]
+ public class RedirectUrlDashboard : IDashboard
+ {
+ public string Alias => "contentRedirectManager";
+
+ public string[] Sections => new [] { "content" };
+
+ public string View => "views/dashboard/content/redirecturls.html";
+
+ public IAccessRule[] AccessRules => Array.Empty();
+ }
+}
diff --git a/src/Umbraco.Web/Dashboards/SettingsDashboards.cs b/src/Umbraco.Web/Dashboards/SettingsDashboards.cs
new file mode 100644
index 0000000000..5cd92e4c3f
--- /dev/null
+++ b/src/Umbraco.Web/Dashboards/SettingsDashboards.cs
@@ -0,0 +1,18 @@
+using System;
+using Umbraco.Core.Composing;
+using Umbraco.Core.Dashboards;
+
+namespace Umbraco.Web.Dashboards
+{
+ [Weight(10)]
+ public class SettingsDashboard : IDashboard
+ {
+ public string Alias => "settingsWelcome";
+
+ public string[] Sections => new [] { "settings" };
+
+ public string View => "views/dashboard/settings/settingsdashboardintro.html";
+
+ public IAccessRule[] AccessRules => Array.Empty();
+ }
+}
diff --git a/src/Umbraco.Web/Editors/DashboardController.cs b/src/Umbraco.Web/Editors/DashboardController.cs
index 44fe04ef92..91a966cef7 100644
--- a/src/Umbraco.Web/Editors/DashboardController.cs
+++ b/src/Umbraco.Web/Editors/DashboardController.cs
@@ -6,8 +6,8 @@ using Umbraco.Web.Mvc;
using Newtonsoft.Json.Linq;
using System.Threading.Tasks;
using System.Net.Http;
-using System.Web.Http;
using System;
+using System.Linq;
using System.Net;
using System.Text;
using Umbraco.Core.Cache;
@@ -16,6 +16,8 @@ using Umbraco.Web.WebApi.Filters;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
using Umbraco.Core.Services;
+using Umbraco.Core.Dashboards;
+using Umbraco.Web.Services;
namespace Umbraco.Web.Editors
{
@@ -25,9 +27,10 @@ namespace Umbraco.Web.Editors
[AngularJsonOnlyConfiguration]
[IsBackOffice]
[WebApi.UmbracoAuthorize]
+
public class DashboardController : UmbracoApiController
{
- private readonly Dashboards _dashboards;
+ private readonly IDashboardService _dashboardService;
///
/// Initializes a new instance of the with auto dependencies.
@@ -38,10 +41,10 @@ namespace Umbraco.Web.Editors
///
/// Initializes a new instance of the with all its dependencies.
///
- public DashboardController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, Dashboards dashboards)
+ public DashboardController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, IDashboardService dashboardService)
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState)
{
- _dashboards = dashboards;
+ _dashboardService = dashboardService;
}
//we have just one instance of HttpClient shared for the entire application
@@ -199,11 +202,24 @@ namespace Umbraco.Web.Editors
}
+ // return IDashboardSlim - we don't need sections nor access rules
[ValidateAngularAntiForgeryToken]
[OutgoingEditorModelEvent]
- public IEnumerable> GetDashboard(string section)
+ public IEnumerable> GetDashboard(string section)
{
- return _dashboards.GetDashboards(section, Security.CurrentUser);
+ return _dashboardService.GetDashboards(section, Security.CurrentUser).Select(x => new Tab
+ {
+ Id = x.Id,
+ Alias = x.Alias,
+ Label = x.Label,
+ Expanded = x.Expanded,
+ IsActive = x.IsActive,
+ Properties = x.Properties.Select(y => new DashboardSlim
+ {
+ Alias = y.Alias,
+ View = y.View
+ })
+ });
}
}
}
diff --git a/src/Umbraco.Web/Editors/Dashboards.cs b/src/Umbraco.Web/Editors/Dashboards.cs
deleted file mode 100644
index c837cbbf33..0000000000
--- a/src/Umbraco.Web/Editors/Dashboards.cs
+++ /dev/null
@@ -1,160 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Umbraco.Core;
-using Umbraco.Core.Configuration.Dashboard;
-using Umbraco.Core.IO;
-using Umbraco.Core.Manifest;
-using Umbraco.Core.Models.Membership;
-using Umbraco.Core.Services;
-using Umbraco.Web.Models.ContentEditing;
-using Umbraco.Web.Services;
-
-namespace Umbraco.Web.Editors
-{
- public class Dashboards
- {
- private readonly ISectionService _sectionService;
- private readonly IDashboardSection _dashboardSection;
- private readonly ManifestParser _manifestParser;
-
- public Dashboards(ISectionService sectionService, IDashboardSection dashboardSection, ManifestParser manifestParser)
- {
- _sectionService = sectionService ?? throw new ArgumentNullException(nameof(sectionService));
- _dashboardSection = dashboardSection;
- _manifestParser = manifestParser;
- }
-
- ///
- /// Gets all dashboards, organized by section, for a user.
- ///
- public IDictionary>> GetDashboards(IUser currentUser)
- {
- return _sectionService.GetSections().ToDictionary(x => x.Alias, x => GetDashboards(x.Alias, currentUser));
- }
-
- ///
- /// Returns dashboards for a specific section, for a user.
- ///
- public IEnumerable> GetDashboards(string section, IUser currentUser)
- {
- var tabId = 1;
- var configDashboards = GetDashboardsFromConfig(ref tabId, section, currentUser);
- var pluginDashboards = GetDashboardsFromPlugins(ref tabId, section, currentUser);
-
- // merge dashboards
- // both collections contain tab.alias -> controls
- var dashboards = configDashboards;
-
- // until now, it was fine to have duplicate tab.aliases in configDashboard
- // so... the rule should be - just merge whatever we get, don't be clever
- dashboards.AddRange(pluginDashboards);
-
- // re-sort by id
- dashboards.Sort((tab1, tab2) => tab1.Id > tab2.Id ? 1 : 0);
-
- // re-assign ids (why?)
- var i = 1;
- foreach (var tab in dashboards)
- {
- tab.Id = i++;
- tab.IsActive = tab.Id == 1;
- }
-
- return configDashboards;
- }
-
- // note:
- // in dashboard.config we have 'sections' which define 'tabs' for 'areas'
- // and 'areas' are the true UI sections - and each tab can have more than
- // one control
- // in a manifest, we directly have 'dashboards' which map to a unique
- // control in a tab
-
- // gets all tabs & controls from the config file
- private List> GetDashboardsFromConfig(ref int tabId, string section, IUser currentUser)
- {
- var tabs = new List>();
-
- // disable packages section dashboard
- if (section == "packages") return tabs;
-
- foreach (var dashboardSection in _dashboardSection.Sections.Where(x => x.Areas.InvariantContains(section)))
- {
- // validate access to this section
- if (!DashboardSecurity.AuthorizeAccess(dashboardSection, currentUser, _sectionService))
- continue;
-
- foreach (var tab in dashboardSection.Tabs)
- {
- // validate access to this tab
- if (!DashboardSecurity.AuthorizeAccess(tab, currentUser, _sectionService))
- continue;
-
- var dashboardControls = new List();
-
- foreach (var control in tab.Controls)
- {
- // validate access to this control
- if (!DashboardSecurity.AuthorizeAccess(control, currentUser, _sectionService))
- continue;
-
- // create and add control
- var dashboardControl = new DashboardControl
- {
- Caption = control.PanelCaption,
- Path = IOHelper.FindFile(control.ControlPath.Trim())
- };
-
- if (dashboardControl.Path.InvariantEndsWith(".ascx"))
- throw new NotSupportedException("Legacy UserControl (.ascx) dashboards are no longer supported.");
-
- dashboardControls.Add(dashboardControl);
- }
-
- // create and add tab
- tabs.Add(new Tab
- {
- Id = tabId++,
- Alias = tab.Caption.ToSafeAlias(),
- Label = tab.Caption,
- Properties = dashboardControls
- });
- }
- }
-
- return tabs;
- }
-
- private List> GetDashboardsFromPlugins(ref int tabId, string section, IUser currentUser)
- {
- var tabs = new List>();
-
- foreach (var dashboard in _manifestParser.Manifest.Dashboards.Where(x => x.Sections.InvariantContains(section)).OrderBy(x => x.Weight))
- {
- // validate access
- if (!DashboardSecurity.CheckUserAccessByRules(currentUser, _sectionService, dashboard.AccessRules))
- continue;
-
- var dashboardControl = new DashboardControl
- {
- Caption = "",
- Path = IOHelper.FindFile(dashboard.View.Trim())
- };
-
- if (dashboardControl.Path.InvariantEndsWith(".ascx"))
- throw new NotSupportedException("Legacy UserControl (.ascx) dashboards are no longer supported.");
-
- tabs.Add(new Tab
- {
- Id = tabId++,
- Alias = dashboard.Alias.ToSafeAlias(),
- Label = dashboard.Name,
- Properties = new[] { dashboardControl }
- });
- }
-
- return tabs;
- }
- }
-}
diff --git a/src/Umbraco.Web/Editors/EditorModelEventManager.cs b/src/Umbraco.Web/Editors/EditorModelEventManager.cs
index 2225f5c577..c3a7d128ec 100644
--- a/src/Umbraco.Web/Editors/EditorModelEventManager.cs
+++ b/src/Umbraco.Web/Editors/EditorModelEventManager.cs
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Web.Http.Filters;
+using Umbraco.Core.Dashboards;
using Umbraco.Core.Events;
using Umbraco.Web.Models.ContentEditing;
@@ -14,9 +15,9 @@ namespace Umbraco.Web.Editors
public static event TypedEventHandler> SendingMediaModel;
public static event TypedEventHandler> SendingMemberModel;
public static event TypedEventHandler> SendingUserModel;
- public static event TypedEventHandler>>> SendingDashboardModel;
+ public static event TypedEventHandler>>> SendingDashboardModel;
- private static void OnSendingDashboardModel(HttpActionExecutedContext sender, EditorModelEventArgs>> e)
+ private static void OnSendingDashboardModel(HttpActionExecutedContext sender, EditorModelEventArgs>> e)
{
var handler = SendingDashboardModel;
handler?.Invoke(sender, e);
@@ -65,8 +66,8 @@ namespace Umbraco.Web.Editors
if (e.Model is UserDisplay)
OnSendingUserModel(sender, new EditorModelEventArgs(e));
- if (e.Model is IEnumerable>)
- OnSendingDashboardModel(sender, new EditorModelEventArgs>>(e));
+ if (e.Model is IEnumerable)
+ OnSendingDashboardModel(sender, new EditorModelEventArgs>>(e));
}
}
}
diff --git a/src/Umbraco.Web/Editors/SectionController.cs b/src/Umbraco.Web/Editors/SectionController.cs
index 74a06d7149..f6973fcbb9 100644
--- a/src/Umbraco.Web/Editors/SectionController.cs
+++ b/src/Umbraco.Web/Editors/SectionController.cs
@@ -22,15 +22,15 @@ namespace Umbraco.Web.Editors
[PluginController("UmbracoApi")]
public class SectionController : UmbracoAuthorizedJsonController
{
- private readonly Dashboards _dashboards;
+ private readonly IDashboardService _dashboardService;
private readonly ISectionService _sectionService;
private readonly ITreeService _treeService;
public SectionController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState,
- Dashboards dashboards, ISectionService sectionService, ITreeService treeService)
+ IDashboardService dashboardService, ISectionService sectionService, ITreeService treeService)
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState)
{
- _dashboards = dashboards;
+ _dashboardService = dashboardService;
_sectionService = sectionService;
_treeService = treeService;
}
@@ -48,7 +48,7 @@ namespace Umbraco.Web.Editors
ControllerContext = ControllerContext
};
- var dashboards = _dashboards.GetDashboards(Security.CurrentUser);
+ var dashboards = _dashboardService.GetDashboards(Security.CurrentUser);
//now we can add metadata for each section so that the UI knows if there's actually anything at all to render for
//a dashboard for a given section, then the UI can deal with it accordingly (i.e. redirect to the first tree)
diff --git a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs b/src/Umbraco.Web/HtmlHelperRenderExtensions.cs
index e18397dea2..c5d2a65cb9 100644
--- a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs
+++ b/src/Umbraco.Web/HtmlHelperRenderExtensions.cs
@@ -830,39 +830,5 @@ namespace Umbraco.Web
}
#endregion
-
-
- #region RelatedLink
-
- ///
- /// Renders an anchor element for a RelatedLink instance.
- /// Format: <a href="relatedLink.Link" target="_blank/_self">relatedLink.Caption</a>
- ///
- /// The HTML helper instance that this method extends.
- /// The RelatedLink instance
- /// An anchor element
- public static MvcHtmlString GetRelatedLinkHtml(this HtmlHelper htmlHelper, RelatedLink relatedLink)
- {
- return htmlHelper.GetRelatedLinkHtml(relatedLink, null);
- }
-
- ///
- /// Renders an anchor element for a RelatedLink instance, accepting htmlAttributes.
- /// Format: <a href="relatedLink.Link" target="_blank/_self" htmlAttributes>relatedLink.Caption</a>
- ///
- /// The HTML helper instance that this method extends.
- /// The RelatedLink instance
- /// An object that contains the HTML attributes to set for the element.
- ///
- public static MvcHtmlString GetRelatedLinkHtml(this HtmlHelper htmlHelper, RelatedLink relatedLink, object htmlAttributes)
- {
- var tagBuilder = new TagBuilder("a");
- tagBuilder.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
- tagBuilder.MergeAttribute("href", relatedLink.Link);
- tagBuilder.MergeAttribute("target", relatedLink.NewWindow ? "_blank" : "_self");
- tagBuilder.InnerHtml = HttpUtility.HtmlEncode(relatedLink.Caption);
- return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.Normal));
- }
- #endregion
}
}
diff --git a/src/Umbraco.Web/Models/ContentEditing/DashboardControl.cs b/src/Umbraco.Web/Models/ContentEditing/DashboardControl.cs
deleted file mode 100644
index aad6bf2d64..0000000000
--- a/src/Umbraco.Web/Models/ContentEditing/DashboardControl.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.Serialization;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Umbraco.Web.Models.ContentEditing
-{
- [DataContract(Name = "control", Namespace = "")]
- public class DashboardControl
- {
- [DataMember(Name = "path")]
- public string Path { get; set; }
-
- [DataMember(Name = "caption")]
- public string Caption { get; set; }
- }
-}
diff --git a/src/Umbraco.Web/Models/PublishedContentBase.cs b/src/Umbraco.Web/Models/PublishedContentBase.cs
index dd6afbd97f..8a7565265f 100644
--- a/src/Umbraco.Web/Models/PublishedContentBase.cs
+++ b/src/Umbraco.Web/Models/PublishedContentBase.cs
@@ -15,7 +15,12 @@ namespace Umbraco.Web.Models
[DebuggerDisplay("Content Id: {Id}, Name: {Name}")]
public abstract class PublishedContentBase : IPublishedContent
{
- private string _url; // FIXME: task - cannot cache urls, they depends on the current request
+ private readonly IUmbracoContextAccessor _umbracoContextAccessor;
+
+ protected PublishedContentBase(IUmbracoContextAccessor umbracoContextAccessor)
+ {
+ _umbracoContextAccessor = umbracoContextAccessor;
+ }
#region ContentType
@@ -81,24 +86,21 @@ namespace Umbraco.Web.Models
///
public virtual string GetUrl(string culture = null) // TODO: consider .GetCulture("fr-FR").Url
{
+ var umbracoContext = _umbracoContextAccessor.UmbracoContext;
switch (ItemType)
{
case PublishedItemType.Content:
- // TODO: consider injecting an umbraco context accessor
- if (UmbracoContext.Current == null)
- throw new InvalidOperationException("Cannot compute Url for a content item when UmbracoContext.Current is null.");
- if (UmbracoContext.Current.UrlProvider == null)
- throw new InvalidOperationException("Cannot compute Url for a content item when UmbracoContext.Current.UrlProvider is null.");
- return UmbracoContext.Current.UrlProvider.GetUrl(this, culture);
+ if (umbracoContext == null)
+ throw new InvalidOperationException("Cannot compute Url for a content item when UmbracoContext is null.");
+ if (umbracoContext.UrlProvider == null)
+ throw new InvalidOperationException("Cannot compute Url for a content item when UmbracoContext.UrlProvider is null.");
+ return umbracoContext.UrlProvider.GetUrl(this, culture);
case PublishedItemType.Media:
- if (_url != null) return _url; // assume it will not depend on current uri/culture
-
var prop = GetProperty(Constants.Conventions.Media.File);
if (prop?.GetValue() == null)
{
- _url = string.Empty;
- return _url;
+ return string.Empty;
}
var propType = ContentType.GetPropertyType(Constants.Conventions.Media.File);
@@ -110,7 +112,7 @@ namespace Umbraco.Web.Models
switch (propType.EditorAlias)
{
case Constants.PropertyEditors.Aliases.UploadField:
- _url = prop.GetValue().ToString();
+ return prop.GetValue().ToString();
break;
case Constants.PropertyEditors.Aliases.ImageCropper:
//get the url from the json format
@@ -118,14 +120,12 @@ namespace Umbraco.Web.Models
var stronglyTyped = prop.GetValue() as ImageCropperValue;
if (stronglyTyped != null)
{
- _url = stronglyTyped.Src;
- break;
+ return stronglyTyped.Src;
}
- _url = prop.GetValue()?.ToString();
- break;
+ return prop.GetValue()?.ToString();
}
- return _url;
+ return string.Empty;
default:
throw new NotSupportedException();
@@ -144,6 +144,7 @@ namespace Umbraco.Web.Models
///
public abstract bool IsDraft(string culture = null);
+ ///
public abstract bool IsPublished(string culture = null);
#endregion
diff --git a/src/Umbraco.Web/Models/RelatedLink.cs b/src/Umbraco.Web/Models/RelatedLink.cs
deleted file mode 100644
index 1e1d7636ad..0000000000
--- a/src/Umbraco.Web/Models/RelatedLink.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using Umbraco.Core.Models.PublishedContent;
-
-namespace Umbraco.Web.Models
-{
- public class RelatedLink : RelatedLinkBase
- {
- public int? Id { get; internal set; }
- internal bool IsDeleted { get; set; }
- public IPublishedContent Content { get; set; }
- }
-}
diff --git a/src/Umbraco.Web/Models/RelatedLinkBase.cs b/src/Umbraco.Web/Models/RelatedLinkBase.cs
deleted file mode 100644
index c2077ce4a9..0000000000
--- a/src/Umbraco.Web/Models/RelatedLinkBase.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Newtonsoft.Json;
-
-namespace Umbraco.Web.Models
-{
- public abstract class RelatedLinkBase
- {
- [JsonProperty("caption")]
- public string Caption { get; set; }
- [JsonProperty("link")]
- public string Link { get; set; }
- [JsonProperty("newWindow")]
- public bool NewWindow { get; set; }
- [JsonProperty("isInternal")]
- public bool IsInternal { get; set; }
- [JsonProperty("type")]
- public RelatedLinkType Type { get; set; }
- }
-}
diff --git a/src/Umbraco.Web/Models/RelatedLinkType.cs b/src/Umbraco.Web/Models/RelatedLinkType.cs
deleted file mode 100644
index eec7817ab6..0000000000
--- a/src/Umbraco.Web/Models/RelatedLinkType.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-//
-// Umbraco
-//
-//
-// Defines the RelatedLinkType type.
-//
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace Umbraco.Web.Models
-{
- ///
- /// The related link type.
- ///
- public enum RelatedLinkType
- {
- ///
- /// Internal link type
- ///
- Internal,
-
- ///
- /// External link type
- ///
- External
- }
-}
diff --git a/src/Umbraco.Web/Models/RelatedLinks.cs b/src/Umbraco.Web/Models/RelatedLinks.cs
deleted file mode 100644
index 22cdcd11b6..0000000000
--- a/src/Umbraco.Web/Models/RelatedLinks.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using System.Collections;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Linq;
-
-namespace Umbraco.Web.Models
-{
- [TypeConverter(typeof(RelatedLinksTypeConverter))]
- public class RelatedLinks : IEnumerable
- {
- private readonly string _propertyData;
-
- private readonly IEnumerable _relatedLinks;
-
- public RelatedLinks(IEnumerable relatedLinks, string propertyData)
- {
- _relatedLinks = relatedLinks;
- _propertyData = propertyData;
- }
-
- ///
- /// Gets the property data.
- ///
- internal string PropertyData
- {
- get
- {
- return this._propertyData;
- }
- }
-
- public IEnumerator GetEnumerator()
- {
- return _relatedLinks.GetEnumerator();
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return this.GetEnumerator();
- }
- }
-}
diff --git a/src/Umbraco.Web/PropertyEditors/MultiUrlPickerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MultiUrlPickerPropertyEditor.cs
index 54bf5c4d15..1648b81623 100644
--- a/src/Umbraco.Web/PropertyEditors/MultiUrlPickerPropertyEditor.cs
+++ b/src/Umbraco.Web/PropertyEditors/MultiUrlPickerPropertyEditor.cs
@@ -7,7 +7,7 @@ using Umbraco.Web.PublishedCache;
namespace Umbraco.Web.PropertyEditors
{
- [DataEditor(Constants.PropertyEditors.Aliases.MultiUrlPicker, EditorType.PropertyValue|EditorType.MacroParameter, "Multi Url Picker", "multiurlpicker", ValueType = "JSON", Group = "pickers", Icon = "icon-link")]
+ [DataEditor(Constants.PropertyEditors.Aliases.MultiUrlPicker, EditorType.PropertyValue|EditorType.MacroParameter, "Multi Url Picker", "multiurlpicker", ValueType = ValueTypes.Json, Group = "pickers", Icon = "icon-link")]
public class MultiUrlPickerPropertyEditor : DataEditor
{
private readonly IEntityService _entityService;
diff --git a/src/Umbraco.Web/PropertyEditors/RelatedLinksConfiguration.cs b/src/Umbraco.Web/PropertyEditors/RelatedLinksConfiguration.cs
deleted file mode 100644
index 5db14c6842..0000000000
--- a/src/Umbraco.Web/PropertyEditors/RelatedLinksConfiguration.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using Umbraco.Core.PropertyEditors;
-
-namespace Umbraco.Web.PropertyEditors
-{
- ///
- /// Represents the configuration for the related links value editor.
- ///
- public class RelatedLinksConfiguration
- {
- [ConfigurationField("max", "Maximum number of links", "number", Description = "Enter the maximum amount of links to be added, enter 0 for unlimited")]
- public int Maximum { get; set; }
- }
-}
\ No newline at end of file
diff --git a/src/Umbraco.Web/PropertyEditors/RelatedLinksConfigurationEditor.cs b/src/Umbraco.Web/PropertyEditors/RelatedLinksConfigurationEditor.cs
deleted file mode 100644
index 07ff359a82..0000000000
--- a/src/Umbraco.Web/PropertyEditors/RelatedLinksConfigurationEditor.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System.Collections.Generic;
-using Umbraco.Core.PropertyEditors;
-
-namespace Umbraco.Web.PropertyEditors
-{
- ///
- /// Represents the configuration editor for the related links value editor.
- ///
- public class RelatedLinksConfigurationEditor : ConfigurationEditor
- {
- public override IDictionary ToValueEditor(object configuration)
- {
- var d = base.ToValueEditor(configuration);
- d["idType"] = "udi";
- return d;
- }
- }
-}
\ No newline at end of file
diff --git a/src/Umbraco.Web/PropertyEditors/RelatedLinksPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/RelatedLinksPropertyEditor.cs
deleted file mode 100644
index b450fcc67f..0000000000
--- a/src/Umbraco.Web/PropertyEditors/RelatedLinksPropertyEditor.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using Umbraco.Core;
-using Umbraco.Core.Logging;
-using Umbraco.Core.PropertyEditors;
-
-namespace Umbraco.Web.PropertyEditors
-{
- [DataEditor(Constants.PropertyEditors.Aliases.RelatedLinks, "Related links", "relatedlinks", ValueType = ValueTypes.Json, Icon = "icon-thumbnail-list", Group = "pickers")]
- public class RelatedLinksPropertyEditor : DataEditor
- {
- public RelatedLinksPropertyEditor(ILogger logger)
- : base(logger)
- { }
-
- protected override IConfigurationEditor CreateConfigurationEditor() => new RelatedLinksConfigurationEditor();
- }
-}
diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksLegacyValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksLegacyValueConverter.cs
deleted file mode 100644
index 6c2a4331d0..0000000000
--- a/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksLegacyValueConverter.cs
+++ /dev/null
@@ -1,132 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Xml;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using Umbraco.Core;
-using Umbraco.Core.Cache;
-using Umbraco.Core.Logging;
-using Umbraco.Core.Models.PublishedContent;
-using Umbraco.Core.PropertyEditors;
-using Umbraco.Core.PropertyEditors.ValueConverters;
-using Umbraco.Core.Services;
-
-namespace Umbraco.Web.PropertyEditors.ValueConverters
-{
- [DefaultPropertyValueConverter(typeof(JsonValueConverter))] //this shadows the JsonValueConverter
- public class RelatedLinksLegacyValueConverter : PropertyValueConverterBase
- {
- private static readonly string[] MatchingEditors = {
- Constants.PropertyEditors.Aliases.RelatedLinks
- };
-
- private readonly IUmbracoContextAccessor _umbracoContextAccessor;
- private readonly ILogger _logger;
- private readonly ServiceContext _services;
-
- public RelatedLinksLegacyValueConverter(IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, ILogger logger)
- {
- _umbracoContextAccessor = umbracoContextAccessor;
- _services = services;
- _logger = logger;
- }
-
- public override bool IsConverter(PublishedPropertyType propertyType)
- => MatchingEditors.Contains(propertyType.EditorAlias);
-
- public override Type GetPropertyValueType(PublishedPropertyType propertyType)
- => typeof (JArray);
-
- public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
- => PropertyCacheLevel.Element;
-
- public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
- {
- if (source == null) return null;
- var sourceString = source.ToString();
-
- if (sourceString.DetectIsJson())
- {
- try
- {
- var obj = JsonConvert.DeserializeObject(sourceString);
- //update the internal links if we have a context
- if (UmbracoContext.Current != null)
- {
- var helper = new UmbracoHelper(_umbracoContextAccessor.UmbracoContext, _services);
- foreach (var a in obj)
- {
- var type = a.Value("type");
- if (type.IsNullOrWhiteSpace() == false)
- {
- if (type == "internal")
- {
- switch (propertyType.EditorAlias)
- {
- case Constants.PropertyEditors.Aliases.RelatedLinks:
- var strLinkId = a.Value("link");
- var udiAttempt = strLinkId.TryConvertTo();
- if (udiAttempt)
- {
- var content = helper.PublishedContent(udiAttempt.Result);
- if (content == null) break;
- a["link"] = helper.Url(content.Id);
- }
- break;
- }
- }
- }
- }
- }
- return obj;
- }
- catch (Exception ex)
- {
- _logger.Error(ex, "Could not parse the string '{Json}' to a json object", sourceString);
- }
- }
-
- //it's not json, just return the string
- return sourceString;
- }
-
- public override object ConvertIntermediateToXPath(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object source, bool preview)
- {
- if (source == null) return null;
- var sourceString = source.ToString();
-
- if (sourceString.DetectIsJson())
- {
- try
- {
- var obj = JsonConvert.DeserializeObject(sourceString);
-
- var d = new XmlDocument();
- var e = d.CreateElement("links");
- d.AppendChild(e);
-
- foreach (dynamic link in obj)
- {
- var ee = d.CreateElement("link");
- ee.SetAttribute("title", link.title);
- ee.SetAttribute("link", link.link);
- ee.SetAttribute("type", link.type);
- ee.SetAttribute("newwindow", link.newWindow);
-
- e.AppendChild(ee);
- }
-
- return d.CreateNavigator();
- }
- catch (Exception ex)
- {
- _logger.Error(ex, "Could not parse the string '{Json}' to a json object", sourceString);
- }
- }
-
- //it's not json, just return the string
- return sourceString;
- }
- }
-}
diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksValueConverter.cs
deleted file mode 100644
index 983d122a83..0000000000
--- a/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksValueConverter.cs
+++ /dev/null
@@ -1,169 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Xml;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using Umbraco.Core;
-using Umbraco.Core.Logging;
-using Umbraco.Core.Models.PublishedContent;
-using Umbraco.Core.PropertyEditors;
-using Umbraco.Core.PropertyEditors.ValueConverters;
-using Umbraco.Web.Models;
-using Umbraco.Web.PublishedCache;
-
-namespace Umbraco.Web.PropertyEditors.ValueConverters
-{
- ///
- /// The related links property value converter.
- ///
- [DefaultPropertyValueConverter(typeof(RelatedLinksLegacyValueConverter), typeof(JsonValueConverter))]
- public class RelatedLinksValueConverter : PropertyValueConverterBase
- {
- private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
- private readonly IUmbracoContextAccessor _umbracoContextAccessor;
- private readonly ILogger _logger;
-
- public RelatedLinksValueConverter(IPublishedSnapshotAccessor publishedSnapshotAccessor, IUmbracoContextAccessor umbracoContextAccessor, ILogger logger)
- {
- _publishedSnapshotAccessor = publishedSnapshotAccessor;
- _umbracoContextAccessor = umbracoContextAccessor;
- _logger = logger;
- }
-
- ///
- /// Checks if this converter can convert the property editor and registers if it can.
- ///
- ///
- /// The property type.
- ///
- ///
- /// The .
- ///
- public override bool IsConverter(PublishedPropertyType propertyType)
- => propertyType.EditorAlias.Equals(Constants.PropertyEditors.Aliases.RelatedLinks);
-
- public override Type GetPropertyValueType(PublishedPropertyType propertyType)
- => typeof (JArray);
-
- public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
- => PropertyCacheLevel.Element;
-
- public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
- {
- if (source == null) return null;
- var sourceString = source.ToString();
-
- var relatedLinksData = JsonConvert.DeserializeObject>(sourceString);
- var relatedLinks = new List();
-
- foreach (var linkData in relatedLinksData)
- {
- var relatedLink = new RelatedLink
- {
- Caption = linkData.Caption,
- NewWindow = linkData.NewWindow,
- IsInternal = linkData.IsInternal,
- Type = linkData.Type,
- Link = linkData.Link
- };
-
- int contentId;
- if (int.TryParse(relatedLink.Link, out contentId))
- {
- relatedLink.Id = contentId;
- relatedLink = CreateLink(relatedLink);
- }
- else
- {
- var strLinkId = linkData.Link;
- var udiAttempt = strLinkId.TryConvertTo();
- if (udiAttempt.Success && udiAttempt.Result != null)
- {
- var content = _publishedSnapshotAccessor.PublishedSnapshot.Content.GetById(udiAttempt.Result.Guid);
- if (content != null)
- {
- relatedLink.Id = content.Id;
- relatedLink = CreateLink(relatedLink);
- relatedLink.Content = content;
- }
- }
- }
-
- if (relatedLink.IsDeleted == false)
- {
- relatedLinks.Add(relatedLink);
- }
- else
- {
- _logger.Warn("Related Links value converter skipped a link as the node has been unpublished/deleted (Internal Link NodeId: {RelatedLinkNodeId}, Link Caption: '{RelatedLinkCaption}')", relatedLink.Link, relatedLink.Caption);
- }
- }
-
- return new RelatedLinks(relatedLinks, sourceString);
- }
-
- private RelatedLink CreateLink(RelatedLink link)
- {
- var umbracoContext = _umbracoContextAccessor.UmbracoContext;
-
- if (link.IsInternal && link.Id != null)
- {
- if (umbracoContext == null)
- return null;
-
- var urlProvider = umbracoContext.UrlProvider;
-
- link.Link = urlProvider.GetUrl((int)link.Id);
- if (link.Link.Equals("#"))
- {
- link.IsDeleted = true;
- link.Link = link.Id.ToString();
- }
- else
- {
- link.IsDeleted = false;
- }
- }
-
- return link;
- }
-
- public override object ConvertIntermediateToXPath(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
- {
- if (inter == null) return null;
- var sourceString = inter.ToString();
-
- if (sourceString.DetectIsJson())
- {
- try
- {
- var obj = JsonConvert.DeserializeObject(sourceString);
-
- var d = new XmlDocument();
- var e = d.CreateElement("links");
- d.AppendChild(e);
-
- foreach (dynamic link in obj)
- {
- var ee = d.CreateElement("link");
- ee.SetAttribute("title", link.title);
- ee.SetAttribute("link", link.link);
- ee.SetAttribute("type", link.type);
- ee.SetAttribute("newwindow", link.newWindow);
-
- e.AppendChild(ee);
- }
-
- return d.CreateNavigator();
- }
- catch (Exception ex)
- {
- _logger.Error(ex, "Could not parse the string {Json} to a json object", sourceString);
- }
- }
-
- //it's not json, just return the string
- return sourceString;
- }
- }
-}
diff --git a/src/Umbraco.Web/PublishedCache/NuCache/ContentCache.cs b/src/Umbraco.Web/PublishedCache/NuCache/ContentCache.cs
index cab6e7d759..74cf960170 100644
--- a/src/Umbraco.Web/PublishedCache/NuCache/ContentCache.cs
+++ b/src/Umbraco.Web/PublishedCache/NuCache/ContentCache.cs
@@ -243,7 +243,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
var n = _snapshot.Get(contentId);
if (n == null) return false;
- return preview || n.Published != null;
+ return preview || n.PublishedModel != null;
}
public override IEnumerable GetAtRoot(bool preview)
@@ -280,8 +280,8 @@ namespace Umbraco.Web.PublishedCache.NuCache
// both .Draft and .Published cannot be null at the same time
return preview
- ? node.Draft ?? GetPublishedContentAsDraft(node.Published)
- : node.Published;
+ ? node.DraftModel ?? GetPublishedContentAsDraft(node.PublishedModel)
+ : node.PublishedModel;
}
// gets a published content as a previewing draft, if preview is true
@@ -302,7 +302,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
return preview
? _snapshot.IsEmpty == false
- : _snapshot.GetAtRoot().Any(x => x.Published != null);
+ : _snapshot.GetAtRoot().Any(x => x.PublishedModel != null);
}
#endregion
diff --git a/src/Umbraco.Web/PublishedCache/NuCache/ContentNode.cs b/src/Umbraco.Web/PublishedCache/NuCache/ContentNode.cs
index 647adaad91..5bab8aa265 100644
--- a/src/Umbraco.Web/PublishedCache/NuCache/ContentNode.cs
+++ b/src/Umbraco.Web/PublishedCache/NuCache/ContentNode.cs
@@ -34,10 +34,11 @@ namespace Umbraco.Web.PublishedCache.NuCache
DateTime createDate, int creatorId,
ContentData draftData, ContentData publishedData,
IPublishedSnapshotAccessor publishedSnapshotAccessor,
- IVariationContextAccessor variationContextAccessor)
+ IVariationContextAccessor variationContextAccessor,
+ IUmbracoContextAccessor umbracoContextAccessor)
: this(id, uid, level, path, sortOrder, parentContentId, createDate, creatorId)
{
- SetContentTypeAndData(contentType, draftData, publishedData, publishedSnapshotAccessor, variationContextAccessor);
+ SetContentTypeAndData(contentType, draftData, publishedData, publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor);
}
// 2-phases ctor, phase 1
@@ -59,7 +60,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
}
// two-phase ctor, phase 2
- public void SetContentTypeAndData(PublishedContentType contentType, ContentData draftData, ContentData publishedData, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor)
+ public void SetContentTypeAndData(PublishedContentType contentType, ContentData draftData, ContentData publishedData, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, IUmbracoContextAccessor umbracoContextAccessor)
{
ContentType = contentType;
@@ -67,13 +68,20 @@ namespace Umbraco.Web.PublishedCache.NuCache
throw new ArgumentException("Both draftData and publishedData cannot be null at the same time.");
if (draftData != null)
- Draft = new PublishedContent(this, draftData, publishedSnapshotAccessor, variationContextAccessor).CreateModel();
+ {
+ DraftContent = new PublishedContent(this, draftData, publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor);
+ DraftModel = DraftContent.CreateModel();
+ }
+
if (publishedData != null)
- Published = new PublishedContent(this, publishedData, publishedSnapshotAccessor, variationContextAccessor).CreateModel();
+ {
+ PublishedContent = new PublishedContent(this, publishedData, publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor);
+ PublishedModel = PublishedContent.CreateModel();
+ }
}
// clone parent
- private ContentNode(ContentNode origin)
+ private ContentNode(ContentNode origin, IUmbracoContextAccessor umbracoContextAccessor)
{
// everything is the same, except for the child items
// list which is a clone of the original list
@@ -88,17 +96,20 @@ namespace Umbraco.Web.PublishedCache.NuCache
CreateDate = origin.CreateDate;
CreatorId = origin.CreatorId;
- var originDraft = origin.Draft == null ? null : PublishedContent.UnwrapIPublishedContent(origin.Draft);
- var originPublished = origin.Published == null ? null : PublishedContent.UnwrapIPublishedContent(origin.Published);
+ var originDraft = origin.DraftContent;
+ var originPublished = origin.PublishedContent;
- Draft = originDraft == null ? null : new PublishedContent(this, originDraft).CreateModel();
- Published = originPublished == null ? null : new PublishedContent(this, originPublished).CreateModel();
+
+ DraftContent = new PublishedContent(this, originDraft, umbracoContextAccessor);
+ PublishedContent = new PublishedContent(this, originPublished, umbracoContextAccessor);
+ DraftModel = DraftContent?.CreateModel();
+ PublishedModel = PublishedContent?.CreateModel();
ChildContentIds = new List(origin.ChildContentIds); // needs to be *another* list
}
// clone with new content type
- public ContentNode(ContentNode origin, PublishedContentType contentType, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor)
+ public ContentNode(ContentNode origin, PublishedContentType contentType, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, IUmbracoContextAccessor umbracoContextAccessor)
{
Id = origin.Id;
Uid = origin.Uid;
@@ -110,11 +121,13 @@ namespace Umbraco.Web.PublishedCache.NuCache
CreateDate = origin.CreateDate;
CreatorId = origin.CreatorId;
- var originDraft = origin.Draft == null ? null : PublishedContent.UnwrapIPublishedContent(origin.Draft);
- var originPublished = origin.Published == null ? null : PublishedContent.UnwrapIPublishedContent(origin.Published);
+ var originDraft = origin.DraftContent;
+ var originPublished = origin.PublishedContent;
- Draft = originDraft == null ? null : new PublishedContent(this, originDraft._contentData, publishedSnapshotAccessor, variationContextAccessor).CreateModel();
- Published = originPublished == null ? null : new PublishedContent(this, originPublished._contentData, publishedSnapshotAccessor, variationContextAccessor).CreateModel();
+ DraftContent = originDraft == null ? null : new PublishedContent(this, originDraft.ContentData, publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor);
+ DraftModel = DraftContent?.CreateModel();
+ PublishedContent = originPublished == null ? null : new PublishedContent(this, originPublished.ContentData, publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor);
+ PublishedModel = PublishedContent?.CreateModel();
ChildContentIds = origin.ChildContentIds; // can be the *same* list
}
@@ -133,32 +146,31 @@ namespace Umbraco.Web.PublishedCache.NuCache
public readonly int CreatorId;
// draft and published version (either can be null, but not both)
- // are models not direct PublishedContent instances
- public IPublishedContent Draft;
- public IPublishedContent Published;
+ // are the direct PublishedContent instances
+ public PublishedContent DraftContent;
+ public PublishedContent PublishedContent;
- public ContentNode CloneParent(IPublishedSnapshotAccessor publishedSnapshotAccessor)
+ // draft and published version (either can be null, but not both)
+ // are models not direct PublishedContent instances
+ public IPublishedContent DraftModel;
+ public IPublishedContent PublishedModel;
+
+ public ContentNode CloneParent(
+ IPublishedSnapshotAccessor publishedSnapshotAccessor,
+ IUmbracoContextAccessor umbracoContextAccessor)
{
- return new ContentNode(this);
+ return new ContentNode(this, umbracoContextAccessor);
}
public ContentNodeKit ToKit()
{
- var draft = Draft is PublishedContentModel draftModel
- ? (PublishedContent) draftModel.Unwrap()
- : (PublishedContent) Draft;
-
- var published = Published is PublishedContentModel publishedModel
- ? (PublishedContent) publishedModel.Unwrap()
- : (PublishedContent) Published;
-
return new ContentNodeKit
{
Node = this,
ContentTypeId = ContentType.Id,
- DraftData = draft?._contentData,
- PublishedData = published?._contentData
+ DraftData = DraftContent?.ContentData,
+ PublishedData = PublishedContent?.ContentData
};
}
}
diff --git a/src/Umbraco.Web/PublishedCache/NuCache/ContentNodeKit.cs b/src/Umbraco.Web/PublishedCache/NuCache/ContentNodeKit.cs
index 5a47b99382..739a6141be 100644
--- a/src/Umbraco.Web/PublishedCache/NuCache/ContentNodeKit.cs
+++ b/src/Umbraco.Web/PublishedCache/NuCache/ContentNodeKit.cs
@@ -17,9 +17,14 @@ namespace Umbraco.Web.PublishedCache.NuCache
public static ContentNodeKit Null { get; } = new ContentNodeKit { ContentTypeId = -1 };
- public void Build(PublishedContentType contentType, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, bool canBePublished)
+ public void Build(
+ PublishedContentType contentType,
+ IPublishedSnapshotAccessor publishedSnapshotAccessor,
+ IVariationContextAccessor variationContextAccessor,
+ bool canBePublished,
+ IUmbracoContextAccessor umbracoContextAccessor)
{
- Node.SetContentTypeAndData(contentType, DraftData, canBePublished ? PublishedData : null, publishedSnapshotAccessor, variationContextAccessor);
+ Node.SetContentTypeAndData(contentType, DraftData, canBePublished ? PublishedData : null, publishedSnapshotAccessor, variationContextAccessor,umbracoContextAccessor);
}
}
}
diff --git a/src/Umbraco.Web/PublishedCache/NuCache/ContentStore.cs b/src/Umbraco.Web/PublishedCache/NuCache/ContentStore.cs
index 353ac83eda..b3996050a6 100644
--- a/src/Umbraco.Web/PublishedCache/NuCache/ContentStore.cs
+++ b/src/Umbraco.Web/PublishedCache/NuCache/ContentStore.cs
@@ -20,6 +20,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
private readonly IVariationContextAccessor _variationContextAccessor;
+ private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly ConcurrentDictionary> _contentNodes;
private readonly ConcurrentDictionary> _contentRootNodes;
private readonly ConcurrentDictionary> _contentTypesById;
@@ -44,10 +45,16 @@ namespace Umbraco.Web.PublishedCache.NuCache
#region Ctor
- public ContentStore(IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, ILogger logger, BPlusTree localDb = null)
+ public ContentStore(
+ IPublishedSnapshotAccessor publishedSnapshotAccessor,
+ IVariationContextAccessor variationContextAccessor,
+ IUmbracoContextAccessor umbracoContextAccessor,
+ ILogger logger,
+ BPlusTree localDb = null)
{
_publishedSnapshotAccessor = publishedSnapshotAccessor;
_variationContextAccessor = variationContextAccessor;
+ _umbracoContextAccessor = umbracoContextAccessor;
_logger = logger;
_localDb = localDb;
@@ -279,7 +286,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
if (node == null) continue;
var contentTypeId = node.ContentType.Id;
if (index.TryGetValue(contentTypeId, out PublishedContentType contentType) == false) continue;
- SetValueLocked(_contentNodes, node.Id, new ContentNode(node, contentType, _publishedSnapshotAccessor, _variationContextAccessor));
+ SetValueLocked(_contentNodes, node.Id, new ContentNode(node, contentType, _publishedSnapshotAccessor, _variationContextAccessor, _umbracoContextAccessor));
}
}
finally
@@ -393,7 +400,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
_contentNodes.TryGetValue(id, out LinkedNode link);
if (link?.Value == null)
continue;
- var node = new ContentNode(link.Value, contentType, _publishedSnapshotAccessor, _variationContextAccessor);
+ var node = new ContentNode(link.Value, contentType, _publishedSnapshotAccessor, _variationContextAccessor, _umbracoContextAccessor);
SetValueLocked(_contentNodes, id, node);
if (_localDb != null) RegisterChange(id, node.ToKit());
}
@@ -419,7 +426,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
var canBePublished = ParentPublishedLocked(kit);
// and use
- kit.Build(link.Value, _publishedSnapshotAccessor, _variationContextAccessor, canBePublished);
+ kit.Build(link.Value, _publishedSnapshotAccessor, _variationContextAccessor, canBePublished, _umbracoContextAccessor);
return true;
}
@@ -631,7 +638,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
var link = GetParentLink(content);
var parent = link.Value;
if (link.Gen < _liveGen)
- parent = parent.CloneParent(_publishedSnapshotAccessor);
+ parent = parent.CloneParent(_publishedSnapshotAccessor, _umbracoContextAccessor);
parent.ChildContentIds.Remove(content.Id);
if (link.Gen < _liveGen)
SetValueLocked(_contentNodes, parent.Id, parent);
@@ -652,7 +659,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
return true;
var link = GetParentLink(kit.Node);
var node = link?.Value;
- return node?.Published != null;
+ return node?.PublishedModel != null;
}
private void AddToParentLocked(ContentNode content)
@@ -670,7 +677,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
var link = GetParentLink(content);
var parent = link.Value;
if (link.Gen < _liveGen)
- parent = parent.CloneParent(_publishedSnapshotAccessor);
+ parent = parent.CloneParent(_publishedSnapshotAccessor, _umbracoContextAccessor);
parent.ChildContentIds.Add(content.Id);
if (link.Gen < _liveGen)
SetValueLocked(_contentNodes, parent.Id, parent);
diff --git a/src/Umbraco.Web/PublishedCache/NuCache/MediaCache.cs b/src/Umbraco.Web/PublishedCache/NuCache/MediaCache.cs
index 28c7c38c36..7a22366165 100644
--- a/src/Umbraco.Web/PublishedCache/NuCache/MediaCache.cs
+++ b/src/Umbraco.Web/PublishedCache/NuCache/MediaCache.cs
@@ -34,14 +34,14 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
// ignore preview, there's only draft for media
var n = _snapshot.Get(contentId);
- return n?.Published;
+ return n?.PublishedModel;
}
public override IPublishedContent GetById(bool preview, Guid contentId)
{
// ignore preview, there's only draft for media
var n = _snapshot.Get(contentId);
- return n?.Published;
+ return n?.PublishedModel;
}
public override bool HasById(bool preview, int contentId)
@@ -73,7 +73,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
var c = _snapshot.GetAtRoot();
// ignore preview, there's only draft for media
- return c.Select(n => n.Published);
+ return c.Select(n => n.PublishedModel);
}
public override bool HasContent(bool preview)
diff --git a/src/Umbraco.Web/PublishedCache/NuCache/MemberCache.cs b/src/Umbraco.Web/PublishedCache/NuCache/MemberCache.cs
index ecf099f90b..f7ffe73109 100644
--- a/src/Umbraco.Web/PublishedCache/NuCache/MemberCache.cs
+++ b/src/Umbraco.Web/PublishedCache/NuCache/MemberCache.cs
@@ -17,18 +17,22 @@ namespace Umbraco.Web.PublishedCache.NuCache
internal class MemberCache : IPublishedMemberCache, INavigableData
{
private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
+
public readonly IVariationContextAccessor VariationContextAccessor;
+ private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IEntityXmlSerializer _entitySerializer;
private readonly IAppCache _snapshotCache;
private readonly IMemberService _memberService;
private readonly PublishedContentTypeCache _contentTypeCache;
private readonly bool _previewDefault;
- public MemberCache(bool previewDefault, IAppCache snapshotCache, IMemberService memberService, PublishedContentTypeCache contentTypeCache, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, IEntityXmlSerializer entitySerializer)
+ public MemberCache(bool previewDefault, IAppCache snapshotCache, IMemberService memberService, PublishedContentTypeCache contentTypeCache,
+ IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, IUmbracoContextAccessor umbracoContextAccessor, IEntityXmlSerializer entitySerializer)
{
_snapshotCache = snapshotCache;
_publishedSnapshotAccessor = publishedSnapshotAccessor;
VariationContextAccessor = variationContextAccessor;
+ _umbracoContextAccessor = umbracoContextAccessor;
_entitySerializer = entitySerializer;
_memberService = memberService;
_previewDefault = previewDefault;
@@ -64,14 +68,14 @@ namespace Umbraco.Web.PublishedCache.NuCache
var member = _memberService.GetById(memberId);
return member == null
? null
- : PublishedMember.Create(member, GetContentType(member.ContentTypeId), _previewDefault, _publishedSnapshotAccessor, VariationContextAccessor);
+ : PublishedMember.Create(member, GetContentType(member.ContentTypeId), _previewDefault, _publishedSnapshotAccessor, VariationContextAccessor, _umbracoContextAccessor);
});
}
private IPublishedContent /*IPublishedMember*/ GetById(IMember member, bool previewing)
{
return GetCacheItem(CacheKeys.MemberCacheMember("ById", _previewDefault, member.Id), () =>
- PublishedMember.Create(member, GetContentType(member.ContentTypeId), previewing, _publishedSnapshotAccessor, VariationContextAccessor));
+ PublishedMember.Create(member, GetContentType(member.ContentTypeId), previewing, _publishedSnapshotAccessor, VariationContextAccessor, _umbracoContextAccessor));
}
public IPublishedContent /*IPublishedMember*/ GetByProviderKey(object key)
@@ -106,7 +110,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
public IPublishedContent /*IPublishedMember*/ GetByMember(IMember member)
{
- return PublishedMember.Create(member, GetContentType(member.ContentTypeId), _previewDefault, _publishedSnapshotAccessor, VariationContextAccessor);
+ return PublishedMember.Create(member, GetContentType(member.ContentTypeId), _previewDefault, _publishedSnapshotAccessor, VariationContextAccessor, _umbracoContextAccessor);
}
public IEnumerable GetAtRoot(bool preview)
@@ -114,7 +118,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
// because members are flat (not a tree) everything is at root
// because we're loading everything... let's just not cache?
var members = _memberService.GetAllMembers();
- return members.Select(m => PublishedMember.Create(m, GetContentType(m.ContentTypeId), preview, _publishedSnapshotAccessor, VariationContextAccessor));
+ return members.Select(m => PublishedMember.Create(m, GetContentType(m.ContentTypeId), preview, _publishedSnapshotAccessor, VariationContextAccessor, _umbracoContextAccessor));
}
public XPathNavigator CreateNavigator()
diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs
index 3dee81f1bb..aa19918ca9 100644
--- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs
+++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Cache;
-using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Composing;
using Umbraco.Web.Models;
@@ -14,23 +13,27 @@ namespace Umbraco.Web.PublishedCache.NuCache
internal class PublishedContent : PublishedContentBase
{
private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
+ private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly ContentNode _contentNode;
- // ReSharper disable once InconsistentNaming
- internal readonly ContentData _contentData; // internal for ContentNode cloning
-
private readonly string _urlSegment;
#region Constructors
- public PublishedContent(ContentNode contentNode, ContentData contentData, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor)
+ public PublishedContent(
+ ContentNode contentNode,
+ ContentData contentData,
+ IPublishedSnapshotAccessor publishedSnapshotAccessor,
+ IVariationContextAccessor variationContextAccessor,
+ IUmbracoContextAccessor umbracoContextAccessor) :base(umbracoContextAccessor)
{
_contentNode = contentNode;
- _contentData = contentData;
+ ContentData = contentData;
_publishedSnapshotAccessor = publishedSnapshotAccessor;
+ _umbracoContextAccessor = umbracoContextAccessor;
VariationContextAccessor = variationContextAccessor;
- _urlSegment = _contentData.Name.ToUrlSegment();
- IsPreviewing = _contentData.Published == false;
+ _urlSegment = ContentData.Name.ToUrlSegment();
+ IsPreviewing = ContentData.Published == false;
var properties = new List();
foreach (var propertyType in _contentNode.ContentType.PropertyTypes)
@@ -66,12 +69,15 @@ namespace Umbraco.Web.PublishedCache.NuCache
}
// (see ContentNode.CloneParent)
- public PublishedContent(ContentNode contentNode, PublishedContent origin)
+ public PublishedContent(
+ ContentNode contentNode,
+ PublishedContent origin,
+ IUmbracoContextAccessor umbracoContextAccessor) :base(umbracoContextAccessor)
{
_contentNode = contentNode;
_publishedSnapshotAccessor = origin._publishedSnapshotAccessor;
VariationContextAccessor = origin.VariationContextAccessor;
- _contentData = origin._contentData;
+ ContentData = origin.ContentData;
_urlSegment = origin._urlSegment;
IsPreviewing = origin.IsPreviewing;
@@ -83,12 +89,14 @@ namespace Umbraco.Web.PublishedCache.NuCache
}
// clone for previewing as draft a published content that is published and has no draft
- private PublishedContent(PublishedContent origin)
+ private PublishedContent(
+ PublishedContent origin,
+ IUmbracoContextAccessor umbracoContextAccessor) :base(umbracoContextAccessor)
{
_publishedSnapshotAccessor = origin._publishedSnapshotAccessor;
VariationContextAccessor = origin.VariationContextAccessor;
_contentNode = origin._contentNode;
- _contentData = origin._contentData;
+ ContentData = origin.ContentData;
_urlSegment = origin._urlSegment;
IsPreviewing = true;
@@ -170,6 +178,8 @@ namespace Umbraco.Web.PublishedCache.NuCache
#region PublishedContent
+ internal ContentData ContentData { get; }
+
///
public override int Id => _contentNode.Id;
@@ -179,11 +189,11 @@ namespace Umbraco.Web.PublishedCache.NuCache
get
{
if (!ContentType.VariesByCulture())
- return _contentData.Name;
+ return ContentData.Name;
var culture = VariationContextAccessor?.VariationContext?.Culture ?? "";
if (culture == "")
- return _contentData.Name;
+ return ContentData.Name;
return Cultures.TryGetValue(culture, out var cultureInfos) ? cultureInfos.Name : null;
}
@@ -215,7 +225,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
public override string Path => _contentNode.Path;
///
- public override int? TemplateId => _contentData.TemplateId;
+ public override int? TemplateId => ContentData.TemplateId;
///
public override int CreatorId => _contentNode.CreatorId;
@@ -227,13 +237,13 @@ namespace Umbraco.Web.PublishedCache.NuCache
public override DateTime CreateDate => _contentNode.CreateDate;
///
- public override int WriterId => _contentData.WriterId;
+ public override int WriterId => ContentData.WriterId;
///
- public override string WriterName => GetProfileNameById(_contentData.WriterId);
+ public override string WriterName => GetProfileNameById(ContentData.WriterId);
///
- public override DateTime UpdateDate => _contentData.VersionDate;
+ public override DateTime UpdateDate => ContentData.VersionDate;
private IReadOnlyDictionary _cultureInfos;
@@ -263,9 +273,9 @@ namespace Umbraco.Web.PublishedCache.NuCache
if (_cultureInfos != null) return _cultureInfos;
- if (_contentData.CultureInfos == null)
+ if (ContentData.CultureInfos == null)
throw new Exception("oops: _contentDate.CultureInfos is null.");
- return _cultureInfos = _contentData.CultureInfos
+ return _cultureInfos = ContentData.CultureInfos
.ToDictionary(x => x.Key, x => new PublishedCultureInfo(x.Key, x.Value.Name, x.Value.Date), StringComparer.OrdinalIgnoreCase);
}
}
@@ -277,7 +287,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
public override bool IsDraft(string culture = null)
{
// if this is the 'published' published content, nothing can be draft
- if (_contentData.Published)
+ if (ContentData.Published)
return false;
// not the 'published' published content, and does not vary = must be draft
@@ -290,24 +300,32 @@ namespace Umbraco.Web.PublishedCache.NuCache
// not the 'published' published content, and varies
// = depends on the culture
- return _contentData.CultureInfos.TryGetValue(culture, out var cvar) && cvar.IsDraft;
+ return ContentData.CultureInfos.TryGetValue(culture, out var cvar) && cvar.IsDraft;
}
+ ///
public override bool IsPublished(string culture = null)
{
+ // whether we are the 'draft' or 'published' content, need to determine whether
+ // there is a 'published' version for the specified culture (or at all, for
+ // invariant content items)
+
+ // if there is no 'published' published content, no culture can be published
+ var hasPublished = _contentNode.PublishedContent != null;
+ if (!hasPublished)
+ return false;
+
+ // if there is a 'published' published content, and does not vary = published
if (!ContentType.VariesByCulture())
- {
- return _contentData.Published;
- }
+ return true;
// handle context culture
if (culture == null)
- {
culture = VariationContextAccessor?.VariationContext?.Culture ?? "";
- }
- //If the current culture is not a draft, it must be the published version
- return _contentData.CultureInfos.TryGetValue(culture, out var cvar) && !cvar.IsDraft;
+ // there is a 'published' published content, and varies
+ // = depends on the culture
+ return _contentNode.PublishedContent.ContentData.CultureInfos.ContainsKey(culture);
}
#endregion
@@ -450,8 +468,8 @@ namespace Umbraco.Web.PublishedCache.NuCache
return this;
var cache = GetAppropriateCache();
- if (cache == null) return new PublishedContent(this).CreateModel();
- return (IPublishedContent)cache.Get(AsPreviewingCacheKey, () => new PublishedContent(this).CreateModel());
+ if (cache == null) return new PublishedContent(this, _umbracoContextAccessor).CreateModel();
+ return (IPublishedContent)cache.Get(AsPreviewingCacheKey, () => new PublishedContent(this, _umbracoContextAccessor).CreateModel());
}
// used by Navigable.Source,...
diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedMember.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedMember.cs
index 47c8d738f1..db50fc3fe6 100644
--- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedMember.cs
+++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedMember.cs
@@ -15,13 +15,26 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
private readonly IMember _member;
- private PublishedMember(IMember member, ContentNode contentNode, ContentData contentData, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor)
- : base(contentNode, contentData, publishedSnapshotAccessor, variationContextAccessor)
+ private PublishedMember(
+ IMember member,
+ ContentNode contentNode,
+ ContentData contentData,
+ IPublishedSnapshotAccessor publishedSnapshotAccessor,
+ IVariationContextAccessor variationContextAccessor,
+ IUmbracoContextAccessor umbracoContextAccessor
+ )
+ : base(contentNode, contentData, publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor)
{
_member = member;
}
- public static IPublishedContent Create(IMember member, PublishedContentType contentType, bool previewing, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor)
+ public static IPublishedContent Create(
+ IMember member,
+ PublishedContentType contentType,
+ bool previewing,
+ IPublishedSnapshotAccessor publishedSnapshotAccessor,
+ IVariationContextAccessor variationContextAccessor,
+ IUmbracoContextAccessor umbracoContextAccessor)
{
var d = new ContentData
{
@@ -37,7 +50,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
member.Level, member.Path, member.SortOrder,
member.ParentId,
member.CreateDate, member.CreatorId);
- return new PublishedMember(member, n, d, publishedSnapshotAccessor, variationContextAccessor).CreateModel();
+ return new PublishedMember(member, n, d, publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor).CreateModel();
}
private static Dictionary GetPropertyValues(PublishedContentType contentType, IMember member)
diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs
index e1cd1ec764..e23e84aabd 100755
--- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs
+++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs
@@ -32,6 +32,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
private readonly ServiceContext _serviceContext;
private readonly IPublishedContentTypeFactory _publishedContentTypeFactory;
+ private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IScopeProvider _scopeProvider;
private readonly IDataSource _dataSource;
private readonly ILogger _logger;
@@ -80,7 +81,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
public PublishedSnapshotService(Options options, IMainDom mainDom, IRuntimeState runtime,
ServiceContext serviceContext, IPublishedContentTypeFactory publishedContentTypeFactory, IdkMap idkMap,
IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor,
- ILogger logger, IScopeProvider scopeProvider,
+ IUmbracoContextAccessor umbracoContextAccessor, ILogger logger, IScopeProvider scopeProvider,
IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository,
IDefaultCultureAccessor defaultCultureAccessor,
IDataSource dataSource, IGlobalSettings globalSettings, ISiteDomainHelper siteDomainHelper,
@@ -92,6 +93,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
_serviceContext = serviceContext;
_publishedContentTypeFactory = publishedContentTypeFactory;
+ _umbracoContextAccessor = umbracoContextAccessor;
_dataSource = dataSource;
_logger = logger;
_scopeProvider = scopeProvider;
@@ -148,13 +150,13 @@ namespace Umbraco.Web.PublishedCache.NuCache
// stores are created with a db so they can write to it, but they do not read from it,
// stores need to be populated, happens in OnResolutionFrozen which uses _localDbExists to
// figure out whether it can read the databases or it should populate them from sql
- _contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger, _localContentDb);
- _mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger, _localMediaDb);
+ _contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, _umbracoContextAccessor, logger, _localContentDb);
+ _mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, _umbracoContextAccessor, logger, _localMediaDb);
}
else
{
- _contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger);
- _mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger);
+ _contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, _umbracoContextAccessor, logger);
+ _mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, _umbracoContextAccessor, logger);
}
_domainStore = new SnapDictionary();
@@ -1015,7 +1017,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
ContentCache = new ContentCache(previewDefault, contentSnap, snapshotCache, elementsCache, domainHelper, _globalSettings, _serviceContext.LocalizationService),
MediaCache = new MediaCache(previewDefault, mediaSnap, snapshotCache, elementsCache),
- MemberCache = new MemberCache(previewDefault, snapshotCache, _serviceContext.MemberService, memberTypeCache, PublishedSnapshotAccessor, VariationContextAccessor, _entitySerializer),
+ MemberCache = new MemberCache(previewDefault, snapshotCache, _serviceContext.MemberService, memberTypeCache, PublishedSnapshotAccessor, VariationContextAccessor, _umbracoContextAccessor, _entitySerializer),
DomainCache = domainCache,
SnapshotCache = snapshotCache,
ElementsCache = elementsCache
diff --git a/src/Umbraco.Web/PublishedCache/PublishedMember.cs b/src/Umbraco.Web/PublishedCache/PublishedMember.cs
index 906cc7a4ae..419c279d46 100644
--- a/src/Umbraco.Web/PublishedCache/PublishedMember.cs
+++ b/src/Umbraco.Web/PublishedCache/PublishedMember.cs
@@ -19,7 +19,11 @@ namespace Umbraco.Web.PublishedCache
private readonly IPublishedProperty[] _properties;
private readonly PublishedContentType _publishedMemberType;
- public PublishedMember(IMember member, PublishedContentType publishedMemberType)
+ public PublishedMember(
+ IMember member,
+ PublishedContentType publishedMemberType,
+ IUmbracoContextAccessor umbracoContextAccessor)
+ :base(umbracoContextAccessor)
{
_member = member ?? throw new ArgumentNullException(nameof(member));
_membershipUser = member;
diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs
index 4e206f73d7..74043a9519 100644
--- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs
+++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs
@@ -38,7 +38,9 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
IAppCache appCache,
PublishedContentTypeCache contentTypeCache,
XPathNavigator nav,
- bool fromExamine)
+ bool fromExamine,
+ IUmbracoContextAccessor umbracoContextAccessor)
+ :base(umbracoContextAccessor)
{
if (valueDictionary == null) throw new ArgumentNullException(nameof(valueDictionary));
if (getParent == null) throw new ArgumentNullException(nameof(getParent));
diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs
index d8c7c41ea1..6fd9f1da2b 100644
--- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs
+++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs
@@ -17,6 +17,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
private readonly IAppCache _appCache;
private readonly IGlobalSettings _globalSettings;
+ private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly RoutesCache _routesCache;
private readonly IDomainCache _domainCache;
private readonly DomainHelper _domainHelper;
@@ -33,6 +34,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
IAppCache appCache, // an IAppCache that should be at request-level
IGlobalSettings globalSettings,
ISiteDomainHelper siteDomainHelper,
+ IUmbracoContextAccessor umbracoContextAccessor,
PublishedContentTypeCache contentTypeCache, // a PublishedContentType cache
RoutesCache routesCache, // a RoutesCache
string previewToken) // a preview token string (or null if not previewing)
@@ -40,6 +42,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
_appCache = appCache;
_globalSettings = globalSettings;
+ _umbracoContextAccessor = umbracoContextAccessor;
_routesCache = routesCache; // may be null for unit-testing
_contentTypeCache = contentTypeCache;
_domainCache = domainCache;
@@ -315,13 +318,13 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
private IPublishedContent ConvertToDocument(XmlNode xmlNode, bool isPreviewing)
{
- return xmlNode == null ? null : XmlPublishedContent.Get(xmlNode, isPreviewing, _appCache, _contentTypeCache);
+ return xmlNode == null ? null : XmlPublishedContent.Get(xmlNode, isPreviewing, _appCache, _contentTypeCache,_umbracoContextAccessor);
}
private IEnumerable ConvertToDocuments(XmlNodeList xmlNodes, bool isPreviewing)
{
return xmlNodes.Cast()
- .Select(xmlNode => XmlPublishedContent.Get(xmlNode, isPreviewing, _appCache, _contentTypeCache));
+ .Select(xmlNode => XmlPublishedContent.Get(xmlNode, isPreviewing, _appCache, _contentTypeCache, _umbracoContextAccessor));
}
#endregion
diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs
index a3aad608d5..7f9a21d24b 100644
--- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs
+++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs
@@ -41,11 +41,14 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
private readonly XmlStore _xmlStore;
private readonly PublishedContentTypeCache _contentTypeCache;
private readonly IEntityXmlSerializer _entitySerializer;
+ private readonly IUmbracoContextAccessor _umbracoContextAccessor;
// must be specified by the ctor
private readonly IAppCache _appCache;
- public PublishedMediaCache(XmlStore xmlStore, IMediaService mediaService, IUserService userService, IAppCache appCache, PublishedContentTypeCache contentTypeCache, IEntityXmlSerializer entitySerializer)
+ public PublishedMediaCache(XmlStore xmlStore, IMediaService mediaService, IUserService userService,
+ IAppCache appCache, PublishedContentTypeCache contentTypeCache, IEntityXmlSerializer entitySerializer,
+ IUmbracoContextAccessor umbracoContextAccessor)
: base(false)
{
_mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService));
@@ -55,6 +58,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
_xmlStore = xmlStore;
_contentTypeCache = contentTypeCache;
_entitySerializer = entitySerializer;
+ _umbracoContextAccessor = umbracoContextAccessor;
}
///
@@ -666,7 +670,8 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
_appCache,
_contentTypeCache,
cacheValues.XPath, // though, outside of tests, that should be null
- cacheValues.FromExamine
+ cacheValues.FromExamine,
+ _umbracoContextAccessor
);
return content.CreateModel();
}
diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMemberCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMemberCache.cs
index 816eb3c545..db6d85fb2d 100644
--- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMemberCache.cs
+++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMemberCache.cs
@@ -16,13 +16,16 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
private readonly IAppCache _requestCache;
private readonly XmlStore _xmlStore;
private readonly PublishedContentTypeCache _contentTypeCache;
+ private readonly IUmbracoContextAccessor _umbracoContextAccessor;
- public PublishedMemberCache(XmlStore xmlStore, IAppCache requestCache, IMemberService memberService, PublishedContentTypeCache contentTypeCache)
+ public PublishedMemberCache(XmlStore xmlStore, IAppCache requestCache, IMemberService memberService,
+ PublishedContentTypeCache contentTypeCache, IUmbracoContextAccessor umbracoContextAccessor)
{
_requestCache = requestCache;
_memberService = memberService;
_xmlStore = xmlStore;
_contentTypeCache = contentTypeCache;
+ _umbracoContextAccessor = umbracoContextAccessor;
}
public IPublishedContent GetByProviderKey(object key)
@@ -39,7 +42,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
var result = _memberService.GetByProviderKey(key);
if (result == null) return null;
var type = _contentTypeCache.Get(PublishedItemType.Member, result.ContentTypeId);
- return new PublishedMember(result, type).CreateModel();
+ return new PublishedMember(result, type, _umbracoContextAccessor).CreateModel();
});
}
@@ -57,7 +60,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
var result = _memberService.GetById(memberId);
if (result == null) return null;
var type = _contentTypeCache.Get(PublishedItemType.Member, result.ContentTypeId);
- return new PublishedMember(result, type).CreateModel();
+ return new PublishedMember(result, type, _umbracoContextAccessor).CreateModel();
});
}
@@ -75,7 +78,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
var result = _memberService.GetByUsername(username);
if (result == null) return null;
var type = _contentTypeCache.Get(PublishedItemType.Member, result.ContentTypeId);
- return new PublishedMember(result, type).CreateModel();
+ return new PublishedMember(result, type, _umbracoContextAccessor).CreateModel();
});
}
@@ -93,14 +96,14 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
var result = _memberService.GetByEmail(email);
if (result == null) return null;
var type = _contentTypeCache.Get(PublishedItemType.Member, result.ContentTypeId);
- return new PublishedMember(result, type).CreateModel();
+ return new PublishedMember(result, type, _umbracoContextAccessor).CreateModel();
});
}
public IPublishedContent GetByMember(IMember member)
{
var type = _contentTypeCache.Get(PublishedItemType.Member, member.ContentTypeId);
- return new PublishedMember(member, type).CreateModel();
+ return new PublishedMember(member, type, _umbracoContextAccessor).CreateModel();
}
public XPathNavigator CreateNavigator()
diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshotService.cs
index c4ce05c9a9..d96bfd8a0a 100644
--- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshotService.cs
+++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshotService.cs
@@ -35,6 +35,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
private readonly IDefaultCultureAccessor _defaultCultureAccessor;
private readonly ISiteDomainHelper _siteDomainHelper;
private readonly IEntityXmlSerializer _entitySerializer;
+ private readonly IUmbracoContextAccessor _umbracoContextAccessor;
#region Constructors
@@ -44,6 +45,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
IScopeProvider scopeProvider,
IAppCache requestCache,
IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor,
+ IUmbracoContextAccessor umbracoContextAccessor,
IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository,
IDefaultCultureAccessor defaultCultureAccessor,
ILogger logger,
@@ -52,12 +54,14 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
IEntityXmlSerializer entitySerializer,
MainDom mainDom,
bool testing = false, bool enableRepositoryEvents = true)
- : this(serviceContext, publishedContentTypeFactory, scopeProvider, requestCache,
- publishedSnapshotAccessor, variationContextAccessor,
+ : this(serviceContext, publishedContentTypeFactory, scopeProvider, requestCache,
+ publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor,
documentRepository, mediaRepository, memberRepository,
defaultCultureAccessor,
logger, globalSettings, siteDomainHelper, entitySerializer, null, mainDom, testing, enableRepositoryEvents)
- { }
+ {
+ _umbracoContextAccessor = umbracoContextAccessor;
+ }
// used in some tests
internal PublishedSnapshotService(ServiceContext serviceContext,
@@ -65,6 +69,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
IScopeProvider scopeProvider,
IAppCache requestCache,
IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor,
+ IUmbracoContextAccessor umbracoContextAccessor,
IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository,
IDefaultCultureAccessor defaultCultureAccessor,
ILogger logger,
@@ -92,6 +97,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
_defaultCultureAccessor = defaultCultureAccessor;
_requestCache = requestCache;
+ _umbracoContextAccessor = umbracoContextAccessor;
_globalSettings = globalSettings;
_siteDomainHelper = siteDomainHelper;
_entitySerializer = entitySerializer;
@@ -138,9 +144,9 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
var domainCache = new DomainCache(_domainService, _defaultCultureAccessor);
return new PublishedSnapshot(
- new PublishedContentCache(_xmlStore, domainCache, _requestCache, _globalSettings, _siteDomainHelper, _contentTypeCache, _routesCache, previewToken),
- new PublishedMediaCache(_xmlStore, _mediaService, _userService, _requestCache, _contentTypeCache, _entitySerializer),
- new PublishedMemberCache(_xmlStore, _requestCache, _memberService, _contentTypeCache),
+ new PublishedContentCache(_xmlStore, domainCache, _requestCache, _globalSettings, _siteDomainHelper,_umbracoContextAccessor, _contentTypeCache, _routesCache, previewToken),
+ new PublishedMediaCache(_xmlStore, _mediaService, _userService, _requestCache, _contentTypeCache, _entitySerializer, _umbracoContextAccessor),
+ new PublishedMemberCache(_xmlStore, _requestCache, _memberService, _contentTypeCache, _umbracoContextAccessor),
domainCache);
}
diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs
index b1037759dc..9a4c1f239c 100644
--- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs
+++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs
@@ -20,21 +20,29 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
[XmlType(Namespace = "http://umbraco.org/webservices/")]
internal class XmlPublishedContent : PublishedContentBase
{
- private XmlPublishedContent(XmlNode xmlNode, bool isPreviewing, IAppCache appCache, PublishedContentTypeCache contentTypeCache)
+ private XmlPublishedContent(
+ XmlNode xmlNode,
+ bool isPreviewing,
+ IAppCache appCache,
+ PublishedContentTypeCache contentTypeCache,
+ IUmbracoContextAccessor umbracoContextAccessor)
+ :base(umbracoContextAccessor)
{
_xmlNode = xmlNode;
_isPreviewing = isPreviewing;
_appCache = appCache;
_contentTypeCache = contentTypeCache;
+ _umbracoContextAccessor = umbracoContextAccessor;
}
private readonly XmlNode _xmlNode;
private readonly bool _isPreviewing;
private readonly IAppCache _appCache; // at snapshot/request level (see PublishedContentCache)
private readonly PublishedContentTypeCache _contentTypeCache;
+ private readonly IUmbracoContextAccessor _umbracoContextAccessor;
- private readonly object _initializeLock = new object();
+ private readonly object _initializeLock = new object();
private bool _nodeInitialized;
private bool _parentInitialized;
@@ -63,7 +71,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
private int _sortOrder;
private int _level;
private bool _isDraft;
- private bool _isPublished;
+
public override IEnumerable Children
{
@@ -232,7 +240,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
public override bool IsPublished(string culture = null)
{
EnsureNodeInitialized();
- return _isPublished;
+ return true; // Intentionally not implemented, because the XmlPublishedContent should not support this.
}
public override IEnumerable Properties
@@ -259,7 +267,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
if (parent == null) return;
if (parent.Attributes?.GetNamedItem("isDoc") != null)
- _parent = Get(parent, _isPreviewing, _appCache, _contentTypeCache);
+ _parent = Get(parent, _isPreviewing, _appCache, _contentTypeCache, _umbracoContextAccessor);
_parentInitialized = true;
}
@@ -287,7 +295,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
InitializeNode(this, _xmlNode, _isPreviewing,
out _id, out _key, out _template, out _sortOrder, out _name, out _writerName,
out _urlName, out _creatorName, out _creatorId, out _writerId, out _docTypeAlias, out _docTypeId, out _path,
- out _createDate, out _updateDate, out _level, out _isDraft, out _isPublished, out _contentType, out _properties,
+ out _createDate, out _updateDate, out _level, out _isDraft, out _contentType, out _properties,
_contentTypeCache.Get);
_nodeInitialized = true;
@@ -297,7 +305,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
internal static void InitializeNode(XmlPublishedContent node, XmlNode xmlNode, bool isPreviewing,
out int id, out Guid key, out int template, out int sortOrder, out string name, out string writerName, out string urlName,
out string creatorName, out int creatorId, out int writerId, out string docTypeAlias, out int docTypeId, out string path,
- out DateTime createDate, out DateTime updateDate, out int level, out bool isDraft,out bool isPublished,
+ out DateTime createDate, out DateTime updateDate, out int level, out bool isDraft,
out PublishedContentType contentType, out Dictionary properties,
Func getPublishedContentType)
{
@@ -309,7 +317,6 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
name = writerName = urlName = creatorName = docTypeAlias = path = null;
createDate = updateDate = default(DateTime);
isDraft = false;
- isPublished = false;
contentType = null;
properties = null;
@@ -417,7 +424,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
var iterator = nav.Select(expr);
_children = iterator.Cast()
- .Select(n => Get(((IHasXmlNode) n).GetNode(), _isPreviewing, _appCache, _contentTypeCache))
+ .Select(n => Get(((IHasXmlNode) n).GetNode(), _isPreviewing, _appCache, _contentTypeCache, _umbracoContextAccessor))
.OrderBy(x => x.SortOrder)
.ToList();
@@ -431,11 +438,13 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
/// A value indicating whether we are previewing or not.
/// A cache.
/// A content type cache.
+ /// A umbraco context accessor
/// The IPublishedContent corresponding to the Xml cache node.
/// Maintains a per-request cache of IPublishedContent items in order to make
/// sure that we create only one instance of each for the duration of a request. The
/// returned IPublishedContent is a model, if models are enabled.
- public static IPublishedContent Get(XmlNode node, bool isPreviewing, IAppCache appCache, PublishedContentTypeCache contentTypeCache)
+ public static IPublishedContent Get(XmlNode node, bool isPreviewing, IAppCache appCache,
+ PublishedContentTypeCache contentTypeCache, IUmbracoContextAccessor umbracoContextAccessor)
{
// only 1 per request
@@ -443,7 +452,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
var id = attrs?.GetNamedItem("id").Value;
if (id.IsNullOrWhiteSpace()) throw new InvalidOperationException("Node has no ID attribute.");
var key = CacheKeyPrefix + id; // dont bother with preview, wont change during request in Xml cache
- return (IPublishedContent) appCache.Get(key, () => (new XmlPublishedContent(node, isPreviewing, appCache, contentTypeCache)).CreateModel());
+ return (IPublishedContent) appCache.Get(key, () => (new XmlPublishedContent(node, isPreviewing, appCache, contentTypeCache, umbracoContextAccessor)).CreateModel());
}
public static void ClearRequest()
diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs
index e1bf60f558..5d47d7b6a5 100644
--- a/src/Umbraco.Web/PublishedContentExtensions.cs
+++ b/src/Umbraco.Web/PublishedContentExtensions.cs
@@ -228,7 +228,7 @@ namespace Umbraco.Web
///
/// Culture is case-insensitive.
public static bool HasCulture(this IPublishedContent content, string culture)
- => content.Cultures.ContainsKey(culture);
+ => content.Cultures.ContainsKey(culture ?? string.Empty);
///
/// Filters a sequence of to return invariant items, and items that are published for the specified culture.
diff --git a/src/Umbraco.Web/RelatedLinksTypeConverter.cs b/src/Umbraco.Web/RelatedLinksTypeConverter.cs
deleted file mode 100644
index 647959b920..0000000000
--- a/src/Umbraco.Web/RelatedLinksTypeConverter.cs
+++ /dev/null
@@ -1,98 +0,0 @@
-using System;
-using System.ComponentModel;
-using System.Globalization;
-using System.Linq;
-
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-
-using Umbraco.Core;
-using Umbraco.Core.Logging;
-using Umbraco.Core.Composing;
-using Umbraco.Web.Models;
-
-namespace Umbraco.Web
-{
- public class RelatedLinksTypeConverter : TypeConverter
- {
- private readonly UmbracoHelper _umbracoHelper;
-
- public RelatedLinksTypeConverter(UmbracoHelper umbracoHelper)
- {
- _umbracoHelper = umbracoHelper;
- }
-
- public RelatedLinksTypeConverter()
- {
-
- }
-
- private static readonly Type[] ConvertableTypes = new[]
- {
- typeof(JArray)
- };
-
- public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
- {
- return ConvertableTypes.Any(x => TypeHelper.IsTypeAssignableFrom(x, destinationType))
- || base.CanConvertFrom(context, destinationType);
- }
-
- public override object ConvertTo(
- ITypeDescriptorContext context,
- CultureInfo culture,
- object value,
- Type destinationType)
- {
- var relatedLinks = value as RelatedLinks;
- if (relatedLinks == null)
- return null;
-
- if (TypeHelper.IsTypeAssignableFrom(destinationType))
- {
- // Conversion to JArray taken from old value converter
-
- var obj = JsonConvert.DeserializeObject(relatedLinks.PropertyData);
-
- var umbracoHelper = GetUmbracoHelper();
-
- //update the internal links if we have a context
- if (umbracoHelper != null)
- {
- foreach (var a in obj)
- {
- var type = a.Value("type");
- if (type.IsNullOrWhiteSpace() == false)
- {
- if (type == "internal")
- {
- var linkId = a.Value("link");
- var link = umbracoHelper.Url(linkId);
- a["link"] = link;
- }
- }
- }
- }
- return obj;
-
- }
-
- return base.ConvertTo(context, culture, value, destinationType);
- }
-
- private UmbracoHelper GetUmbracoHelper()
- {
- if (_umbracoHelper != null)
- return _umbracoHelper;
-
- if (UmbracoContext.Current == null)
- {
- Current.Logger.Warn("Cannot create an UmbracoHelper the UmbracoContext is null");
- return null;
- }
-
- //DO NOT assign to _umbracoHelper variable, this is a singleton class and we cannot assign this based on an UmbracoHelper which is request based
- return new UmbracoHelper(UmbracoContext.Current, Current.Services);
- }
- }
-}
diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs
index de30590e92..b8a7fee2f7 100644
--- a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs
+++ b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs
@@ -6,6 +6,7 @@ using Microsoft.AspNet.SignalR;
using Umbraco.Core;
using Umbraco.Core.Components;
using Umbraco.Core.Composing;
+using Umbraco.Core.Dashboards;
using Umbraco.Core.Dictionary;
using Umbraco.Core.Events;
using Umbraco.Core.Models.PublishedContent;
@@ -17,6 +18,7 @@ using Umbraco.Web.Actions;
using Umbraco.Web.Cache;
using Umbraco.Web.Composing.Composers;
using Umbraco.Web.ContentApps;
+using Umbraco.Web.Dashboards;
using Umbraco.Web.Dictionary;
using Umbraco.Web.Editors;
using Umbraco.Web.Features;
@@ -95,14 +97,13 @@ namespace Umbraco.Web.Runtime
composition.RegisterUnique();
composition.RegisterUnique();
+ composition.RegisterUnique();
+
composition.RegisterUnique(factory => ExamineManager.Instance);
// configure the container for web
composition.ConfigureForWeb();
-
- composition.RegisterUnique