Skip to content

Commit

Permalink
Merge branch '14-add-missing-field-validation' into 9-get-ip-adresses…
Browse files Browse the repository at this point in the history
…-automatically
  • Loading branch information
geirkairam committed Oct 25, 2015
2 parents adeccde + 8e9a8bd commit abe0623
Show file tree
Hide file tree
Showing 7 changed files with 240 additions and 34 deletions.
94 changes: 72 additions & 22 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,23 @@ <h2>
name="routerName"
placeholder="{{'basicRouterSetup.routerName.placeholder' | translate }}"
data-ng-model="wizard.router.name"
data-ng-required="(wizard.internet.share && wizard.internet.vpn03.enabled && state.internet.vpn03.generate) || state.ip.register"
required pattern="[A-Za-z0-9_\-]{0,16}"
>
<span class="fa form-control-feedback"
ng-class="formControlFeedback('routerName')"></span>
<p class="text-muted" translate>
<p class="text-muted" ng-hide="hasError('routerName')" translate>
.routerName.help
</p>
<span class="fa form-control-feedback" ng-class="{
'fa-times': hasError('routerName'),
'fa-check': wizardForm.routerName.$valid
}"></span>
<div class="help-block" ng-show="hasError('routerName')">
<div ng-show="wizardForm.routerName.$error.required" translate>
.routerName.error.required
</div>
</div>
</div>
</div>

Expand Down Expand Up @@ -173,7 +183,7 @@ <h2>
<div class="help-block" ng-if="hasError('email')" translate>
.email.error
</div>
<p class="text-muted" translate>
<p class="text-muted" ng-hide="hasError('email')" translate>
.email.help
</p>
</div>
Expand Down Expand Up @@ -377,26 +387,36 @@ <h2>

<div class="row" data-collapse="state.internet.vpn03.generate" translate-namespace=".generateCertificate">
<div class="col-md-offset-3 col-md-9">
<div class="form-group">
<div class="form-group has-feedback" data-ng-class="formFeedback('vpn03Cert')">
<label for="vpn03Cert" class="col-md-3 control-label" translate>
.certificate.label
</label>
<div class="col-md-9">
<span class="btn btn-primary btn-file">
<span translate>.browse</span>
<input type="file" data-ng-model="wizard.internet.vpn03.cert">
</span>
<input type="file" name="vpn03Cert"
data-ng-model="wizard.internet.vpn03.cert"
data-file-valid
data-ng-required="!state.internet.vpn03.generate && wizard.internet.vpn03.enabled && wizard.internet.share">
<div class="help-block" ng-show="hasError('vpn03Cert')">
<div ng-show="wizardForm.vpn03Cert.$error.required" translate>
.error.required
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="form-group has-feedback" data-ng-class="formFeedback('vpn03Key')">
<label for="vpn03Key" class="col-md-3 control-label" translate>
.key.label
</label>
<div class="col-md-9">
<span class="btn btn-primary btn-file">
<span translate>.browse</span>
<input type="file" data-ng-model="wizard.internet.vpn03.key">
</span>
<input type="file" name="vpn03Key"
data-ng-model="wizard.internet.vpn03.key"
data-file-valid
data-ng-required="!state.internet.vpn03.generate && wizard.internet.vpn03.enabled && wizard.internet.share">
<div class="help-block" ng-show="hasError('vpn03Cert')">
<div ng-show="wizardForm.vpn03Cert.$error.required" translate>
.error.required
</div>
</div>
</div>
</div>
</div>
Expand Down Expand Up @@ -440,14 +460,24 @@ <h2>

<div class="row" data-collapse="state.ip.register">
<div class="col-md-offset-3 col-md-9">
<div class="form-group">
<div class="form-group hasFeedback" ng-class="formFeedback('ipv6Prefix')">
<label for="ipv6Prefix" class="col-md-3 control-label" translate>
.v6Prefix.label
</label>
<div class="col-md-9">
<input type="text" class="form-control" id="ipv6Prefix"
<input type="text" class="form-control" name="ipv6Prefix" id="ipv6Prefix"
placeholder="{{'ip.v6Prefix.placeholder' | translate}}"
data-ng-model="wizard.ip.v6Prefix">
data-ng-model="wizard.ip.v6Prefix"
data-ng-required="!state.ip.register"
data-ip-address data-ip-version="6" data-ip-type="subnet">
<div class="help-block" ng-show="hasError('ipv6Prefix')">
<div ng-show="wizardForm['ipv6Prefix'].$error.required" translate>
.error.required
</div>
<div ng-show="wizardForm['ipv6Prefix'].$error.ipv6Subnet" translate>
.v6Prefix.error.subnet
</div>
</div>
</div>
</div>

