#8919 - Avoid having fat controller and do not new up a controller in a model

This commit is contained in:
Bjarke Berg
2020-09-22 08:58:16 +02:00
parent b327399cd2
commit ccc0e82579
10 changed files with 234 additions and 87 deletions

View File

@@ -146,6 +146,9 @@ namespace Umbraco.Web.Composing
public static ISectionService SectionService
=> Factory.GetInstance<ISectionService>();
public static IIconService IconService
=> Factory.GetInstance<IIconService>();
#endregion
#region Web Constants

View File

@@ -26,6 +26,7 @@ using Umbraco.Web.Composing;
using Umbraco.Web.Features;
using Umbraco.Web.JavaScript;
using Umbraco.Web.Security;
using Umbraco.Web.Services;
using Constants = Umbraco.Core.Constants;
using JArray = Newtonsoft.Json.Linq.JArray;
@@ -42,15 +43,54 @@ namespace Umbraco.Web.Editors
private readonly ManifestParser _manifestParser;
private readonly UmbracoFeatures _features;
private readonly IRuntimeState _runtimeState;
private readonly IIconService _iconService;
private BackOfficeUserManager<BackOfficeIdentityUser> _userManager;
private BackOfficeSignInManager _signInManager;
public BackOfficeController(ManifestParser manifestParser, UmbracoFeatures features, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
[Obsolete("Use the constructor that injects IIconService.")]
public BackOfficeController(
ManifestParser manifestParser,
UmbracoFeatures features,
IGlobalSettings globalSettings,
IUmbracoContextAccessor umbracoContextAccessor,
ServiceContext services,
AppCaches appCaches,
IProfilingLogger profilingLogger,
IRuntimeState runtimeState,
UmbracoHelper umbracoHelper)
: this(manifestParser,
features,
globalSettings,
umbracoContextAccessor,
services,
appCaches,
profilingLogger,
runtimeState,
umbracoHelper,
Current.IconService)
{
_manifestParser = manifestParser;
_features = features;
_runtimeState = runtimeState;
}
public BackOfficeController(
ManifestParser manifestParser,
UmbracoFeatures features,
IGlobalSettings globalSettings,
IUmbracoContextAccessor umbracoContextAccessor,
ServiceContext services,
AppCaches appCaches,
IProfilingLogger profilingLogger,
IRuntimeState runtimeState,
UmbracoHelper umbracoHelper,
IIconService iconService)
: base(globalSettings, umbracoContextAccessor, services, appCaches, profilingLogger, umbracoHelper)
{
_manifestParser = manifestParser;
_features = features;
_runtimeState = runtimeState;
_iconService = iconService;
}
protected BackOfficeSignInManager SignInManager => _signInManager ?? (_signInManager = OwinContext.GetBackOfficeSignInManager());
@@ -66,8 +106,8 @@ namespace Umbraco.Web.Editors
public async Task<ActionResult> Default()
{
return await RenderDefaultOrProcessExternalLoginAsync(
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings)),
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings)));
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings, _iconService)),
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings, _iconService)));
}
[HttpGet]
@@ -150,7 +190,7 @@ namespace Umbraco.Web.Editors
{
return await RenderDefaultOrProcessExternalLoginAsync(
//The default view to render when there is no external login info or errors
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/AuthorizeUpgrade.cshtml", new BackOfficeModel(_features, GlobalSettings)),
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/AuthorizeUpgrade.cshtml", new BackOfficeModel(_features, GlobalSettings, _iconService)),
//The ActionResult to perform if external login is successful
() => Redirect("/"));
}

View File

