using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Umbraco.Core.IO;
using Umbraco.Core.Services;
namespace Umbraco.Web.HealthCheck.Checks.Config
{
public abstract class AbstractConfigCheck : HealthCheck
{
private readonly ConfigurationService _configurationService;
private readonly ILocalizedTextService _textService;
///
/// Gets the config file path.
///
public abstract string FilePath { get; }
///
/// Gets XPath statement to the config element to check.
///
public abstract string XPath { get; }
///
/// Gets the values to compare against.
///
public abstract IEnumerable Values { get; }
///
/// Gets the current value
///
public string CurrentValue { get; set; }
///
/// Gets the provided value
///
public string ProvidedValue { get; set; }
///
/// Gets the comparison type for checking the value.
///
public abstract ValueComparisonType ValueComparisonType { get; }
///
/// Gets the flag indicating if the check is considered successful if the config value is missing (defaults to false - an error - if missing)
///
public virtual bool ValidIfConfigMissing
{
get { return false; }
}
protected AbstractConfigCheck(HealthCheckContext healthCheckContext) : base(healthCheckContext)
{
_textService = healthCheckContext.ApplicationContext.Services.TextService;
_configurationService = new ConfigurationService(AbsoluteFilePath, XPath);
}
///
/// Gets the name of the file.
///
private string FileName
{
get { return Path.GetFileName(FilePath); }
}
///
/// Gets the absolute file path.
///
private string AbsoluteFilePath
{
get { return IOHelper.MapPath(FilePath); }
}
///
/// Gets the message for when the check has succeeded.
///
public virtual string CheckSuccessMessage
{
get
{
return _textService.Localize("healthcheck/checkSuccessMessage",
new[] { CurrentValue, Values.First(v => v.IsRecommended).Value, XPath, AbsoluteFilePath });
}
}
///
/// Gets the message for when the check has failed.
///
public virtual string CheckErrorMessage
{
get
{
return ValueComparisonType == ValueComparisonType.ShouldEqual
? _textService.Localize("healthcheck/checkErrorMessageDifferentExpectedValue",
new[] { CurrentValue, Values.First(v => v.IsRecommended).Value, XPath, AbsoluteFilePath })
: _textService.Localize("healthcheck/checkErrorMessageUnexpectedValue",
new[] { CurrentValue, Values.First(v => v.IsRecommended).Value, XPath, AbsoluteFilePath });
}
}
///
/// Gets the rectify success message.
///
public virtual string RectifySuccessMessage
{
get
{
var recommendedValue = Values.FirstOrDefault(v => v.IsRecommended);
var rectifiedValue = recommendedValue != null
? recommendedValue.Value
: ProvidedValue;
return _textService.Localize("healthcheck/rectifySuccessMessage",
new[]
{
CurrentValue,
rectifiedValue,
XPath,
AbsoluteFilePath
});
}
}
///
/// Gets a value indicating whether this check can be rectified automatically.
///
public virtual bool CanRectify
{
get { return ValueComparisonType == ValueComparisonType.ShouldEqual; }
}
///
/// Gets a value indicating whether this check can be rectified automatically if a value is provided.
///
public virtual bool CanRectifyWithValue
{
get { return ValueComparisonType == ValueComparisonType.ShouldNotEqual; }
}
public override IEnumerable GetStatus()
{
var successMessage = string.Format(CheckSuccessMessage, FileName, XPath, Values);
var configValue = _configurationService.GetConfigurationValue();
if (configValue.Success == false)
{
if (ValidIfConfigMissing)
{
return new[] { new HealthCheckStatus(successMessage) { ResultType = StatusResultType.Success } };
}
var errorMessage = configValue.Result;
return new[] { new HealthCheckStatus(errorMessage) { ResultType = StatusResultType.Error } };
}
CurrentValue = configValue.Result;
// need to update the successMessage with the CurrentValue
successMessage = string.Format(CheckSuccessMessage, FileName, XPath, Values, CurrentValue);
var valueFound = Values.Any(value => string.Equals(CurrentValue, value.Value, StringComparison.InvariantCultureIgnoreCase));
if (ValueComparisonType == ValueComparisonType.ShouldEqual && valueFound || ValueComparisonType == ValueComparisonType.ShouldNotEqual && valueFound == false)
{
return new[] { new HealthCheckStatus(successMessage) { ResultType = StatusResultType.Success } };
}
// Declare the action for rectifying the config value
var rectifyAction = new HealthCheckAction("rectify", Id)
{
Name = _textService.Localize("healthcheck/rectifyButton"),
ValueRequired = CanRectifyWithValue,
};
var resultMessage = string.Format(CheckErrorMessage, FileName, XPath, Values, CurrentValue);
return new[]
{
new HealthCheckStatus(resultMessage)
{
ResultType = StatusResultType.Error,
Actions = CanRectify || CanRectifyWithValue ? new[] { rectifyAction } : new HealthCheckAction[0]
}
};
}
///
/// Rectifies this check.
///
///
public virtual HealthCheckStatus Rectify()
{
if (ValueComparisonType == ValueComparisonType.ShouldNotEqual)
throw new InvalidOperationException(_textService.Localize("healthcheck/cannotRectifyShouldNotEqual"));
var recommendedValue = Values.First(v => v.IsRecommended).Value;
return UpdateConfigurationValue(recommendedValue);
}
///
/// Rectifies this check with a provided value.
///
/// Value provided
///
public virtual HealthCheckStatus Rectify(string value)
{
if (ValueComparisonType == ValueComparisonType.ShouldEqual)
throw new InvalidOperationException(_textService.Localize("healthcheck/cannotRectifyShouldEqualWithValue"));
if (string.IsNullOrWhiteSpace(value))
throw new InvalidOperationException(_textService.Localize("healthcheck/valueToRectifyNotProvided"));
// Need to track provided value in order to correctly put together the rectify message
ProvidedValue = value;
return UpdateConfigurationValue(value);
}
private HealthCheckStatus UpdateConfigurationValue(string value)
{
var updateConfigFile = _configurationService.UpdateConfigFile(value);
if (updateConfigFile.Success == false)
{
var message = updateConfigFile.Result;
return new HealthCheckStatus(message) { ResultType = StatusResultType.Error };
}
var resultMessage = string.Format(RectifySuccessMessage, FileName, XPath, Values);
return new HealthCheckStatus(resultMessage) { ResultType = StatusResultType.Success };
}
public override HealthCheckStatus ExecuteAction(HealthCheckAction action)
{
return string.IsNullOrEmpty(action.ProvidedValue)
? Rectify()
: Rectify(action.ProvidedValue);
}
}
}