more validation

This commit is contained in:
Keivan Beigi 2013-08-21 17:36:35 -07:00
parent e4c8255d69
commit 488da59143
14 changed files with 105 additions and 69 deletions

View File

@ -165,7 +165,7 @@
<Compile Include="System\SystemModule.cs" />
<Compile Include="TinyIoCNancyBootstrapper.cs" />
<Compile Include="Update\UpdateModule.cs" />
<Compile Include="Validation\IdValidationRule.cs" />
<Compile Include="Validation\RuleBuilderExtensions.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View File

@ -14,7 +14,7 @@ namespace NzbDrone.Api.REST
public IRuleBuilderInitial<TResource, TProperty> RuleForField<TProperty>(Expression<Func<TResource, IEnumerable<Field>>> fieldListAccessor, string fieldName)
{
var rule = new PropertyRule(fieldListAccessor.GetMember(), c => GetValue(c, fieldListAccessor.Compile(), fieldName), null, () => CascadeMode.Continue, typeof(TProperty), typeof(TResource));
rule.PropertyName += "." + fieldName;
rule.PropertyName = fieldName;
rule.DisplayName = new StaticStringSource(fieldName);
AddRule(rule);
@ -34,7 +34,4 @@ namespace NzbDrone.Api.REST
return resource.Value;
}
}
}

View File

@ -30,9 +30,11 @@ namespace NzbDrone.Api.Series
DeleteResource = DeleteSeries;
SharedValidator.RuleFor(s => s.QualityProfileId).ValidId();
SharedValidator.RuleFor(s => s.Path).NotEmpty().When(s => String.IsNullOrEmpty(s.RootFolderPath));
SharedValidator.RuleFor(s => s.RootFolderPath).NotEmpty().When(s => String.IsNullOrEmpty(s.Path));
PutValidator.RuleFor(s => s.Path).NotEmpty();
PostValidator.RuleFor(s => s.Path).NotEmpty().When(s => String.IsNullOrEmpty(s.RootFolderPath));
PostValidator.RuleFor(s => s.RootFolderPath).NotEmpty().When(s => String.IsNullOrEmpty(s.Path));
PostValidator.RuleFor(s => s.Title).NotEmpty();
}

View File

@ -15,5 +15,4 @@ namespace NzbDrone.Api.Validation
return ruleBuilder.SetValidator(new EqualValidator(0));
}
}
}

View File

@ -38,8 +38,9 @@
<inspection_tool class="HtmlUnknownAttribute" enabled="true" level="WARNING" enabled_by_default="true">
<option name="myValues">
<value>
<list size="1">
<list size="2">
<item index="0" class="java.lang.String" itemvalue="name" />
<item index="1" class="java.lang.String" itemvalue="validation-name" />
</list>
</value>
</option>

View File

@ -2,7 +2,7 @@
<label class="control-label">{{label}}</label>
<div class="controls">
<input type="password" name="fields.{{order}}.value"/>
<input type="password" name="fields.{{order}}.value" validation-name="{{name}}"/>
{{#if helpText}}
<span class="help-inline">
<i class="icon-question-sign" title="{{helpText}}"/>

View File

@ -2,7 +2,7 @@
<label class="control-label">{{label}}</label>
<div class="controls">
<input type="text" name="fields.{{order}}.value" spellcheck="false"/>
<input type="text" name="fields.{{order}}.value" validation-name="{{name}}" spellcheck="false"/>
{{> FormHelpPartial}}
</div>
</div>

View File

@ -69,10 +69,13 @@
return false;
//message.message = 'NzbDrone Server Not Reachable. make sure NzbDrone is running.';
}
else {
message.message = '[{0}] {1} : {2}'.format(ajaxOptions.type, xmlHttpRequest.statusText, ajaxOptions.url);
else if (xmlHttpRequest.status === 400 && ajaxOptions.isValidatedCall) {
return false;
}
message.message = '[{0}] {1} : {2}'.format(ajaxOptions.type, xmlHttpRequest.statusText, ajaxOptions.url);
window.Messenger().post(message);
return false;
});

View File

