Revert "Temp8 tinymce"

This commit is contained in:
Warren Buckley
2018-11-22 14:05:51 +00:00
committed by GitHub
parent 2a0748fc1e
commit 54a2aa00a7
6677 changed files with 646351 additions and 410535 deletions

View File

@@ -10,8 +10,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
public abstract class AbstractConfigCheck : HealthCheck
{
private readonly ConfigurationService _configurationService;
protected ILocalizedTextService TextService { get; }
private readonly ILocalizedTextService _textService;
/// <summary>
/// Gets the config file path.
@@ -51,21 +50,27 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
get { return false; }
}
protected AbstractConfigCheck(ILocalizedTextService textService)
protected AbstractConfigCheck(HealthCheckContext healthCheckContext) : base(healthCheckContext)
{
TextService = textService;
_configurationService = new ConfigurationService(AbsoluteFilePath, XPath, textService);
_textService = healthCheckContext.ApplicationContext.Services.TextService;
_configurationService = new ConfigurationService(AbsoluteFilePath, XPath, _textService);
}
/// <summary>
/// Gets the name of the file.
/// </summary>
private string FileName => Path.GetFileName(FilePath);
private string FileName
{
get { return Path.GetFileName(FilePath); }
}
/// <summary>
/// Gets the absolute file path.
/// </summary>
private string AbsoluteFilePath => IOHelper.MapPath(FilePath);
private string AbsoluteFilePath
{
get { return IOHelper.MapPath(FilePath); }
}
/// <summary>
/// Gets the message for when the check has succeeded.
@@ -74,7 +79,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
{
get
{
return TextService.Localize("healthcheck/checkSuccessMessage",
return _textService.Localize("healthcheck/checkSuccessMessage",
new[] { CurrentValue, Values.First(v => v.IsRecommended).Value, XPath, AbsoluteFilePath });
}
}
@@ -87,9 +92,9 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
get
{
return ValueComparisonType == ValueComparisonType.ShouldEqual
? TextService.Localize("healthcheck/checkErrorMessageDifferentExpectedValue",
? _textService.Localize("healthcheck/checkErrorMessageDifferentExpectedValue",
new[] { CurrentValue, Values.First(v => v.IsRecommended).Value, XPath, AbsoluteFilePath })
: TextService.Localize("healthcheck/checkErrorMessageUnexpectedValue",
: _textService.Localize("healthcheck/checkErrorMessageUnexpectedValue",
new[] { CurrentValue, Values.First(v => v.IsRecommended).Value, XPath, AbsoluteFilePath });
}
}
@@ -105,7 +110,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
var rectifiedValue = recommendedValue != null
? recommendedValue.Value
: ProvidedValue;
return TextService.Localize("healthcheck/rectifySuccessMessage",
return _textService.Localize("healthcheck/rectifySuccessMessage",
new[]
{
CurrentValue,
@@ -119,12 +124,18 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
/// <summary>
/// Gets a value indicating whether this check can be rectified automatically.
/// </summary>
public virtual bool CanRectify => ValueComparisonType == ValueComparisonType.ShouldEqual;
public virtual bool CanRectify
{
get { return ValueComparisonType == ValueComparisonType.ShouldEqual; }
}
/// <summary>
/// Gets a value indicating whether this check can be rectified automatically if a value is provided.
/// </summary>
public virtual bool CanRectifyWithValue => ValueComparisonType == ValueComparisonType.ShouldNotEqual;
public virtual bool CanRectifyWithValue
{
get { return ValueComparisonType == ValueComparisonType.ShouldNotEqual; }
}
public override IEnumerable<HealthCheckStatus> GetStatus()
{
@@ -156,7 +167,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
// Declare the action for rectifying the config value
var rectifyAction = new HealthCheckAction("rectify", Id)
{
Name = TextService.Localize("healthcheck/rectifyButton"),
Name = _textService.Localize("healthcheck/rectifyButton"),
ValueRequired = CanRectifyWithValue,
};
@@ -178,7 +189,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
public virtual HealthCheckStatus Rectify()
{
if (ValueComparisonType == ValueComparisonType.ShouldNotEqual)
throw new InvalidOperationException(TextService.Localize("healthcheck/cannotRectifyShouldNotEqual"));
throw new InvalidOperationException(_textService.Localize("healthcheck/cannotRectifyShouldNotEqual"));
var recommendedValue = Values.First(v => v.IsRecommended).Value;
return UpdateConfigurationValue(recommendedValue);
@@ -192,10 +203,10 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
public virtual HealthCheckStatus Rectify(string value)
{
if (ValueComparisonType == ValueComparisonType.ShouldEqual)
throw new InvalidOperationException(TextService.Localize("healthcheck/cannotRectifyShouldEqualWithValue"));
throw new InvalidOperationException(_textService.Localize("healthcheck/cannotRectifyShouldEqualWithValue"));
if (string.IsNullOrWhiteSpace(value))
throw new InvalidOperationException(TextService.Localize("healthcheck/valueToRectifyNotProvided"));
throw new InvalidOperationException(_textService.Localize("healthcheck/valueToRectifyNotProvided"));
// Need to track provided value in order to correctly put together the rectify message
ProvidedValue = value;
@@ -224,4 +235,4 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
: Rectify(action.ProvidedValue);
}
}
}
}

View File

@@ -1,8 +1,8 @@
namespace Umbraco.Web.HealthCheck.Checks.Config
namespace Umbraco.Web.HealthCheck.Checks.Config
{
public class AcceptableConfiguration
{
public string Value { get; set; }
public bool IsRecommended { get; set; }
}
}
}

View File

@@ -8,27 +8,57 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
Group = "Live Environment")]
public class CompilationDebugCheck : AbstractConfigCheck
{
public CompilationDebugCheck(ILocalizedTextService textService)
: base(textService)
{ }
private readonly ILocalizedTextService _textService;
public override string FilePath => "~/Web.config";
public override string XPath => "/configuration/system.web/compilation/@debug";
public override ValueComparisonType ValueComparisonType => ValueComparisonType.ShouldEqual;
public override bool ValidIfConfigMissing => true;
public override IEnumerable<AcceptableConfiguration> Values => new List<AcceptableConfiguration>
public CompilationDebugCheck(HealthCheckContext healthCheckContext) : base(healthCheckContext)
{
new AcceptableConfiguration { IsRecommended = true, Value = bool.FalseString.ToLower() }
};
_textService = healthCheckContext.ApplicationContext.Services.TextService;
}
public override string CheckSuccessMessage => TextService.Localize("healthcheck/compilationDebugCheckSuccessMessage");
public override string FilePath
{
get { return "~/Web.config"; }
}
public override string CheckErrorMessage => TextService.Localize("healthcheck/compilationDebugCheckErrorMessage");
public override string XPath
{
get { return "/configuration/system.web/compilation/@debug"; }
}
public override string RectifySuccessMessage => TextService.Localize("healthcheck/compilationDebugCheckRectifySuccessMessage");
public override ValueComparisonType ValueComparisonType
{
get { return ValueComparisonType.ShouldEqual; }
}
public override bool ValidIfConfigMissing
{
get { return true; }
}
public override IEnumerable<AcceptableConfiguration> Values
{
get
{
return new List<AcceptableConfiguration>
{
new AcceptableConfiguration { IsRecommended = true, Value = bool.FalseString.ToLower() }
};
}
}
public override string CheckSuccessMessage
{
get { return _textService.Localize("healthcheck/compilationDebugCheckSuccessMessage"); }
}
public override string CheckErrorMessage
{
get { return _textService.Localize("healthcheck/compilationDebugCheckErrorMessage"); }
}
public override string RectifySuccessMessage
{
get { return _textService.Localize("healthcheck/compilationDebugCheckRectifySuccessMessage"); }
}
}
}
}

View File

@@ -1,9 +1,8 @@
using System;
using System;
using System.IO;
using System.Xml;
using Umbraco.Core.Logging;
using Umbraco.Core.Services;
using Umbraco.Web.Composing;
namespace Umbraco.Web.HealthCheck.Checks.Config
{
@@ -26,7 +25,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
}
/// <summary>
/// Gets a value from a given configuration file with the given XPath
/// Gets a value from a given configuration file with the given XPath
/// </summary>
public ConfigurationServiceResult GetConfigurationValue()
{
@@ -56,19 +55,19 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
Result = string.Format(xmlNode.Value ?? xmlNode.InnerText)
};
}
catch (Exception ex)
catch (Exception exception)
{
Current.Logger.Error<ConfigurationService>(ex, "Error trying to get configuration value");
LogHelper.Error<ConfigurationService>("Error trying to get configuration value", exception);
return new ConfigurationServiceResult
{
Success = false,
Result = _textService.Localize("healthcheck/configurationServiceError", new[] { ex.Message })
Result = _textService.Localize("healthcheck/configurationServiceError", new[] { exception.Message })
};
}
}
/// <summary>
/// Updates a value in a given configuration file with the given XPath
/// Updates a value in a given configuration file with the given XPath
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
@@ -102,15 +101,15 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
xmlDocument.Save(_configFilePath);
return new ConfigurationServiceResult { Success = true };
}
catch (Exception ex)
catch (Exception exception)
{
Current.Logger.Error<ConfigurationService>(ex, "Error trying to update configuration");
LogHelper.Error<ConfigurationService>("Error trying to update configuration", exception);
return new ConfigurationServiceResult
{
Success = false,
Result = _textService.Localize("healthcheck/configurationServiceError", new[] { ex.Message })
Result = _textService.Localize("healthcheck/configurationServiceError", new[] { exception.Message })
};
}
}
}
}
}

