mirror of https://github.com/Radarr/Radarr
Better validation for Growl settings.
This commit is contained in:
parent
c0e0bf7e66
commit
b86a19451d
|
@ -0,0 +1,101 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Web;
|
||||||
|
using System.Web.Mvc;
|
||||||
|
|
||||||
|
namespace NzbDrone.Web.Helpers.Validation
|
||||||
|
{
|
||||||
|
public class RequiredIfAnyAttribute : ValidationAttribute, IClientValidatable
|
||||||
|
{
|
||||||
|
private RequiredAttribute _innerAttribute = new RequiredAttribute();
|
||||||
|
|
||||||
|
public string[] DependentProperties { get; set; }
|
||||||
|
public object[] TargetValues { get; set; }
|
||||||
|
|
||||||
|
public RequiredIfAnyAttribute(string[] dependentProperties, params object[] targetValues)
|
||||||
|
{
|
||||||
|
if (dependentProperties.Count() != targetValues.Count())
|
||||||
|
throw new ArgumentException("Dependent properties count must equal values count");
|
||||||
|
|
||||||
|
this.DependentProperties = dependentProperties;
|
||||||
|
this.TargetValues = targetValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < DependentProperties.Count(); i++)
|
||||||
|
{
|
||||||
|
// get a reference to the property this validation depends upon
|
||||||
|
var containerType = validationContext.ObjectInstance.GetType();
|
||||||
|
var field = containerType.GetProperty(this.DependentProperties[i]);
|
||||||
|
|
||||||
|
if (field != null)
|
||||||
|
{
|
||||||
|
// get the value of the dependent property
|
||||||
|
var dependentvalue = field.GetValue(validationContext.ObjectInstance, null);
|
||||||
|
|
||||||
|
// compare the value against the target value
|
||||||
|
if ((dependentvalue == null && this.TargetValues[i] == null) ||
|
||||||
|
(dependentvalue != null && dependentvalue.Equals(this.TargetValues[i])))
|
||||||
|
{
|
||||||
|
// match => means we should try validating this field
|
||||||
|
if (!_innerAttribute.IsValid(value))
|
||||||
|
// validation failed - return an error
|
||||||
|
return new ValidationResult(this.ErrorMessage, new[] { validationContext.MemberName });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ValidationResult.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
|
||||||
|
{
|
||||||
|
var rule = new ModelClientValidationRule()
|
||||||
|
{
|
||||||
|
ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
|
||||||
|
ValidationType = "requiredifany",
|
||||||
|
};
|
||||||
|
|
||||||
|
var properties = new List<string>();
|
||||||
|
var values = new List<object>();
|
||||||
|
|
||||||
|
for (int i = 0; i < DependentProperties.Count(); i++)
|
||||||
|
{
|
||||||
|
string depProp = BuildDependentPropertyId(metadata, context as ViewContext, DependentProperties[i]);
|
||||||
|
|
||||||
|
// find the value on the control we depend on;
|
||||||
|
// if it's a bool, format it javascript style
|
||||||
|
// (the default is True or False!)
|
||||||
|
string targetValue = (TargetValues[i] ?? "").ToString();
|
||||||
|
if (TargetValues[i].GetType() == typeof(bool))
|
||||||
|
targetValue = targetValue.ToLower();
|
||||||
|
|
||||||
|
properties.Add(depProp);
|
||||||
|
values.Add(targetValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
rule.ValidationParameters.Add("dependentproperties", String.Join("|", properties));
|
||||||
|
rule.ValidationParameters.Add("targetvalues", String.Join("|", values));
|
||||||
|
|
||||||
|
yield return rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string BuildDependentPropertyId(ModelMetadata metadata, ViewContext viewContext, string dependentProperty)
|
||||||
|
{
|
||||||
|
// build the ID of the property
|
||||||
|
string depProp = viewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(dependentProperty);
|
||||||
|
// unfortunately this will have the name of the current field appended to the beginning,
|
||||||
|
// because the TemplateInfo's context has had this fieldname appended to it. Instead, we
|
||||||
|
// want to get the context as though it was one level higher (i.e. outside the current property,
|
||||||
|
// which is the containing object (our Person), and hence the same level as the dependent property.
|
||||||
|
var thisField = metadata.PropertyName + "_";
|
||||||
|
if (depProp.StartsWith(thisField))
|
||||||
|
// strip it off again
|
||||||
|
depProp = depProp.Substring(thisField.Length);
|
||||||
|
return depProp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -201,7 +201,7 @@ namespace NzbDrone.Web.Models
|
||||||
[DataType(DataType.Text)]
|
[DataType(DataType.Text)]
|
||||||
[DisplayName("Client Hosts")]
|
[DisplayName("Client Hosts")]
|
||||||
[Description("Plex client hosts with port, comma separated for multiple clients")]
|
[Description("Plex client hosts with port, comma separated for multiple clients")]
|
||||||
[RequiredIf("PlexNotifyOnGrab", true, ErrorMessage = "Required when Plex Notifications are enabled")]
|
[RequiredIfAny(new string[]{ "PlexNotifyOnGrab", "PlexNotifyOnDownload" }, new object[]{ true, true }, ErrorMessage = "Required when Plex Notifications are enabled")]
|
||||||
[DisplayFormat(ConvertEmptyStringToNull = false)]
|
[DisplayFormat(ConvertEmptyStringToNull = false)]
|
||||||
public string PlexClientHosts { get; set; }
|
public string PlexClientHosts { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -131,6 +131,7 @@
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Helpers\Validation\RequiredIfAnyAttribute.cs" />
|
||||||
<Compile Include="Helpers\Validation\RequiredIfAttribute.cs" />
|
<Compile Include="Helpers\Validation\RequiredIfAttribute.cs" />
|
||||||
<Content Include="Content\DataTables-1.9.0\media\css\jquery.dataTables.css" />
|
<Content Include="Content\DataTables-1.9.0\media\css\jquery.dataTables.css" />
|
||||||
<Content Include="Content\DataTables-1.9.0\media\images\back_disabled.png" />
|
<Content Include="Content\DataTables-1.9.0\media\images\back_disabled.png" />
|
||||||
|
|
|
@ -41,3 +41,53 @@ $.validator.unobtrusive.adapters.add(
|
||||||
};
|
};
|
||||||
options.messages['requiredif'] = options.message;
|
options.messages['requiredif'] = options.message;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
$.validator.addMethod('requiredifany',
|
||||||
|
function (value, element, parameters) {
|
||||||
|
|
||||||
|
console.log(parameters['dependentproperties']);
|
||||||
|
console.log(parameters['targetvalues']);
|
||||||
|
|
||||||
|
var dependentProperties = parameters['dependentproperties'].split('|');
|
||||||
|
var targetValues = parameters['targetvalues'].split('|');
|
||||||
|
|
||||||
|
for (var i = 0; i < dependentProperties.length; i++) {
|
||||||
|
var id = '#' + dependentProperties[i];
|
||||||
|
|
||||||
|
// get the target value (as a string,
|
||||||
|
// as that's what actual value will be)
|
||||||
|
var targetvalue = targetValues[i];
|
||||||
|
targetvalue =
|
||||||
|
(targetvalue == null ? '' : targetvalue).toString();
|
||||||
|
|
||||||
|
// get the actual value of the target control
|
||||||
|
// note - this probably needs to cater for more
|
||||||
|
// control types, e.g. radios
|
||||||
|
var control = $(id);
|
||||||
|
var controltype = control.attr('type');
|
||||||
|
var actualvalue =
|
||||||
|
controltype === 'checkbox' ?
|
||||||
|
(control.attr('checked') == "checked" ? "true" : "false") :
|
||||||
|
control.val();
|
||||||
|
|
||||||
|
// if the condition is true, reuse the existing
|
||||||
|
// required field validator functionality
|
||||||
|
if (targetvalue === actualvalue)
|
||||||
|
return $.validator.methods.required.call(
|
||||||
|
this, value, element, parameters);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$.validator.unobtrusive.adapters.add(
|
||||||
|
'requiredifany',
|
||||||
|
['dependentproperties', 'targetvalues'],
|
||||||
|
function (options) {
|
||||||
|
options.rules['requiredifany'] = {
|
||||||
|
dependentproperties: options.params['dependentproperties'],
|
||||||
|
targetvalues: options.params['targetvalues']
|
||||||
|
};
|
||||||
|
options.messages['requiredifany'] = options.message;
|
||||||
|
});
|
Loading…
Reference in New Issue