Port 7.7 - WIP

This commit is contained in:
Stephan
2017-09-13 17:35:20 +02:00
parent e6de96cb90
commit 37171d96bc
25 changed files with 295 additions and 705 deletions

View File

@@ -0,0 +1,89 @@
using System;
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
namespace Umbraco.Core.Publishing
{
/// <summary>
/// Used to perform scheduled publishing/unpublishing
/// </summary>
internal class ScheduledPublisher
{
private readonly IContentService _contentService;
private readonly ILogger _logger;
public ScheduledPublisher(IContentService contentService, ILogger logger)
{
_contentService = contentService;
_logger = logger;
}
/// <summary>
/// Processes scheduled operations
/// </summary>
/// <returns>
/// Returns the number of items successfully completed
/// </returns>
public int CheckPendingAndProcess()
{
var counter = 0;
var contentForRelease = _contentService.GetContentForRelease().ToArray();
if (contentForRelease.Length > 0)
_logger.Debug<ScheduledPublisher>($"There's {contentForRelease.Length} item(s) of content to be published");
foreach (var d in contentForRelease)
{
try
{
d.ReleaseDate = null;
var result = _contentService.SaveAndPublishWithStatus(d, d.GetWriterProfile().Id);
_logger.Debug<ContentService>($"Result of publish attempt: {result.Result.StatusType}");
if (result.Success == false)
{
if (result.Exception != null)
{
_logger.Error<ScheduledPublisher>("Could not published the document (" + d.Id + ") based on it's scheduled release, status result: " + result.Result.StatusType, result.Exception);
}
else
{
_logger.Warn<ScheduledPublisher>("Could not published the document (" + d.Id + ") based on it's scheduled release. Status result: " + result.Result.StatusType);
}
}
else
{
counter++;
}
}
catch (Exception ee)
{
_logger.Error<ScheduledPublisher>($"Error publishing node {d.Id}", ee);
throw;
}
}
var contentForExpiration = _contentService.GetContentForExpiration().ToArray();
if (contentForExpiration.Length > 0)
_logger.Debug<ScheduledPublisher>($"There's {contentForExpiration.Length} item(s) of content to be unpublished");
foreach (var d in contentForExpiration)
{
try
{
d.ExpireDate = null;
var result = _contentService.UnPublish(d, d.GetWriterProfile().Id);
if (result)
{
counter++;
}
}
catch (Exception ee)
{
_logger.Error<ScheduledPublisher>($"Error unpublishing node {d.Id}", ee);
throw;
}
}
return counter;
}
}
}

View File

@@ -1264,6 +1264,7 @@
<Compile Include="PropertyEditors\ValueConverters\UploadPropertyConverter.cs" />
<Compile Include="PropertyEditors\ValueConverters\YesNoValueConverter.cs" />
<Compile Include="PropertyEditors\ValueValidatorAttribute.cs" />
<Compile Include="Publishing\ScheduledPublisher.cs" />
<Compile Include="ReadLock.cs" />
<Compile Include="RenderingEngine.cs" />
<Compile Include="RuntimeLevel.cs" />

View File

@@ -3,6 +3,7 @@ using Umbraco.Core.Cache;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors.ValueConverters;
using Umbraco.Core.Services;
using Umbraco.Web.PropertyEditors;
using Umbraco.Web.PropertyEditors.ValueConverters;
using Umbraco.Web.PublishedCache;
@@ -50,15 +51,13 @@ namespace Umbraco.Web.Cache
var dataTypeCache = CacheHelper.IsolatedRuntimeCache.GetCache<IDataTypeDefinition>();
//clears the prevalue cache
if (dataTypeCache)
foreach (var payload in payloads)
dataTypeCache.Result.ClearCacheByKeySearch(CacheKeys.DataTypePreValuesCacheKey + "_" + payload.Id);
foreach (var payload in payloads)
{
{
if (dataTypeCache)
dataTypeCache.Result.ClearCacheByKeySearch(CacheKeys.DataTypePreValuesCacheKey + "_" + payload.Id);
_idkMap.ClearCache(payload.Id);
#error also nested content see 7.7
NestedContentHelper.ClearCache(payload.Id); // fixme refactor nested content
}
// fixme - not sure I like these?

View File

@@ -9,7 +9,6 @@ using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.ModelBinding;
using AutoMapper;
using umbraco.BusinessLogic.Actions;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;

View File

@@ -1,6 +1,8 @@
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using Umbraco.Core.Services;
using AutoMapper;
using Umbraco.Core.Composing;
using Umbraco.Core.Services;
using Umbraco.Web.Models;
using Umbraco.Web.Models.ContentEditing;
@@ -8,7 +10,6 @@ using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi;
using Umbraco.Core.Security;
using Umbraco.Web.WebApi.Filters;
using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.Editors
@@ -66,7 +67,7 @@ namespace Umbraco.Web.Editors
public async Task<HttpResponseMessage> PostSetAvatar()
{
//borrow the logic from the user controller
return await UsersController.PostSetAvatarInternal(Request, Services.UserService, ApplicationContext.ApplicationCache.StaticCache, Security.GetUserId());
return await UsersController.PostSetAvatarInternal(Request, Services.UserService, Current.ApplicationCache.StaticCache, Security.GetUserId());
}
/// <summary>

View File

@@ -1,10 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Net;
using System.Text;
using System.Web.Http;
using AutoMapper;
using Umbraco.Core;
@@ -16,8 +13,6 @@ using System.Net.Http;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models;
using Constants = Umbraco.Core.Constants;
using Examine;
using System.Text.RegularExpressions;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using System.Web.Http.Controllers;
using Umbraco.Core.Xml;
@@ -36,7 +31,6 @@ namespace Umbraco.Web.Editors
[PluginController("UmbracoApi")]
public class EntityController : UmbracoAuthorizedJsonController
{
/// <summary>
/// Configures this controller with a custom action selector
/// </summary>
@@ -56,6 +50,12 @@ namespace Umbraco.Web.Editors
}
private readonly UmbracoTreeSearcher _treeSearcher = new UmbracoTreeSearcher();
private readonly SearchableTreeCollection _searchableTreeCollection;
public EntityController(SearchableTreeCollection searchableTreeCollection)
{
_searchableTreeCollection = searchableTreeCollection;
}
/// <summary>
/// Returns an Umbraco alias given a string
@@ -65,7 +65,7 @@ namespace Umbraco.Web.Editors
/// <returns></returns>
public dynamic GetSafeAlias(string value, bool camelCase = true)
{
var returnValue = (string.IsNullOrWhiteSpace(value)) ? string.Empty : value.ToSafeAlias(camelCase);
var returnValue = string.IsNullOrWhiteSpace(value) ? string.Empty : value.ToSafeAlias(camelCase);
dynamic returnObj = new System.Dynamic.ExpandoObject();
returnObj.alias = returnValue;
returnObj.original = value;
@@ -107,7 +107,7 @@ namespace Umbraco.Web.Editors
///
/// The reason a user is allowed to search individual entity types that they are not allowed to edit is because those search
/// methods might be used in things like pickers in the content editor.
/// </remarks>
/// </remarks>
[HttpGet]
public IDictionary<string, TreeSearchResult> SearchAll(string query)
{
@@ -115,17 +115,17 @@ namespace Umbraco.Web.Editors
if (string.IsNullOrEmpty(query))
return result;
var allowedSections = Security.CurrentUser.AllowedSections.ToArray();
var searchableTrees = SearchableTreeResolver.Current.GetSearchableTrees();
var searchableTrees = _searchableTreeCollection.AsReadOnlyDictionary();
foreach (var searchableTree in searchableTrees)
{
if (allowedSections.Contains(searchableTree.Value.AppAlias))
{
var tree = Services.ApplicationTreeService.GetByAlias(searchableTree.Key);
if (tree == null) continue; //shouldn't occur
#error why cannot we use a collectino?
var searchableTreeAttribute = searchableTree.Value.SearchableTree.GetType().GetCustomAttribute<SearchableTreeAttribute>(false);
var treeAttribute = tree.GetTreeAttribute();
@@ -140,7 +140,7 @@ namespace Umbraco.Web.Editors
JsFormatterMethod = searchableTreeAttribute == null ? "" : searchableTreeAttribute.MethodName
};
}
}
}
return result;
}
@@ -616,7 +616,7 @@ namespace Umbraco.Web.Editors
return _treeSearcher.ExamineSearch(Umbraco, query, entityType, 200, 0, out total, searchFrom);
}
private IEnumerable<EntityBasic> GetResultForChildren(int id, UmbracoEntityTypes entityType)