@ -2,7 +2,7 @@ define(
[
'backbone.validation',
'underscore',
'jQuery/Validation'
'jQuery/jquery.validation'
], function (Validation, _) {
'use strict';
@ -27,7 +27,10 @@ define(
var boundHandler = errorHandler.bind(this);
this.model.sync = function () {
self.$el.removeBootstrapError();
self.$el.removeAllErrors();
arguments[2].isValidatedCall = true;
return self.originalSync.apply(this, arguments).fail(boundHandler);
};
}
@ -71,9 +74,13 @@ define(
var validationErrors = JSON.parse(response.responseText);
_.each(validationErrors, function (error) {
view.$el.addBootstrapError(error);
view.$el.processServerError(error);
});
}
};
return this;
};
});

View File

@ -5,8 +5,9 @@ define(
'marionette',
'Quality/QualityProfileCollection',
'Mixins/AsModelBoundView',
'Mixins/AsValidatedView',
'Mixins/AutoComplete'
], function (App, Marionette, QualityProfiles, AsModelBoundView) {
], function (App, Marionette, QualityProfiles, AsModelBoundView, AsValidatedView) {
var view = Marionette.ItemView.extend({
template: 'Series/Edit/EditSeriesTemplate',
@ -49,5 +50,6 @@ define(
});
return AsModelBoundView.apply(view);
AsModelBoundView.apply(view);
return AsValidatedView.apply(view);
});

View File

@ -1,26 +1,29 @@
'use strict';
define([
'app',
'marionette',
'Settings/Notifications/DeleteView',
'Mixins/AsModelBoundView'],
function (App, Marionette, DeleteView, AsModelBoundView) {
define(
[
'app',
'marionette',
'Settings/Notifications/DeleteView',
'Mixins/AsModelBoundView',
'Mixins/AsValidatedView'
], function (App, Marionette, DeleteView, AsModelBoundView, AsValidatedView) {
var view = Marionette.ItemView.extend({
template: 'Settings/Indexers/ItemTemplate',
tagName : 'li',
var view = Marionette.ItemView.extend({
template: 'Settings/Indexers/ItemTemplate',
tagName : 'li',
events: {
'click .x-delete': '_deleteIndexer'
},
events: {
'click .x-delete': '_deleteIndexer'
},
_deleteIndexer: function () {
var view = new DeleteView({ model: this.model});
App.modalRegion.show(view);
}
});
AsModelBoundView.call(view);
return AsValidatedView.call(view);
_deleteIndexer: function () {
var view = new DeleteView({ model: this.model});
App.modalRegion.show(view);
}
});
return AsModelBoundView.call(view);
});

View File

@ -1,5 +1,5 @@
<fieldset>
<legend>Sorting</legend>
<legend>Season Folder</legend>
<!--TODO: Remove this and move it to Add Series-->
<div class="control-group">

View File

@ -1,30 +0,0 @@
define(
[
'jquery'
], function ($) {
'use strict';
$.fn.addBootstrapError = function (error) {
var input = this.find('[name]').filter(function () {
return this.name.toLowerCase() === error.propertyName.toLowerCase();
});
var controlGroup = input.parents('.control-group');
if (controlGroup.find('.help-inline').length === 0) {
controlGroup.find('.controls').append('<span class="help-inline error-message">' + error.errorMessage + '</span>');
}
controlGroup.addClass('error');
return controlGroup.find('.help-inline').text();
};
$.fn.removeBootstrapError = function () {
this.removeClass('error');
return this.parents('.control-group').find('.help-inline.error-message').remove();
};
});

View File

@ -0,0 +1,52 @@
define(
[
'jquery'
], function ($) {
'use strict';
$.fn.processServerError = function (error) {
var validationName = error.propertyName.toLowerCase();
var input = this.find('[name]').filter(function () {
return this.name.toLowerCase() === validationName;
});
if (input.length === 0) {
input = this.find('[validation-name]').filter(function () {
return $(this).attr('validation-name').toLowerCase() === validationName;
});
//still not found?
if (input.length === 0) {
this.addFormError(error);
console.error('couldn\'t find input for ' + error.propertyName);
return this;
}
}
var controlGroup = input.parents('.control-group');
controlGroup.find('.controls').append('<span class="help-inline error-message">' + error.errorMessage + '</span>');
controlGroup.addClass('error');
return controlGroup.find('.help-inline').text();
};
$.fn.processClientError = function (error) {
};
$.fn.addFormError = function (error) {
this.find('.control-group').parent().prepend('<div class="alert alert-error validation-error">'+ error.errorMessage +'</div>')
};
$.fn.removeAllErrors = function () {
this.find('.error').removeClass('error');
this.find('.validation-error').remove();
return this.find('.help-inline.error-message').remove();
};
});