Expand All @@ -462,12 +492,14 @@ <h2>
<input type="text" class="form-control" id="ipv4Wifi_{{$index}}" name="ipv4Wifi_{{$index}}"
translate translate-attr-placeholder=".v4.placeholder"
translate-values="{index: $index + 1}"
data-ng-model="wizard.ip.v4[name]" data-ipv4-address required>
data-ng-model="wizard.ip.v4[name]"
data-ng-required="!state.ip.register"
data-ip-address data-ip-version="4">
<span class="fa form-control-feedback"
ng-class="formControlFeedback('ipv4Wifi_' + $index)"></span>
<div class="help-block" ng-show="hasError('ipv4Wifi_' + $index)">
<div ng-show="wizardForm['ipv4Wifi_' + $index].$error.required" translate>
.v4.error.required
.error.required
</div>
<div ng-show="wizardForm['ipv4Wifi_' + $index].$error.ipv4Address" translate>
.v4.error.ipv4Address
Expand Down Expand Up @@ -503,12 +535,15 @@ <h2>
name="ipv4Lan"
translate translate-attr-placeholder=".v4.placeholder"
translate-values="{index: (state.wifi.devices | objectLength) + 1}"
data-ng-model="wizard.ip.v4.lan" data-ipv4-address required>
data-ng-model="wizard.ip.v4.lan"
data-ng-required="wizard.ip.meshLan && !state.ip.generate"
data-ip-address
data-ip-version="4">
<span class="fa form-control-feedback"
ng-class="formControlFeedback('ipv4Lan')"></span>
<div class="help-block" ng-show="hasError('ipv4Lan')">
<div ng-show="wizardForm.ipv4Lan.$error.required" translate>
.v4.error.required
.error.required
</div>
<div ng-show="wizardForm.ipv4Lan.$error.ipv4Address" translate>
.v4.error.ipv4Address
Expand Down Expand Up @@ -537,15 +572,30 @@ <h2>
<div class="col-md-offset-3 col-md-9">

<div data-collapse="state.ip.register">
<div class="form-group">
<div class="form-group has-feedback" data-ng-class="formFeedback('ipv4ClientSubnet')">
<label for="ipv4ClientSubnet" class="col-md-3 control-label" translate>
.distribute.subnet.label
</label>
<div class="col-md-9">
<input type="text" class="form-control" id="ipv4ClientSubnet"
name="ipv4ClientSubnet"
placeholder="{{'ip.distribute.subnet.placeholder' | translate}}"
data-ng-model="wizard.ip.v4ClientSubnet">
<p class="text-muted" translate>.distribute.subnet.help</p>
data-ng-model="wizard.ip.v4ClientSubnet"
data-ng-required="wizard.ip.distribute && !state.ip.register"
data-ip-address
data-ip-version="4"
data-ip-type="subnet">
<p class="text-muted" data-ng-hide="hasError('ipv4ClientSubnet')" translate>
.distribute.subnet.help
</p>
<div class="help-block" data-ng-show="hasError('ipv4ClientSubnet')">
<div data-ng-show="wizardForm.ipv4ClientSubnet.$error.required" translate>
.error.required
</div>
<div data-ng-show="wizardForm.ipv4ClientSubnet.$error.ipv4Subnet" translate>
.distribute.subnet.error.pattern
</div>
</div>
</div>
</div>
</div>
Expand Down
1 change: 0 additions & 1 deletion src/js/controllers/wizard.js
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,6 @@ module.exports = function(app) {
});
};

