diff --git a/src/Umbraco.Core/EmailSender.cs b/src/Umbraco.Abstractions/EmailSender.cs similarity index 78% rename from src/Umbraco.Core/EmailSender.cs rename to src/Umbraco.Abstractions/EmailSender.cs index 698034a7e9..5cfdd765bc 100644 --- a/src/Umbraco.Core/EmailSender.cs +++ b/src/Umbraco.Abstractions/EmailSender.cs @@ -2,6 +2,7 @@ using System.Net.Mail; using System.Threading.Tasks; using Umbraco.Core.Composing; +using Umbraco.Core.Configuration; using Umbraco.Core.Events; namespace Umbraco.Core @@ -13,21 +14,22 @@ namespace Umbraco.Core { // TODO: This should encapsulate a BackgroundTaskRunner with a queue to send these emails! + private readonly IGlobalSettings _globalSettings; private readonly bool _enableEvents; - /// - /// Default constructor - /// - public EmailSender() : this(false) + public EmailSender(IGlobalSettings globalSettings) : this(globalSettings, false) { } - internal EmailSender(bool enableEvents) + internal EmailSender(IGlobalSettings globalSettings, bool enableEvents) { + _globalSettings = globalSettings; _enableEvents = enableEvents; + + _smtpConfigured = new Lazy(() => _globalSettings.IsSmtpServerConfigured); } - private static readonly Lazy SmtpConfigured = new Lazy(() => Current.Configs.Global().IsSmtpServerConfigured); + private readonly Lazy _smtpConfigured; /// /// Sends the message non-async @@ -35,7 +37,7 @@ namespace Umbraco.Core /// public void Send(MailMessage message) { - if (SmtpConfigured.Value == false && _enableEvents) + if (_smtpConfigured.Value == false && _enableEvents) { OnSendEmail(new SendEmailEventArgs(message)); } @@ -55,7 +57,7 @@ namespace Umbraco.Core /// public async Task SendAsync(MailMessage message) { - if (SmtpConfigured.Value == false && _enableEvents) + if (_smtpConfigured.Value == false && _enableEvents) { OnSendEmail(new SendEmailEventArgs(message)); } @@ -81,10 +83,7 @@ namespace Umbraco.Core /// /// We assume this is possible if either an event handler is registered or an smtp server is configured /// - internal static bool CanSendRequiredEmail - { - get { return EventHandlerRegistered || SmtpConfigured.Value; } - } + internal static bool CanSendRequiredEmail(IGlobalSettings globalSettings) => EventHandlerRegistered || globalSettings.IsSmtpServerConfigured; /// /// returns true if an event handler has been registered diff --git a/src/Umbraco.Core/ReflectionUtilities.cs b/src/Umbraco.Abstractions/ReflectionUtilities.cs similarity index 99% rename from src/Umbraco.Core/ReflectionUtilities.cs rename to src/Umbraco.Abstractions/ReflectionUtilities.cs index a8e6836ca1..b3fd8c1b59 100644 --- a/src/Umbraco.Core/ReflectionUtilities.cs +++ b/src/Umbraco.Abstractions/ReflectionUtilities.cs @@ -18,7 +18,7 @@ namespace Umbraco.Core /// Supports emitting constructors, instance and static methods, instance property getters and /// setters. Does not support static properties yet. /// - public static partial class ReflectionUtilities + public static class ReflectionUtilities { #region Fields diff --git a/src/Umbraco.Abstractions/Umbraco.Abstractions.csproj b/src/Umbraco.Abstractions/Umbraco.Abstractions.csproj index 7e00359c37..a4d379d2bf 100644 --- a/src/Umbraco.Abstractions/Umbraco.Abstractions.csproj +++ b/src/Umbraco.Abstractions/Umbraco.Abstractions.csproj @@ -12,6 +12,7 @@ + diff --git a/src/Umbraco.Core/Runtime/CoreInitialComponent.cs b/src/Umbraco.Core/Runtime/CoreInitialComponent.cs index 40dd4575dc..1432e6b7f2 100644 --- a/src/Umbraco.Core/Runtime/CoreInitialComponent.cs +++ b/src/Umbraco.Core/Runtime/CoreInitialComponent.cs @@ -1,4 +1,5 @@ using Umbraco.Core.Composing; +using Umbraco.Core.Configuration; using Umbraco.Core.IO; namespace Umbraco.Core.Runtime @@ -6,10 +7,12 @@ namespace Umbraco.Core.Runtime public class CoreInitialComponent : IComponent { private readonly IIOHelper _ioHelper; + private readonly IGlobalSettings _globalSettings; - public CoreInitialComponent(IIOHelper ioHelper) + public CoreInitialComponent(IIOHelper ioHelper, IGlobalSettings globalSettings) { _ioHelper = ioHelper; + _globalSettings = globalSettings; } public void Initialize() @@ -17,7 +20,7 @@ namespace Umbraco.Core.Runtime // ensure we have some essential directories // every other component can then initialize safely _ioHelper.EnsurePathExists(Constants.SystemDirectories.Data); - _ioHelper.EnsurePathExists(Current.Configs.Global().UmbracoMediaPath); + _ioHelper.EnsurePathExists(_globalSettings.UmbracoMediaPath); _ioHelper.EnsurePathExists(Constants.SystemDirectories.MvcViews); _ioHelper.EnsurePathExists(Constants.SystemDirectories.PartialViews); _ioHelper.EnsurePathExists(Constants.SystemDirectories.MacroPartials); diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 5f6a877415..5bbd3942a4 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -314,7 +314,6 @@ - @@ -325,7 +324,6 @@ - @@ -701,7 +699,6 @@ - diff --git a/src/Umbraco.Tests.Benchmarks/CtorInvokeBenchmarks.cs b/src/Umbraco.Tests.Benchmarks/CtorInvokeBenchmarks.cs index 8d15613791..0ce1b3eac3 100644 --- a/src/Umbraco.Tests.Benchmarks/CtorInvokeBenchmarks.cs +++ b/src/Umbraco.Tests.Benchmarks/CtorInvokeBenchmarks.cs @@ -145,8 +145,8 @@ namespace Umbraco.Tests.Benchmarks //_expressionMethod3 = (Func) Delegate.CreateDelegate(typeof (Func), _expressionMethod.Method); // but, our utilities know how to do it! - _expressionMethod3 = ReflectionUtilities.CompileToDelegate(expr); - _expressionMethod4 = ReflectionUtilities.GetCtor(); + _expressionMethod3 = ReflectionUtilitiesForTest.CompileToDelegate(expr); + _expressionMethod4 = ReflectionUtilitiesForTest.GetCtor(); // however, unfortunately, the generated "compiled to delegate" code cannot access private stuff :( diff --git a/src/Umbraco.Core/ReflectionUtilities-Unused.cs b/src/Umbraco.Tests.Benchmarks/ReflectionUtilities-Unused.cs similarity index 99% rename from src/Umbraco.Core/ReflectionUtilities-Unused.cs rename to src/Umbraco.Tests.Benchmarks/ReflectionUtilities-Unused.cs index 53317f7101..1182891477 100644 --- a/src/Umbraco.Core/ReflectionUtilities-Unused.cs +++ b/src/Umbraco.Tests.Benchmarks/ReflectionUtilities-Unused.cs @@ -5,12 +5,12 @@ using System.Linq.Expressions; using System.Reflection; using System.Reflection.Emit; -namespace Umbraco.Core +namespace Umbraco.Tests.Benchmarks { /// /// Provides utilities to simplify reflection. /// - public static partial class ReflectionUtilities + public static class ReflectionUtilitiesForTest { // the code below should NOT be used // @@ -363,4 +363,4 @@ namespace Umbraco.Core return module.DefineType("Class", TypeAttributes.Public | TypeAttributes.Abstract); } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj index b6858bd5cb..8ccb49b67c 100644 --- a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj +++ b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj @@ -57,6 +57,7 @@ + diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs index a15b5bf63b..010487b4c0 100644 --- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs @@ -101,6 +101,7 @@ namespace Umbraco.Web.Editors /// internal Dictionary GetServerVariables() { + var globalSettings = Current.Configs.Global(); var defaultVals = new Dictionary { { @@ -319,7 +320,7 @@ namespace Umbraco.Web.Editors "umbracoSettings", new Dictionary { {"umbracoPath", _globalSettings.Path}, - {"mediaPath", Current.IOHelper.ResolveUrl(Current.Configs.Global().UmbracoMediaPath).TrimEnd('/')}, + {"mediaPath", Current.IOHelper.ResolveUrl(globalSettings.UmbracoMediaPath).TrimEnd('/')}, {"appPluginsPath", Current.IOHelper.ResolveUrl(Constants.SystemDirectories.AppPlugins).TrimEnd('/')}, { "imageFileTypes", @@ -339,11 +340,11 @@ namespace Umbraco.Web.Editors }, {"keepUserLoggedIn", Current.Configs.Settings().Security.KeepUserLoggedIn}, {"usernameIsEmail", Current.Configs.Settings().Security.UsernameIsEmail}, - {"cssPath", Current.IOHelper.ResolveUrl(Current.Configs.Global().UmbracoCssPath).TrimEnd('/')}, + {"cssPath", Current.IOHelper.ResolveUrl(globalSettings.UmbracoCssPath).TrimEnd('/')}, {"allowPasswordReset", Current.Configs.Settings().Security.AllowPasswordReset}, {"loginBackgroundImage", Current.Configs.Settings().Content.LoginBackgroundImage}, - {"showUserInvite", EmailSender.CanSendRequiredEmail}, - {"canSendRequiredEmail", EmailSender.CanSendRequiredEmail}, + {"showUserInvite", EmailSender.CanSendRequiredEmail(globalSettings)}, + {"canSendRequiredEmail", EmailSender.CanSendRequiredEmail(globalSettings)}, } }, { diff --git a/src/Umbraco.Web/Editors/UsersController.cs b/src/Umbraco.Web/Editors/UsersController.cs index 2211813f63..1e751d2383 100644 --- a/src/Umbraco.Web/Editors/UsersController.cs +++ b/src/Umbraco.Web/Editors/UsersController.cs @@ -40,9 +40,12 @@ namespace Umbraco.Web.Editors [IsCurrentUserModelFilter] public class UsersController : UmbracoAuthorizedJsonController { + private readonly IGlobalSettings _globalSettings; + public UsersController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) { + _globalSettings = globalSettings; } /// @@ -343,7 +346,7 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState)); } - if (EmailSender.CanSendRequiredEmail == false) + if (EmailSender.CanSendRequiredEmail(_globalSettings) == false) { throw new HttpResponseException( Request.CreateNotificationValidationErrorResponse("No Email server is configured")); @@ -473,7 +476,7 @@ namespace Umbraco.Web.Editors await UserManager.EmailService.SendAsync( //send the special UmbracoEmailMessage which configures it's own sender //to allow for events to handle sending the message if no smtp is configured - new UmbracoEmailMessage(new EmailSender(true)) + new UmbracoEmailMessage(new EmailSender(_globalSettings, true)) { Body = emailBody, Destination = userDisplay.Email, diff --git a/src/Umbraco.Web/HealthCheck/NotificationMethods/EmailNotificationMethod.cs b/src/Umbraco.Web/HealthCheck/NotificationMethods/EmailNotificationMethod.cs index 87c0e4f46d..ddde3f7b98 100644 --- a/src/Umbraco.Web/HealthCheck/NotificationMethods/EmailNotificationMethod.cs +++ b/src/Umbraco.Web/HealthCheck/NotificationMethods/EmailNotificationMethod.cs @@ -17,8 +17,9 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods private readonly ILocalizedTextService _textService; private readonly IRuntimeState _runtimeState; private readonly ILogger _logger; + private readonly IGlobalSettings _globalSettings; - public EmailNotificationMethod(ILocalizedTextService textService, IRuntimeState runtimeState, ILogger logger) + public EmailNotificationMethod(ILocalizedTextService textService, IRuntimeState runtimeState, ILogger logger, IGlobalSettings globalSettings) { var recipientEmail = Settings["recipientEmail"]?.Value; if (string.IsNullOrWhiteSpace(recipientEmail)) @@ -32,6 +33,7 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods _textService = textService ?? throw new ArgumentNullException(nameof(textService)); _runtimeState = runtimeState; _logger = logger; + _globalSettings = globalSettings; } public string RecipientEmail { get; } @@ -61,7 +63,7 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods var subject = _textService.Localize("healthcheck/scheduledHealthCheckEmailSubject", new[] { host.ToString() }); - var mailSender = new EmailSender(); + var mailSender = new EmailSender(_globalSettings); using (var mailMessage = CreateMailMessage(subject, message)) { await mailSender.SendAsync(mailMessage); diff --git a/src/Umbraco.Web/Security/AppBuilderExtensions.cs b/src/Umbraco.Web/Security/AppBuilderExtensions.cs index ede574671f..3f459cf734 100644 --- a/src/Umbraco.Web/Security/AppBuilderExtensions.cs +++ b/src/Umbraco.Web/Security/AppBuilderExtensions.cs @@ -96,7 +96,8 @@ namespace Umbraco.Web.Security customUserStore, contentSettings, passwordConfiguration, - ipResolver)); + ipResolver, + globalSettings)); app.SetBackOfficeUserManagerType(); diff --git a/src/Umbraco.Web/Security/BackOfficeUserManager.cs b/src/Umbraco.Web/Security/BackOfficeUserManager.cs index 52bf901bfa..c644f5e428 100644 --- a/src/Umbraco.Web/Security/BackOfficeUserManager.cs +++ b/src/Umbraco.Web/Security/BackOfficeUserManager.cs @@ -28,11 +28,12 @@ namespace Umbraco.Web.Security IdentityFactoryOptions options, IContentSection contentSectionConfig, IPasswordConfiguration passwordConfiguration, - IIpResolver ipResolver) + IIpResolver ipResolver, + IGlobalSettings globalSettings) : base(store, passwordConfiguration, ipResolver) { if (options == null) throw new ArgumentNullException("options"); - InitUserManager(this, passwordConfiguration, options.DataProtectionProvider, contentSectionConfig); + InitUserManager(this, passwordConfiguration, options.DataProtectionProvider, contentSectionConfig, globalSettings); } #region Static Create methods @@ -64,7 +65,7 @@ namespace Umbraco.Web.Security if (externalLoginService == null) throw new ArgumentNullException("externalLoginService"); var store = new BackOfficeUserStore(userService, entityService, externalLoginService, globalSettings, mapper); - var manager = new BackOfficeUserManager(store, options, contentSectionConfig, passwordConfiguration, ipResolver); + var manager = new BackOfficeUserManager(store, options, contentSectionConfig, passwordConfiguration, ipResolver, globalSettings); return manager; } @@ -81,9 +82,10 @@ namespace Umbraco.Web.Security BackOfficeUserStore customUserStore, IContentSection contentSectionConfig, IPasswordConfiguration passwordConfiguration, - IIpResolver ipResolver) + IIpResolver ipResolver, + IGlobalSettings globalSettings) { - var manager = new BackOfficeUserManager(customUserStore, options, contentSectionConfig, passwordConfiguration, ipResolver); + var manager = new BackOfficeUserManager(customUserStore, options, contentSectionConfig, passwordConfiguration, ipResolver, globalSettings); return manager; } #endregion @@ -157,7 +159,8 @@ namespace Umbraco.Web.Security BackOfficeUserManager manager, IPasswordConfiguration passwordConfig, IDataProtectionProvider dataProtectionProvider, - IContentSection contentSectionConfig) + IContentSection contentSectionConfig, + IGlobalSettings globalSettings) { // Configure validation logic for usernames manager.UserValidator = new BackOfficeUserValidator(manager) @@ -192,7 +195,7 @@ namespace Umbraco.Web.Security manager.EmailService = new EmailService( contentSectionConfig.NotificationEmailAddress, - new EmailSender()); + new EmailSender(globalSettings)); //NOTE: Not implementing these, if people need custom 2 factor auth, they'll need to implement their own UserStore to support it diff --git a/src/Umbraco.Web/Trees/ContentTreeController.cs b/src/Umbraco.Web/Trees/ContentTreeController.cs index 1ef0683916..1a56642a74 100644 --- a/src/Umbraco.Web/Trees/ContentTreeController.cs +++ b/src/Umbraco.Web/Trees/ContentTreeController.cs @@ -39,6 +39,7 @@ namespace Umbraco.Web.Trees { private readonly UmbracoTreeSearcher _treeSearcher; private readonly ActionCollection _actions; + private readonly IGlobalSettings _globalSettings; protected override int RecycleBinId => Constants.System.RecycleBinContent; @@ -53,6 +54,7 @@ namespace Umbraco.Web.Trees { _treeSearcher = treeSearcher; _actions = actions; + _globalSettings = globalSettings; } /// @@ -240,7 +242,7 @@ namespace Umbraco.Web.Trees AddActionNode(item, menu, opensDialog: true); AddActionNode(item, menu, true, opensDialog: true); - if (EmailSender.CanSendRequiredEmail) + if (EmailSender.CanSendRequiredEmail(_globalSettings)) { menu.Items.Add(new MenuItem("notify", Services.TextService) {