Makes the TourFilterResolver a real resolver

This commit is contained in:
Shannon
2018-01-11 18:00:42 +11:00
parent ce11a377e6
commit d7f2041ee9
6 changed files with 172 additions and 25 deletions

View File

@@ -394,7 +394,7 @@ namespace Umbraco.Core.ObjectResolution
/// WARNING! Do not use this unless you know what you are doing, clear all types registered and instances
/// created. Typically only used if a resolver is no longer used in an application and memory is to be GC'd
/// </summary>
internal void ResetCollections()
internal virtual void ResetCollections()
{
using (new WriteLock(_lock))
{

View File

@@ -23,15 +23,21 @@ namespace Umbraco.Web.Editors
if (UmbracoConfig.For.UmbracoSettings().BackOffice.Tours.EnableTours == false)
return result;
var filters = TourFilterResolver.Current.Filters.ToList();
//get all filters that will be applied to all tour aliases
var aliasOnlyFilters = filters.Where(x => x.PluginName == null && x.TourFileName == null).ToList();
//don't pass in any filters for core tours that have a plugin name assigned
var nonPluginFilters = filters.Where(x => x.PluginName == null).ToList();
//add core tour files
var coreToursPath = Path.Combine(IOHelper.MapPath(SystemDirectories.Config), "BackOfficeTours");
if (Directory.Exists(coreToursPath))
{
var coreTourFiles = Directory.GetFiles(coreToursPath, "*.json");
foreach (var tourFile in coreTourFiles)
foreach (var tourFile in Directory.EnumerateFiles(coreToursPath, "*.json"))
{
TryParseTourFile(tourFile, result);
TryParseTourFile(tourFile, result, nonPluginFilters, aliasOnlyFilters);
}
}
@@ -39,6 +45,14 @@ namespace Umbraco.Web.Editors
foreach (var plugin in Directory.EnumerateDirectories(IOHelper.MapPath(SystemDirectories.AppPlugins)))
{
var pluginName = Path.GetFileName(plugin.TrimEnd('\\'));
var pluginFilters = filters.Where(x => x.PluginName != null && x.PluginName.IsMatch(pluginName)).ToList();
//If there is any filter applied to match the plugin only (no file or tour alias) then ignore the plugin entirely
var isPluginFiltered = pluginFilters.Any(x => x.TourFileName == null && x.TourAlias == null);
if (isPluginFiltered) continue;
//combine matched package filters with filters not specific to a package
var combinedFilters = nonPluginFilters.Concat(pluginFilters).ToList();
foreach (var backofficeDir in Directory.EnumerateDirectories(plugin, "backoffice"))
{
@@ -46,7 +60,7 @@ namespace Umbraco.Web.Editors
{
foreach (var tourFile in Directory.EnumerateFiles(tourDir, "*.json"))
{
TryParseTourFile(tourFile, result, pluginName);
TryParseTourFile(tourFile, result, combinedFilters, aliasOnlyFilters, pluginName);
}
}
}
@@ -55,22 +69,44 @@ namespace Umbraco.Web.Editors
return result.OrderBy(x => x.FileName, StringComparer.InvariantCultureIgnoreCase);
}
private void TryParseTourFile(string tourFile, List<BackOfficeTourFile> result, string pluginName = null)
private void TryParseTourFile(string tourFile,
ICollection<BackOfficeTourFile> result,
List<BackOfficeTourFilter> filters,
List<BackOfficeTourFilter> aliasOnlyFilters,
string pluginName = null)
{
var fileName = Path.GetFileNameWithoutExtension(tourFile);
if (fileName == null) return;
//get the filters specific to this file
var fileFilters = filters.Where(x => x.TourFileName != null && x.TourFileName.IsMatch(fileName)).ToList();
//If there is any filter applied to match the file only (no tour alias) then ignore the file entirely
var isFileFiltered = fileFilters.Any(x => x.TourAlias == null);
if (isFileFiltered) return;
//now combine all aliases to filter below
var aliasFilters = aliasOnlyFilters.Concat(filters.Where(x => x.TourAlias != null))
.Select(x => x.TourAlias)
.ToList();
try
{
var contents = File.ReadAllText(tourFile);
var tours = JsonConvert.DeserializeObject<BackOfficeTour[]>(contents);
var disabledTours = TourFilterResolver.Current.DisabledTours;
result.Add(new BackOfficeTourFile
var tour = new BackOfficeTourFile
{
FileName = Path.GetFileNameWithoutExtension(tourFile),
PluginName = pluginName,
Tours = tours
.Where(x => disabledTours.Contains(x.Alias, StringComparer.InvariantCultureIgnoreCase) == false)
.Where(x => aliasFilters.Count == 0 || aliasFilters.All(filter => filter.IsMatch(x.Alias)) == false)
.ToArray()
});
};
//don't add if all of the tours are filtered
if (tour.Tours.Any())
result.Add(tour);
}
catch (IOException e)
{

View File

@@ -0,0 +1,61 @@
using System.Text.RegularExpressions;
namespace Umbraco.Web.Models
{
public class BackOfficeTourFilter
{
public Regex PluginName { get; private set; }
public Regex TourFileName { get; private set; }
public Regex TourAlias { get; private set; }
/// <summary>
/// Create a filter to filter out a whole plugin's tours
/// </summary>
/// <param name="pluginName"></param>
/// <returns></returns>
public static BackOfficeTourFilter FilterPlugin(Regex pluginName)
{
return new BackOfficeTourFilter(pluginName, null, null);
}
/// <summary>
/// Create a filter to filter out a whole tour file
/// </summary>
/// <param name="tourFileName"></param>
/// <returns></returns>
public static BackOfficeTourFilter FilterFile(Regex tourFileName)
{
return new BackOfficeTourFilter(null, tourFileName, null);
}
/// <summary>
/// Create a filter to filter out a tour alias, this will filter out the same alias found in all files
/// </summary>
/// <param name="tourAlias"></param>
/// <returns></returns>
public static BackOfficeTourFilter FilterAlias(Regex tourAlias)
{
return new BackOfficeTourFilter(null, null, tourAlias);
}
/// <summary>
/// Constructor to create a tour filter
/// </summary>
/// <param name="pluginName">Value to filter out tours by a plugin, can be null</param>
/// <param name="tourFileName">Value to filter out a tour file, can be null</param>
/// <param name="tourAlias">Value to filter out a tour alias, can be null</param>
/// <remarks>
/// Depending on what is null will depend on how the filter is applied.
/// If pluginName is not NULL and it's matched then we check if tourFileName is not NULL and it's matched then we check tour alias is not NULL and then match it,
/// if any steps is NULL then the filters upstream are applied.
/// Example, pluginName = "hello", tourFileName="stuff", tourAlias=NULL = we will filter out the tour file "stuff" from the plugin "hello" but not from other plugins if the same file name exists.
/// Example, tourAlias="test.*" = we will filter out all tour aliases that start with the word "test" regardless of the plugin or file name
/// </remarks>
public BackOfficeTourFilter(Regex pluginName, Regex tourFileName, Regex tourAlias)
{
PluginName = pluginName;
TourFileName = tourFileName;
TourAlias = tourAlias;
}
}
}

View File

@@ -1,32 +1,79 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.ObjectResolution;
using Umbraco.Web.Models;
namespace Umbraco.Web
{
public class TourFilterResolver
/// <summary>
/// Allows for adding filters for tours during startup
/// </summary>
public class TourFilterResolver : ManyObjectsResolverBase<TourFilterResolver, BackOfficeTourFilter>
{
private static TourFilterResolver _current;
private readonly HashSet<string> _disabledTours;
public TourFilterResolver()
public TourFilterResolver(IServiceProvider serviceProvider, ILogger logger) : base(serviceProvider, logger)
{
_disabledTours = new HashSet<string>();
}
public static TourFilterResolver Current
private readonly HashSet<BackOfficeTourFilter> _instances = new HashSet<BackOfficeTourFilter>();
public IEnumerable<BackOfficeTourFilter> Filters
{
get { return _current ?? (_current = new TourFilterResolver()); }
get { return Values; }
}
public void Disable(string tour)
/// <summary>
/// Adds a filter instance
/// </summary>
/// <param name="filter"></param>
public void AddFilter(BackOfficeTourFilter filter)
{
_disabledTours.Add(tour);
using (Resolution.Configuration)
_instances.Add(filter);
}
public string[] DisabledTours
/// <summary>
/// Removes a filter instance
/// </summary>
/// <param name="filter"></param>
public void RemoveFilter(BackOfficeTourFilter filter)
{
get { return _disabledTours.ToArray(); }
using (Resolution.Configuration)
_instances.Remove(filter);
}
/// <summary>
/// Removes a filter instance based on callback
/// </summary>
/// <param name="filter"></param>
public void RemoveFilterWhere(Func<BackOfficeTourFilter, bool> filter)
{
using (Resolution.Configuration)
_instances.RemoveWhere(new Predicate<BackOfficeTourFilter>(filter));
}
/// <inheritdoc />
/// <summary>
/// Overridden to return the combined created instances based on the resolved Types and the Concrete values added with AddFilter
/// </summary>
/// <returns></returns>
protected override IEnumerable<BackOfficeTourFilter> CreateInstances()
{
var createdInstances = base.CreateInstances();
return createdInstances.Concat(_instances);
}
public override void Clear()
{
base.Clear();
_instances.Clear();
}
internal override void ResetCollections()
{
base.ResetCollections();
_instances.Clear();
}
}
}

View File

@@ -328,6 +328,7 @@
<Compile Include="Editors\ParameterSwapControllerActionSelector.cs" />
<Compile Include="Editors\CodeFileController.cs" />
<Compile Include="Editors\TourController.cs" />
<Compile Include="Models\BackOfficeTourFilter.cs" />
<Compile Include="TourFilterResolver.cs" />
<Compile Include="Editors\UserEditorAuthorizationHelper.cs" />
<Compile Include="Editors\UserGroupAuthorizationAttribute.cs" />

View File

@@ -353,6 +353,8 @@ namespace Umbraco.Web
{
base.InitializeResolvers();
TourFilterResolver.Current = new TourFilterResolver(ServiceProvider, LoggerResolver.Current.Logger);
SearchableTreeResolver.Current = new SearchableTreeResolver(ServiceProvider, LoggerResolver.Current.Logger, ApplicationContext.Services.ApplicationTreeService, () => PluginManager.ResolveSearchableTrees());
XsltExtensionsResolver.Current = new XsltExtensionsResolver(ServiceProvider, LoggerResolver.Current.Logger, () => PluginManager.ResolveXsltExtensions());