View File

@@ -1,40 +1,28 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using ClientDependency.Core.Config;
using Microsoft.Owin.Security;
using Newtonsoft.Json;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Composing;
using Umbraco.Web.Editors;
using Umbraco.Web.Models;
namespace Umbraco.Web
{
using Umbraco.Core.Configuration;
using Core.Configuration;
/// <summary>
/// HtmlHelper extensions for the back office
/// </summary>
public static class HtmlHelperBackOfficeExtensions
{
[Obsolete("Use the overload with all required parameters instead")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static IHtmlString BareMinimumServerVariablesScript(this HtmlHelper html, UrlHelper uri, string externalLoginsUrl)
{
return html.BareMinimumServerVariablesScript(uri, ApplicationContext.Current, externalLoginsUrl);
}
/// <summary>
/// Outputs a script tag containing the bare minimum (non secure) server vars for use with the angular app
/// </summary>
/// <param name="html"></param>
/// <param name="uri"></param>
/// <param name="appCtx"></param>
/// <param name="externalLoginsUrl">
/// The post url used to sign in with external logins - this can change depending on for what service the external login is service.
/// Example: normal back office login or authenticating upgrade login
@@ -44,9 +32,9 @@ namespace Umbraco.Web
/// These are the bare minimal server variables that are required for the application to start without being authenticated,
/// we will load the rest of the server vars after the user is authenticated.
/// </remarks>
public static IHtmlString BareMinimumServerVariablesScript(this HtmlHelper html, UrlHelper uri, ApplicationContext appCtx, string externalLoginsUrl)
public static IHtmlString BareMinimumServerVariablesScript(this HtmlHelper html, UrlHelper uri, string externalLoginsUrl)
{
var serverVars = new BackOfficeServerVariables(uri, appCtx, UmbracoConfig.For.UmbracoSettings());
var serverVars = new BackOfficeServerVariables(uri, Current.RuntimeState);
var minVars = serverVars.BareMinimumServerVariables();
var str = @"<script type=""text/javascript"">

View File

@@ -1,9 +1,6 @@
using System;
using System.Configuration;
using System.Linq;
using System.Linq;
using System.Web.Configuration;
using System.Xml.Linq;
using Umbraco.Core;
using Umbraco.Core.IO;
using Umbraco.Core.Security;
using Umbraco.Web.Install.Models;
@@ -16,26 +13,15 @@ namespace Umbraco.Web.Install.InstallSteps
PerformsAppRestart = true)]
internal class ConfigureMachineKey : InstallSetupStep<bool?>
{
private readonly ApplicationContext _appContext;
public ConfigureMachineKey(ApplicationContext appContext)
{
if (appContext == null) throw new ArgumentNullException("appContext");
_appContext = appContext;
}
public override string View
{
get { return HasMachineKey() == false ? base.View : ""; }
}
public override string View => HasMachineKey() == false ? base.View : "";
/// <summary>
/// Don't display the view or execute if a machine key already exists
/// </summary>
/// <returns></returns>
private bool HasMachineKey()
private static bool HasMachineKey()
{
var section = (MachineKeySection)WebConfigurationManager.GetSection("system.web/machineKey");
var section = (MachineKeySection) WebConfigurationManager.GetSection("system.web/machineKey");
return section.ElementInformation.Source != null;
}
@@ -49,7 +35,7 @@ namespace Umbraco.Web.Install.InstallSteps
if (model.HasValue && model.Value == false) return null;
//install the machine key
var fileName = IOHelper.MapPath(string.Format("{0}/web.config", SystemDirectories.Root));
var fileName = IOHelper.MapPath($"{SystemDirectories.Root}/web.config");
var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
var systemWeb = xml.Root.DescendantsAndSelf("system.web").Single();

View File

@@ -1,52 +1,44 @@
using System;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.Models
{
internal class DetachedPublishedProperty : IPublishedProperty
{
private readonly PublishedPropertyType _propertyType;
private readonly object _rawValue;
private readonly Lazy<object> _sourceValue;
private readonly object _sourceValue;
private readonly Lazy<object> _objectValue;
private readonly Lazy<object> _xpathValue;
private readonly bool _isPreview;
public DetachedPublishedProperty(PublishedPropertyType propertyType, object value)
: this(propertyType, value, false)
{
}
{ }
public DetachedPublishedProperty(PublishedPropertyType propertyType, object value, bool isPreview)
{
_propertyType = propertyType;
_isPreview = isPreview;
_rawValue = value;
_sourceValue = value;
_sourceValue = new Lazy<object>(() => _propertyType.ConvertDataToSource(_rawValue, _isPreview));
_objectValue = new Lazy<object>(() => _propertyType.ConvertSourceToObject(_sourceValue.Value, _isPreview));
_xpathValue = new Lazy<object>(() => _propertyType.ConvertSourceToXPath(_sourceValue.Value, _isPreview));
IPropertySet propertySet = null; // fixme!! nested content needs complete refactoring!
var interValue = new Lazy<object>(() => _propertyType.ConvertSourceToInter(propertySet, _sourceValue, _isPreview));
_objectValue = new Lazy<object>(() => _propertyType.ConvertInterToObject(propertySet, PropertyCacheLevel.None, interValue.Value, _isPreview));
_xpathValue = new Lazy<object>(() => _propertyType.ConvertInterToXPath(propertySet, PropertyCacheLevel.None, interValue.Value, _isPreview));
}
public string PropertyTypeAlias
{
get
{
return _propertyType.PropertyTypeAlias;
}
}
public string PropertyTypeAlias => _propertyType.PropertyTypeAlias;
public bool HasValue
{
get { return DataValue != null && DataValue.ToString().Trim().Length > 0; }
}
public bool HasValue => SourceValue != null && SourceValue.ToString().Trim().Length > 0;
public object DataValue { get { return _rawValue; } }
public object SourceValue => _sourceValue;
public object Value { get { return _objectValue.Value; } }
public object Value => _objectValue.Value;
public object XPathValue { get { return _xpathValue.Value; } }
public object XPathValue => _xpathValue.Value;
}
}

View File

@@ -6,6 +6,7 @@ using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Services;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web._Legacy.Actions;
namespace Umbraco.Web.Models.Mapping

View File

@@ -1,4 +1,4 @@
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Web.Models
{

View File

@@ -1,327 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Publishing;
using Umbraco.Core.Services;
using Umbraco.Core.Strings;
using Umbraco.Core.Sync;
using Umbraco.Web.Cache;
using Umbraco.Web.PublishedCache;
namespace Umbraco.Web.Routing
{
/// <summary>
/// Implements an Application Event Handler for managing redirect urls tracking.
/// </summary>
/// <remarks>
/// <para>when content is renamed or moved, we want to create a permanent 301 redirect from it's old url</para>
/// <para>not managing domains because we don't know how to do it - changing domains => must create a higher level strategy using rewriting rules probably</para>
/// <para>recycle bin = moving to and from does nothing: to = the node is gone, where would we redirect? from = same</para>
/// </remarks>
public class RedirectTrackingEventHandler : ApplicationEventHandler
{
private const string ContextKey1 = "Umbraco.Web.Routing.RedirectTrackingEventHandler.1";
private const string ContextKey2 = "Umbraco.Web.Routing.RedirectTrackingEventHandler.2";
private const string ContextKey3 = "Umbraco.Web.Routing.RedirectTrackingEventHandler.3";
/// <inheritdoc />
protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
if (UmbracoConfig.For.UmbracoSettings().WebRouting.DisableRedirectUrlTracking)
{
ContentFinderResolver.Current.RemoveType<ContentFinderByRedirectUrl>();
}
else
{
// if any of these dlls are loaded we don't want to run our finder
var dlls = new[]
{
"InfoCaster.Umbraco.UrlTracker",
"SEOChecker",
"Simple301",
"Terabyte.Umbraco.Modules.PermanentRedirect",
"CMUmbracoTools",
"PWUrlRedirect"
};
// assuming all assemblies have been loaded already
// check if any of them matches one of the above dlls
var found = AppDomain.CurrentDomain.GetAssemblies()
.Select(x => x.FullName.Split(',')[0])
.Any(x => dlls.Contains(x));
if (found)
ContentFinderResolver.Current.RemoveType<ContentFinderByRedirectUrl>();
}
}
/// <inheritdoc />
protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
// don't let the event handlers kick in if Redirect Tracking is turned off in the config
if (UmbracoConfig.For.UmbracoSettings().WebRouting.DisableRedirectUrlTracking) return;
// events are weird
// on 'published' we 'could' get the old or the new route depending on event handlers order
// so it is not reliable. getting the old route in 'publishing' to be sure and storing in http
// context. then for the same reason, we have to process these old items only when the cache
// is ready
// when moving, the moved node is also published, which is causing all sorts of troubles with
// descendants, so when moving, we lock events so that neither 'published' nor 'publishing'
// are processed more than once
//
// this is all verrrry weird but it seems to work
ContentService.Publishing += ContentService_Publishing;
ContentService.Published += ContentService_Published;
ContentService.Moving += ContentService_Moving;
ContentService.Moved += ContentService_Moved;
PageCacheRefresher.CacheUpdated += PageCacheRefresher_CacheUpdated;
// kill all redirects once a content is deleted
//ContentService.Deleted += ContentService_Deleted;
// BUT, doing it here would prevent content deletion due to FK
// so the rows are actually deleted by the ContentRepository (see GetDeleteClauses)
// rolled back items have to be published, so publishing will take care of that
}
/// <summary>
/// Tracks a documents URLs during publishing in the current request
/// </summary>
private static Dictionary<int, Tuple<Guid, string>> OldRoutes
{
get
{
var oldRoutes = RequestCache.GetCacheItem<Dictionary<int, Tuple<Guid, string>>>(
ContextKey3,
() => new Dictionary<int, Tuple<Guid, string>>());
return oldRoutes;
}
}
private static bool LockedEvents
{
get
{
return Moving && RequestCache.GetCacheItem(ContextKey2) != null;
}
set
{
if (Moving && value)
{
//this forces true into the cache
RequestCache.GetCacheItem(ContextKey2, () => true);
}
else
{
RequestCache.ClearCacheItem(ContextKey2);
}
}
}
private static bool Moving
{
get { return RequestCache.GetCacheItem(ContextKey1) != null; }
set
{
if (value)
{
//this forces true into the cache
RequestCache.GetCacheItem(ContextKey1, () => true);
}
else
{
RequestCache.ClearCacheItem(ContextKey1);
RequestCache.ClearCacheItem(ContextKey2);
}
}
}
/// <summary>
/// Before the items are published, we need to get it's current URL before it changes
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
private static void ContentService_Publishing(IPublishingStrategy sender, PublishEventArgs<IContent> args)
{
if (LockedEvents) return;
var contentCache = GetPublishedCache();
if (contentCache == null) return;
// prepare entities
var entities = PrepareEntities(args.PublishedEntities);
foreach (var entity in entities)
{
// for each entity, we want to save the 'old route' of any impacted entity.
//
// previously, we'd save the routes of all descendants - super safe but has an
// impact on perfs - assuming that the descendant routes will NOT change if the
// entity's segment does not change (else... outside of the scope of the simple,
// built -in, tracker) then we can compare the entity's old and new segments
// and avoid processing the descendants
var process = true;
if (Moving == false) // always process descendants when moving
{
// SD: in 7.5.0 we re-lookup the entity that is published, which gets its
// current state in the DB, which we use to get the 'old' segment. In the
// future this will certainly cause some problems, to fix this we'd need to
// change the IUrlSegmentProvider to support being able to determine if a
// segment is going to change for an entity. See notes in IUrlSegmentProvider.
var oldEntity = ApplicationContext.Current.Services.ContentService.GetById(entity.Id);
if (oldEntity == null) continue;
var oldSegment = oldEntity.GetUrlSegment();
var newSegment = entity.GetUrlSegment();
process = oldSegment != newSegment;
}
// skip if no segment change
if (process == false) continue;
// else save routes for all descendants
var entityContent = contentCache.GetById(entity.Id);
if (entityContent == null) continue;
foreach (var x in entityContent.DescendantsOrSelf())
{
var route = contentCache.GetRouteById(x.Id);
if (IsNotRoute(route)) continue;
var wk = UnwrapToKey(x);
if (wk == null) continue;
OldRoutes[x.Id] = Tuple.Create(wk.Key, route);
}
}
LockedEvents = true; // we only want to see the "first batch"
}
private static IEnumerable<IContent> PrepareEntities(IEnumerable<IContent> eventEntities)
{
// prepare entities
// - exclude entities without an identity (new entities)
// - exclude duplicates (in case publishing a parent and its children)
var entities = new List<IContent>();
foreach (var e in eventEntities.Where(x => x.HasIdentity).OrderBy(x => x.Level))
{
var pathIds = e.Path.Split(',').Select(int.Parse);
if (entities.Any(x => pathIds.Contains(x.Id))) continue;
entities.Add(e);
}
return entities;
}
private static IPublishedContentWithKey UnwrapToKey(IPublishedContent content)
{
if (content == null) return null;
var withKey = content as IPublishedContentWithKey;
if (withKey != null) return withKey;
var extended = content as PublishedContentExtended;
while (extended != null)
extended = (content = extended.Unwrap()) as PublishedContentExtended;
withKey = content as IPublishedContentWithKey;
return withKey;
}
/// <summary>
/// Executed when the cache updates, which means we can know what the new URL is for a given document
/// </summary>
/// <param name="sender"></param>
/// <param name="cacheRefresherEventArgs"></param>
private void PageCacheRefresher_CacheUpdated(PageCacheRefresher sender, CacheRefresherEventArgs cacheRefresherEventArgs)
{
// only on master / single, not on slaves!
if (IsSlaveServer) return;
// simply getting OldRoutes will register it in the request cache,
// so whatever we do with it, try/finally it to ensure it's cleared
try
{
foreach (var oldRoute in OldRoutes)
{
// assuming we cannot have 'CacheUpdated' for only part of the infos else we'd need
// to set a flag in 'Published' to indicate which entities have been refreshed ok
CreateRedirect(oldRoute.Key, oldRoute.Value.Item1, oldRoute.Value.Item2);
}
}
finally
{
OldRoutes.Clear();
RequestCache.ClearCacheItem(ContextKey3);
}
}
private static void ContentService_Published(IPublishingStrategy sender, PublishEventArgs<IContent> e)
{
// look note in CacheUpdated
// we might want to set a flag on the entities we are seeing here
}
private static void ContentService_Moving(IContentService sender, MoveEventArgs<IContent> e)
{
Moving = true;
}
private static void ContentService_Moved(IContentService sender, MoveEventArgs<IContent> e)
{
Moving = false;
LockedEvents = false;
}
private static void CreateRedirect(int contentId, Guid contentKey, string oldRoute)
{
var contentCache = GetPublishedCache();
if (contentCache == null) return;
var newRoute = contentCache.GetRouteById(contentId);
if (IsNotRoute(newRoute) || oldRoute == newRoute) return;
var redirectUrlService = ApplicationContext.Current.Services.RedirectUrlService;
redirectUrlService.Register(oldRoute, contentKey);
}
private static bool IsNotRoute(string route)
{
// null if content not found
return route == null;
}
// gets a value indicating whether server is 'slave'
private static bool IsSlaveServer
{
get
{
var serverRole = ApplicationContext.Current.GetCurrentServerRole();
return serverRole != ServerRole.Master && serverRole != ServerRole.Single;
}
}
/// <summary>
/// Gets the current request cache to persist the values between handlers
/// </summary>
private static ContextualPublishedContentCache GetPublishedCache()
{
return UmbracoContext.Current == null ? null : UmbracoContext.Current.ContentCache;
}
/// <summary>
/// Gets the current request cache to persist the values between handlers
/// </summary>
private static ICacheProvider RequestCache
{
get { return ApplicationContext.Current.ApplicationCache.RequestCache; }
}
}
}

View File

@@ -1,10 +1,8 @@
using System.Configuration;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.HealthChecks;
using Umbraco.Core.Logging;
using Umbraco.Core.Sync;
using Umbraco.Web.HealthCheck;
@@ -13,39 +11,48 @@ namespace Umbraco.Web.Scheduling
{
internal class HealthCheckNotifier : RecurringTaskBase
{
private readonly ApplicationContext _appContext;
private readonly IHealthCheckResolver _healthCheckResolver;
private readonly IRuntimeState _runtimeState;
private readonly HealthCheckCollection _healthChecks;
private readonly HealthCheckNotificationMethodCollection _notifications;
private readonly ILogger _logger;
private readonly ProfilingLogger _proflog;
public HealthCheckNotifier(IBackgroundTaskRunner<RecurringTaskBase> runner, int delayMilliseconds, int periodMilliseconds,
ApplicationContext appContext)
public HealthCheckNotifier(IBackgroundTaskRunner<RecurringTaskBase> runner, int delayMilliseconds, int periodMilliseconds,
HealthCheckCollection healthChecks, HealthCheckNotificationMethodCollection notifications,
IRuntimeState runtimeState,
ILogger logger, ProfilingLogger proflog)
: base(runner, delayMilliseconds, periodMilliseconds)
{
_appContext = appContext;
_healthCheckResolver = HealthCheckResolver.Current;
_healthChecks = healthChecks;
_notifications = notifications;
_runtimeState = runtimeState;
_logger = logger;
_proflog = proflog;
}
public override async Task<bool> PerformRunAsync(CancellationToken token)
{
if (_appContext == null) return true; // repeat...
if (_runtimeState.Level != RuntimeLevel.Run)
return true; // repeat...
switch (_appContext.GetCurrentServerRole())
switch (_runtimeState.ServerRole)
{
case ServerRole.Slave:
LogHelper.Debug<HealthCheckNotifier>("Does not run on slave servers.");
_logger.Debug<HealthCheckNotifier>("Does not run on slave servers.");
return true; // DO repeat, server role can change
case ServerRole.Unknown:
LogHelper.Debug<HealthCheckNotifier>("Does not run on servers with unknown role.");
_logger.Debug<HealthCheckNotifier>("Does not run on servers with unknown role.");
return true; // DO repeat, server role can change
}
// ensure we do not run if not main domain, but do NOT lock it
if (_appContext.MainDom.IsMainDom == false)
if (_runtimeState.IsMainDom == false)
{
LogHelper.Debug<HealthCheckNotifier>("Does not run if not MainDom.");
_logger.Debug<HealthCheckNotifier>("Does not run if not MainDom.");
return false; // do NOT repeat, going down
}
using (_appContext.ProfilingLogger.DebugDuration<KeepAlive>("Health checks executing", "Health checks complete"))
using (_proflog.DebugDuration<KeepAlive>("Health checks executing", "Health checks complete"))
{
var healthCheckConfig = UmbracoConfig.For.HealthCheck();
@@ -58,26 +65,20 @@ namespace Umbraco.Web.Scheduling
.Distinct()
.ToArray();
var checks = _healthCheckResolver.HealthChecks
var checks = _healthChecks
.Where(x => disabledCheckIds.Contains(x.Id) == false);
var results = new HealthCheckResults(checks);
results.LogResults();
// Send using registered notification methods
var registeredNotificationMethods = HealthCheckNotificationMethodResolver.Current.NotificationMethods;
foreach (var notificationMethod in registeredNotificationMethods)
{
await notificationMethod.SendAsync(results);
}
foreach (var notificationMethod in _notifications)
await notificationMethod.SendAsync(results, token);
}
return true; // repeat
}
public override bool IsAsync
{
get { return true; }
}
public override bool IsAsync => true;
}
}

View File

@@ -1,39 +1,27 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Hosting;
using umbraco;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Scoping;
using Umbraco.Core.Publishing;
using Umbraco.Core.Services;
using Umbraco.Core.Sync;
using Umbraco.Web.Routing;
using Umbraco.Web.Security;
namespace Umbraco.Web.Scheduling
{
internal class ScheduledPublishing : RecurringTaskBase
{
private readonly IRuntimeState _runtime;
private readonly IUserService _userService;
private readonly IScopeProvider _scopeProvider;
private readonly IContentService _contentService;
private readonly ILogger _logger;
private readonly ProfilingLogger _proflog;
public ScheduledPublishing(IBackgroundTaskRunner<RecurringTaskBase> runner, int delayMilliseconds, int periodMilliseconds,
IRuntimeState runtime, IUserService userService, IScopeProvider scopeProvider, ILogger logger, ProfilingLogger proflog)
IRuntimeState runtime, IContentService contentService, ILogger logger)
: base(runner, delayMilliseconds, periodMilliseconds)
{
_runtime = runtime;
_userService = userService;
_scopeProvider = scopeProvider;
_contentService = contentService;
_logger = logger;
_proflog = proflog;
}
public override async Task<bool> PerformRunAsync(CancellationToken token)
@@ -55,38 +43,19 @@ namespace Umbraco.Web.Scheduling
return false; // do NOT repeat, going down
}
UmbracoContext tempContext = null;
try
{
// DO not run publishing if content is re-loading
if (content.Instance.isInitializing == false)
if (_runtime.Level != RuntimeLevel.Run)
{
//TODO: We should remove this in v8, this is a backwards compat hack
// see notes in CacheRefresherEventHandler
// because notifications will not be sent if there is no UmbracoContext
// see NotificationServiceExtensions
var httpContext = new HttpContextWrapper(new HttpContext(new SimpleWorkerRequest("temp.aspx", "", new StringWriter())));
tempContext = UmbracoContext.EnsureContext(
httpContext,
_appContext,
new WebSecurity(httpContext, _appContext),
_settings,
UrlProviderResolver.Current.Providers,
true);
var publisher = new ScheduledPublisher(_appContext.Services.ContentService);
var publisher = new ScheduledPublisher(_contentService, _logger);
var count = publisher.CheckPendingAndProcess();
_logger.Warn<ScheduledPublishing>("No url for service (yet), skip.");
}
}
catch (Exception e)
{
_logger.Error<ScheduledPublishing>("Could not acquire application url", e);
}
finally
{
if (tempContext != null)
tempContext.Dispose(); // nulls the ThreadStatic context
_logger.Error<ScheduledPublishing>("Failed.", e);
}
return true; // repeat

View File

@@ -1,12 +1,15 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Threading;
using Umbraco.Core;
using Umbraco.Core.Components;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.HealthChecks;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
using Umbraco.Core.Scoping;
using Umbraco.Core.Services;
using Umbraco.Web.HealthCheck;
using Umbraco.Web.Routing;
namespace Umbraco.Web.Scheduling
@@ -22,35 +25,45 @@ namespace Umbraco.Web.Scheduling
internal sealed class SchedulerComponent : UmbracoComponentBase, IUmbracoCoreComponent
{
private IRuntimeState _runtime;
private IUserService _userService;
private IContentService _contentService;
private IAuditService _auditService;
private ILogger _logger;
private ProfilingLogger _proflog;
private IScopeProvider _scopeProvider;
private HealthCheckCollection _healthChecks;
private HealthCheckNotificationMethodCollection _notifications;
private BackgroundTaskRunner<IBackgroundTask> _keepAliveRunner;
private BackgroundTaskRunner<IBackgroundTask> _publishingRunner;
private BackgroundTaskRunner<IBackgroundTask> _tasksRunner;
private BackgroundTaskRunner<IBackgroundTask> _scrubberRunner;
private BackgroundTaskRunner<IBackgroundTask> _healthCheckRunner;
private bool _started;
private object _locker = new object();
private IBackgroundTask[] _tasks;
public void Initialize(IRuntimeState runtime, IUserService userService, IAuditService auditService, IScopeProvider scopeProvider, ILogger logger, ProfilingLogger proflog)
public void Initialize(IRuntimeState runtime,
IContentService contentService, IAuditService auditService,
HealthCheckCollection healthChecks, HealthCheckNotificationMethodCollection notifications,
IScopeProvider scopeProvider, ILogger logger, ProfilingLogger proflog)
{
_runtime = runtime;
_userService = userService;
_contentService = contentService;
_auditService = auditService;
_scopeProvider = scopeProvider;
_logger = logger;
_proflog = proflog;
_healthChecks = healthChecks;
_notifications = notifications;
// backgrounds runners are web aware, if the app domain dies, these tasks will wind down correctly
_keepAliveRunner = new BackgroundTaskRunner<IBackgroundTask>("KeepAlive", logger);
_publishingRunner = new BackgroundTaskRunner<IBackgroundTask>("ScheduledPublishing", logger);
_tasksRunner = new BackgroundTaskRunner<IBackgroundTask>("ScheduledTasks", logger);
_scrubberRunner = new BackgroundTaskRunner<IBackgroundTask>("LogScrubber", logger);
_healthCheckRunner = new BackgroundTaskRunner<IBackgroundTask>("HealthCheckNotifier", logger);
// we will start the whole process when a successful request is made
UmbracoModule.RouteAttempt += UmbracoModuleRouteAttempt;
@@ -62,12 +75,12 @@ namespace Umbraco.Web.Scheduling
{
case EnsureRoutableOutcome.IsRoutable:
case EnsureRoutableOutcome.NotDocumentRequest:
RegisterBackgroundTasks(e);
RegisterBackgroundTasks();
break;
}
}
private void RegisterBackgroundTasks(UmbracoRequestEventArgs e)
private void RegisterBackgroundTasks()
{
// remove handler, we're done
UmbracoModule.RouteAttempt -= UmbracoModuleRouteAttempt;
@@ -77,30 +90,78 @@ namespace Umbraco.Web.Scheduling
_logger.Debug<SchedulerComponent>(() => "Initializing the scheduler");
var settings = UmbracoConfig.For.UmbracoSettings();
var tasks = new List<IBackgroundTask>
{
new KeepAlive(_keepAliveRunner, 60000, 300000, _runtime, _logger, _proflog),
new ScheduledPublishing(_publishingRunner, 60000, 60000, _runtime, _userService, _scopeProvider, _logger, _proflog),
new ScheduledTasks(_tasksRunner, 60000, 60000, _runtime, settings, _logger, _proflog),
new LogScrubber(_scrubberRunner, 60000, LogScrubber.GetLogScrubbingInterval(settings, _logger), _runtime, _auditService, settings, _scopeProvider, _logger, _proflog)
};
var tasks = new List<IBackgroundTask>();
// ping/keepalive
// on all servers
_keepAliveRunner.TryAdd(tasks[0]);
tasks.Add(RegisterKeepAlive());
tasks.Add(RegisterScheduledPublishing());
tasks.Add(RegisterTaskRunner(settings));
tasks.Add(RegisterLogScrubber(settings));
// scheduled publishing/unpublishing
// install on all, will only run on non-slaves servers
_publishingRunner.TryAdd(tasks[1]);
_tasksRunner.TryAdd(tasks[2]);
// log scrubbing
// install on all, will only run on non-slaves servers
_scrubberRunner.TryAdd(tasks[3]);
var healthCheckConfig = UmbracoConfig.For.HealthCheck();
if (healthCheckConfig.NotificationSettings.Enabled)
tasks.Add(RegisterHealthCheckNotifier(healthCheckConfig, _healthChecks, _notifications, _logger, _proflog));
return tasks.ToArray();
});
}
private IBackgroundTask RegisterKeepAlive()
{
// ping/keepalive
// on all servers
var task = new KeepAlive(_keepAliveRunner, 60000, 300000, _runtime, _logger, _proflog);
_keepAliveRunner.TryAdd(task);
return task;
}
private IBackgroundTask RegisterScheduledPublishing()
{
// scheduled publishing/unpublishing
// install on all, will only run on non-slaves servers
var task = new ScheduledPublishing(_publishingRunner, 60000, 60000, _runtime, _contentService, _logger);
_publishingRunner.TryAdd(task);
return task;
}
private IBackgroundTask RegisterTaskRunner(IUmbracoSettingsSection settings)
{
var task = new ScheduledTasks(_tasksRunner, 60000, 60000, _runtime, settings, _logger, _proflog);
_tasksRunner.TryAdd(task);
return task;
}
private IBackgroundTask RegisterHealthCheckNotifier(IHealthChecks healthCheckConfig,
HealthCheckCollection healthChecks, HealthCheckNotificationMethodCollection notifications,
ILogger logger, ProfilingLogger proflog)
{
// If first run time not set, start with just small delay after application start
int delayInMilliseconds;
if (string.IsNullOrEmpty(healthCheckConfig.NotificationSettings.FirstRunTime))
{
delayInMilliseconds = 60000;
}
else
{
// Otherwise start at scheduled time
delayInMilliseconds = DateTime.Now.PeriodicMinutesFrom(healthCheckConfig.NotificationSettings.FirstRunTime) * 60 * 1000;
if (delayInMilliseconds < 60000)
{
delayInMilliseconds = 60000;
}
}
var periodInMilliseconds = healthCheckConfig.NotificationSettings.PeriodInHours * 60 * 60 * 1000;
var task = new HealthCheckNotifier(_healthCheckRunner, delayInMilliseconds, periodInMilliseconds, healthChecks, notifications, _runtime, logger, proflog);
return task;
}
private IBackgroundTask RegisterLogScrubber(IUmbracoSettingsSection settings)
{
// log scrubbing
// install on all, will only run on non-slaves servers
var task = new LogScrubber(_scrubberRunner, 60000, LogScrubber.GetLogScrubbingInterval(settings, _logger), _runtime, _auditService, settings, _scopeProvider, _logger, _proflog);
_scrubberRunner.TryAdd(task);
return task;
}
}
}

