From fbf60fbac47eb0fe19074bab6e96c87330f6f220 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Mon, 22 Oct 2018 09:39:22 +0200 Subject: [PATCH 1/6] Don't add the "Notification" tree menu item if Umbraco can't send emails --- src/Umbraco.Web/Trees/ContentTreeController.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web/Trees/ContentTreeController.cs b/src/Umbraco.Web/Trees/ContentTreeController.cs index 293cc3d36a..54adb24b74 100644 --- a/src/Umbraco.Web/Trees/ContentTreeController.cs +++ b/src/Umbraco.Web/Trees/ContentTreeController.cs @@ -238,7 +238,10 @@ namespace Umbraco.Web.Trees menu.Items.Add(ui.Text("actions", ActionRights.Instance.Alias), true); menu.Items.Add(ui.Text("actions", ActionProtect.Instance.Alias), true).ConvertLegacyMenuItem(item, "content", "content"); - menu.Items.Add(ui.Text("actions", ActionNotify.Instance.Alias), true); + if (EmailSender.CanSendRequiredEmail) + { + menu.Items.Add(ui.Text("actions", ActionNotify.Instance.Alias), true); + } menu.Items.Add(ui.Text("actions", ActionSendToTranslate.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content"); menu.Items.Add(ui.Text("actions", ActionRefresh.Instance.Alias), true); From b08e9226001f59d144fca943c59c5486964569b0 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Wed, 7 Nov 2018 12:27:50 +0100 Subject: [PATCH 2/6] Only allow setting up scheduled publishing if the user has the correct permissions to do so --- .../components/content/umbcontentnodeinfo.directive.js | 3 +++ .../src/views/components/content/umb-content-node-info.html | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js index 8f613469a3..c753ac67d2 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js @@ -53,6 +53,9 @@ if (scope.documentType !== null) { scope.previewOpenUrl = '#/settings/documenttypes/edit/' + scope.documentType.id; } + + // only allow configuring scheduled publishing if the user has publish ("U") and unpublish ("Z") permissions on this node + scope.allowScheduledPublishing = _.contains(scope.node.allowedActions, "U") && _.contains(scope.node.allowedActions, "Z"); } scope.auditTrailPageChange = function (pageNumber) { diff --git a/src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html b/src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html index 7085babf59..0ed3986fe3 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html @@ -107,7 +107,7 @@
- + From 05f1a24caff54e2ae9b6ec3f5289b9eb95410df9 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 14 Jan 2019 08:28:58 +0100 Subject: [PATCH 3/6] Fix duplicate IIS Express settings --- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 81ca9c5a37..fc24d2b40f 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -1041,9 +1041,6 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\" 7140 / http://localhost:7140 - 7131 - / - http://localhost:7131 False False From db8954e0a5d532943e9885581ef154cb21872cc4 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Mon, 14 Jan 2019 08:52:02 +0100 Subject: [PATCH 4/6] Verify that the current member is approved and not locked out (#3588) --- .../Routing/PublishedContentRequestEngine.cs | 853 +++++++++--------- 1 file changed, 438 insertions(+), 415 deletions(-) diff --git a/src/Umbraco.Web/Routing/PublishedContentRequestEngine.cs b/src/Umbraco.Web/Routing/PublishedContentRequestEngine.cs index 217f407f02..0341c083f9 100644 --- a/src/Umbraco.Web/Routing/PublishedContentRequestEngine.cs +++ b/src/Umbraco.Web/Routing/PublishedContentRequestEngine.cs @@ -26,61 +26,61 @@ using RenderingEngine = Umbraco.Core.RenderingEngine; namespace Umbraco.Web.Routing { internal class PublishedContentRequestEngine - { - private readonly PublishedContentRequest _pcr; - private readonly RoutingContext _routingContext; - private readonly IWebRoutingSection _webRoutingSection; + { + private readonly PublishedContentRequest _pcr; + private readonly RoutingContext _routingContext; + private readonly IWebRoutingSection _webRoutingSection; - /// - /// Initializes a new instance of the class with a content request. - /// - /// - /// The content request. - public PublishedContentRequestEngine( + /// + /// Initializes a new instance of the class with a content request. + /// + /// + /// The content request. + public PublishedContentRequestEngine( IWebRoutingSection webRoutingSection, PublishedContentRequest pcr) - { - if (pcr == null) throw new ArgumentException("pcr is null."); - if (webRoutingSection == null) throw new ArgumentNullException("webRoutingSection"); - - _pcr = pcr; - _webRoutingSection = webRoutingSection; + { + if (pcr == null) throw new ArgumentException("pcr is null."); + if (webRoutingSection == null) throw new ArgumentNullException("webRoutingSection"); - _routingContext = pcr.RoutingContext; - if (_routingContext == null) throw new ArgumentException("pcr.RoutingContext is null."); - - var umbracoContext = _routingContext.UmbracoContext; - if (umbracoContext == null) throw new ArgumentException("pcr.RoutingContext.UmbracoContext is null."); - if (umbracoContext.RoutingContext != _routingContext) throw new ArgumentException("RoutingContext confusion."); - // no! not set yet. - //if (umbracoContext.PublishedContentRequest != _pcr) throw new ArgumentException("PublishedContentRequest confusion."); - } + _pcr = pcr; + _webRoutingSection = webRoutingSection; + + _routingContext = pcr.RoutingContext; + if (_routingContext == null) throw new ArgumentException("pcr.RoutingContext is null."); + + var umbracoContext = _routingContext.UmbracoContext; + if (umbracoContext == null) throw new ArgumentException("pcr.RoutingContext.UmbracoContext is null."); + if (umbracoContext.RoutingContext != _routingContext) throw new ArgumentException("RoutingContext confusion."); + // no! not set yet. + //if (umbracoContext.PublishedContentRequest != _pcr) throw new ArgumentException("PublishedContentRequest confusion."); + } protected ProfilingLogger ProfilingLogger - { + { get { return _routingContext.UmbracoContext.Application.ProfilingLogger; } - } + } - protected ServiceContext Services - { + protected ServiceContext Services + { get { return _routingContext.UmbracoContext.Application.Services; } - } + } - #region Public + #region Public /// /// Tries to route the request. /// - internal bool TryRouteRequest() - { + internal bool TryRouteRequest() + { // disabled - is it going to change the routing? //_pcr.OnPreparing(); FindDomain(); - if (_pcr.IsRedirect) return false; - if (_pcr.HasPublishedContent) return true; - FindPublishedContent(); + if (_pcr.IsRedirect) return false; + if (_pcr.HasPublishedContent) return true; + FindPublishedContent(); if (_pcr.IsRedirect) return false; // don't handle anything - we just want to ensure that we find the content @@ -93,51 +93,51 @@ namespace Umbraco.Web.Routing //_pcr.OnPrepared(); return _pcr.HasPublishedContent; - } + } - /// - /// Prepares the request. - /// - /// - /// Returns false if the request was not successfully prepared - /// - public bool PrepareRequest() - { - // note - at that point the original legacy module did something do handle IIS custom 404 errors - // ie pages looking like /anything.aspx?404;/path/to/document - I guess the reason was to support - // "directory urls" without having to do wildcard mapping to ASP.NET on old IIS. This is a pain - // to maintain and probably not used anymore - removed as of 06/2012. @zpqrtbnk. - // - // to trigger Umbraco's not-found, one should configure IIS and/or ASP.NET custom 404 errors - // so that they point to a non-existing page eg /redirect-404.aspx - // TODO: SD: We need more information on this for when we release 4.10.0 as I'm not sure what this means. + /// + /// Prepares the request. + /// + /// + /// Returns false if the request was not successfully prepared + /// + public bool PrepareRequest() + { + // note - at that point the original legacy module did something do handle IIS custom 404 errors + // ie pages looking like /anything.aspx?404;/path/to/document - I guess the reason was to support + // "directory urls" without having to do wildcard mapping to ASP.NET on old IIS. This is a pain + // to maintain and probably not used anymore - removed as of 06/2012. @zpqrtbnk. + // + // to trigger Umbraco's not-found, one should configure IIS and/or ASP.NET custom 404 errors + // so that they point to a non-existing page eg /redirect-404.aspx + // TODO: SD: We need more information on this for when we release 4.10.0 as I'm not sure what this means. // trigger the Preparing event - at that point anything can still be changed // the idea is that it is possible to change the uri // - _pcr.OnPreparing(); + _pcr.OnPreparing(); - //find domain - FindDomain(); + //find domain + FindDomain(); - // if request has been flagged to redirect then return - // whoever called us is in charge of actually redirecting - if (_pcr.IsRedirect) - { - return false; - } + // if request has been flagged to redirect then return + // whoever called us is in charge of actually redirecting + if (_pcr.IsRedirect) + { + return false; + } - // set the culture on the thread - once, so it's set when running document lookups - Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = _pcr.Culture; + // set the culture on the thread - once, so it's set when running document lookups + Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = _pcr.Culture; //find the published content if it's not assigned. This could be manually assigned with a custom route handler, or // with something like EnsurePublishedContentRequestAttribute or UmbracoVirtualNodeRouteHandler. Those in turn call this method // to setup the rest of the pipeline but we don't want to run the finders since there's one assigned. - if (_pcr.PublishedContent == null) - { + if (_pcr.PublishedContent == null) + { // find the document & template FindPublishedContentAndTemplate(); - } + } // handle wildcard domains HandleWildcardDomains(); @@ -145,19 +145,19 @@ namespace Umbraco.Web.Routing // set the culture on the thread -- again, 'cos it might have changed due to a finder or wildcard domain Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = _pcr.Culture; - // trigger the Prepared event - at that point it is still possible to change about anything + // trigger the Prepared event - at that point it is still possible to change about anything // even though the request might be flagged for redirection - we'll redirect _after_ the event // // also, OnPrepared() will make the PublishedContentRequest readonly, so nothing can change // - _pcr.OnPrepared(); + _pcr.OnPrepared(); // we don't take care of anything so if the content has changed, it's up to the user // to find out the appropriate template //complete the PCR and assign the remaining values - return ConfigureRequest(); - } + return ConfigureRequest(); + } /// /// Called by PrepareRequest once everything has been discovered, resolved and assigned to the PCR. This method @@ -210,73 +210,73 @@ namespace Umbraco.Web.Routing return true; } - /// - /// Updates the request when there is no template to render the content. - /// - /// This is called from Mvc when there's a document to render but no template. - public void UpdateRequestOnMissingTemplate() - { - // clear content - var content = _pcr.PublishedContent; - _pcr.PublishedContent = null; + /// + /// Updates the request when there is no template to render the content. + /// + /// This is called from Mvc when there's a document to render but no template. + public void UpdateRequestOnMissingTemplate() + { + // clear content + var content = _pcr.PublishedContent; + _pcr.PublishedContent = null; - HandlePublishedContent(); // will go 404 - FindTemplate(); + HandlePublishedContent(); // will go 404 + FindTemplate(); - // if request has been flagged to redirect then return - // whoever called us is in charge of redirecting - if (_pcr.IsRedirect) - return; + // if request has been flagged to redirect then return + // whoever called us is in charge of redirecting + if (_pcr.IsRedirect) + return; - if (_pcr.HasPublishedContent == false) - { - // means the engine could not find a proper document to handle 404 - // restore the saved content so we know it exists - _pcr.PublishedContent = content; - return; - } + if (_pcr.HasPublishedContent == false) + { + // means the engine could not find a proper document to handle 404 + // restore the saved content so we know it exists + _pcr.PublishedContent = content; + return; + } - if (_pcr.HasTemplate == false) - { - // means we may have a document, but we have no template - // at that point there isn't much we can do and there is no point returning - // to Mvc since Mvc can't do much either - return; - } + if (_pcr.HasTemplate == false) + { + // means we may have a document, but we have no template + // at that point there isn't much we can do and there is no point returning + // to Mvc since Mvc can't do much either + return; + } // see note in PrepareRequest() - // assign the legacy page back to the docrequest - // handlers like default.aspx will want it and most macros currently need it - _pcr.UmbracoPage = new page(_pcr); + // assign the legacy page back to the docrequest + // handlers like default.aspx will want it and most macros currently need it + _pcr.UmbracoPage = new page(_pcr); - // these two are used by many legacy objects - _routingContext.UmbracoContext.HttpContext.Items["pageID"] = _pcr.PublishedContent.Id; - _routingContext.UmbracoContext.HttpContext.Items["pageElements"] = _pcr.UmbracoPage.Elements; - } + // these two are used by many legacy objects + _routingContext.UmbracoContext.HttpContext.Items["pageID"] = _pcr.PublishedContent.Id; + _routingContext.UmbracoContext.HttpContext.Items["pageElements"] = _pcr.UmbracoPage.Elements; + } - #endregion + #endregion - #region Domain + #region Domain - /// - /// Finds the site root (if any) matching the http request, and updates the PublishedContentRequest accordingly. - /// - /// A value indicating whether a domain was found. - internal bool FindDomain() - { - const string tracePrefix = "FindDomain: "; + /// + /// Finds the site root (if any) matching the http request, and updates the PublishedContentRequest accordingly. + /// + /// A value indicating whether a domain was found. + internal bool FindDomain() + { + const string tracePrefix = "FindDomain: "; - // note - we are not handling schemes nor ports here. + // note - we are not handling schemes nor ports here. - ProfilingLogger.Logger.Debug("{0}Uri=\"{1}\"", () => tracePrefix, () => _pcr.Uri); + ProfilingLogger.Logger.Debug("{0}Uri=\"{1}\"", () => tracePrefix, () => _pcr.Uri); - // try to find a domain matching the current request + // try to find a domain matching the current request var domainAndUri = DomainHelper.DomainForUri(Services.DomainService.GetAll(false), _pcr.Uri); - // handle domain - if (domainAndUri != null && domainAndUri.UmbracoDomain.LanguageIsoCode.IsNullOrWhiteSpace() == false) - { + // handle domain + if (domainAndUri != null && domainAndUri.UmbracoDomain.LanguageIsoCode.IsNullOrWhiteSpace() == false) + { // matching an existing domain ProfilingLogger.Logger.Debug("{0}Matches domain=\"{1}\", rootId={2}, culture=\"{3}\"", () => tracePrefix, @@ -296,49 +296,49 @@ namespace Umbraco.Web.Routing // } } else - { - // not matching any existing domain - ProfilingLogger.Logger.Debug("{0}Matches no domain", () => tracePrefix); + { + // not matching any existing domain + ProfilingLogger.Logger.Debug("{0}Matches no domain", () => tracePrefix); var defaultLanguage = Services.LocalizationService.GetAllLanguages().FirstOrDefault(); - _pcr.Culture = defaultLanguage == null ? CultureInfo.CurrentUICulture : new CultureInfo(defaultLanguage.IsoCode); - } + _pcr.Culture = defaultLanguage == null ? CultureInfo.CurrentUICulture : new CultureInfo(defaultLanguage.IsoCode); + } - ProfilingLogger.Logger.Debug("{0}Culture=\"{1}\"", () => tracePrefix, () => _pcr.Culture.Name); + ProfilingLogger.Logger.Debug("{0}Culture=\"{1}\"", () => tracePrefix, () => _pcr.Culture.Name); - return _pcr.UmbracoDomain != null; - } + return _pcr.UmbracoDomain != null; + } - /// - /// Looks for wildcard domains in the path and updates Culture accordingly. - /// - internal void HandleWildcardDomains() - { - const string tracePrefix = "HandleWildcardDomains: "; + /// + /// Looks for wildcard domains in the path and updates Culture accordingly. + /// + internal void HandleWildcardDomains() + { + const string tracePrefix = "HandleWildcardDomains: "; - if (_pcr.HasPublishedContent == false) - return; + if (_pcr.HasPublishedContent == false) + return; - var nodePath = _pcr.PublishedContent.Path; - ProfilingLogger.Logger.Debug("{0}Path=\"{1}\"", () => tracePrefix, () => nodePath); + var nodePath = _pcr.PublishedContent.Path; + ProfilingLogger.Logger.Debug("{0}Path=\"{1}\"", () => tracePrefix, () => nodePath); var rootNodeId = _pcr.HasDomain ? _pcr.UmbracoDomain.RootContentId : (int?)null; var domain = DomainHelper.FindWildcardDomainInPath(Services.DomainService.GetAll(true), nodePath, rootNodeId); - if (domain != null && domain.LanguageIsoCode.IsNullOrWhiteSpace() == false) - { + if (domain != null && domain.LanguageIsoCode.IsNullOrWhiteSpace() == false) + { _pcr.Culture = new CultureInfo(domain.LanguageIsoCode); ProfilingLogger.Logger.Debug("{0}Got domain on node {1}, set culture to \"{2}\".", () => tracePrefix, () => domain.RootContentId, () => _pcr.Culture.Name); } - else - { - ProfilingLogger.Logger.Debug("{0}No match.", () => tracePrefix); - } - } + else + { + ProfilingLogger.Logger.Debug("{0}No match.", () => tracePrefix); + } + } - #endregion + #endregion - #region Rendering engine + #region Rendering engine /// /// Finds the rendering engine to use to render a template specified by its alias. @@ -383,264 +383,287 @@ namespace Umbraco.Web.Routing return directory.GetFiles().Any(f => extensions.Any(e => f.Name.InvariantEquals(alias + e))); } - #endregion + #endregion - #region Document and template + #region Document and template - /// - /// Finds the Umbraco document (if any) matching the request, and updates the PublishedContentRequest accordingly. - /// - /// A value indicating whether a document and template were found. - private void FindPublishedContentAndTemplate() - { - const string tracePrefix = "FindPublishedContentAndTemplate: "; - ProfilingLogger.Logger.Debug("{0}Path=\"{1}\"", () => tracePrefix, () => _pcr.Uri.AbsolutePath); + /// + /// Finds the Umbraco document (if any) matching the request, and updates the PublishedContentRequest accordingly. + /// + /// A value indicating whether a document and template were found. + private void FindPublishedContentAndTemplate() + { + const string tracePrefix = "FindPublishedContentAndTemplate: "; + ProfilingLogger.Logger.Debug("{0}Path=\"{1}\"", () => tracePrefix, () => _pcr.Uri.AbsolutePath); - // run the document finders - FindPublishedContent(); + // run the document finders + FindPublishedContent(); // if request has been flagged to redirect then return // whoever called us is in charge of actually redirecting // -- do not process anything any further -- if (_pcr.IsRedirect) - return; + return; - // not handling umbracoRedirect here but after LookupDocument2 - // so internal redirect, 404, etc has precedence over redirect + // not handling umbracoRedirect here but after LookupDocument2 + // so internal redirect, 404, etc has precedence over redirect - // handle not-found, redirects, access... - HandlePublishedContent(); + // handle not-found, redirects, access... + HandlePublishedContent(); - // find a template - FindTemplate(); + // find a template + FindTemplate(); - // handle umbracoRedirect - FollowExternalRedirect(); - } + // handle umbracoRedirect + FollowExternalRedirect(); + } - /// - /// Tries to find the document matching the request, by running the IPublishedContentFinder instances. - /// + /// + /// Tries to find the document matching the request, by running the IPublishedContentFinder instances. + /// /// There is no finder collection. - internal void FindPublishedContent() - { - const string tracePrefix = "FindPublishedContent: "; + internal void FindPublishedContent() + { + const string tracePrefix = "FindPublishedContent: "; - // look for the document - // the first successful finder, if any, will set this.PublishedContent, and may also set this.Template - // some finders may implement caching + // look for the document + // the first successful finder, if any, will set this.PublishedContent, and may also set this.Template + // some finders may implement caching using (ProfilingLogger.DebugDuration( - string.Format("{0}Begin finders", tracePrefix), - string.Format("{0}End finders, {1}", tracePrefix, (_pcr.HasPublishedContent ? "a document was found" : "no document was found")))) - { - if (_routingContext.PublishedContentFinders == null) + string.Format("{0}Begin finders", tracePrefix), + string.Format("{0}End finders, {1}", tracePrefix, (_pcr.HasPublishedContent ? "a document was found" : "no document was found")))) + { + if (_routingContext.PublishedContentFinders == null) throw new InvalidOperationException("There is no finder collection."); //iterate but return on first one that finds it - var found = _routingContext.PublishedContentFinders.Any(finder => finder.TryFindContent(_pcr)); - } + var found = _routingContext.PublishedContentFinders.Any(finder => finder.TryFindContent(_pcr)); + } - // indicate that the published content (if any) we have at the moment is the - // one that was found by the standard finders before anything else took place. - _pcr.SetIsInitialPublishedContent(); - } + // indicate that the published content (if any) we have at the moment is the + // one that was found by the standard finders before anything else took place. + _pcr.SetIsInitialPublishedContent(); + } - /// - /// Handles the published content (if any). - /// - /// - /// Handles "not found", internal redirects, access validation... - /// things that must be handled in one place because they can create loops - /// - private void HandlePublishedContent() - { - const string tracePrefix = "HandlePublishedContent: "; + /// + /// Handles the published content (if any). + /// + /// + /// Handles "not found", internal redirects, access validation... + /// things that must be handled in one place because they can create loops + /// + private void HandlePublishedContent() + { + const string tracePrefix = "HandlePublishedContent: "; - // because these might loop, we have to have some sort of infinite loop detection - int i = 0, j = 0; - const int maxLoop = 8; - do - { - ProfilingLogger.Logger.Debug("{0}{1}", () => tracePrefix, () => (i == 0 ? "Begin" : "Loop")); + // because these might loop, we have to have some sort of infinite loop detection + int i = 0, j = 0; + const int maxLoop = 8; + do + { + ProfilingLogger.Logger.Debug("{0}{1}", () => tracePrefix, () => (i == 0 ? "Begin" : "Loop")); - // handle not found - if (_pcr.HasPublishedContent == false) - { - _pcr.Is404 = true; - ProfilingLogger.Logger.Debug("{0}No document, try last chance lookup", () => tracePrefix); + // handle not found + if (_pcr.HasPublishedContent == false) + { + _pcr.Is404 = true; + ProfilingLogger.Logger.Debug("{0}No document, try last chance lookup", () => tracePrefix); - // if it fails then give up, there isn't much more that we can do - var lastChance = _routingContext.PublishedContentLastChanceFinder; - if (lastChance == null || lastChance.TryFindContent(_pcr) == false) - { - ProfilingLogger.Logger.Debug("{0}Failed to find a document, give up", () => tracePrefix); - break; - } + // if it fails then give up, there isn't much more that we can do + var lastChance = _routingContext.PublishedContentLastChanceFinder; + if (lastChance == null || lastChance.TryFindContent(_pcr) == false) + { + ProfilingLogger.Logger.Debug("{0}Failed to find a document, give up", () => tracePrefix); + break; + } - ProfilingLogger.Logger.Debug("{0}Found a document", () => tracePrefix); - } + ProfilingLogger.Logger.Debug("{0}Found a document", () => tracePrefix); + } - // follow internal redirects as long as it's not running out of control ie infinite loop of some sort - j = 0; - while (FollowInternalRedirects() && j++ < maxLoop) - { } - if (j == maxLoop) // we're running out of control - break; + // follow internal redirects as long as it's not running out of control ie infinite loop of some sort + j = 0; + while (FollowInternalRedirects() && j++ < maxLoop) + { } + if (j == maxLoop) // we're running out of control + break; - // ensure access - if (_pcr.HasPublishedContent) - EnsurePublishedContentAccess(); + // ensure access + if (_pcr.HasPublishedContent) + EnsurePublishedContentAccess(); - // loop while we don't have page, ie the redirect or access - // got us to nowhere and now we need to run the notFoundLookup again - // as long as it's not running out of control ie infinite loop of some sort + // loop while we don't have page, ie the redirect or access + // got us to nowhere and now we need to run the notFoundLookup again + // as long as it's not running out of control ie infinite loop of some sort - } while (_pcr.HasPublishedContent == false && i++ < maxLoop); + } while (_pcr.HasPublishedContent == false && i++ < maxLoop); - if (i == maxLoop || j == maxLoop) - { - ProfilingLogger.Logger.Debug("{0}Looks like we're running into an infinite loop, abort", () => tracePrefix); - _pcr.PublishedContent = null; - } + if (i == maxLoop || j == maxLoop) + { + ProfilingLogger.Logger.Debug("{0}Looks like we're running into an infinite loop, abort", () => tracePrefix); + _pcr.PublishedContent = null; + } - ProfilingLogger.Logger.Debug("{0}End", () => tracePrefix); - } + ProfilingLogger.Logger.Debug("{0}End", () => tracePrefix); + } - /// - /// Follows internal redirections through the umbracoInternalRedirectId document property. - /// - /// A value indicating whether redirection took place and led to a new published document. - /// - /// Redirecting to a different site root and/or culture will not pick the new site root nor the new culture. - /// As per legacy, if the redirect does not work, we just ignore it. - /// - private bool FollowInternalRedirects() - { - const string tracePrefix = "FollowInternalRedirects: "; + /// + /// Follows internal redirections through the umbracoInternalRedirectId document property. + /// + /// A value indicating whether redirection took place and led to a new published document. + /// + /// Redirecting to a different site root and/or culture will not pick the new site root nor the new culture. + /// As per legacy, if the redirect does not work, we just ignore it. + /// + private bool FollowInternalRedirects() + { + const string tracePrefix = "FollowInternalRedirects: "; + + if (_pcr.PublishedContent == null) + throw new InvalidOperationException("There is no PublishedContent."); - if (_pcr.PublishedContent == null) - throw new InvalidOperationException("There is no PublishedContent."); - // don't try to find a redirect if the property doesn't exist - if (_pcr.PublishedContent.HasProperty(Constants.Conventions.Content.InternalRedirectId) == false) - return false; + if (_pcr.PublishedContent.HasProperty(Constants.Conventions.Content.InternalRedirectId) == false) + return false; var redirect = false; - IPublishedContent internalRedirectNode = null; - var internalRedirectId = - _pcr.PublishedContent.GetPropertyValue(Constants.Conventions.Content.InternalRedirectId, -1); - var valueValid = false; - if (internalRedirectId > 0) - { - valueValid = true; - // Try and get the redirect node from a legacy integer ID - internalRedirectNode = _routingContext.UmbracoContext.ContentCache.GetById(internalRedirectId); - } - else - { - var udiInternalRedirectId = - _pcr.PublishedContent.GetPropertyValue(Constants.Conventions.Content.InternalRedirectId); + IPublishedContent internalRedirectNode = null; + var internalRedirectId = + _pcr.PublishedContent.GetPropertyValue(Constants.Conventions.Content.InternalRedirectId, -1); + var valueValid = false; + if (internalRedirectId > 0) + { + valueValid = true; + // Try and get the redirect node from a legacy integer ID + internalRedirectNode = _routingContext.UmbracoContext.ContentCache.GetById(internalRedirectId); + } + else + { + var udiInternalRedirectId = + _pcr.PublishedContent.GetPropertyValue(Constants.Conventions.Content.InternalRedirectId); if (udiInternalRedirectId != null) - { - valueValid = true; - // Try and get the redirect node from a UDI Guid - internalRedirectNode = - _routingContext.UmbracoContext.ContentCache.GetById(udiInternalRedirectId.Guid); - } - } + { + valueValid = true; + // Try and get the redirect node from a UDI Guid + internalRedirectNode = + _routingContext.UmbracoContext.ContentCache.GetById(udiInternalRedirectId.Guid); + } + } if (valueValid == false) - { + { // bad redirect - log and display the current page (legacy behavior) ProfilingLogger - .Logger.Debug( - "{0}Failed to redirect, value of '{1}' is not an int nor a GuidUdi", - () => tracePrefix, () => Constants.Conventions.Content.InternalRedirectId); - } + .Logger.Debug( + "{0}Failed to redirect, value of '{1}' is not an int nor a GuidUdi", + () => tracePrefix, () => Constants.Conventions.Content.InternalRedirectId); + } - if (internalRedirectNode == null) - { - ProfilingLogger.Logger.Debug( - "{0}Failed to redirect, value of '{1}' does not lead to a published document", () => tracePrefix, - () => Constants.Conventions.Content.InternalRedirectId); - } - else if (internalRedirectNode.Id == _pcr.PublishedContent.Id) - { - // redirect to self - ProfilingLogger.Logger.Debug("{0}Redirecting to self, ignore", - () => tracePrefix); - } - else - { - // Redirect to another page - _pcr.SetInternalRedirectPublishedContent(internalRedirectNode); - redirect = true; - ProfilingLogger.Logger.Debug("{0}Redirecting to id={1}", () => tracePrefix, - () => internalRedirectNode.Id); - } + if (internalRedirectNode == null) + { + ProfilingLogger.Logger.Debug( + "{0}Failed to redirect, value of '{1}' does not lead to a published document", () => tracePrefix, + () => Constants.Conventions.Content.InternalRedirectId); + } + else if (internalRedirectNode.Id == _pcr.PublishedContent.Id) + { + // redirect to self + ProfilingLogger.Logger.Debug("{0}Redirecting to self, ignore", + () => tracePrefix); + } + else + { + // Redirect to another page + _pcr.SetInternalRedirectPublishedContent(internalRedirectNode); + redirect = true; + ProfilingLogger.Logger.Debug("{0}Redirecting to id={1}", () => tracePrefix, + () => internalRedirectNode.Id); + } - return redirect; - } + return redirect; + } - /// - /// Ensures that access to current node is permitted. - /// - /// Redirecting to a different site root and/or culture will not pick the new site root nor the new culture. - private void EnsurePublishedContentAccess() - { - const string tracePrefix = "EnsurePublishedContentAccess: "; + /// + /// Ensures that access to current node is permitted. + /// + /// Redirecting to a different site root and/or culture will not pick the new site root nor the new culture. + private void EnsurePublishedContentAccess() + { + const string tracePrefix = "EnsurePublishedContentAccess: "; - if (_pcr.PublishedContent == null) - throw new InvalidOperationException("There is no PublishedContent."); + if (_pcr.PublishedContent == null) + throw new InvalidOperationException("There is no PublishedContent."); - var path = _pcr.PublishedContent.Path; + var path = _pcr.PublishedContent.Path; - var publicAccessAttempt = Services.PublicAccessService.IsProtected(path); + var publicAccessAttempt = Services.PublicAccessService.IsProtected(path); if (publicAccessAttempt) - { - ProfilingLogger.Logger.Debug("{0}Page is protected, check for access", () => tracePrefix); + { + ProfilingLogger.Logger.Debug("{0}Page is protected, check for access", () => tracePrefix); - var membershipHelper = new MembershipHelper(_routingContext.UmbracoContext); + var membershipHelper = new MembershipHelper(_routingContext.UmbracoContext); - if (membershipHelper.IsLoggedIn() == false) - { - ProfilingLogger.Logger.Debug("{0}Not logged in, redirect to login page", () => tracePrefix); + if (membershipHelper.IsLoggedIn() == false) + { + ProfilingLogger.Logger.Debug("{0}Not logged in, redirect to login page", () => tracePrefix); var loginPageId = publicAccessAttempt.Result.LoginNodeId; - if (loginPageId != _pcr.PublishedContent.Id) + if (loginPageId != _pcr.PublishedContent.Id) _pcr.PublishedContent = _routingContext.UmbracoContext.ContentCache.GetById(loginPageId); - } + } else if (Services.PublicAccessService.HasAccess(_pcr.PublishedContent.Id, Services.ContentService, _pcr.GetRolesForLogin(membershipHelper.CurrentUserName)) == false) - { - ProfilingLogger.Logger.Debug("{0}Current member has not access, redirect to error page", () => tracePrefix); - var errorPageId = publicAccessAttempt.Result.NoAccessNodeId; - if (errorPageId != _pcr.PublishedContent.Id) + { + ProfilingLogger.Logger.Debug("{0}Current member has not access, redirect to error page", () => tracePrefix); + var errorPageId = publicAccessAttempt.Result.NoAccessNodeId; + if (errorPageId != _pcr.PublishedContent.Id) _pcr.PublishedContent = _routingContext.UmbracoContext.ContentCache.GetById(errorPageId); - } - else - { - ProfilingLogger.Logger.Debug("{0}Current member has access", () => tracePrefix); - } - } - else - { - ProfilingLogger.Logger.Debug("{0}Page is not protected", () => tracePrefix); - } - } + } + else + { + // grab the current member + var member = membershipHelper.GetCurrentMember(); + // if the member has the "approved" and/or "locked out" properties, make sure they're correctly set before allowing access + var memberIsActive = true; + if (member != null) + { + if (member.HasProperty(Constants.Conventions.Member.IsApproved) == false) + memberIsActive = member.GetPropertyValue(Constants.Conventions.Member.IsApproved); - /// - /// Finds a template for the current node, if any. - /// - private void FindTemplate() - { - // NOTE: at the moment there is only 1 way to find a template, and then ppl must - // use the Prepared event to change the template if they wish. Should we also - // implement an ITemplateFinder logic? + if (member.HasProperty(Constants.Conventions.Member.IsLockedOut) == false) + memberIsActive = member.GetPropertyValue(Constants.Conventions.Member.IsLockedOut) == false; + } - const string tracePrefix = "FindTemplate: "; + if (memberIsActive == false) + { + ProfilingLogger.Logger.Debug("{0}Current member is either unapproved or locked out, redirect to error page", () => tracePrefix); + var errorPageId = publicAccessAttempt.Result.NoAccessNodeId; + if (errorPageId != _pcr.PublishedContent.Id) + _pcr.PublishedContent = _routingContext.UmbracoContext.ContentCache.GetById(errorPageId); + } + else + { + ProfilingLogger.Logger.Debug("{0}Current member has access", () => tracePrefix); + } + } + } + else + { + ProfilingLogger.Logger.Debug("{0}Page is not protected", () => tracePrefix); + } + } + + /// + /// Finds a template for the current node, if any. + /// + private void FindTemplate() + { + // NOTE: at the moment there is only 1 way to find a template, and then ppl must + // use the Prepared event to change the template if they wish. Should we also + // implement an ITemplateFinder logic? + + const string tracePrefix = "FindTemplate: "; if (_pcr.PublishedContent == null) { @@ -648,49 +671,49 @@ namespace Umbraco.Web.Routing return; } - // read the alternate template alias, from querystring, form, cookie or server vars, - // only if the published content is the initial once, else the alternate template - // does not apply + // read the alternate template alias, from querystring, form, cookie or server vars, + // only if the published content is the initial once, else the alternate template + // does not apply // + optionnally, apply the alternate template on internal redirects var useAltTemplate = _pcr.IsInitialPublishedContent || (_webRoutingSection.InternalRedirectPreservesTemplate && _pcr.IsInternalRedirectPublishedContent); string altTemplate = useAltTemplate ? _routingContext.UmbracoContext.HttpContext.Request[Constants.Conventions.Url.AltTemplate] - : null; + : null; - if (string.IsNullOrWhiteSpace(altTemplate)) - { - // we don't have an alternate template specified. use the current one if there's one already, - // which can happen if a content lookup also set the template (LookupByNiceUrlAndTemplate...), - // else lookup the template id on the document then lookup the template with that id. + if (string.IsNullOrWhiteSpace(altTemplate)) + { + // we don't have an alternate template specified. use the current one if there's one already, + // which can happen if a content lookup also set the template (LookupByNiceUrlAndTemplate...), + // else lookup the template id on the document then lookup the template with that id. - if (_pcr.HasTemplate) - { - ProfilingLogger.Logger.Debug("{0}Has a template already, and no alternate template.", () => tracePrefix); - return; - } + if (_pcr.HasTemplate) + { + ProfilingLogger.Logger.Debug("{0}Has a template already, and no alternate template.", () => tracePrefix); + return; + } - // TODO: When we remove the need for a database for templates, then this id should be irrelavent, - // not sure how were going to do this nicely. + // TODO: When we remove the need for a database for templates, then this id should be irrelavent, + // not sure how were going to do this nicely. - var templateId = _pcr.PublishedContent.TemplateId; + var templateId = _pcr.PublishedContent.TemplateId; // This code was moved to GetTemplateModel to allow the same functionality on a failed altTemplate (U4-8550) // The only change is a diffent logger prefix and null will be set to _pcr.TemplateModel if the templateId is <= 0 // rather than no set taking place _pcr.TemplateModel = GetTemplateModel(_pcr.PublishedContent.TemplateId); } - else - { - // we have an alternate template specified. lookup the template with that alias - // this means the we override any template that a content lookup might have set - // so /path/to/page/template1?altTemplate=template2 will use template2 + else + { + // we have an alternate template specified. lookup the template with that alias + // this means the we override any template that a content lookup might have set + // so /path/to/page/template1?altTemplate=template2 will use template2 - // ignore if the alias does not match - just trace + // ignore if the alias does not match - just trace - if (_pcr.HasTemplate) - ProfilingLogger.Logger.Debug("{0}Has a template already, but also an alternate template.", () => tracePrefix); - ProfilingLogger.Logger.Debug("{0}Look for alternate template alias=\"{1}\"", () => tracePrefix, () => altTemplate); + if (_pcr.HasTemplate) + ProfilingLogger.Logger.Debug("{0}Has a template already, but also an alternate template.", () => tracePrefix); + ProfilingLogger.Logger.Debug("{0}Look for alternate template alias=\"{1}\"", () => tracePrefix, () => altTemplate); if (_pcr.PublishedContent.IsAllowedTemplate(altTemplate)) { @@ -705,26 +728,26 @@ namespace Umbraco.Web.Routing LogHelper.Warn("{0}Configuration settings prevent template \"{1}\" from showing for node \"{2}\"", () => tracePrefix, () => altTemplate, () => _pcr.PublishedContent.Id); _pcr.TemplateModel = GetTemplateModel(_pcr.PublishedContent.TemplateId); } - } + } - if (_pcr.HasTemplate == false) - { - ProfilingLogger.Logger.Debug("{0}No template was found.", () => tracePrefix); + if (_pcr.HasTemplate == false) + { + ProfilingLogger.Logger.Debug("{0}No template was found.", () => tracePrefix); - // initial idea was: if we're not already 404 and UmbracoSettings.HandleMissingTemplateAs404 is true - // then reset _pcr.Document to null to force a 404. - // - // but: because we want to let MVC hijack routes even though no template is defined, we decide that - // a missing template is OK but the request will then be forwarded to MVC, which will need to take - // care of everything. - // - // so, don't set _pcr.Document to null here - } - else - { - ProfilingLogger.Logger.Debug("{0}Running with template id={1} alias=\"{2}\"", () => tracePrefix, () => _pcr.TemplateModel.Id, () => _pcr.TemplateModel.Alias); - } - } + // initial idea was: if we're not already 404 and UmbracoSettings.HandleMissingTemplateAs404 is true + // then reset _pcr.Document to null to force a 404. + // + // but: because we want to let MVC hijack routes even though no template is defined, we decide that + // a missing template is OK but the request will then be forwarded to MVC, which will need to take + // care of everything. + // + // so, don't set _pcr.Document to null here + } + else + { + ProfilingLogger.Logger.Debug("{0}Running with template id={1} alias=\"{2}\"", () => tracePrefix, () => _pcr.TemplateModel.Id, () => _pcr.TemplateModel.Alias); + } + } private ITemplate GetTemplateModel(int templateId) { @@ -751,32 +774,32 @@ namespace Umbraco.Web.Routing /// /// As per legacy, if the redirect does not work, we just ignore it. private void FollowExternalRedirect() - { - if (_pcr.HasPublishedContent == false) return; + { + if (_pcr.HasPublishedContent == false) return; - // don't try to find a redirect if the property doesn't exist + // don't try to find a redirect if the property doesn't exist if (_pcr.PublishedContent.HasProperty(Constants.Conventions.Content.Redirect) == false) - return; - - var redirectId = _pcr.PublishedContent.GetPropertyValue(Constants.Conventions.Content.Redirect, -1); + return; - var redirectUrl = "#"; - if (redirectId > 0) - { - redirectUrl = _routingContext.UrlProvider.GetUrl(redirectId); - } - else - { + var redirectId = _pcr.PublishedContent.GetPropertyValue(Constants.Conventions.Content.Redirect, -1); + + var redirectUrl = "#"; + if (redirectId > 0) + { + redirectUrl = _routingContext.UrlProvider.GetUrl(redirectId); + } + else + { // might be a UDI instead of an int Id - var redirectUdi = _pcr.PublishedContent.GetPropertyValue(Constants.Conventions.Content.Redirect); - if (redirectUdi != null) - redirectUrl = _routingContext.UrlProvider.GetUrl(redirectUdi.Guid); - } - if (redirectUrl != "#") - { - _pcr.SetRedirect(redirectUrl); - } - } - #endregion - } + var redirectUdi = _pcr.PublishedContent.GetPropertyValue(Constants.Conventions.Content.Redirect); + if (redirectUdi != null) + redirectUrl = _routingContext.UrlProvider.GetUrl(redirectUdi.Guid); + } + if (redirectUrl != "#") + { + _pcr.SetRedirect(redirectUrl); + } + } + #endregion + } } From b9430158cedb0bf5b1c0b93f543ec5383d8bec41 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Mon, 14 Jan 2019 09:25:59 +0100 Subject: [PATCH 5/6] Move member group picker property data store from NVarchar to NText (#3712) --- .../UpdateMemberGroupPickerData.cs | 36 +++++++++++++++++++ src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../MemberGroupPickerPropertyEditor.cs | 2 +- 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenFourteenZero/UpdateMemberGroupPickerData.cs diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenFourteenZero/UpdateMemberGroupPickerData.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenFourteenZero/UpdateMemberGroupPickerData.cs new file mode 100644 index 0000000000..2dbc69e58a --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenFourteenZero/UpdateMemberGroupPickerData.cs @@ -0,0 +1,36 @@ +using Umbraco.Core.Logging; +using Umbraco.Core.Persistence.SqlSyntax; + +namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFourteenZero +{ + /// + /// Migrates member group picker properties from NVarchar to NText. See https://github.com/umbraco/Umbraco-CMS/issues/3268. + /// + [Migration("7.14.0", 1, Constants.System.UmbracoMigrationName)] + public class UpdateMemberGroupPickerData : MigrationBase + { + public UpdateMemberGroupPickerData(ISqlSyntaxProvider sqlSyntax, ILogger logger) : base(sqlSyntax, logger) + { + } + + public override void Up() + { + // move the data for all member group properties from the NVarchar to the NText column and clear the NVarchar column + Execute.Sql(@"UPDATE cmsPropertyData SET dataNtext = dataNvarchar, dataNvarchar = NULL + WHERE dataNtext IS NULL AND id IN ( + SELECT id FROM cmsPropertyData WHERE propertyTypeId in ( + SELECT id from cmsPropertyType where dataTypeID IN ( + SELECT nodeId FROM cmsDataType WHERE propertyEditorAlias = 'Umbraco.MemberGroupPicker' + ) + ) + )"); + + // ensure that all exising member group properties are defined as NText + Execute.Sql("UPDATE cmsDataType SET dbType = 'Ntext' WHERE propertyEditorAlias = 'Umbraco.MemberGroupPicker'"); + } + + public override void Down() + { + } + } +} diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index c7393e524f..8ee29e777f 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -572,6 +572,7 @@ + diff --git a/src/Umbraco.Web/PropertyEditors/MemberGroupPickerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MemberGroupPickerPropertyEditor.cs index 433199c536..6d7dd9e344 100644 --- a/src/Umbraco.Web/PropertyEditors/MemberGroupPickerPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MemberGroupPickerPropertyEditor.cs @@ -8,7 +8,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.MemberGroupPickerAlias, "Member Group Picker", "membergrouppicker", Group="People", Icon="icon-users")] + [PropertyEditor(Constants.PropertyEditors.MemberGroupPickerAlias, "Member Group Picker", PropertyEditorValueTypes.Text, "membergrouppicker", Group="People", Icon="icon-users")] public class MemberGroupPickerPropertyEditor : PropertyEditor { } From f7671ec9a7653082d432352a7801e5bedb621c5c Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Tue, 15 Jan 2019 08:39:43 +0100 Subject: [PATCH 6/6] Fixes #4071 - Error executing scheduled task - This instance has already started one or more requests. --- src/Umbraco.Web/Scheduling/ScheduledTasks.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web/Scheduling/ScheduledTasks.cs b/src/Umbraco.Web/Scheduling/ScheduledTasks.cs index 4278b82c34..7387bca000 100644 --- a/src/Umbraco.Web/Scheduling/ScheduledTasks.cs +++ b/src/Umbraco.Web/Scheduling/ScheduledTasks.cs @@ -63,10 +63,11 @@ namespace Umbraco.Web.Scheduling private async Task GetTaskByHttpAync(string url, CancellationToken token) { if (_httpClient == null) - _httpClient = new HttpClient(); - - if (Uri.TryCreate(_appContext.UmbracoApplicationUrl, UriKind.Absolute, out var baseUri)) - _httpClient.BaseAddress = baseUri; + { + _httpClient = Uri.TryCreate(_appContext.UmbracoApplicationUrl, UriKind.Absolute, out var baseUri) + ? new HttpClient { BaseAddress = baseUri } + : new HttpClient(); + } var request = new HttpRequestMessage(HttpMethod.Get, url);