View File

@@ -1,8 +1,8 @@
namespace Umbraco.Web.HealthCheck.Checks.Config
namespace Umbraco.Web.HealthCheck.Checks.Config
{
public class ConfigurationServiceResult
{
public bool Success { get; set; }
public string Result { get; set; }
}
}
}

View File

@@ -10,27 +10,46 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
Group = "Live Environment")]
public class CustomErrorsCheck : AbstractConfigCheck
{
public CustomErrorsCheck(ILocalizedTextService textService)
: base(textService)
{ }
private readonly ILocalizedTextService _textService;
public override string FilePath => "~/Web.config";
public override string XPath => "/configuration/system.web/customErrors/@mode";
public override ValueComparisonType ValueComparisonType => ValueComparisonType.ShouldEqual;
public override IEnumerable<AcceptableConfiguration> Values => new List<AcceptableConfiguration>
public CustomErrorsCheck(HealthCheckContext healthCheckContext) : base(healthCheckContext)
{
new AcceptableConfiguration { IsRecommended = true, Value = CustomErrorsMode.RemoteOnly.ToString() },
new AcceptableConfiguration { IsRecommended = false, Value = "On" }
};
_textService = healthCheckContext.ApplicationContext.Services.TextService;
}
public override string FilePath
{
get { return "~/Web.config"; }
}
public override string XPath
{
get { return "/configuration/system.web/customErrors/@mode"; }
}
public override ValueComparisonType ValueComparisonType
{
get { return ValueComparisonType.ShouldEqual; }
}
public override IEnumerable<AcceptableConfiguration> Values
{
get
{
return new List<AcceptableConfiguration>
{
new AcceptableConfiguration { IsRecommended = true, Value = CustomErrorsMode.RemoteOnly.ToString() },
new AcceptableConfiguration { IsRecommended = false, Value = "On" }
};
}
}
public override string CheckSuccessMessage
{
get
{
return TextService.Localize("healthcheck/customErrorsCheckSuccessMessage", new[] { CurrentValue });
return _textService.Localize("healthcheck/customErrorsCheckSuccessMessage",
new[] { CurrentValue });
}
}
@@ -38,7 +57,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
{
get
{
return TextService.Localize("healthcheck/customErrorsCheckErrorMessage",
return _textService.Localize("healthcheck/customErrorsCheckErrorMessage",
new[] { CurrentValue, Values.First(v => v.IsRecommended).Value });
}
}
@@ -47,9 +66,9 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
{
get
{
return TextService.Localize("healthcheck/customErrorsCheckRectifySuccessMessage",
return _textService.Localize("healthcheck/customErrorsCheckRectifySuccessMessage",
new[] { Values.First(v => v.IsRecommended).Value });
}
}
}
}
}

View File

@@ -9,15 +9,27 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
Group = "Configuration")]
public class MacroErrorsCheck : AbstractConfigCheck
{
public MacroErrorsCheck(ILocalizedTextService textService)
: base(textService)
{ }
private readonly ILocalizedTextService _textService;
public override string FilePath => "~/Config/umbracoSettings.config";
public MacroErrorsCheck(HealthCheckContext healthCheckContext) : base(healthCheckContext)
{
_textService = healthCheckContext.ApplicationContext.Services.TextService;
}
public override string XPath => "/settings/content/MacroErrors";
public override string FilePath
{
get { return "~/Config/umbracoSettings.config"; }
}
public override ValueComparisonType ValueComparisonType => ValueComparisonType.ShouldEqual;
public override string XPath
{
get { return "/settings/content/MacroErrors"; }
}
public override ValueComparisonType ValueComparisonType
{
get { return ValueComparisonType.ShouldEqual; }
}
public override IEnumerable<AcceptableConfiguration> Values
{
@@ -40,12 +52,12 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
return values;
}
}
public override string CheckSuccessMessage
{
get
{
return TextService.Localize("healthcheck/macroErrorModeCheckSuccessMessage",
return _textService.Localize("healthcheck/macroErrorModeCheckSuccessMessage",
new[] { CurrentValue, Values.First(v => v.IsRecommended).Value });
}
}
@@ -54,7 +66,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
{
get
{
return TextService.Localize("healthcheck/macroErrorModeCheckErrorMessage",
return _textService.Localize("healthcheck/macroErrorModeCheckErrorMessage",
new[] { CurrentValue, Values.First(v => v.IsRecommended).Value });
}
}
@@ -63,9 +75,9 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
{
get
{
return TextService.Localize("healthcheck/macroErrorModeCheckRectifySuccessMessage",
return _textService.Localize("healthcheck/macroErrorModeCheckRectifySuccessMessage",
new[] { Values.First(v => v.IsRecommended).Value });
}
}
}
}
}

View File

@@ -8,25 +8,48 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
Group = "Configuration")]
public class NotificationEmailCheck : AbstractConfigCheck
{
private readonly ILocalizedTextService _textService;
private const string DefaultFromEmail = "your@email.here";
public NotificationEmailCheck(ILocalizedTextService textService)
: base(textService)
{ }
public override string FilePath => "~/Config/umbracoSettings.config";
public override string XPath => "/settings/content/notifications/email";
public override ValueComparisonType ValueComparisonType => ValueComparisonType.ShouldNotEqual;
public override IEnumerable<AcceptableConfiguration> Values => new List<AcceptableConfiguration>
public NotificationEmailCheck(HealthCheckContext healthCheckContext) : base(healthCheckContext)
{
new AcceptableConfiguration { IsRecommended = false, Value = DefaultFromEmail }
};
_textService = healthCheckContext.ApplicationContext.Services.TextService;
}
public override string CheckSuccessMessage => TextService.Localize("healthcheck/notificationEmailsCheckSuccessMessage", new [] { CurrentValue } );
public override string FilePath
{
get { return "~/Config/umbracoSettings.config"; }
}
public override string CheckErrorMessage => TextService.Localize("healthcheck/notificationEmailsCheckErrorMessage", new[] { DefaultFromEmail });
public override string XPath
{
get { return "/settings/content/notifications/email"; }
}
public override ValueComparisonType ValueComparisonType
{
get { return ValueComparisonType.ShouldNotEqual; }
}
public override IEnumerable<AcceptableConfiguration> Values
{
get
{
return new List<AcceptableConfiguration>
{
new AcceptableConfiguration { IsRecommended = false, Value = DefaultFromEmail }
};
}
}
public override string CheckSuccessMessage
{
get { return _textService.Localize("healthcheck/notificationEmailsCheckSuccessMessage", new [] { CurrentValue } ); }
}
public override string CheckErrorMessage
{
get { return _textService.Localize("healthcheck/notificationEmailsCheckErrorMessage", new[] { DefaultFromEmail }); }
}
}
}
}

View File

@@ -8,26 +8,52 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
Group = "Live Environment")]
public class TraceCheck : AbstractConfigCheck
{
private readonly ILocalizedTextService _textService;
public TraceCheck(ILocalizedTextService textService)
: base(textService)
{ }
public override string FilePath => "~/Web.config";
public override string XPath => "/configuration/system.web/trace/@enabled";
public override ValueComparisonType ValueComparisonType => ValueComparisonType.ShouldEqual;
public override IEnumerable<AcceptableConfiguration> Values => new List<AcceptableConfiguration>
public TraceCheck(HealthCheckContext healthCheckContext) : base(healthCheckContext)
{
new AcceptableConfiguration { IsRecommended = true, Value = bool.FalseString.ToLower() }
};
_textService = healthCheckContext.ApplicationContext.Services.TextService;
}
public override string CheckSuccessMessage => TextService.Localize("healthcheck/traceModeCheckSuccessMessage");
public override string FilePath
{
get { return "~/Web.config"; }
}
public override string CheckErrorMessage => TextService.Localize("healthcheck/traceModeCheckErrorMessage");
public override string XPath
{
get { return "/configuration/system.web/trace/@enabled"; }
}
public override string RectifySuccessMessage => TextService.Localize("healthcheck/traceModeCheckRectifySuccessMessage");
public override ValueComparisonType ValueComparisonType
{
get { return ValueComparisonType.ShouldEqual; }
}
public override IEnumerable<AcceptableConfiguration> Values
{
get
{
return new List<AcceptableConfiguration>
{
new AcceptableConfiguration { IsRecommended = true, Value = bool.FalseString.ToLower() }
};
}
}
public override string CheckSuccessMessage
{
get { return _textService.Localize("healthcheck/traceModeCheckSuccessMessage"); }
}
public override string CheckErrorMessage
{
get { return _textService.Localize("healthcheck/traceModeCheckErrorMessage"); }
}
public override string RectifySuccessMessage
{
get { return _textService.Localize("healthcheck/traceModeCheckRectifySuccessMessage"); }
}
}
}
}