View File

@@ -7,7 +7,7 @@ using Umbraco.Web.Trees;
namespace Umbraco.Web.Search
{
internal class SearchableTreeCollection : BuilderCollectionBase<ISearchableTree>
public class SearchableTreeCollection : BuilderCollectionBase<ISearchableTree>
{
private readonly Dictionary<string, SearchableApplicationTree> _dictionary;

View File

@@ -1,51 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.ObjectResolution;
using Umbraco.Core.Services;
using Umbraco.Web.Editors;
using Umbraco.Web.Trees;
namespace Umbraco.Web.Search
{
/// <summary>
/// A resolver to return the collection of searchable trees
/// </summary>
/// <remarks>
/// This collection has a request scoped lifetime therefore any instance of ISearchableTree needs to support being a request scoped lifetime
/// </remarks>
public class SearchableTreeResolver : LazyManyObjectsResolverBase<SearchableTreeResolver, ISearchableTree>
{
private readonly IApplicationTreeService _treeService;
public SearchableTreeResolver(IServiceProvider serviceProvider, ILogger logger, IApplicationTreeService treeService, Func<IEnumerable<Type>> searchableTrees)
: base(serviceProvider, logger, searchableTrees, ObjectLifetimeScope.HttpRequest)
{
_treeService = treeService;
}
/// <summary>
/// Returns the a dictionary of tree alias with it's affiliated <see cref="ISearchableTree"/>
/// </summary>
public IReadOnlyDictionary<string, SearchableApplicationTree> GetSearchableTrees()
{
var appTrees = _treeService.GetAll().ToArray();
var collection = new SearchableTreeCollection();
var searchableTrees = Values.ToArray();
foreach (var searchableTree in searchableTrees)
{
var found = appTrees.FirstOrDefault(x => x.Alias == searchableTree.TreeAlias);
if (found != null)
{
collection.Add(new SearchableApplicationTree(found.ApplicationAlias, found.Alias, searchableTree));
}
}
return collection.AsReadOnlyDictionary();
}
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Security;
using System.Web;

View File

@@ -1,21 +1,13 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Net.Http.Formatting;
using System.Web.Http;
using umbraco;
using umbraco.businesslogic.Actions;
using umbraco.BusinessLogic.Actions;
using Umbraco.Core;
using Umbraco.Core.Services;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence;
using Umbraco.Web.Models.Trees;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi.Filters;
using Umbraco.Web._Legacy.Actions;
using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.Trees
@@ -75,22 +67,20 @@ namespace Umbraco.Web.Trees
return nodes;
}
else
{
var intId = id.TryConvertTo<int>();
//Get the content type
var ct = Services.ContentTypeService.GetContentType(intId.Result);
if (ct == null) return nodes;
var blueprintsForDocType = entities.Where(x => ct.Alias == ((UmbracoEntity) x).ContentTypeAlias);
nodes.AddRange(blueprintsForDocType
.Select(entity =>
{
var treeNode = CreateTreeNode(entity, Constants.ObjectTypes.DocumentBlueprintGuid, id, queryStrings, "icon-blueprint", false);
treeNode.Path = string.Format("-1,{0},{1}", ct.Id, entity.Id);
return treeNode;
}));
}
var intId = id.TryConvertTo<int>();
//Get the content type
var ct = Services.ContentTypeService.Get(intId.Result);
if (ct == null) return nodes;
var blueprintsForDocType = entities.Where(x => ct.Alias == ((UmbracoEntity) x).ContentTypeAlias);
nodes.AddRange(blueprintsForDocType
.Select(entity =>
{
var treeNode = CreateTreeNode(entity, Constants.ObjectTypes.DocumentBlueprintGuid, id, queryStrings, "icon-blueprint", false);
treeNode.Path = $"-1,{ct.Id},{entity.Id}";
return treeNode;
}));
return nodes;
}
@@ -109,16 +99,16 @@ namespace Umbraco.Web.Trees
//only refresh & create if it's a content type
if (cte != null)
{
var ct = Services.ContentTypeService.GetContentType(cte.Id);
var createItem = menu.Items.Add<ActionCreateBlueprintFromContent>(Services.TextService.Localize(string.Format("actions/{0}", ActionCreateBlueprintFromContent.Instance.Alias)));
var ct = Services.ContentTypeService.Get(cte.Id);
var createItem = menu.Items.Add<ActionCreateBlueprintFromContent>(Services.TextService.Localize($"actions/{ActionCreateBlueprintFromContent.Instance.Alias}"));
createItem.NavigateToRoute("/settings/contentBlueprints/edit/-1?create=true&doctype=" + ct.Alias);
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize($"actions/{ActionRefresh.Instance.Alias}"), true);
return menu;
}
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
menu.Items.Add<ActionDelete>(Services.TextService.Localize($"actions/{ActionDelete.Instance.Alias}"));
return menu;
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http.Formatting;
@@ -11,7 +12,6 @@ using Umbraco.Web.Composing;
using Umbraco.Web.Models.Trees;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi.Filters;
using umbraco.businesslogic.Actions;
using Umbraco.Web._Legacy.Actions;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Search;

View File

@@ -1,31 +0,0 @@
using System;
using Umbraco.Core;
using umbraco.cms.presentation.Trees;
using Umbraco.Core.Composing;
namespace Umbraco.Web.Trees
{
/// <summary>
/// This attribute is used purely to maintain some compatibility with legacy webform tree pickers
/// </summary>
/// <remarks>
/// This allows us to attribute new trees with their legacy counterparts and when a legacy tree is loaded this will indicate
/// on the new tree which legacy tree to load (it won't actually render using the new tree)
/// </remarks>
[AttributeUsage(AttributeTargets.Class)]
[Obsolete("Remove this in v8, it should no longer be necessary!")]
internal sealed class LegacyBaseTreeAttribute : Attribute
{
public Type BaseTreeType { get; private set; }
public LegacyBaseTreeAttribute(Type baseTreeType)
{
if (!TypeHelper.IsTypeAssignableFrom<BaseTree>(baseTreeType))
{
throw new InvalidOperationException("The type for baseTreeType must be assignable from " + typeof(BaseTree));
}
BaseTreeType = baseTreeType;
}
}
}

View File

@@ -16,7 +16,6 @@ namespace Umbraco.Web.Trees
[Tree(Constants.Applications.Developer, Constants.Trees.Packages, null, sortOrder: 0)]
[PluginController("UmbracoTrees")]
[CoreTree]
[LegacyBaseTree(typeof(loadPackager))]
public class PackagesTreeController : TreeController
{
/// <summary>

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Http.Formatting;

View File

@@ -1,5 +1,4 @@
using System.Net.Http.Formatting;
using umbraco;
using Umbraco.Web.Models.Trees;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi.Filters;
@@ -10,22 +9,9 @@ namespace Umbraco.Web.Trees
[UmbracoTreeAuthorize(Constants.Trees.Users)]
[Tree(Constants.Applications.Users, Constants.Trees.Users, null, sortOrder: 0)]
[PluginController("UmbracoTrees")]
[LegacyBaseTree(typeof(loadUsers))]
[CoreTree]
public class UserTreeController : TreeController
{
public UserTreeController()
{
}
public UserTreeController(UmbracoContext umbracoContext) : base(umbracoContext)
{
}
public UserTreeController(UmbracoContext umbracoContext, UmbracoHelper umbracoHelper) : base(umbracoContext, umbracoHelper)
{
}
/// <summary>
/// Helper method to create a root model for a tree
/// </summary>

View File

@@ -194,6 +194,8 @@
<Compile Include="HealthCheck\StatusResultType.cs" />
<Compile Include="HealthCheck\Checks\DataIntegrity\XmlDataIntegrityHealthCheck.cs" />
<Compile Include="Media\ImageUrlProviderCollection.cs" />
<Compile Include="Models\ContentEditing\AssignedContentPermissions.cs" />
<Compile Include="Models\ContentEditing\AssignedUserGroupPermissions.cs" />
<Compile Include="Models\ContentEditing\CodeFileDisplay.cs" />
<Compile Include="Models\ContentEditing\ContentRedirectUrl.cs" />
<Compile Include="Media\ImageUrlProviderCollectionBuilder.cs" />
@@ -203,8 +205,18 @@
<Compile Include="Editors\IEditorValidator.cs" />
<Compile Include="Editors\EditorModelEventManager.cs" />
<Compile Include="HtmlHelperBackOfficeExtensions.cs" />
<Compile Include="Models\ContentEditing\Permission.cs" />
<Compile Include="Models\ContentEditing\SnippetDisplay.cs" />
<Compile Include="Models\ContentEditing\TemplateDisplay.cs" />
<Compile Include="Models\ContentEditing\TreeSearchResult.cs" />
<Compile Include="Models\ContentEditing\UserDisplay.cs" />
<Compile Include="Models\ContentEditing\UserGroupBasic.cs" />
<Compile Include="Models\ContentEditing\UserGroupDisplay.cs" />
<Compile Include="Models\ContentEditing\UserGroupPermissionsSave.cs" />
<Compile Include="Models\ContentEditing\UserGroupSave.cs" />
<Compile Include="Models\ContentEditing\UserInvite.cs" />
<Compile Include="Models\ContentEditing\UserProfile.cs" />
<Compile Include="Models\ContentEditing\UserSave.cs" />
<Compile Include="Models\DetachedPublishedContent.cs" />
<Compile Include="Models\DetachedPublishedProperty.cs" />
<Compile Include="Models\Mapping\ActionButtonsResolver.cs" />
@@ -297,7 +309,6 @@
<Compile Include="Routing\ContentFinderCollectionBuilder.cs" />
<Compile Include="Routing\Domain.cs" />
<Compile Include="Routing\IContentLastChanceFinder.cs" />
<Compile Include="Routing\RedirectTrackingEventHandler.cs" />
<Compile Include="Routing\UrlProviderCollection.cs" />
<Compile Include="Routing\UrlProviderCollectionBuilder.cs" />
<Compile Include="Scheduling\HealthCheckNotifier.cs" />
@@ -305,7 +316,6 @@
<Compile Include="Search\SearchableTreeAttribute.cs" />
<Compile Include="Search\SearchableTreeCollection.cs" />
<Compile Include="Search\SearchableTreeCollectionBuilder.cs" />
<Compile Include="Search\SearchableTreeResolver.cs" />
<Compile Include="Search\UmbracoTreeSearcher.cs" />
<Compile Include="SignalR\IPreviewHub.cs" />
<Compile Include="SignalR\PreviewHub.cs" />
@@ -560,7 +570,6 @@
<Compile Include="Install\Controllers\InstallApiController.cs" />
<Compile Include="Install\Controllers\InstallController.cs" />
<Compile Include="Install\InstallAuthorizeAttribute.cs" />
<Compile Include="Models\ContentEditing\EntityTypeSearchResult.cs" />
<Compile Include="Models\ContentEditing\ListViewAwareContentItemDisplayBase.cs" />
<Compile Include="Models\ContentEditing\PropertyTypeValidation.cs" />
<Compile Include="Models\ImageCropData.cs" />
@@ -703,7 +712,6 @@
<Compile Include="Trees\DataTypeTreeController.cs" />
<Compile Include="Trees\FileSystemTreeController.cs" />
<Compile Include="Trees\LanguageTreeController.cs" />
<Compile Include="Trees\LegacyBaseTreeAttribute.cs" />
<Compile Include="Trees\MemberTreeController.cs" />
<Compile Include="Trees\MenuRenderingEventArgs.cs" />
<Compile Include="Models\Trees\CreateChildEntity.cs" />
@@ -717,18 +725,15 @@
<Compile Include="umbraco.presentation\umbraco\create.aspx.cs">
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="umbraco.presentation\umbraco\create\script.ascx.cs" />
<Compile Include="umbraco.presentation\umbraco\create\Language.ascx.cs">
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="umbraco.presentation\umbraco\create\PartialViewTasksBase.cs" />
<Compile Include="umbraco.presentation\umbraco\create\xslt.ascx.cs">
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="umbraco.presentation\umbraco\developer\Packages\Installer.aspx.cs">
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="umbraco.presentation\umbraco\dialogs\cruds.aspx.cs" />
<Compile Include="umbraco.presentation\umbraco\Trees\loadPackager.cs" />
<Compile Include="UmbracoComponentRenderer.cs" />
<Compile Include="Web References\org.umbraco.our\Reference.cs">
@@ -902,7 +907,6 @@
<Compile Include="UI\Bundles\JsUmbracoApplicationUI.cs" />
<Compile Include="UI\Bundles\JsUmbracoTree.cs" />
<Compile Include="UI\CdfLogger.cs" />
<Compile Include="umbraco.presentation\umbraco\controls\PasswordChanger.ascx.cs" />
<Compile Include="umbraco.presentation\umbraco\controls\Tree\TreeControl.ascx.cs">
<SubType>ASPXCodeBehind</SubType>
</Compile>
@@ -922,7 +926,6 @@
<Compile Include="umbraco.presentation\umbraco\dialogs\AssignDomain2.aspx.designer.cs">
<DependentUpon>AssignDomain2.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\users\EditUser.aspx.cs" />
<Compile Include="umbraco.presentation\umbraco\settings\stylesheet\editstylesheet.aspx.cs">
<SubType>ASPXCodeBehind</SubType>
</Compile>
@@ -1106,8 +1109,6 @@
<Compile Include="umbraco.presentation\umbraco\ping.aspx.cs">
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="umbraco.presentation\umbraco\create\PartialViewMacrosTasks.cs" />
<Compile Include="umbraco.presentation\umbraco\create\PartialViewTasks.cs" />
<Compile Include="umbraco.presentation\umbraco\developer\Macros\editMacro.aspx.cs">
<SubType>ASPXCodeBehind</SubType>
</Compile>
@@ -1126,7 +1127,6 @@
<Compile Include="umbraco.presentation\umbraco\masterpages\umbracoDialog.master.cs">
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="umbraco.presentation\umbraco\settings\editTemplate.aspx.cs" />
<Compile Include="umbraco.presentation\umbraco\settings\modals\ShowUmbracoTags.aspx.cs">
<SubType>ASPXCodeBehind</SubType>
</Compile>
@@ -1252,11 +1252,8 @@
<Compile Include="umbraco.presentation\umbraco\create\dictionaryTasks.cs" />
<Compile Include="umbraco.presentation\umbraco\create\macroTasks.cs" />
<Compile Include="umbraco.presentation\umbraco\create\MemberGroupTasks.cs" />
<Compile Include="umbraco.presentation\umbraco\create\ScriptTasks.cs" />
<Compile Include="umbraco.presentation\umbraco\create\stylesheetPropertyTasks.cs" />
<Compile Include="umbraco.presentation\umbraco\create\StylesheetTasks.cs" />
<Compile Include="umbraco.presentation\umbraco\create\templateTasks.cs" />
<Compile Include="umbraco.presentation\umbraco\create\userTasks.cs" />
<Compile Include="umbraco.presentation\umbraco\create\XsltTasks.cs" />
<Compile Include="umbraco.presentation\umbraco\dashboard\FeedProxy.aspx.cs">
<DependentUpon>FeedProxy.aspx</DependentUpon>
@@ -1345,12 +1342,6 @@
<Compile Include="umbraco.presentation\umbraco\developer\Macros\assemblyBrowser.aspx.designer.cs">
<DependentUpon>assemblyBrowser.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\developer\autoDoc.aspx.cs">
<DependentUpon>autoDoc.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\developer\autoDoc.aspx.designer.cs">
<DependentUpon>autoDoc.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\developer\Packages\editPackage.aspx.cs">
<DependentUpon>editPackage.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
@@ -1376,12 +1367,6 @@
<Compile Include="umbraco.presentation\umbraco\developer\Xslt\xsltInsertValueOf.aspx.designer.cs">
<DependentUpon>xsltInsertValueOf.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\dialogs\about.aspx.cs">
<DependentUpon>about.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\dialogs\about.aspx.designer.cs">
<DependentUpon>about.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\dialogs\exportDocumenttype.aspx.cs">
<DependentUpon>exportDocumenttype.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
@@ -1438,9 +1423,6 @@
<Compile Include="umbraco.presentation\umbraco\settings\editLanguage.aspx.designer.cs">
<DependentUpon>editLanguage.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\settings\scripts\editScript.aspx.cs">
<DependentUpon>editScript.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\Trees\ITreeService.cs">
<SubType>Code</SubType>
</Compile>
@@ -1497,29 +1479,6 @@
<DependentUpon>XmlTree.xsd</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\urlRewriter\UrlRewriterFormWriter.cs" />
<Compile Include="umbraco.presentation\umbraco\users\EditUserType.aspx.cs">
<DependentUpon>EditUserType.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\users\EditUserType.aspx.designer.cs">
<DependentUpon>EditUserType.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\users\NodePermissions.ascx.cs">
<DependentUpon>NodePermissions.ascx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\users\NodePermissions.ascx.designer.cs">
<DependentUpon>NodePermissions.ascx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\users\PermissionEditor.aspx.cs">
<DependentUpon>PermissionEditor.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\users\PermissionEditor.aspx.designer.cs">
<DependentUpon>PermissionEditor.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\users\PermissionsHandler.asmx.cs">
<DependentUpon>PermissionsHandler.asmx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\users\UserPermissions.cs" />
<Compile Include="umbraco.presentation\umbraco\users\UserTypeTasks.cs" />
<Compile Include="umbraco.presentation\umbraco\webservices\ajaxHelpers.cs" />
<Compile Include="umbraco.presentation\umbraco\webservices\CacheRefresher.asmx.cs">
<DependentUpon>CacheRefresher.asmx</DependentUpon>
@@ -1533,9 +1492,6 @@
<DependentUpon>codeEditorSave.asmx</DependentUpon>
<SubType>Component</SubType>
</Compile>
<Compile Include="umbraco.presentation\umbraco\webservices\Developer.asmx.cs">
<DependentUpon>Developer.asmx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\webservices\legacyAjaxCalls.asmx.cs">
<DependentUpon>legacyAjaxCalls.asmx</DependentUpon>
<SubType>Component</SubType>
@@ -1544,9 +1500,6 @@
<DependentUpon>nodeSorter.asmx</DependentUpon>
<SubType>Component</SubType>
</Compile>
<Compile Include="umbraco.presentation\umbraco\webservices\templates.asmx.cs">
<DependentUpon>templates.asmx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\Web\UI\ContentPage.cs">
<SubType>ASPXCodeBehind</SubType>
</Compile>
@@ -1595,32 +1548,22 @@
<EmbeddedResource Include="UI\JavaScript\Main.js" />
<EmbeddedResource Include="UI\JavaScript\JsInitialize.js" />
<EmbeddedResource Include="UI\JavaScript\ServerVariables.js" />
<EmbeddedResource Include="_Legacy\Packager\FileResources\PackageFiles.resx" />
</ItemGroup>
<ItemGroup>
<WebReferences Include="Web References\" />
</ItemGroup>
<ItemGroup>
<Content Include="umbraco.presentation\umbraco\users\NodePermissions.ascx">
<SubType>ASPXCodeBehind</SubType>
</Content>
<Content Include="umbraco.presentation\umbraco\users\PermissionEditor.aspx">
<SubType>ASPXCodeBehind</SubType>
</Content>
<Content Include="umbraco.presentation\umbraco\users\PermissionsHandler.asmx" />
<Content Include="umbraco.presentation\umbraco\webservices\CheckForUpgrade.asmx" />
<Content Include="umbraco.presentation\umbraco\settings\DictionaryItemList.aspx">
<SubType>ASPXCodeBehind</SubType>
</Content>
<Content Include="umbraco.presentation\umbraco\settings\scripts\editScript.aspx">
<SubType>ASPXCodeBehind</SubType>
</Content>
<Content Include="umbraco.presentation\umbraco\translation\default.aspx">
<SubType>ASPXCodeBehind</SubType>
</Content>
<Content Include="umbraco.presentation\umbraco\translation\preview.aspx" />
<Content Include="umbraco.presentation\umbraco\translation\xml.aspx" />
<Content Include="umbraco.presentation\umbraco\developer\Macros\assemblyBrowser.aspx" />
<Content Include="umbraco.presentation\umbraco\developer\autoDoc.aspx" />
<Content Include="umbraco.presentation\umbraco\developer\Xslt\getXsltStatus.asmx" />
<Content Include="umbraco.presentation\umbraco\developer\Xslt\xsltChooseExtension.aspx" />
<Content Include="umbraco.presentation\umbraco\developer\Xslt\xsltInsertValueOf.aspx" />
@@ -1628,18 +1571,13 @@
<SubType>ASPXCodeBehind</SubType>
</Content>
<Content Include="umbraco.presentation\umbraco\settings\editLanguage.aspx" />
<Content Include="umbraco.presentation\umbraco\users\EditUserType.aspx">
<SubType>ASPXCodeBehind</SubType>
</Content>
<!--<Content Include="umbraco.presentation\umbraco\users\PermissionEditor.aspx" />-->
<Content Include="umbraco.presentation\umbraco\webservices\CacheRefresher.asmx">
<SubType>Form</SubType>
</Content>
<Content Include="umbraco.presentation\umbraco\webservices\codeEditorSave.asmx" />
<Content Include="umbraco.presentation\umbraco\webservices\Developer.asmx" />
<Content Include="umbraco.presentation\umbraco\webservices\legacyAjaxCalls.asmx" />
<Content Include="umbraco.presentation\umbraco\webservices\nodeSorter.asmx" />
<Content Include="umbraco.presentation\umbraco\webservices\templates.asmx" />
<Content Include="PublishedCache\NuCache\notes.txt" />
<Content Include="umbraco.presentation\umbraco\controls\Tree\CustomTreeService.asmx" />
<Content Include="umbraco.presentation\umbraco\developer\RelationTypes\EditRelationType.aspx">
@@ -1680,9 +1618,6 @@
<Content Include="umbraco.presentation\umbraco\developer\Packages\editPackage.aspx">
<SubType>ASPXCodeBehind</SubType>
</Content>
<Content Include="umbraco.presentation\umbraco\dialogs\about.aspx">
<SubType>ASPXCodeBehind</SubType>
</Content>
<Content Include="umbraco.presentation\umbraco\dialogs\exportDocumenttype.aspx" />
<Content Include="umbraco.presentation\umbraco\dialogs\importDocumenttype.aspx" />
<Content Include="umbraco.presentation\umbraco\dialogs\notifications.aspx">