Skip to content

Commit

Permalink
Validation on Deploy Page: Labels -> Label Key(validation for 'value'…
Browse files Browse the repository at this point in the history
… will be in a separate PR).
  • Loading branch information
digitalfishpond committed Mar 4, 2016
1 parent 056e9cc commit b546ce3
Show file tree
Hide file tree
Showing 4 changed files with 345 additions and 7 deletions.
8 changes: 8 additions & 0 deletions src/app/frontend/deploy/deploylabel.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@
placeholder="{{labelCtrl.label.key}}" ng-disabled="!labelCtrl.label.editable">
<ng-messages for="labelForm.key.$error" ng-if="labelForm.key.$invalid">
<ng-message when="unique">{{labelCtrl.label.key}} is not unique.</ng-message>
<ng-message when="prefixPattern">
Prefix (before slash) is not a valid DNS subdomain prefix eg. my-domain.com
</ng-message>
<ng-message when="namePattern">
Label key name should be lower or upper-case alphanumeric with '-', '_' and '.' between words only
</ng-message>
<ng-message when="prefixLength">Prefix should not exceed 253 characters</ng-message>
<ng-message when="nameLength">Label Key name should not exceed 63 characters</ng-message>
</ng-messages>
</md-input-container>
<p flex="5"></p>
Expand Down
110 changes: 105 additions & 5 deletions src/app/frontend/deploy/deploylabel_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,22 +88,44 @@ export default class DeployLabelController {
addNewLabel_() { this.labels.push(new DeployLabel()); }

/**
* Validates label withing label form.
* Validates label within label form.
* Current checks:
* - duplicated key
* - key prefix pattern
* - key name pattern
* - key prefix length
* - key name length
* @param {!angular.FormController|undefined} labelForm
* @private
*/
// TODO: @digitalfishpond Move these validations to directives
validateKey_(labelForm) {
if (angular.isDefined(labelForm)) {
/** @type {!angular.NgModelController} */
let elem = labelForm.key;
/** @type {!RegExp} */
let PrefixPattern = /^(.*\/.*)$/;
/** @type {boolean} */
let isPrefixed = PrefixPattern.test(this.label.key);
/** @type {number} */
let slashPosition = isPrefixed ? this.label.key.indexOf("/") : -1;

// TODO(floreks): Validate label key/value.
/** @type {boolean} */
let isValid = !this.isDuplicated_();
let isUnique = !this.isKeyDuplicated_();
/** @type {boolean} */
let isKeyPrefixPatternOk = this.matchesKeyPrefixPattern_(isPrefixed, slashPosition);
/** @type {boolean} */
let isKeyNamePatternOk = this.matchesKeyNamePattern_(isPrefixed, slashPosition);
/** @type {boolean} */
let isKeyPrefixLengthOk = this.matchesKeyPrefixLength_(isPrefixed, slashPosition);
/** @type {boolean} */
let isKeyNameLengthOk = this.matchesKeyNameLength_(isPrefixed, slashPosition);

elem.$setValidity('unique', isValid);
elem.$setValidity('unique', isUnique);
elem.$setValidity('prefixPattern', isKeyPrefixPatternOk);
elem.$setValidity('namePattern', isKeyNamePatternOk);
elem.$setValidity('prefixLength', isKeyPrefixLengthOk);
elem.$setValidity('nameLength', isKeyNameLengthOk);
}
}

Expand All @@ -113,7 +135,7 @@ export default class DeployLabelController {
* @return {boolean}
* @private
*/
isDuplicated_() {
isKeyDuplicated_() {
/** @type {number} */
let duplications = 0;

Expand All @@ -126,6 +148,84 @@ export default class DeployLabelController {
return duplications > 1;
}

/**
* Returns true if the label key prefix (before the "/" if there is one) matches a lowercase
* alphanumeric character
* optionally followed by lowercase alphanumeric or '-' or '.' and ending with a lower case
* alphanumeric character,
* with '.' only permitted if surrounded by lowercase alphanumeric characters (eg:
* 'good.prefix-pattern',
* otherwise returns false.
* @return {boolean}
* @param {boolean} isPrefixed
* @param {number} slashPosition
* @private
*/
matchesKeyPrefixPattern_(isPrefixed, slashPosition) {
/** @type {!RegExp} */
let labelKeyPrefixPattern = /^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$/;
/** @type {string} */
let labelPrefix = isPrefixed ? this.label.key.substring(0, slashPosition) : "valid-pattern";

return (labelKeyPrefixPattern.test(labelPrefix));
}

/**
* Returns true if the label key name (after the "/" if there is one) matches an alphanumeric
* character (upper
* or lower case) optionally followed by alphanumeric or -_. and ending with an alphanumeric
* character
* (upper or lower case), otherwise returns false.
* @return {boolean}
* @param {boolean} isPrefixed
* @param {number} slashPosition
* @private
*/
matchesKeyNamePattern_(isPrefixed, slashPosition) {
/** @type {!RegExp} */
let labelKeyNamePattern = /^([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$/;
/** @type {string} */
let labelName = isPrefixed ? this.label.key.substring(slashPosition + 1) : this.label.key;

return (labelKeyNamePattern.test(labelName));
}

/**
* Returns true if the label key name (after the "/" if there is one) is equal or shorter than 253
* characters,
* otherwise returns false.
* @return {boolean}
* @param {boolean} isPrefixed
* @param {number} slashPosition
* @private
*/
matchesKeyPrefixLength_(isPrefixed, slashPosition) {
/** @type {number} */
let maxLength = 253;
/** @type {string} */
let labelPrefix = isPrefixed ? this.label.key.substring(0, slashPosition) : '';

return (labelPrefix.length <= maxLength);
}

/**
* Returns true if the label key name (after the "/" if there is one) is equal or shorter than 63
* characters,
* otherwise returns false.
* @return {boolean}
* @param {boolean} isPrefixed
* @param {number} slashPosition
* @private
*/
matchesKeyNameLength_(isPrefixed, slashPosition) {
/** @type {number} */
let maxLength = 63;
/** @type {string} */
let labelName = isPrefixed ? this.label.key.substring(slashPosition + 1) : this.label.key;

return (labelName.length <= maxLength);
}

/**
* Returns true if label key and value are not empty, false otherwise.
* @param {!DeployLabel} label
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -403,11 +403,11 @@ describe('DeployFromSettings controller', () => {
};

// then
for (let pattern in allPatterns) {
Object.keys(allPatterns).forEach((pattern) => {
expect('mylowercasename'.match(allPatterns[pattern])).toBeDefined();
expect('my-name-with-dashes-between'.match(allPatterns[pattern])).toBeDefined();
expect('my-n4m3-with-numb3r5'.match(allPatterns[pattern])).toBeDefined();
}
});
});

/**
Expand Down
Loading

0 comments on commit b546ce3

Please sign in to comment.