View File

@@ -12,16 +12,27 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
public class TrySkipIisCustomErrorsCheck : AbstractConfigCheck
{
private readonly Version _serverVersion = HttpRuntime.IISVersion;
private readonly ILocalizedTextService _textService;
public TrySkipIisCustomErrorsCheck(ILocalizedTextService textService)
: base(textService)
{ }
public TrySkipIisCustomErrorsCheck(HealthCheckContext healthCheckContext) : base(healthCheckContext)
{
_textService = healthCheckContext.ApplicationContext.Services.TextService;
}
public override string FilePath => "~/Config/umbracoSettings.config";
public override string FilePath
{
get { return "~/Config/umbracoSettings.config"; }
}
public override string XPath => "/settings/web.routing/@trySkipIisCustomErrors";
public override string XPath
{
get { return "/settings/web.routing/@trySkipIisCustomErrors"; }
}
public override ValueComparisonType ValueComparisonType => ValueComparisonType.ShouldEqual;
public override ValueComparisonType ValueComparisonType
{
get { return ValueComparisonType.ShouldEqual; }
}
public override IEnumerable<AcceptableConfiguration> Values
{
@@ -39,7 +50,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
{
get
{
return TextService.Localize("healthcheck/trySkipIisCustomErrorsCheckSuccessMessage",
return _textService.Localize("healthcheck/trySkipIisCustomErrorsCheckSuccessMessage",
new[] { Values.First(v => v.IsRecommended).Value, _serverVersion.ToString() });
}
}
@@ -48,7 +59,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
{
get
{
return TextService.Localize("healthcheck/trySkipIisCustomErrorsCheckErrorMessage",
return _textService.Localize("healthcheck/trySkipIisCustomErrorsCheckErrorMessage",
new[] { CurrentValue, Values.First(v => v.IsRecommended).Value, _serverVersion.ToString() });
}
}
@@ -57,9 +68,9 @@ namespace Umbraco.Web.HealthCheck.Checks.Config
{
get
{
return TextService.Localize("healthcheck/trySkipIisCustomErrorsCheckRectifySuccessMessage",
return _textService.Localize("healthcheck/trySkipIisCustomErrorsCheckRectifySuccessMessage",
new[] { Values.First(v => v.IsRecommended).Value, _serverVersion.ToString() });
}
}
}
}
}

View File

@@ -5,4 +5,4 @@
ShouldEqual,
ShouldNotEqual,
}
}
}

View File

@@ -1,8 +1,10 @@
using System;
using System;
using System.Collections.Generic;
using Umbraco.Core.Composing;
using Umbraco.Core;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Services;
using Umbraco.Web.PublishedCache;
namespace Umbraco.Web.HealthCheck.Checks.DataIntegrity
{
@@ -14,25 +16,26 @@ namespace Umbraco.Web.HealthCheck.Checks.DataIntegrity
"XML Data Integrity",
Description = "This checks the data integrity for the xml structures for content, media and members that are stored in the cmsContentXml table. This does not check the data integrity of the xml cache file, only the xml structures stored in the database used to create the xml cache file.",
Group = "Data Integrity")]
[HideFromTypeFinder] // only if running the Xml cache! added by XmlCacheComponent!
public class XmlDataIntegrityHealthCheck : HealthCheck
{
private readonly ILocalizedTextService _textService;
private readonly PublishedCache.XmlPublishedCache.PublishedSnapshotService _publishedSnapshotService;
private const string CheckContentXmlTableAction = "checkContentXmlTable";
private const string CheckMediaXmlTableAction = "checkMediaXmlTable";
private const string CheckMembersXmlTableAction = "checkMembersXmlTable";
public XmlDataIntegrityHealthCheck(ILocalizedTextService textService, IPublishedSnapshotService publishedSnapshotService)
public XmlDataIntegrityHealthCheck(HealthCheckContext healthCheckContext) : base(healthCheckContext)
{
_textService = textService;
_publishedSnapshotService = publishedSnapshotService as PublishedCache.XmlPublishedCache.PublishedSnapshotService;
if (_publishedSnapshotService == null)
throw new NotSupportedException("Unsupported IPublishedSnapshotService, only the Xml one is supported.");
_sqlSyntax = HealthCheckContext.ApplicationContext.DatabaseContext.SqlSyntax;
_services = HealthCheckContext.ApplicationContext.Services;
_database = HealthCheckContext.ApplicationContext.DatabaseContext.Database;
_textService = healthCheckContext.ApplicationContext.Services.TextService;
}
private readonly ISqlSyntaxProvider _sqlSyntax;
private readonly ServiceContext _services;
private readonly UmbracoDatabase _database;
/// <summary>
/// Get the status for this health check
/// </summary>
@@ -53,13 +56,13 @@ namespace Umbraco.Web.HealthCheck.Checks.DataIntegrity
switch (action.Alias)
{
case CheckContentXmlTableAction:
_publishedSnapshotService.RebuildContentAndPreviewXml();
_services.ContentService.RebuildXmlStructures();
return CheckContent();
case CheckMediaXmlTableAction:
_publishedSnapshotService.RebuildMediaXml();
_services.MediaService.RebuildXmlStructures();
return CheckMedia();
case CheckMembersXmlTableAction:
_publishedSnapshotService.RebuildMemberXml();
_services.MemberService.RebuildXmlStructures();
return CheckMembers();
default:
throw new ArgumentOutOfRangeException();
@@ -68,30 +71,128 @@ namespace Umbraco.Web.HealthCheck.Checks.DataIntegrity
private HealthCheckStatus CheckMembers()
{
return Check(_publishedSnapshotService.VerifyMemberXml(), CheckMembersXmlTableAction, "healthcheck/xmlDataIntegrityCheckMembers");
var total = _services.MemberService.Count();
var memberObjectType = Guid.Parse(Constants.ObjectTypes.Member);
var subQuery = new Sql()
.Select("Count(*)")
.From<ContentXmlDto>(_sqlSyntax)
.InnerJoin<NodeDto>(_sqlSyntax)
.On<ContentXmlDto, NodeDto>(_sqlSyntax, left => left.NodeId, right => right.NodeId)
.Where<NodeDto>(dto => dto.NodeObjectType == memberObjectType);
var totalXml = _database.ExecuteScalar<int>(subQuery);
var actions = new List<HealthCheckAction>();
if (totalXml != total)
actions.Add(new HealthCheckAction(CheckMembersXmlTableAction, Id));
return new HealthCheckStatus(_textService.Localize("healthcheck/xmlDataIntegrityCheckMembers", new[] { totalXml.ToString(), total.ToString(), (total - totalXml).ToString() }))
{
ResultType = totalXml == total ? StatusResultType.Success : StatusResultType.Error,
Actions = actions
};
}
/// <summary>
/// Checks the cmsContentXml table to see if the number of entries for media matches the number of media entities
/// </summary>
/// <returns></returns>
/// <remarks>
/// Further to just counting the data integrity, this also checks if the XML stored in the cmsContentXml table contains the correct
/// GUID identifier. In older versions of Umbraco, the GUID is not persisted to the content cache, that will cause problems in newer
/// versions of Umbraco, so the xml table would need a rebuild.
/// </remarks>
private HealthCheckStatus CheckMedia()
{
return Check(_publishedSnapshotService.VerifyMediaXml(), CheckMediaXmlTableAction, "healthcheck/xmlDataIntegrityCheckMedia");
var total = _services.MediaService.CountNotTrashed();
var mediaObjectType = Guid.Parse(Constants.ObjectTypes.Media);
//count entries
var countTotalSubQuery = new Sql()
.Select("Count(*)")
.From<ContentXmlDto>(_sqlSyntax)
.InnerJoin<NodeDto>(_sqlSyntax)
.On<ContentXmlDto, NodeDto>(_sqlSyntax, left => left.NodeId, right => right.NodeId)
.Where<NodeDto>(dto => dto.NodeObjectType == mediaObjectType);
var totalXml = _database.ExecuteScalar<int>(countTotalSubQuery);
//count invalid entries
var countNonGuidQuery = new Sql()
.Select("Count(*)")
.From<ContentXmlDto>(_sqlSyntax)
.InnerJoin<NodeDto>(_sqlSyntax)
.On<ContentXmlDto, NodeDto>(_sqlSyntax, left => left.NodeId, right => right.NodeId)
.Where<NodeDto>(dto => dto.NodeObjectType == mediaObjectType)
.Where(string.Format("{0}.{1} NOT LIKE '% key=\"%'", _sqlSyntax.GetQuotedTableName("cmsContentXml"), _sqlSyntax.GetQuotedColumnName("xml")));
var totalNonGuidXml = _database.ExecuteScalar<int>(countNonGuidQuery);
var hasError = false;
var actions = new List<HealthCheckAction>();
if (totalXml != total || totalNonGuidXml > 0)
{
//if the counts don't match
actions.Add(new HealthCheckAction(CheckMediaXmlTableAction, Id));
hasError = true;
}
return new HealthCheckStatus(_textService.Localize("healthcheck/xmlDataIntegrityCheckMedia",
new[] { totalXml.ToString(), total.ToString(), totalNonGuidXml.ToString() }))
{
ResultType = hasError == false
? StatusResultType.Success
: StatusResultType.Error,
Actions = actions
};
}
/// <summary>
/// Checks the cmsContentXml table to see if the number of entries for content matches the number of published content entities
/// </summary>
/// <returns></returns>
/// <remarks>
/// Further to just counting the data integrity, this also checks if the XML stored in the cmsContentXml table contains the correct
/// GUID identifier. In older versions of Umbraco, the GUID is not persisted to the content cache, that will cause problems in newer
/// versions of Umbraco, so the xml table would need a rebuild.
/// </remarks>
private HealthCheckStatus CheckContent()
{
return Check(_publishedSnapshotService.VerifyContentAndPreviewXml(), CheckContentXmlTableAction, "healthcheck/xmlDataIntegrityCheckContent");
}
var total = _services.ContentService.CountPublished();
var documentObjectType = Guid.Parse(Constants.ObjectTypes.Document);
private HealthCheckStatus Check(bool ok, string action, string text)
{
//count entires
var countTotalSubQuery = new Sql()
.Select(string.Format("DISTINCT {0}.{1}", _sqlSyntax.GetQuotedTableName("cmsContentXml"), _sqlSyntax.GetQuotedColumnName("nodeId")))
.From<ContentXmlDto>(_sqlSyntax)
.InnerJoin<DocumentDto>(_sqlSyntax)
.On<DocumentDto, ContentXmlDto>(_sqlSyntax, left => left.NodeId, right => right.NodeId);
var totalXml = _database.ExecuteScalar<int>("SELECT COUNT(*) FROM (" + countTotalSubQuery.SQL + ") as tmp");
//count invalid entries
var countNonGuidQuery = new Sql()
.Select("Count(*)")
.From<ContentXmlDto>(_sqlSyntax)
.InnerJoin<NodeDto>(_sqlSyntax)
.On<ContentXmlDto, NodeDto>(_sqlSyntax, left => left.NodeId, right => right.NodeId)
.Where<NodeDto>(dto => dto.NodeObjectType == documentObjectType)
.Where(string.Format("{0}.{1} NOT LIKE '% key=\"%'", _sqlSyntax.GetQuotedTableName("cmsContentXml"), _sqlSyntax.GetQuotedColumnName("xml")));
var totalNonGuidXml = _database.ExecuteScalar<int>(countNonGuidQuery);
var hasError = false;
var actions = new List<HealthCheckAction>();
if (ok == false)
actions.Add(new HealthCheckAction(action, Id));
return new HealthCheckStatus(_textService.Localize(text, new[] { ok ? "ok" : "not ok" }))
if (totalXml != total || totalNonGuidXml > 0)
{
ResultType = ok ? StatusResultType.Success : StatusResultType.Error,
//if the counts don't match
actions.Add(new HealthCheckAction(CheckContentXmlTableAction, Id));
hasError = true;
}
return new HealthCheckStatus(_textService.Localize("healthcheck/xmlDataIntegrityCheckContent",
new[] { totalXml.ToString(), total.ToString(), totalNonGuidXml.ToString() }))
{
ResultType = hasError == false
? StatusResultType.Success
: StatusResultType.Error,
Actions = actions
};
}
}
}
}