// helpers for validation
$scope.hasError = function(field) {
var form = $scope.wizardForm;
return (form.$submitted || form[field].$dirty) && form[field].$invalid;
Expand Down
31 changes: 31 additions & 0 deletions src/js/directives/fileRequired.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//required validation for input type file is not supported yet
//see: https://github.com/angular/angular.js/issues/1375
//see: https://github.com/angular/angular.js/pull/8987

'use strict';

module.exports = function(app) {
app.directive('fileValid', function() {
return {
require: 'ngModel',
scope: {
required: '=ngRequired'
},
link: function(scope, element, attributes, ngModel) {
console.log(scope.required);
scope.$watch('required', function(newValue, oldValue) {
console.log('required changed');
});

//handle element change
element.bind('change',function() {
scope.$apply(function() {
ngModel.$setViewValue(element.val());
ngModel.$render();
});
});

}
};
});
};
1 change: 1 addition & 0 deletions src/js/directives/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
module.exports = function(app) {
require('./compareTo')(app);
require('./ipv4Address')(app);
require('./fileRequired')(app);
require('./objectLength')(app);
};
118 changes: 114 additions & 4 deletions src/js/directives/ipv4Address.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,32 @@ var ip = require('ip');

module.exports = function(app) {
// check if the provided value is a valid ipv4 address
app.directive('ipv4Address', function() {
app.directive('ipAddress', function() {
return {
require: 'ngModel',
link: function(scope, element, attributes, ngModel) {
ngModel.$validators.ipv4Address = function(modelValue) {

var ipv4Pattern = '(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}' +
'(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)';
var ipv4SubnetPattern = ipv4Pattern + '\/(25|26|27|28)';

// there are a lot of regex for ipv6
// http://regexlib.com/Search.aspx?k=ipv6
// this one matches the expanded ipv6 pattern
var ipv6Pattern = '([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}';
var ipv6SubnetPattern = ipv6Pattern + '\/(64|65)';

var ipv4AddressValidator = function(modelValue) {
//validation for required should be done via ng-required directive
//or the validation even fails if the field is not required
if (isEmpty(modelValue)) {
return true;
}

// we run an additional regular expression against the model
// because the 'ip' module does not catch all cases
var ipRegex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
if (!ipRegex.exec(modelValue)) {
if (!regexMatches(ipv4Pattern, modelValue)) {
console.log('ipv4 pattern does not match');
return false;
}

Expand All @@ -26,6 +43,99 @@ module.exports = function(app) {
return true;
};

var ipv4SubnetValidator = function(modelValue) {
//validation for required should be done via ng-required directive
//or the validation even fails if the field is not required
if (isEmpty(modelValue)) {
return true;
}
return regexMatches(ipv4SubnetPattern, modelValue);
};

var ipv6AddressValidator = function(modelValue) {
if (isEmpty(modelValue)) {
return true;
}
modelValue = expandV6Address(modelValue);
return regexMatches(ipv6Pattern, modelValue);
};

var ipv6SubnetValidator = function(modelValue) {
if (isEmpty(modelValue)) {
return true;
}

var splitted = modelValue.split('/');
modelValue = expandV6Address(splitted[0]) + '/' + splitted[1];
var valid = regexMatches(ipv6SubnetPattern, modelValue);
return valid;
};

//expands an ipv6 address
var expandV6Address = function(modelValue) {
var collapsedV6 = modelValue.split(':');
modelValue = '';
for (var i = 0; i < collapsedV6.length; i++) {
if (isEmpty(collapsedV6[i]) && isEmpty(collapsedV6[i + 1])) {
//if there are two empty array items in a row
//it means the pattern :: has to be replaced with :0
for (var j = 8; j > collapsedV6.length - 2; j--) {
modelValue = modelValue + ':0';
}
//skip next entry
i++;
} else {
modelValue = modelValue + ':' + collapsedV6[i];
}
}
return modelValue.substr(1);
};

var regexMatches = function(pattern, modelValue) {
var ipRegex = new RegExp('^' + pattern + '$');
if (ipRegex.exec(modelValue)) {
return true;
}
return false;
};

var isEmpty = function(modelValue) {
if (typeof modelValue == 'undefined' || modelValue === '') {
return true;
}
return false;
};

//add validators
if (typeof attributes.ipVersion == 'undefined' ||
attributes.ipVersion == '4') {
if (typeof attributes.ipType == 'undefined') {
ngModel.$validators.ipv4Address = ipv4AddressValidator;
} else if (attributes.ipType == 'subnet') {
ngModel.$validators.ipv4Subnet = ipv4SubnetValidator;
} else {
if (console) {
console.error('ip type >' + attributes.ipType +
'< is not supported');
}
}
} else if (attributes.ipVersion == '6') {
if (typeof attributes.ipType == 'undefined') {
ngModel.$validators.ipv6Address = ipv6AddressValidator;
} else if (attributes.ipType == 'subnet') {
ngModel.$validators.ipv6Subnet = ipv6SubnetValidator;
} else {
if (console) {
console.error('ip type >' + attributes.ipType +
'< is not supported');
}
}
} else {
if (console) {
console.error('ip version >' + attributes.ipVersion +
'< is not supported');
}
}
}
};
});
Expand Down
Loading

0 comments on commit abe0623

Please sign in to comment.