@@ -1,21 +1,29 @@
using Umbraco.Core.Configuration;
using System;
using Umbraco.Core.Configuration;
using Umbraco.Web.Composing;
using Umbraco.Web.Features;
using Umbraco.Web.Services;
namespace Umbraco.Web.Editors
{
public class BackOfficeModel
{
private IconController IconController { get; }
public BackOfficeModel(UmbracoFeatures features, IGlobalSettings globalSettings)
[Obsolete("Use the overload that injects IIconService.")]
public BackOfficeModel(UmbracoFeatures features, IGlobalSettings globalSettings) : this(features, globalSettings, Current.IconService)
{
}
public BackOfficeModel(UmbracoFeatures features, IGlobalSettings globalSettings, IIconService iconService)
{
Features = features;
GlobalSettings = globalSettings;
IconController = new IconController();
IconCheckData = IconController.GetIcon("icon-check")?.SvgString;
IconDeleteData = IconController.GetIcon("icon-delete")?.SvgString;
IconCheckData = iconService.GetIcon("icon-check")?.SvgString;
IconDeleteData = iconService.GetIcon("icon-delete")?.SvgString;
}
public UmbracoFeatures Features { get; }
public IGlobalSettings GlobalSettings { get; }
public string IconCheckData { get; }

View File

@@ -1,7 +1,11 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models;
using Umbraco.Web.Composing;
using Umbraco.Web.Features;
using Umbraco.Web.Services;
namespace Umbraco.Web.Editors
{
@@ -10,7 +14,21 @@ namespace Umbraco.Web.Editors
private readonly UmbracoFeatures _features;
public IEnumerable<ILanguage> Languages { get; }
public BackOfficePreviewModel(UmbracoFeatures features, IGlobalSettings globalSettings, IEnumerable<ILanguage> languages) : base(features, globalSettings)
[Obsolete("Use the overload that injects IIconService.")]
public BackOfficePreviewModel(
UmbracoFeatures features,
IGlobalSettings globalSettings,
IEnumerable<ILanguage> languages)
: this(features, globalSettings, languages, Current.IconService)
{
}
public BackOfficePreviewModel(
UmbracoFeatures features,
IGlobalSettings globalSettings,
IEnumerable<ILanguage> languages,
IIconService iconService)
: base(features, globalSettings, iconService)
{
_features = features;
Languages = languages;

View File

@@ -1,21 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections.Generic;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi;
using Umbraco.Core.Logging;
using Umbraco.Web.Models;
using System.IO;
using Umbraco.Core;
using Umbraco.Core.IO;
using Ganss.XSS;
using Umbraco.Core.Cache;
using Umbraco.Web.Services;
namespace Umbraco.Web.Editors
{
[PluginController("UmbracoApi")]
public class IconController : UmbracoAuthorizedApiController
{
private readonly IIconService _iconService;
public IconController(IIconService iconService)
{
_iconService = iconService;
}
/// <summary>
/// Gets an IconModel containing the icon name and SvgString according to an icon name found at the global icons path
@@ -24,76 +23,16 @@ namespace Umbraco.Web.Editors
/// <returns></returns>
public IconModel GetIcon(string iconName)
{
return string.IsNullOrWhiteSpace(iconName)
? null
: CreateIconModel(iconName.StripFileExtension(), IOHelper.MapPath($"{GlobalSettings.IconsPath}/{iconName}.svg"));
}
/// <summary>
/// Gets an IconModel using values from a FileInfo model
/// </summary>
/// <param name="fileInfo"></param>
/// <returns></returns>
public IconModel GetIcon(FileInfo fileInfo)
{
return fileInfo == null || string.IsNullOrWhiteSpace(fileInfo.Name)
? null
: CreateIconModel(fileInfo.Name.StripFileExtension(), fileInfo.FullName);
return _iconService.GetIcon(iconName);
}
/// <summary>
/// Gets a list of all svg icons found at at the global icons path.
/// </summary>
/// <returns></returns>
public List<IconModel> GetAllIcons()
public IList<IconModel> GetAllIcons()
{
var icons = new List<IconModel>();
var directory = new DirectoryInfo(IOHelper.MapPath($"{GlobalSettings.IconsPath}/"));
var iconNames = directory.GetFiles("*.svg");
iconNames.OrderBy(f => f.Name).ToList().ForEach(iconInfo =>
{
var icon = GetIcon(iconInfo);
if (icon != null)
{
icons.Add(icon);
}
});
return icons;
}
/// <summary>
/// Gets an IconModel containing the icon name and SvgString
/// </summary>
/// <param name="iconName"></param>
/// <param name="iconPath"></param>
/// <returns></returns>
private IconModel CreateIconModel(string iconName, string iconPath)
{
var sanitizer = new HtmlSanitizer();
sanitizer.AllowedAttributes.UnionWith(Core.Constants.SvgSanitizer.Attributes);
sanitizer.AllowedCssProperties.UnionWith(Core.Constants.SvgSanitizer.Attributes);
sanitizer.AllowedTags.UnionWith(Core.Constants.SvgSanitizer.Tags);
try
{
var svgContent = File.ReadAllText(iconPath);
var sanitizedString = sanitizer.Sanitize(svgContent);
var svg = new IconModel
{
Name = iconName,
SvgString = sanitizedString
};
return svg;
}
catch
{
return null;
}
return _iconService.GetAllIcons();
}
}
}

View File

@@ -12,6 +12,7 @@ using Umbraco.Web.JavaScript;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Mvc;
using Umbraco.Web.PublishedCache;
using Umbraco.Web.Services;
using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.Editors
@@ -24,19 +25,39 @@ namespace Umbraco.Web.Editors
private readonly IPublishedSnapshotService _publishedSnapshotService;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly ILocalizationService _localizationService;
private readonly IIconService _iconService;
[Obsolete("Use the constructor that injects IIconService.")]
public PreviewController(
UmbracoFeatures features,
IGlobalSettings globalSettings,
IPublishedSnapshotService publishedSnapshotService,
IUmbracoContextAccessor umbracoContextAccessor,
ILocalizationService localizationService)
:this(features,
globalSettings,
publishedSnapshotService,
umbracoContextAccessor,
localizationService,
Current.IconService)
{
}
public PreviewController(
UmbracoFeatures features,
IGlobalSettings globalSettings,
IPublishedSnapshotService publishedSnapshotService,
IUmbracoContextAccessor umbracoContextAccessor,
ILocalizationService localizationService,
IIconService iconService)
{
_features = features;
_globalSettings = globalSettings;
_publishedSnapshotService = publishedSnapshotService;
_umbracoContextAccessor = umbracoContextAccessor;
_localizationService = localizationService;
_iconService = iconService;
}
[UmbracoAuthorize(redirectToUmbracoLogin: true)]
@@ -45,7 +66,7 @@ namespace Umbraco.Web.Editors
{
var availableLanguages = _localizationService.GetAllLanguages();
var model = new BackOfficePreviewModel(_features, _globalSettings, availableLanguages);
var model = new BackOfficePreviewModel(_features, _globalSettings, availableLanguages, _iconService);
if (model.PreviewExtendedHeaderView.IsNullOrWhiteSpace() == false)
{

View File

@@ -139,6 +139,7 @@ namespace Umbraco.Web.Runtime
composition.RegisterUnique<ISectionService, SectionService>();
composition.RegisterUnique<IDashboardService, DashboardService>();
composition.RegisterUnique<IIconService, IconService>();
composition.RegisterUnique<IExamineManager>(factory => ExamineManager.Instance);

View File

@@ -0,0 +1,21 @@
using System.Collections.Generic;
using Umbraco.Web.Models;
namespace Umbraco.Web.Services
{
public interface IIconService
{
/// <summary>
/// Gets an IconModel containing the icon name and SvgString according to an icon name found at the global icons path
/// </summary>
/// <param name="iconName"></param>
/// <returns></returns>
IconModel GetIcon(string iconName);
/// <summary>
/// Gets a list of all svg icons found at at the global icons path.
/// </summary>
/// <returns></returns>
IList<IconModel> GetAllIcons();
}
}

View File

@@ -0,0 +1,94 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Ganss.XSS;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Web.Models;
namespace Umbraco.Web.Services
{
public class IconService : IIconService
{
private readonly IGlobalSettings _globalSettings;
public IconService(IGlobalSettings globalSettings)
{
_globalSettings = globalSettings;
}
/// <inheritdoc />
public IList<IconModel> GetAllIcons()
{
var icons = new List<IconModel>();
var directory = new DirectoryInfo(IOHelper.MapPath($"{_globalSettings.IconsPath}/"));
var iconNames = directory.GetFiles("*.svg");
iconNames.OrderBy(f => f.Name).ToList().ForEach(iconInfo =>
{
var icon = GetIcon(iconInfo);
if (icon != null)
{
icons.Add(icon);
}
});
return icons;
}
/// <inheritdoc />
public IconModel GetIcon(string iconName)
{
return string.IsNullOrWhiteSpace(iconName)
? null
: CreateIconModel(iconName.StripFileExtension(), IOHelper.MapPath($"{_globalSettings.IconsPath}/{iconName}.svg"));
}
/// <summary>
/// Gets an IconModel using values from a FileInfo model
/// </summary>
/// <param name="fileInfo"></param>
/// <returns></returns>
private IconModel GetIcon(FileInfo fileInfo)
{
return fileInfo == null || string.IsNullOrWhiteSpace(fileInfo.Name)
? null
: CreateIconModel(fileInfo.Name.StripFileExtension(), fileInfo.FullName);
}
/// <summary>
/// Gets an IconModel containing the icon name and SvgString
/// </summary>
/// <param name="iconName"></param>
/// <param name="iconPath"></param>
/// <returns></returns>
private IconModel CreateIconModel(string iconName, string iconPath)
{
var sanitizer = new HtmlSanitizer();
sanitizer.AllowedAttributes.UnionWith(Core.Constants.SvgSanitizer.Attributes);
sanitizer.AllowedCssProperties.UnionWith(Core.Constants.SvgSanitizer.Attributes);
sanitizer.AllowedTags.UnionWith(Core.Constants.SvgSanitizer.Tags);
try
{
var svgContent = File.ReadAllText(iconPath);
var sanitizedString = sanitizer.Sanitize(svgContent);
var svg = new IconModel
{
Name = iconName,
SvgString = sanitizedString
};
return svg;
}
catch
{
return null;
}
}
}
}

View File

@@ -238,8 +238,8 @@
<Compile Include="Models\ContentEditing\LinkDisplay.cs" />
<Compile Include="Models\ContentEditing\MacroDisplay.cs" />
<Compile Include="Models\ContentEditing\MacroParameterDisplay.cs" />
<Compile Include="Models\IconModel.cs" />
<Compile Include="Models\ContentEditing\UrlAndAnchors.cs" />
<Compile Include="Models\IconModel.cs" />
<Compile Include="Models\ImageProcessorImageUrlGenerator.cs" />
<Compile Include="Models\Mapping\CommonMapper.cs" />
<Compile Include="Models\Mapping\MapperContextExtensions.cs" />
@@ -284,10 +284,12 @@
<Compile Include="Search\IUmbracoTreeSearcherFields.cs" />
<Compile Include="Search\UmbracoTreeSearcherFields.cs" />
<Compile Include="Services\DashboardService.cs" />
<Compile Include="Services\IconService.cs" />
<Compile Include="Services\IDashboardService.cs" />
<Compile Include="Models\Link.cs" />
<Compile Include="Models\LinkType.cs" />
<Compile Include="Models\TemplateQuery\OperatorFactory.cs" />
<Compile Include="Services\IIconService.cs" />
<Compile Include="Templates\HtmlLocalLinkParser.cs" />
<Compile Include="Templates\HtmlImageSourceParser.cs" />
<Compile Include="Templates\HtmlUrlParser.cs" />