View File

@@ -28,9 +28,9 @@ namespace Umbraco.Web.HealthCheck.Checks.Permissions
{
private readonly ILocalizedTextService _textService;
public FolderAndFilePermissionsCheck(ILocalizedTextService textService)
public FolderAndFilePermissionsCheck(HealthCheckContext healthCheckContext) : base(healthCheckContext)
{
_textService = textService;
_textService = healthCheckContext.ApplicationContext.Services.TextService;
}
/// <summary>
@@ -69,8 +69,10 @@ namespace Umbraco.Web.HealthCheck.Checks.Permissions
{ SystemDirectories.Media, PermissionCheckRequirement.Optional },
{ SystemDirectories.Scripts, PermissionCheckRequirement.Optional },
{ SystemDirectories.Umbraco, PermissionCheckRequirement.Optional },
{ SystemDirectories.UmbracoClient, PermissionCheckRequirement.Optional },
{ SystemDirectories.UserControls, PermissionCheckRequirement.Optional },
{ SystemDirectories.MvcViews, PermissionCheckRequirement.Optional }
{ SystemDirectories.MvcViews, PermissionCheckRequirement.Optional },
{ SystemDirectories.Xslt, PermissionCheckRequirement.Optional },
};
//These are special paths to check that will restart an app domain if a file is written to them,
@@ -82,16 +84,16 @@ namespace Umbraco.Web.HealthCheck.Checks.Permissions
};
// Run checks for required and optional paths for modify permission
var requiredPathCheckResult = FilePermissionHelper.EnsureDirectories(
GetPathsToCheck(pathsToCheck, PermissionCheckRequirement.Required), out var requiredFailedPaths);
var optionalPathCheckResult = FilePermissionHelper.EnsureDirectories(
GetPathsToCheck(pathsToCheck, PermissionCheckRequirement.Optional), out var optionalFailedPaths);
List<string> requiredFailedPaths;
List<string> optionalFailedPaths;
var requiredPathCheckResult = FilePermissionHelper.TestDirectories(GetPathsToCheck(pathsToCheck, PermissionCheckRequirement.Required), out requiredFailedPaths);
var optionalPathCheckResult = FilePermissionHelper.TestDirectories(GetPathsToCheck(pathsToCheck, PermissionCheckRequirement.Optional), out optionalFailedPaths);
//now check the special folders
var requiredPathCheckResult2 = FilePermissionHelper.EnsureDirectories(
GetPathsToCheck(pathsToCheckWithRestarts, PermissionCheckRequirement.Required), out var requiredFailedPaths2, writeCausesRestart:true);
var optionalPathCheckResult2 = FilePermissionHelper.EnsureDirectories(
GetPathsToCheck(pathsToCheckWithRestarts, PermissionCheckRequirement.Optional), out var optionalFailedPaths2, writeCausesRestart: true);
List<string> requiredFailedPaths2;
List<string> optionalFailedPaths2;
var requiredPathCheckResult2 = FilePermissionHelper.TestDirectories(GetPathsToCheck(pathsToCheckWithRestarts, PermissionCheckRequirement.Required), out requiredFailedPaths2, writeCausesRestart:true);
var optionalPathCheckResult2 = FilePermissionHelper.TestDirectories(GetPathsToCheck(pathsToCheckWithRestarts, PermissionCheckRequirement.Optional), out optionalFailedPaths2, writeCausesRestart: true);
requiredPathCheckResult = requiredPathCheckResult && requiredPathCheckResult2;
optionalPathCheckResult = optionalPathCheckResult && optionalPathCheckResult2;
@@ -113,10 +115,10 @@ namespace Umbraco.Web.HealthCheck.Checks.Permissions
};
// Run checks for required and optional paths for modify permission
IEnumerable<string> requiredFailedPaths;
IEnumerable<string> optionalFailedPaths;
var requiredPathCheckResult = FilePermissionHelper.EnsureFiles(GetPathsToCheck(pathsToCheck, PermissionCheckRequirement.Required), out requiredFailedPaths);
var optionalPathCheckResult = FilePermissionHelper.EnsureFiles(GetPathsToCheck(pathsToCheck, PermissionCheckRequirement.Optional), out optionalFailedPaths);
List<string> requiredFailedPaths;
List<string> optionalFailedPaths;
var requiredPathCheckResult = FilePermissionHelper.TestFiles(GetPathsToCheck(pathsToCheck, PermissionCheckRequirement.Required), out requiredFailedPaths);
var optionalPathCheckResult = FilePermissionHelper.TestFiles(GetPathsToCheck(pathsToCheck, PermissionCheckRequirement.Optional), out optionalFailedPaths);
return GetStatus(requiredPathCheckResult, requiredFailedPaths, optionalPathCheckResult, optionalFailedPaths, PermissionCheckFor.File);
}
@@ -131,7 +133,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Permissions
.ToArray();
}
private HealthCheckStatus GetStatus(bool requiredPathCheckResult, IEnumerable<string> requiredFailedPaths,
private HealthCheckStatus GetStatus(bool requiredPathCheckResult, List<string> requiredFailedPaths,
bool optionalPathCheckResult, IEnumerable<string> optionalFailedPaths,
PermissionCheckFor checkingFor)
{
@@ -178,4 +180,4 @@ namespace Umbraco.Web.HealthCheck.Checks.Permissions
return filePath.Replace(rootFolder, string.Empty);
}
}
}
}

View File

