summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbeccabroek <beccabroek@gmail.com>2019-03-22 15:38:49 -0500
committerGunnar Mills <gmills@us.ibm.com>2019-04-05 19:56:23 +0000
commita5deeeafe84893722d601b2343943eb78f263e4f (patch)
tree467be7aeae3a452abd67f04495a7052883291be0
parent2f481e4cb83f0c72a9f3aad11431e4abcf5d632c (diff)
downloadphosphor-webui-a5deeeafe84893722d601b2343943eb78f263e4f.tar.gz
phosphor-webui-a5deeeafe84893722d601b2343943eb78f263e4f.zip
Add form validation and toast messages to user mgmt
Adds form field validation with ng-messages and toast messages with toast service to the User management page. Also adds check that the number of users does not exceed 15 and that the username does not already exist prior to sending call to the backend. Resolves openbmc/phosphor-webui#73 Resolves openbmc/phosphor-webui#74 Tested: Able to add/delete/edit users as before. Page presents appropriate message to user upon creating or updating a user when: 1. A field is missing 2. Passwords don't match 3. Password is longer than max or shorter than min 4. Username already exists when creating new user 5. User tries to create the 16th user Change-Id: I5ae1a7979f7a396b0fb2ea280b875afc805a7f9f Signed-off-by: beccabroek <beccabroek@gmail.com>
-rw-r--r--app/users/controllers/user-accounts-controller.html53
-rw-r--r--app/users/controllers/user-accounts-controller.js82
-rw-r--r--app/users/styles/user-accounts.scss7
3 files changed, 69 insertions, 73 deletions
diff --git a/app/users/controllers/user-accounts-controller.html b/app/users/controllers/user-accounts-controller.html
index b48626d..f5bdda0 100644
--- a/app/users/controllers/user-accounts-controller.html
+++ b/app/users/controllers/user-accounts-controller.html
@@ -19,18 +19,6 @@
<input type="number" id="lockoutThreshold" min="3" max="10" ng-model="properties.AccountLockoutThreshold"/>
</div>
</div>
- <div class= "col-sm-12">
- <label class="col-md-1 control-label"> Max Password Length </label>
- <div class="col-md-3 acnt-prop__span-wrapper">
- <span>{{properties.MaxPasswordLength}}</span>
- </div>
- </div>
- <div class="col-sm-12">
- <label class="col-md-1 control-label"> Min Password Length </label>
- <div class="col-md-3 acnt-prop__span-wrapper">
- <span>{{properties.MinPasswordLength}}</span>
- </div>
- </div>
<div class="acnt-prop__submit-wrapper">
<button type="button" class="btn-primary inline" ng-click="saveAllValues()">Save settings</button>
</div>
@@ -67,43 +55,59 @@
<span>No users exist in system</span>
</div>
- <form role="form" class="user-manage__form">
- <section class="row column" aria-label="user manage form">
+ <form role="form" name="user__form" class="user-manage__form">
+ <section class="row column" aria-label="user manage form" ng-class="{'submitted':submitted}">
<div class="column small-12 page-header">
<h2 class="inline">User account settings</h2>
</div>
<div class='col-sm-12'>
<label class="col-md-1 control-label" for="user-manage__username">UserName</label>
<div class="col-md-3">
- <input type="text" name="UserName" id="user-manage__username" ng-model="selectedUser.UserName" />
+ <input type="text" name="UserName" id="user-manage__username" ng-model="selectedUser.UserName" has-error="doesUserExist()" required />
+ <div ng-messages="user__form.UserName.$error" class="form-error" ng-class="{'visible' : user__form.UserName.$touched || submitted}">
+ <p ng-message="required">Field is required</p>
+ <p ng-message="hasError">Username exists</p>
+ </div>
</div>
</div>
<div class='col-sm-12 inline'>
<label class="col-md-1 control-label" for="user-manage__passwd">Password</label>
<div class="col-md-3 user-manage__input-wrapper inline">
- <input type="{{showpassword ? 'text' : 'password'}}" class="user-manage__new-password inline" name="Password" id="user-manage__passwd" ng-model="selectedUser.Password" autocomplete="off"/>
+ <input type="{{showpassword ? 'text' : 'password'}}" class="user-manage__new-password inline" name="Password" id="user-manage__passwd" ng-model="selectedUser.Password" ng-minlength="properties.MinPasswordLength" ng-maxlength="properties.MaxPasswordLength" required autocomplete="off"/>
<button ng-model="showpassword" ng-click="togglePassword = !togglePassword; showpassword = !showpassword;" class="password-toggle">
<span ng-hide="togglePassword">Show</span>
<span ng-show="togglePassword">Hide</span>
</button>
+ <div ng-messages="user__form.Password.$error" class="form-error" ng-class="{'visible' : user__form.Password.$touched || submitted}">
+ <p ng-message="required">Field is required</p>
+ <p ng-message="minlength">Must be at least {{properties.MinPasswordLength}} characters</p>
+ <p ng-message="maxlength">Must be {{properties.MaxPasswordLength}} characters or less</p>
+ </div>
</div>
</div>
<div class='col-sm-12'>
<label class="col-md-1 control-label" for="user-manage__verifypasswd">Retype Password</label>
<div class="col-md-3 user-manage__input-wrapper inline">
- <input type="{{showpasswordVerify ? 'text' : 'password'}}" class="user-manage__verify-password inline" name="VerifyPassword" id="user-manage__verifypasswd" ng-model="selectedUser.VerifyPassword" autocomplete="off">
+ <input type="{{showpasswordVerify ? 'text' : 'password'}}" class="user-manage__verify-password inline" name="VerifyPassword" id="user-manage__verifypasswd" ng-model="selectedUser.VerifyPassword" has-error="selectedUser.VerifyPassword != selectedUser.Password" required autocomplete="off">
<button ng-model="showpasswordVerify" ng-click="toggleVerify = !toggleVerify; showpasswordVerify = !showpasswordVerify;" class="password-toggle">
<span ng-hide="toggleVerify">Show</span>
<span ng-show="toggleVerify">Hide</span>
</button>
+ <div ng-messages="user__form.VerifyPassword.$error" class="form-error" ng-class="{'visible' : user__form.VerifyPassword.$touched || submitted}">
+ <p ng-message="required">Field is required</p>
+ <p ng-message="hasError">Passwords do not match</p>
+ </div>
</div>
</div>
<div class='col-sm-12'>
- <label class="col-md-1 control-label" for="user-manage__role">Role</label>
+ <label class="col-md-1 control-label" for="role">Role</label>
<div class="col-md-3 user-manage__input-wrapper inline">
- <select ng-model="selectedUser.RoleId" id="user-manage__role" class="inline">
+ <select ng-model="selectedUser.RoleId" id="role" name="role" class="inline" required>
<option ng-repeat="role in roles" class="inline">{{role}}</option>
</select>
+ <div ng-messages="user__form.role.$error" class="form-error" ng-class="{'visible' : user__form.role.$touched || submitted}">
+ <p ng-message="required">Field is required</p>
+ </div>
</div>
</div>
<div class='col-sm-12'>
@@ -116,17 +120,10 @@
</div>
</div>
<div class="user-manage__submit-wrapper">
- <button type="button" class="btn-primary inline" ng-if="!isUserSelected" ng-click="createNewUser()">Create User</button>
- <button type="button" class="btn-primary inline" ng-if="isUserSelected" ng-click="updateUserInfo()">Save</button>
+ <button type="button" ng-click="submitted=true; user__form.$valid && createNewUser(); user__form.$setUntouched()" ng-show="!isUserSelected" class="btn-primary inline">Create user</button>
+ <button type="button" class="btn-primary inline" ng-click="submitted=true; user__form.$valid && updateUserInfo(); user__form.$setUntouched()" ng-show="isUserSelected">Save</button>
<button type="button" class="btn-primary inline" ng-if="isUserSelected" ng-click="cancel()">Cancel</button>
</div>
</section>
- <section class="row column">
- <div class='col-sm-12'>
- <p ng-class="'user-manage__' + state" role="alert">
- {{outMsg}}
- </p>
- </div>
- </section>
</form>
</div>
diff --git a/app/users/controllers/user-accounts-controller.js b/app/users/controllers/user-accounts-controller.js
index e12db00..12ec170 100644
--- a/app/users/controllers/user-accounts-controller.js
+++ b/app/users/controllers/user-accounts-controller.js
@@ -10,20 +10,20 @@ window.angular && (function(angular) {
'use strict';
angular.module('app.users').controller('userAccountsController', [
- '$scope', '$q', 'APIUtils',
- function($scope, $q, APIUtils) {
+ '$scope', '$q', 'APIUtils', 'toastService',
+ function($scope, $q, APIUtils, toastService) {
$scope.users = [];
$scope.roles = [];
- $scope.state = 'none';
- $scope.outMsg = '';
$scope.loading = true;
$scope.properties = {};
$scope.origProp = {};
+ $scope.submitted = false;
function loadUserInfo() {
$scope.loading = true;
+ $scope.submitted = false;
$scope.isUserSelected = false;
- $scope.selectedUser = null;
+ $scope.selectedUser = {};
$scope.togglePassword = false;
$scope.toggleVerify = false;
@@ -58,14 +58,10 @@ window.angular && (function(angular) {
};
$scope.cancel = function() {
- $scope.state = 'none';
- $scope.outMsg = '';
loadUserInfo();
};
$scope.saveAllValues = function() {
- $scope.state = 'none';
- $scope.outMsg = '';
$scope.loading = true;
var data = {};
if ($scope.properties.AccountLockoutDuration !=
@@ -93,12 +89,11 @@ window.angular && (function(angular) {
data['AccountLockoutDuration'], data['AccountLockoutThreshold'])
.then(
function(response) {
- $scope.state = 'success';
- $scope.outMsg =
- 'User account properties has been updated successfully';
+ toastService.success(
+ 'User account properties have been updated successfully');
},
function(error) {
- $scope.outMsg = 'Account Properties Updation failed.';
+ toastService.error('Unable to update account properties');
})
.finally(function() {
loadUserInfo();
@@ -107,9 +102,6 @@ window.angular && (function(angular) {
};
$scope.setSelectedUser = function(user) {
- $scope.state = 'none';
- $scope.outMsg = '';
-
$scope.isUserSelected = true;
$scope.selectedUser = angular.copy(user);
$scope.selectedUser.VerifyPassword = null;
@@ -117,18 +109,22 @@ window.angular && (function(angular) {
$scope.selectedUser.CurrentUserName = $scope.selectedUser.UserName;
};
$scope.createNewUser = function() {
- $scope.state = 'none';
- $scope.outMsg = '';
-
+ if ($scope.users.length >= 15) {
+ toastService.error(
+ 'Cannot create user. The maximum number of users that can be created is 15');
+ return;
+ }
if (!$scope.selectedUser.UserName || !$scope.selectedUser.Password) {
- $scope.state = 'error';
- $scope.outMsg = 'Username or Password can\'t be empty';
+ toastService.error('Username or password cannot be empty');
return;
}
if ($scope.selectedUser.Password !==
$scope.selectedUser.VerifyPassword) {
- $scope.state = 'error';
- $scope.outMsg = 'Passwords do not match';
+ toastService.error('Passwords do not match');
+ return;
+ }
+ if ($scope.doesUserExist()) {
+ toastService.error('Username already exists');
return;
}
var user = $scope.selectedUser.UserName;
@@ -143,12 +139,10 @@ window.angular && (function(angular) {
APIUtils.createUser(user, passwd, role, enabled)
.then(
function(response) {
- $scope.state = 'success';
- $scope.outMsg = 'User has been created successfully';
+ toastService.success('User has been created successfully');
},
function(error) {
- $scope.state = 'error';
- $scope.outMsg = 'Failed to create new user';
+ toastService.error('Failed to create new user');
})
.finally(function() {
loadUserInfo();
@@ -156,12 +150,13 @@ window.angular && (function(angular) {
});
};
$scope.updateUserInfo = function() {
- $scope.state = 'none';
- $scope.outMsg = '';
if ($scope.selectedUser.Password !==
$scope.selectedUser.VerifyPassword) {
- $scope.state = 'error';
- $scope.outMsg = 'Passwords do not match';
+ toastService.error('Passwords do not match');
+ return;
+ }
+ if ($scope.doesUserExist()) {
+ toastService.error('Username already exists');
return;
}
var data = {};
@@ -183,12 +178,10 @@ window.angular && (function(angular) {
data['Password'], data['RoleId'], data['Enabled'])
.then(
function(response) {
- $scope.state = 'success';
- $scope.outMsg = 'User has been updated successfully';
+ toastService.success('User has been updated successfully');
},
function(error) {
- $scope.state = 'error';
- $scope.outMsg = 'Updating user failed';
+ toastService.error('Unable to update user');
})
.finally(function() {
loadUserInfo();
@@ -196,19 +189,14 @@ window.angular && (function(angular) {
});
};
$scope.deleteUser = function(userName) {
- $scope.state = 'none';
- $scope.outMsg = '';
-
$scope.loading = true;
APIUtils.deleteUser(userName)
.then(
function(response) {
- $scope.state = 'success';
- $scope.outMsg = 'User has been deleted successfully';
+ toastService.success('User has been deleted successfully');
},
function(error) {
- $scope.state = 'error';
- $scope.outMsg = 'Deleting user failed';
+ toastService.error('Unable to delete user');
})
.finally(function() {
loadUserInfo();
@@ -216,6 +204,16 @@ window.angular && (function(angular) {
});
};
+ $scope.doesUserExist = function() {
+ for (var i in $scope.users) {
+ // If a user exists with the same user name and a different Id then
+ // the username already exists and isn't valid
+ if (($scope.users[i].UserName === $scope.selectedUser.UserName) &&
+ ($scope.users[i].Id !== $scope.selectedUser.Id)) {
+ return true;
+ }
+ }
+ };
loadUserInfo();
}
]);
diff --git a/app/users/styles/user-accounts.scss b/app/users/styles/user-accounts.scss
index 858d1aa..1027229 100644
--- a/app/users/styles/user-accounts.scss
+++ b/app/users/styles/user-accounts.scss
@@ -51,9 +51,10 @@ $userInputHeight: 40px;
}
.acnt-prop__input-wrapper,
.user-manage__input-wrapper {
- position: relative;
- height: $userInputHeight;
margin-bottom: 5px;
+ select {
+ margin-bottom: 0;
+ }
}
.acnt-prop__span-wrapper {
position: relative;
@@ -63,11 +64,11 @@ $userInputHeight: 40px;
.password-toggle {
position: absolute;
right: 5px;
+ top:.8em;
padding: 3px;
margin-right: 20px;
color: $primebtn__bg;
font-size: .8em;
- @include vertCenter;
}
.acnt-prop__submit-wrapper,
.user-manage__submit-wrapper {
OpenPOWER on IntegriCloud