@@ -6,7 +6,6 @@ using System.Net;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using System.Xml.XPath;
using Umbraco.Core;
using Umbraco.Core.IO;
using Umbraco.Core.Services;
@@ -14,8 +13,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
{
public abstract class BaseHttpHeaderCheck : HealthCheck
{
protected IRuntimeState Runtime { get; }
protected ILocalizedTextService TextService { get; }
private readonly ILocalizedTextService _textService;
private const string SetHeaderInConfigAction = "setHeaderInConfig";
@@ -24,13 +22,10 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
private readonly string _localizedTextPrefix;
private readonly bool _metaTagOptionAvailable;
protected BaseHttpHeaderCheck(
IRuntimeState runtime,
ILocalizedTextService textService,
string header, string value, string localizedTextPrefix, bool metaTagOptionAvailable)
public BaseHttpHeaderCheck(HealthCheckContext healthCheckContext,
string header, string value, string localizedTextPrefix, bool metaTagOptionAvailable) : base(healthCheckContext)
{
Runtime = runtime;
TextService = textService ?? throw new ArgumentNullException(nameof(textService));
_textService = healthCheckContext.ApplicationContext.Services.TextService;
_header = header;
_value = value;
@@ -70,7 +65,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
var success = false;
// Access the site home page and check for the click-jack protection header or meta tag
var url = Runtime.ApplicationUrl;
var url = HealthCheckContext.SiteUrl;
var request = WebRequest.Create(url);
request.Method = "GET";
try
@@ -87,12 +82,12 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
}
message = success
? TextService.Localize($"healthcheck/{_localizedTextPrefix}CheckHeaderFound")
: TextService.Localize($"healthcheck/{_localizedTextPrefix}CheckHeaderNotFound");
? _textService.Localize(string.Format("healthcheck/{0}CheckHeaderFound", _localizedTextPrefix))
: _textService.Localize(string.Format("healthcheck/{0}CheckHeaderNotFound", _localizedTextPrefix));
}
catch (Exception ex)
{
message = TextService.Localize("healthcheck/healthCheckInvalidUrl", new[] { url.ToString(), ex.Message });
message = _textService.Localize("healthcheck/healthCheckInvalidUrl", new[] { url, ex.Message });
}
var actions = new List<HealthCheckAction>();
@@ -100,8 +95,8 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
{
actions.Add(new HealthCheckAction(SetHeaderInConfigAction, Id)
{
Name = TextService.Localize("healthcheck/setHeaderInConfig"),
Description = TextService.Localize($"healthcheck/{_localizedTextPrefix}SetHeaderInConfigDescription")
Name = _textService.Localize("healthcheck/setHeaderInConfig"),
Description = _textService.Localize(string.Format("healthcheck/{0}SetHeaderInConfigDescription", _localizedTextPrefix))
});
}
@@ -149,14 +144,14 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
if (success)
{
return
new HealthCheckStatus(TextService.Localize(string.Format("healthcheck/{0}SetHeaderInConfigSuccess", _localizedTextPrefix)))
new HealthCheckStatus(_textService.Localize(string.Format("healthcheck/{0}SetHeaderInConfigSuccess", _localizedTextPrefix)))
{
ResultType = StatusResultType.Success
};
}
return
new HealthCheckStatus(TextService.Localize("healthcheck/setHeaderInConfigError", new [] { errorMessage }))
new HealthCheckStatus(_textService.Localize("healthcheck/setHeaderInConfigError", new [] { errorMessage }))
{
ResultType = StatusResultType.Error
};

View File

@@ -1,7 +1,4 @@
using Umbraco.Core;
using Umbraco.Core.Services;
namespace Umbraco.Web.HealthCheck.Checks.Security
namespace Umbraco.Web.HealthCheck.Checks.Security
{
[HealthCheck(
"ED0D7E40-971E-4BE8-AB6D-8CC5D0A6A5B0",
@@ -10,8 +7,8 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
Group = "Security")]
public class ClickJackingCheck : BaseHttpHeaderCheck
{
public ClickJackingCheck(IRuntimeState runtime, ILocalizedTextService textService)
: base(runtime, textService, "X-Frame-Options", "sameorigin", "clickJacking", true)
public ClickJackingCheck(HealthCheckContext healthCheckContext)
: base(healthCheckContext, "X-Frame-Options", "sameorigin", "clickJacking", true)
{
}
}

View File

@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
using Umbraco.Core;
using Umbraco.Core.Services;
namespace Umbraco.Web.HealthCheck.Checks.Security
@@ -15,14 +14,10 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
public class ExcessiveHeadersCheck : HealthCheck
{
private readonly ILocalizedTextService _textService;
private readonly IRuntimeState _runtime;
private readonly IHttpContextAccessor _httpContextAccessor;
public ExcessiveHeadersCheck(ILocalizedTextService textService, IRuntimeState runtime, IHttpContextAccessor httpContextAccessor)
public ExcessiveHeadersCheck(HealthCheckContext healthCheckContext) : base(healthCheckContext)
{
_textService = textService;
_runtime = runtime;
_httpContextAccessor = httpContextAccessor;
_textService = healthCheckContext.ApplicationContext.Services.TextService;
}
/// <summary>
@@ -49,9 +44,9 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
{
var message = string.Empty;
var success = false;
var url = _runtime.ApplicationUrl;
// Access the site home page and check for the headers
var url = HealthCheckContext.SiteUrl;
// Access the site home page and check for the headers
var request = WebRequest.Create(url);
request.Method = "HEAD";
try
@@ -69,7 +64,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
}
catch (Exception ex)
{
message = _textService.Localize("healthcheck/httpsCheckInvalidUrl", new[] { url.ToString(), ex.Message });
message = _textService.Localize("healthcheck/healthCheckInvalidUrl", new[] { url, ex.Message });
}
var actions = new List<HealthCheckAction>();

View File

@@ -1,7 +1,4 @@
using Umbraco.Core;
using Umbraco.Core.Services;
namespace Umbraco.Web.HealthCheck.Checks.Security
namespace Umbraco.Web.HealthCheck.Checks.Security
{
[HealthCheck(
"E2048C48-21C5-4BE1-A80B-8062162DF124",
@@ -15,8 +12,8 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
// and the blogpost of Troy Hunt (https://www.troyhunt.com/understanding-http-strict-transport/)
// If you want do to it perfectly, you have to submit it https://hstspreload.appspot.com/,
// but then you should include subdomains and I wouldn't suggest to do that for Umbraco-sites.
public HstsCheck(IRuntimeState runtime, ILocalizedTextService textService)
: base(runtime, textService, "Strict-Transport-Security", "max-age=10886400; preload", "hSTS", true)
public HstsCheck(HealthCheckContext healthCheckContext)
: base(healthCheckContext, "Strict-Transport-Security", "max-age=10886400; preload", "hSTS", true)
{
}
}

View File

@@ -3,8 +3,6 @@ using System.Collections.Generic;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Web;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Services;
using Umbraco.Web.HealthCheck.Checks.Config;
@@ -19,16 +17,12 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
public class HttpsCheck : HealthCheck
{
private readonly ILocalizedTextService _textService;
private readonly IRuntimeState _runtime;
private readonly IGlobalSettings _globalSettings;
private const string FixHttpsSettingAction = "fixHttpsSetting";
public HttpsCheck(ILocalizedTextService textService, IRuntimeState runtime, IGlobalSettings globalSettings)
public HttpsCheck(HealthCheckContext healthCheckContext) : base(healthCheckContext)
{
_textService = textService;
_runtime = runtime;
_globalSettings = globalSettings;
_textService = healthCheckContext.ApplicationContext.Services.TextService;
}
/// <summary>
@@ -62,10 +56,10 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
var message = string.Empty;
StatusResultType result;
// Attempt to access the site over HTTPS to see if it HTTPS is supported
// Attempt to access the site over HTTPS to see if it HTTPS is supported
// and a valid certificate has been configured
var url = _runtime.ApplicationUrl.ToString().Replace("http:", "https:");
var request = (HttpWebRequest) WebRequest.Create(url);
var url = HealthCheckContext.SiteUrl.Replace("http:", "https:");
var request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "HEAD";
try
@@ -132,7 +126,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
private HealthCheckStatus CheckIfCurrentSchemeIsHttps()
{
var uri = _runtime.ApplicationUrl;
var uri = new Uri(HealthCheckContext.SiteUrl);
var success = uri.Scheme == "https";
var actions = new List<HealthCheckAction>();
@@ -147,8 +141,8 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
private HealthCheckStatus CheckHttpsConfigurationSetting()
{
var httpsSettingEnabled = _globalSettings.UseHttps;
var uri = _runtime.ApplicationUrl;
var httpsSettingEnabled = Core.Configuration.GlobalSettings.UseSSL;
var uri = new Uri(HealthCheckContext.SiteUrl);
var actions = new List<HealthCheckAction>();
string resultMessage;
@@ -171,7 +165,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
new[] {httpsSettingEnabled.ToString(), httpsSettingEnabled ? string.Empty : "not"});
resultType = httpsSettingEnabled ? StatusResultType.Success: StatusResultType.Error;
}
return
new HealthCheckStatus(resultMessage)
{

View File

@@ -1,7 +1,4 @@
using Umbraco.Core;
using Umbraco.Core.Services;
namespace Umbraco.Web.HealthCheck.Checks.Security
namespace Umbraco.Web.HealthCheck.Checks.Security
{
[HealthCheck(
"1CF27DB3-EFC0-41D7-A1BB-EA912064E071",
@@ -10,8 +7,8 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
Group = "Security")]
public class NoSniffCheck : BaseHttpHeaderCheck
{
public NoSniffCheck(IRuntimeState runtime, ILocalizedTextService textService)
: base(runtime, textService, "X-Content-Type-Options", "nosniff", "noSniff", false)
public NoSniffCheck(HealthCheckContext healthCheckContext)
: base(healthCheckContext, "X-Content-Type-Options", "nosniff", "noSniff", false)
{
}
}

View File

@@ -1,7 +1,4 @@
using Umbraco.Core;
using Umbraco.Core.Services;
namespace Umbraco.Web.HealthCheck.Checks.Security
namespace Umbraco.Web.HealthCheck.Checks.Security
{
[HealthCheck(
"F4D2B02E-28C5-4999-8463-05759FA15C3A",
@@ -15,8 +12,8 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
// and the blogpost of Troy Hunt (https://www.troyhunt.com/understanding-http-strict-transport/)
// If you want do to it perfectly, you have to submit it https://hstspreload.appspot.com/,
// but then you should include subdomains and I wouldn't suggest to do that for Umbraco-sites.
public XssProtectionCheck(IRuntimeState runtime, ILocalizedTextService textService)
: base(runtime, textService, "X-XSS-Protection", "1; mode=block", "xssProtection", true)
public XssProtectionCheck(HealthCheckContext healthCheckContext)
: base(healthCheckContext, "X-XSS-Protection", "1; mode=block", "xssProtection", true)
{
}
}

View File

@@ -4,7 +4,6 @@ using System.IO;
using System.Net.Configuration;
using System.Net.Sockets;
using System.Web.Configuration;
using Umbraco.Core;
using Umbraco.Core.Services;
namespace Umbraco.Web.HealthCheck.Checks.Services
@@ -17,12 +16,10 @@ namespace Umbraco.Web.HealthCheck.Checks.Services
public class SmtpCheck : HealthCheck
{
private readonly ILocalizedTextService _textService;
private readonly IRuntimeState _runtime;
public SmtpCheck(ILocalizedTextService textService, IRuntimeState runtime)
public SmtpCheck(HealthCheckContext healthCheckContext) : base(healthCheckContext)
{
_textService = textService;
_runtime = runtime;
_textService = healthCheckContext.ApplicationContext.Services.TextService;
}
/// <summary>
@@ -51,8 +48,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Services
var message = string.Empty;
var success = false;
// appPath is the virtual application root path on the server
var config = WebConfigurationManager.OpenWebConfiguration(_runtime.ApplicationVirtualPath);
var config = WebConfigurationManager.OpenWebConfiguration(HealthCheckContext.ApplicationPath);
var settings = (MailSettingsSectionGroup)config.GetSectionGroup("system.net/mailSettings");
if (settings == null)
{
@@ -110,4 +106,4 @@ namespace Umbraco.Web.HealthCheck.Checks.Services
}
}
}
}
}

View File

@@ -1,30 +1,35 @@
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using umbraco.interfaces;
using Umbraco.Core;
using Umbraco.Core.Composing;
namespace Umbraco.Web.HealthCheck
{
/// <summary>
/// Provides a base class for health checks.
/// The abstract health check class
/// </summary>
[DataContract(Name = "healtCheck", Namespace = "")]
public abstract class HealthCheck : IDiscoverable
{
protected HealthCheck()
protected HealthCheck(HealthCheckContext healthCheckContext)
{
HealthCheckContext = healthCheckContext;
//Fill in the metadata
var thisType = GetType();
var thisType = this.GetType();
var meta = thisType.GetCustomAttribute<HealthCheckAttribute>(false);
if (meta == null)
throw new InvalidOperationException($"The health check {thisType} requires a {typeof (HealthCheckAttribute)}");
throw new InvalidOperationException(
string.Format("The health check {0} requires a {1}", thisType, typeof(HealthCheckAttribute)));
Name = meta.Name;
Description = meta.Description;
Group = meta.Group;
Id = meta.Id;
}
[IgnoreDataMember]
public HealthCheckContext HealthCheckContext { get; private set; }
[DataMember(Name = "id")]
public Guid Id { get; private set; }
@@ -51,5 +56,6 @@ namespace Umbraco.Web.HealthCheck
public abstract HealthCheckStatus ExecuteAction(HealthCheckAction action);
//TODO: What else?
}
}
}

View File

@@ -1,8 +1,7 @@
using System;
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using Umbraco.Core.Services;
using Umbraco.Web.Composing;
namespace Umbraco.Web.HealthCheck
{
@@ -47,6 +46,7 @@ namespace Umbraco.Web.HealthCheck
[DataMember(Name = "actionParameters")]
public Dictionary<string, object> ActionParameters { get; set; }
/// <summary>
/// The name of the action - this is used to name the fix button
/// </summary>

View File

@@ -1,4 +1,4 @@
using System;
using System;
namespace Umbraco.Web.HealthCheck
{
@@ -7,7 +7,7 @@ namespace Umbraco.Web.HealthCheck
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class HealthCheckAttribute : Attribute
{
{
public HealthCheckAttribute(string id, string name)
{
Id = new Guid(id);
@@ -23,4 +23,4 @@ namespace Umbraco.Web.HealthCheck
//TODO: Do we need more metadata?
}
}
}

View File

@@ -1,12 +0,0 @@
using System.Collections.Generic;
using Umbraco.Core.Composing;
namespace Umbraco.Web.HealthCheck
{
public class HealthCheckCollection : BuilderCollectionBase<HealthCheck>
{
public HealthCheckCollection(IEnumerable<HealthCheck> items)
: base(items)
{ }
}
}

View File

@@ -0,0 +1,52 @@
using System;
using System.Web;
using Umbraco.Core;
namespace Umbraco.Web.HealthCheck
{
/// <summary>
/// Context exposing all services that could be required for health check classes to perform and/or fix their checks
/// </summary>
public class HealthCheckContext
{
private readonly HttpContextBase _httpContext;
private readonly UmbracoContext _umbracoContext;
public HealthCheckContext(HttpContextBase httpContext, UmbracoContext umbracoContext)
{
if (httpContext == null) throw new ArgumentNullException("httpContext");
if (umbracoContext == null) throw new ArgumentNullException("umbracoContext");
_httpContext = httpContext;
_umbracoContext = umbracoContext;
ApplicationContext = _umbracoContext.Application;
}
public HealthCheckContext(ApplicationContext applicationContext)
{
ApplicationContext = applicationContext;
}
public ApplicationContext ApplicationContext { get; private set; }
public string SiteUrl
{
get
{
return _httpContext != null
? _httpContext.Request.Url.GetLeftPart(UriPartial.Authority)
: ApplicationContext.UmbracoApplicationUrl.Replace("/umbraco", string.Empty);
}
}
public string ApplicationPath
{
get
{
return _httpContext != null
? _httpContext.Request.ApplicationPath
: "/";
}
}
}
}

View File

@@ -1,10 +1,9 @@
using System;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Linq;
using System.Web.Http;
using Umbraco.Core.Logging;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.HealthChecks;
using Umbraco.Web.Editors;
@@ -15,17 +14,15 @@ namespace Umbraco.Web.HealthCheck
/// <summary>
/// The API controller used to display the health check info and execute any actions
/// </summary>
[UmbracoApplicationAuthorize(Core.Constants.Applications.Settings)]
[UmbracoApplicationAuthorize(Core.Constants.Applications.Developer)]
public class HealthCheckController : UmbracoAuthorizedJsonController
{
private readonly HealthCheckCollection _checks;
private readonly IHealthCheckResolver _healthCheckResolver;
private readonly IList<Guid> _disabledCheckIds;
private readonly ILogger _logger;
public HealthCheckController(HealthCheckCollection checks, ILogger logger)
public HealthCheckController()
{
_checks = checks ?? throw new ArgumentNullException(nameof(checks));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_healthCheckResolver = HealthCheckResolver.Current;
var healthCheckConfig = UmbracoConfig.For.HealthCheck();
_disabledCheckIds = healthCheckConfig.DisabledChecks
@@ -33,13 +30,35 @@ namespace Umbraco.Web.HealthCheck
.ToList();
}
[Obsolete("Use the contructor specifying all parameters instead")]
[EditorBrowsable(EditorBrowsableState.Never)]
public HealthCheckController(IHealthCheckResolver healthCheckResolver)
{
_healthCheckResolver = healthCheckResolver;
var healthCheckConfig = UmbracoConfig.For.HealthCheck();
_disabledCheckIds = healthCheckConfig.DisabledChecks
.Select(x => x.Id)
.ToList();
}
public HealthCheckController(IHealthCheckResolver healthCheckResolver, IHealthChecks healthCheckConfig)
{
if (healthCheckResolver == null) throw new ArgumentNullException("healthCheckResolver");
if (healthCheckConfig == null) throw new ArgumentNullException("healthCheckConfig");
_healthCheckResolver = healthCheckResolver;
_disabledCheckIds = healthCheckConfig.DisabledChecks
.Select(x => x.Id)
.ToList();
}
/// <summary>
/// Gets a grouped list of health checks, but doesn't actively check the status of each health check.
/// </summary>
/// <returns>Returns a collection of anonymous objects representing each group.</returns>
public object GetAllHealthChecks()
{
var groups = _checks
var groups = _healthCheckResolver.HealthChecks
.Where(x => _disabledCheckIds.Contains(x.Id) == false)
.GroupBy(x => x.Group)
.OrderBy(x => x.Key);
@@ -63,15 +82,15 @@ namespace Umbraco.Web.HealthCheck
public object GetStatus(Guid id)
{
var check = GetCheckById(id);
try
{
//Core.Logging.LogHelper.Debug<HealthCheckController>("Running health check: " + check.Name);
return check.GetStatus();
}
catch (Exception ex)
catch (Exception e)
{
_logger.Error<HealthCheckController>(ex, "Exception in health check: {HealthCheckName}", check.Name);
Core.Logging.LogHelper.Error<HealthCheckController>("Exception in health check: " + check.Name, e);
throw;
}
}
@@ -85,13 +104,13 @@ namespace Umbraco.Web.HealthCheck
private HealthCheck GetCheckById(Guid id)
{
var check = _checks
var check = _healthCheckResolver.HealthChecks
.Where(x => _disabledCheckIds.Contains(x.Id) == false)
.FirstOrDefault(x => x.Id == id);
if (check == null) throw new InvalidOperationException($"No health check found with id {id}");
if (check == null) throw new InvalidOperationException(string.Format("No health check found with id {0}", id));
return check;
}
}
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
namespace Umbraco.Web.HealthCheck
{
@@ -7,12 +7,12 @@ namespace Umbraco.Web.HealthCheck
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class HealthCheckNotificationMethodAttribute : Attribute
{
{
public HealthCheckNotificationMethodAttribute(string alias)
{
Alias = alias;
}
public string Alias { get; }
public string Alias { get; private set; }
}
}
}

View File

@@ -1,13 +0,0 @@
using System.Collections.Generic;
using Umbraco.Core.Composing;
using Umbraco.Web.HealthCheck.NotificationMethods;
namespace Umbraco.Web.HealthCheck
{
public class HealthCheckNotificationMethodCollection : BuilderCollectionBase<IHealthCheckNotificationMethod>
{
public HealthCheckNotificationMethodCollection(IEnumerable<IHealthCheckNotificationMethod> items)
: base(items)
{ }
}
}

View File

@@ -1,15 +0,0 @@
using LightInject;
using Umbraco.Core.Composing;
using Umbraco.Web.HealthCheck.NotificationMethods;
namespace Umbraco.Web.HealthCheck
{
internal class HealthCheckNotificationMethodCollectionBuilder : LazyCollectionBuilderBase<HealthCheckNotificationMethodCollectionBuilder, HealthCheckNotificationMethodCollection, IHealthCheckNotificationMethod>
{
public HealthCheckNotificationMethodCollectionBuilder(IServiceContainer container)
: base(container)
{ }
protected override HealthCheckNotificationMethodCollectionBuilder This => this;
}
}

View File

@@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Configuration;
using System.Reflection;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.ObjectResolution;
using Umbraco.Web.HealthCheck.NotificationMethods;
using Umbraco.Core.Configuration.HealthChecks;
namespace Umbraco.Web.HealthCheck
{
/// <summary>
/// Resolves all health check instances
/// </summary>
/// <remarks>
/// Each instance scoped to the lifespan of the http request
/// </remarks>
internal class HealthCheckNotificationMethodResolver : LazyManyObjectsResolverBase<HealthCheckNotificationMethodResolver, IHealthCheckNotificatationMethod>, IHealthCheckNotificationMethodsResolver
{
public HealthCheckNotificationMethodResolver(ILogger logger, Func<IEnumerable<Type>> lazyTypeList)
: base(new HealthCheckNotificationMethodServiceProvider(), logger, lazyTypeList, ObjectLifetimeScope.Application)
{
}
/// <summary>
/// Returns all health check notification method instances
/// </summary>
public IEnumerable<IHealthCheckNotificatationMethod> NotificationMethods
{
get { return Values; }
}
/// <summary>
/// This will ctor the IHealthCheckNotificatationMethod instances
/// </summary>
private class HealthCheckNotificationMethodServiceProvider : IServiceProvider
{
public object GetService(Type serviceType)
{
var ctor = serviceType.GetConstructors().FirstOrDefault();
if (ctor == null)
{
return null;
}
// Load attribute from type in order to find alias for notification method
var attribute = serviceType.GetCustomAttributes(typeof(HealthCheckNotificationMethodAttribute), true)
.FirstOrDefault() as HealthCheckNotificationMethodAttribute;
if (attribute == null)
{
return null;
}
// Using alias, get related configuration
var healthCheckConfig = UmbracoConfig.For.HealthCheck();
var notificationMethods = healthCheckConfig.NotificationSettings.NotificationMethods;
var notificationMethod = notificationMethods[attribute.Alias];
// Create array for constructor paramenters. Will consists of common ones that all notification methods have as well
// as those specific to this particular notification method.
var baseType = typeof(NotificationMethodBase);
var baseTypeCtor = baseType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance).First();
var baseTypeCtorParamNames = baseTypeCtor.GetParameters().Select(x => x.Name);
List<object> ctorParams;
if (notificationMethod != null)
{
// configuration found so set ctorParams to config values
ctorParams = new List<object>
{
notificationMethod.Enabled,
notificationMethod.FailureOnly,
notificationMethod.Verbosity
};
ctorParams.AddRange(ctor.GetParameters()
.Where(x => baseTypeCtorParamNames.Contains(x.Name) == false)
.Select(x => notificationMethod.Settings[x.Name].Value));
}
else
{
// no configuration found so set to default values, enabled = false
ctorParams = new List<object> { false, false, HealthCheckNotificationVerbosity.Detailed };
ctorParams.AddRange(ctor.GetParameters()
.Where(x => baseTypeCtorParamNames.Contains(x.Name) == false)
.Select(x => string.Empty));
}
// Instantiate the type with the constructor parameters
return Activator.CreateInstance(serviceType, ctorParams.ToArray());
}
}
}
}

View File

@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Web;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.ObjectResolution;
namespace Umbraco.Web.HealthCheck
{
/// <summary>
/// Resolves all health check instances
/// </summary>
/// <remarks>
/// Each instance scoped to the lifespan of the http request
/// </remarks>
public class HealthCheckResolver : LazyManyObjectsResolverBase<HealthCheckResolver, HealthCheck>, IHealthCheckResolver
{
public HealthCheckResolver(ILogger logger, Func<IEnumerable<Type>> lazyTypeList)
: base(new HealthCheckServiceProvider(), logger, lazyTypeList, ObjectLifetimeScope.Application)
{
}
/// <summary>
/// Returns all health check instances
/// </summary>
public IEnumerable<HealthCheck> HealthChecks
{
get { return Values; }
}
/// <summary>
/// This will ctor the HealthCheck instances
/// </summary>
/// <remarks>
/// This is like a super crappy DI - in v8 we have real DI
/// </remarks>
private class HealthCheckServiceProvider : IServiceProvider
{
public object GetService(Type serviceType)
{
var normalArgs = new[] { typeof(HealthCheckContext) };
var found = serviceType.GetConstructor(normalArgs);
if (found != null)
{
var gotUmbracoContext = UmbracoContext.Current != null;
var healthCheckContext = gotUmbracoContext
? new HealthCheckContext(new HttpContextWrapper(HttpContext.Current), UmbracoContext.Current)
: new HealthCheckContext(ApplicationContext.Current);
return found.Invoke(new object[]
{
healthCheckContext
});
}
//use normal ctor
return Activator.CreateInstance(serviceType);
}
}
}
}

View File

@@ -2,8 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HeyRed.MarkdownSharp;
using Umbraco.Core.Composing;
using MarkdownSharp;
using Umbraco.Core.Configuration.HealthChecks;
using Umbraco.Core.Logging;
@@ -14,12 +13,10 @@ namespace Umbraco.Web.HealthCheck
private readonly Dictionary<string, IEnumerable<HealthCheckStatus>> _results;
public readonly bool AllChecksSuccessful;
private ILogger Logger => Current.Logger; // fixme inject
public HealthCheckResults(IEnumerable<HealthCheck> checks)
{
_results = checks.ToDictionary(
t => t.Name,
t => t.Name,
t => {
try
{
@@ -27,8 +24,8 @@ namespace Umbraco.Web.HealthCheck
}
catch (Exception ex)
{
Logger.Error<HealthCheckResults>(ex, "Error running scheduled health check: {HealthCheckName}", t.Name);
var message = $"Health check failed with exception: {ex.Message}. See logs for details.";
LogHelper.Error<HealthCheckResults>(string.Format("Error running scheduled health check: {0}", t.Name), ex);
var message = string.Format("Health check failed with exception: {0}. See logs for details.", ex.Message);
return new List<HealthCheckStatus>
{
new HealthCheckStatus(message)
@@ -36,9 +33,9 @@ namespace Umbraco.Web.HealthCheck
ResultType = StatusResultType.Error
}
};
}
}
});
// find out if all checks pass or not
AllChecksSuccessful = true;
foreach (var result in _results)
@@ -54,7 +51,7 @@ namespace Umbraco.Web.HealthCheck
public void LogResults()
{
Logger.Info<HealthCheckResults>("Scheduled health check results:");
LogHelper.Info<HealthCheckResults>("Scheduled health check results:");
foreach (var result in _results)
{
var checkName = result.Key;
@@ -62,16 +59,16 @@ namespace Umbraco.Web.HealthCheck
var checkIsSuccess = result.Value.All(x => x.ResultType == StatusResultType.Success);
if (checkIsSuccess)
{
Logger.Info<HealthCheckResults>("Checks for '{HealthCheckName}' all completed succesfully.", checkName);
LogHelper.Info<HealthCheckResults>(string.Format(" Checks for '{0}' all completed succesfully.", checkName));
}
else
{
Logger.Warn<HealthCheckResults>("Checks for '{HealthCheckName}' completed with errors.", checkName);
LogHelper.Warn<HealthCheckResults>(string.Format(" Checks for '{0}' completed with errors.", checkName));
}
foreach (var checkResult in checkResults)
{
Logger.Info<HealthCheckResults>("Result for {HealthCheckName}: {HealthCheckResult}, Message: '{HealthCheckMessage}'", checkName, checkResult.ResultType, checkResult.Message);
LogHelper.Info<HealthCheckResults>(string.Format(" Result: {0}, Message: '{1}'", checkResult.ResultType, checkResult.Message));
}
}
}

View File

@@ -51,4 +51,4 @@ namespace Umbraco.Web.HealthCheck
//TODO: What else?
}
}
}

View File

@@ -1,18 +0,0 @@
using LightInject;
using Umbraco.Core.Composing;
namespace Umbraco.Web.HealthCheck
{
public class HealthCheckCollectionBuilder : LazyCollectionBuilderBase<HealthCheckCollectionBuilder, HealthCheckCollection, HealthCheck>
{
public HealthCheckCollectionBuilder(IServiceContainer container)
: base(container)
{ }
protected override HealthCheckCollectionBuilder This => this;
// note: in v7 they were per-request, not sure why?
// the collection is injected into the controller & there's only 1 controller per request anyways
protected override ILifetime CollectionLifetime => null; // transient!
}
}

View File

@@ -0,0 +1,10 @@
using System.Collections.Generic;
using Umbraco.Web.HealthCheck.NotificationMethods;
namespace Umbraco.Web.HealthCheck
{
public interface IHealthCheckNotificationMethodsResolver
{
IEnumerable<IHealthCheckNotificatationMethod> NotificationMethods { get; }
}
}

View File

@@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Umbraco.Web.HealthCheck
{
public interface IHealthCheckResolver
{
IEnumerable<HealthCheck> HealthChecks { get; }
}
}

View File

@@ -1,35 +1,52 @@
using System;
using System.Net.Mail;
using System.Threading;
using System.Threading.Tasks;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.HealthChecks;
using Umbraco.Core.Services;
namespace Umbraco.Web.HealthCheck.NotificationMethods
{
[HealthCheckNotificationMethod("email")]
public class EmailNotificationMethod : NotificationMethodBase
public class EmailNotificationMethod : NotificationMethodBase, IHealthCheckNotificatationMethod
{
private readonly ILocalizedTextService _textService;
public EmailNotificationMethod(ILocalizedTextService textService)
/// <summary>
/// Default constructor which is used in the provider model
/// </summary>
/// <param name="enabled"></param>
/// <param name="failureOnly"></param>
/// <param name="verbosity"></param>
/// <param name="recipientEmail"></param>
public EmailNotificationMethod(bool enabled, bool failureOnly, HealthCheckNotificationVerbosity verbosity,
string recipientEmail)
: this(enabled, failureOnly, verbosity, recipientEmail, ApplicationContext.Current.Services.TextService)
{
var recipientEmail = Settings["recipientEmail"]?.Value;
if (string.IsNullOrWhiteSpace(recipientEmail))
{
Enabled = false;
return;
}
RecipientEmail = recipientEmail;
_textService = textService ?? throw new ArgumentNullException(nameof(textService));
}
public string RecipientEmail { get; }
/// <summary>
/// Constructor that could be used for testing
/// </summary>
/// <param name="enabled"></param>
/// <param name="failureOnly"></param>
/// <param name="verbosity"></param>
/// <param name="recipientEmail"></param>
/// <param name="textService"></param>
internal EmailNotificationMethod(bool enabled, bool failureOnly, HealthCheckNotificationVerbosity verbosity,
string recipientEmail, ILocalizedTextService textService)
: base(enabled, failureOnly, verbosity)
{
if (textService == null) throw new ArgumentNullException("textService");
_textService = textService;
RecipientEmail = recipientEmail;
Verbosity = verbosity;
}
public override async Task SendAsync(HealthCheckResults results, CancellationToken token)
public string RecipientEmail { get; private set; }
public async Task SendAsync(HealthCheckResults results)
{
if (ShouldSend(results) == false)
{
@@ -51,23 +68,17 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods
var subject = _textService.Localize("healthcheck/scheduledHealthCheckEmailSubject");
var mailSender = new EmailSender();
using (var mailMessage = CreateMailMessage(subject, message))
using (var mailMessage = new MailMessage(UmbracoConfig.For.UmbracoSettings().Content.NotificationEmailAddress,
RecipientEmail,
string.IsNullOrEmpty(subject) ? "Umbraco Health Check Status" : subject,
message)
{
IsBodyHtml = message.IsNullOrWhiteSpace() == false
&& message.Contains("<") && message.Contains("</")
})
{
await mailSender.SendAsync(mailMessage);
}
}
private MailMessage CreateMailMessage(string subject, string message)
{
var to = UmbracoConfig.For.UmbracoSettings().Content.NotificationEmailAddress;
if (string.IsNullOrWhiteSpace(subject))
subject = "Umbraco Health Check Status";
return new MailMessage(to, RecipientEmail, subject, message)
{
IsBodyHtml = message.IsNullOrWhiteSpace() == false && message.Contains("<") && message.Contains("</")
};
}
}
}

View File

@@ -0,0 +1,10 @@
using System.Threading.Tasks;
namespace Umbraco.Web.HealthCheck.NotificationMethods
{
public interface IHealthCheckNotificatationMethod
{
bool Enabled { get; }
Task SendAsync(HealthCheckResults results);
}
}

View File

@@ -1,11 +0,0 @@
using System.Threading;
using System.Threading.Tasks;
namespace Umbraco.Web.HealthCheck.NotificationMethods
{
public interface IHealthCheckNotificationMethod
{
bool Enabled { get; }
Task SendAsync(HealthCheckResults results, CancellationToken token);
}
}

View File

@@ -1,37 +1,14 @@
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.HealthChecks;
using Umbraco.Core.Configuration.HealthChecks;
namespace Umbraco.Web.HealthCheck.NotificationMethods
{
public abstract class NotificationMethodBase : IHealthCheckNotificationMethod
public abstract class NotificationMethodBase
{
protected NotificationMethodBase()
protected NotificationMethodBase(bool enabled, bool failureOnly, HealthCheckNotificationVerbosity verbosity)
{
var type = GetType();
var attribute = type.GetCustomAttribute<HealthCheckNotificationMethodAttribute>();
if (attribute == null)
{
Enabled = false;
return;
}
var healthCheckConfig = UmbracoConfig.For.HealthCheck();
var notificationMethods = healthCheckConfig.NotificationSettings.NotificationMethods;
var notificationMethod = notificationMethods[attribute.Alias];
if (notificationMethod == null)
{
Enabled = false;
return;
}
Enabled = notificationMethod.Enabled;
FailureOnly = notificationMethod.FailureOnly;
Verbosity = notificationMethod.Verbosity;
Settings = notificationMethod.Settings;
Enabled = enabled;
FailureOnly = failureOnly;
Verbosity = verbosity;
}
public bool Enabled { get; protected set; }
@@ -40,13 +17,19 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods
public HealthCheckNotificationVerbosity Verbosity { get; protected set; }
public IReadOnlyDictionary<string, INotificationMethodSettings> Settings { get; }
protected bool ShouldSend(HealthCheckResults results)
{
return Enabled && (!FailureOnly || !results.AllChecksSuccessful);
}
if (Enabled == false)
{
return false;
}
public abstract Task SendAsync(HealthCheckResults results, CancellationToken token);
if (FailureOnly && results.AllChecksSuccessful)
{
return false;
}
return true;
}
}
}

View File

@@ -7,4 +7,4 @@
Error,
Info
}
}
}