WebUI: User management full implementation.
Added webui user accounts management. This support
both redfish and rest based backend API calls
depending on redfishSupportEnabled flag.
It does following actions:
- View all user list and there properties like
name, privilege, enabled state, Locked etc..
- Create new user account.
- Delete existing user account.
- Update the existing user properties like
password, privilege, enabled state.
Unit Test:
- Viewed all user information is proper or not.
- Created new user and validated.
- Deleted specific user and checked.
- Modified user info and validated the change.
All tests are done by enabling and disabling
redfishSupportEnabled flag using conifg.json.
Change-Id: Ifecf63844dc42c44771509958bf75947a92997ac
Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
diff --git a/app/users/controllers/user-accounts-controller.html b/app/users/controllers/user-accounts-controller.html
index 9d388bc..d37c5e1 100644
--- a/app/users/controllers/user-accounts-controller.html
+++ b/app/users/controllers/user-accounts-controller.html
@@ -1,46 +1,95 @@
+<loader loading="loading"></loader>
<div id="user-accounts">
<div class="row column">
- <h1>Manage user account</h1>
- <div class="column small-12 page-header">
- <h2 class="h4">Change password</h2>
+ <h1>User account information</h1>
+ </div>
+ <div class="table row column" ng-show="users.length != 0">
+ <div class="table__head">
+ <div class="table__row">
+ <div class="table__cell"> Username </div>
+ <div class="table__cell"> Enabled </div>
+ <div class="table__cell"> Role </div>
+ <div class="table__cell"> Locked </div>
+ <div class="table__cell"> Action </div>
+ </div>
+ </div>
+ <div class="table__body">
+ <div class="table__row" ng-repeat="user in users">
+ <div class="table__cell"> {{user.UserName}} </div>
+ <div class="table__cell"> {{user.Enabled}} </div>
+ <div class="table__cell"> {{user.RoleId}} </div>
+ <div class="table__cell"> {{user.Locked}} </div>
+ <div class="table__cell">
+ <button type="button" class="btn-primary inline" ng-disabled="isUserSelected" ng-click="setSelectedUser(user)">Edit</button>
+ <button type="button" class="btn-primary inline" ng-disabled="isUserSelected" ng-click="deleteUser(user.UserName)">Delete</button>
+ </div>
+ </div>
</div>
</div>
- <section class="row column" aria-label="change password form">
- <form class="user-manage__form" role="form">
- <fieldset>
- <legend aria-label="user manager" class="accessible-text">Change password form</legend>
- <div class="row column">
- <label for="user-manage__current-password">Current password</label>
- <input id="user-manage__current-password" type="password" ng-model="oldPassword" class="user-manage__current-password inline" autocomplete="off"/>
+ <div class="table row column" ng-show="users.length == 0">
+ <span>No users exist in system</span>
+ </div>
+
+ <form role="form" class="user-manage__form">
+ <section class="row column" aria-label="user manage form">
+ <div class="column small-12 page-header">
+ <h2 class="inline h4">User account settings</h2>
+ </div>
+ <div class='col-sm-12'>
+ <label class="col-md-1 control-label">UserName</label>
+ <div class="col-md-3">
+ <input type="text" class="form-control" name="UserName" ng-model="selectedUser.UserName" />
+ </div>
</div>
- <div class="inline">
- <label for="user-manage__new-password">New password</label>
- <div class="user-manage__input-wrapper inline">
- <input id="user-manage__new-password" type="{{showpassword ? 'text' : 'password'}}" ng-model="password" class="user-manage__new-password inline" autocomplete="off"/>
+ <div class='col-sm-12 inline'>
+ <label class="col-md-1 control-label">Password</label>
+ <div class="col-md-3 user-manage__input-wrapper inline">
+ <input type="{{showpassword ? 'text' : 'password'}}" class="form-control user-manage__new-password inline" name="Password" ng-model="selectedUser.Password" 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>
</div>
- <div class="inline">
- <label for="user-manage__verify-password">Retype new password</label>
- <div class="user-manage__input-wrapper inline">
- <input id="user-manage__verify-password" type="{{showpasswordVerify ? 'text' : 'password'}}" ng-model="passwordVerify" class="user-manage__verify-password inline" autocomplete="off"/>
+ <div class='col-sm-12'>
+ <label class="col-md-1 control-label">Retype Password</label>
+ <div class="col-md-3 user-manage__input-wrapper inline">
+ <input type="{{showpasswordVerify ? 'text' : 'password'}}" class="form-control user-manage__verify-password inline" name="VerifyPassword" ng-model="selectedUser.VerifyPassword" 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>
</div>
- </fieldset>
- <div class="user-manage__submit-wrapper">
- <button class="btn-primary inline" ng-click="changePassword(oldPassword, password, passwordVerify)">Save change</button>
+ <div class='col-sm-12'>
+ <label class="col-md-1 control-label">Role</label>
+ <div class="col-md-3 user-manage__input-wrapper inline">
+ <select ng-model="selectedUser.RoleId" class="form-control inline">
+ <option ng-repeat="role in roles" class="inline">{{role}}</option>
+ </select>
+ </div>
+ </div>
+ <div class='col-sm-12'>
+ <label class="col-md-1 control-label">Enabled</label>
+ <div class="col-md-3 user-manage__input-wrapper inline">
+ <label class="control-check">
+ <input type="checkbox" name="Enabled" ng-model="selectedUser.Enabled"/>
+ <span class="control__indicator"></span>
+ </label>
+ </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" 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>
- <p ng-class="'change-password__' + state" role="alert">
- {{state === 'error' ? errorMsg : ''}}
- {{state === 'success' ? 'Success! User Password has been changed!' : ''}}
- </p>
- </form>
- </section>
+ </section>
+ </form>
</div>
diff --git a/app/users/controllers/user-accounts-controller.js b/app/users/controllers/user-accounts-controller.js
index 24a93cb..5f90844 100644
--- a/app/users/controllers/user-accounts-controller.js
+++ b/app/users/controllers/user-accounts-controller.js
@@ -10,58 +10,168 @@
'use strict';
angular.module('app.users').controller('userAccountsController', [
- '$scope', '$window', 'APIUtils', 'dataService',
- function($scope, $window, APIUtils, dataService) {
- $scope.dataService = dataService;
+ '$scope', 'APIUtils',
+ function($scope, APIUtils) {
+ // TODO: Get the roles using Roles redfish URI.
+ $scope.roles = ['Administrator', 'Operator', 'User', 'Callback'];
$scope.state = 'none';
- $scope.errorMsg = '';
+ $scope.outMsg = '';
+ $scope.loading = true;
- $scope.changePassword = function(
- oldPassword, newPassword, confirmNewPassword) {
- var user = $scope.dataService.getUser();
- if (!oldPassword || !newPassword || !confirmNewPassword) {
- $scope.state = 'error';
- $scope.errorMsg = 'Field is required!';
- return false;
- }
- if (newPassword !== confirmNewPassword) {
- $scope.state = 'error';
- $scope.errorMsg = 'New passwords do not match!';
- return false;
- }
- if (newPassword === oldPassword) {
- $scope.state = 'error';
- $scope.errorMsg = 'New password and old password match!';
- return false;
- }
+ function loadUserInfo() {
+ $scope.users = [];
+ $scope.loading = true;
+ $scope.isUserSelected = false;
+ $scope.selectedUser = null;
- // Verify the oldPassword is correct
- dataService.ignoreHttpError = true;
- APIUtils.testPassword(user, oldPassword)
+ APIUtils.getAllUserAccounts()
.then(
- function(state) {
- APIUtils.changePassword(user, newPassword)
- .then(
- function(response) {
- // Clear the textboxes on a success
- $scope.passwordVerify = '';
- $scope.password = '';
- $scope.oldPassword = '';
- $scope.state = 'success';
- },
- function(error) {
- $scope.state = 'error';
- $scope.errorMsg = 'Error changing password!';
- });
+ function(res) {
+ $scope.users = res;
+ },
+ function(error) {
+ console.log(JSON.stringify(error));
+ })
+ .finally(function() {
+ $scope.loading = false;
+ });
+ };
+ $scope.cancel = function() {
+ $scope.state = 'none';
+ $scope.outMsg = '';
+ loadUserInfo();
+ };
+ $scope.setSelectedUser = function(user) {
+ $scope.state = 'none';
+ $scope.outMsg = '';
+
+ $scope.isUserSelected = true;
+ $scope.selectedUser = angular.copy(user);
+ $scope.selectedUser.VerifyPassword = null;
+ // Used while renaming the user.
+ $scope.selectedUser.CurrentUserName = $scope.selectedUser.UserName;
+ };
+ $scope.createNewUser = function() {
+ $scope.state = 'none';
+ $scope.outMsg = '';
+
+ if (!$scope.selectedUser.UserName || !$scope.selectedUser.Password) {
+ $scope.state = 'error';
+ $scope.outMsg = 'Username or Password can\'t be empty';
+ return;
+ }
+ if ($scope.selectedUser.Password !==
+ $scope.selectedUser.VerifyPassword) {
+ $scope.state = 'error';
+ $scope.outMsg = 'Passwords do not match';
+ return;
+ }
+ var user = $scope.selectedUser.UserName;
+ var passwd = $scope.selectedUser.Password;
+ var role = $scope.selectedUser.RoleId;
+ var enabled = false;
+ if ($scope.selectedUser.Enabled != null) {
+ enabled = $scope.selectedUser.Enabled;
+ }
+
+ $scope.loading = true;
+ APIUtils.createUser(user, passwd, role, enabled)
+ .then(
+ function(response) {
+ $scope.state = 'success';
+ $scope.outMsg = 'User has been created successfully';
},
function(error) {
$scope.state = 'error';
- $scope.errorMsg = 'Old password is not correct!';
+ if ((error.data.error['@Message.ExtendedInfo'] !=
+ undefined) &&
+ (error.data.error['@Message.ExtendedInfo'].length != 0)) {
+ $scope.outMsg =
+ error.data.error['@Message.ExtendedInfo'][0].Message;
+ } else {
+ $scope.outMsg = 'Failed to create new user.';
+ }
})
.finally(function() {
- dataService.ignoreHttpError = false;
+ loadUserInfo();
+ $scope.loading = false;
});
};
+ $scope.updateUserInfo = function() {
+ $scope.state = 'none';
+ $scope.outMsg = '';
+ if ($scope.selectedUser.Password !==
+ $scope.selectedUser.VerifyPassword) {
+ $scope.state = 'error';
+ $scope.outMsg = 'Passwords do not match';
+ return;
+ }
+ var data = {};
+ if ($scope.selectedUser.UserName !==
+ $scope.selectedUser.CurrentUserName) {
+ data['UserName'] = $scope.selectedUser.UserName;
+ }
+ $scope.selectedUser.VerifyPassword = null;
+ if ($scope.selectedUser.Password != null) {
+ data['Password'] = $scope.selectedUser.Password;
+ }
+ data['RoleId'] = $scope.selectedUser.RoleId;
+ data['Enabled'] = $scope.selectedUser.Enabled;
+
+ $scope.loading = true;
+ APIUtils
+ .updateUser(
+ $scope.selectedUser.CurrentUserName, data['UserName'],
+ data['Password'], data['RoleId'], data['Enabled'])
+ .then(
+ function(response) {
+ $scope.state = 'success';
+ $scope.outMsg = 'User has been updated successfully';
+ },
+ function(error) {
+ $scope.state = 'error';
+ if ((error.data.error['@Message.ExtendedInfo'] !=
+ undefined) &&
+ (error.data.error['@Message.ExtendedInfo'].length != 0)) {
+ $scope.outMsg =
+ error.data.error['@Message.ExtendedInfo'][0].Message;
+ } else {
+ $scope.outMsg = 'Updating user failed.';
+ }
+ })
+ .finally(function() {
+ loadUserInfo();
+ $scope.loading = false;
+ });
+ };
+ $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';
+ },
+ function(error) {
+ $scope.state = 'error';
+ if ((error.data.error['@Message.ExtendedInfo'] !=
+ undefined) &&
+ (error.data.error['@Message.ExtendedInfo'].length != 0)) {
+ $scope.outMsg =
+ error.data.error['@Message.ExtendedInfo'][0].Message;
+ } else {
+ $scope.outMsg = 'Deleting user failed.';
+ }
+ })
+ .finally(function() {
+ loadUserInfo();
+ $scope.loading = false;
+ });
+ };
+ loadUserInfo();
}
]);
})(angular);
diff --git a/app/users/styles/index.scss b/app/users/styles/index.scss
index 5162e09..da9c25e 100644
--- a/app/users/styles/index.scss
+++ b/app/users/styles/index.scss
@@ -1 +1 @@
-@import "./user-accounts.scss";
\ No newline at end of file
+@import "./user-accounts.scss";
diff --git a/app/users/styles/user-accounts.scss b/app/users/styles/user-accounts.scss
index 891b3a9..fb6d162 100644
--- a/app/users/styles/user-accounts.scss
+++ b/app/users/styles/user-accounts.scss
@@ -2,6 +2,9 @@
.user-manage__form {
width: 100%;
+ .dropdown__button {
+ margin-bottom: 1.2em;
+ }
label {
width: 100%;
min-width: 210px;
@@ -12,13 +15,16 @@
width: 225px;
height: $userInputHeight;
}
+ select {
+ width: 225px;
+ height: $userInputHeight;
+ }
fieldset {
display: block;
padding-left: 1.5em;
margin-bottom: 1em;
border-bottom: 1px solid $medgrey;
}
-
.user-manage__input-wrapper {
position: relative;
height: $userInputHeight;
@@ -31,15 +37,22 @@
position: absolute;
right: 5px;
padding: 3px;
+ margin-right: 20px;
color: $primebtn__bg;
font-size: .8em;
@include vertCenter;
}
- .user-manage__submit-wrapper button {
- float: right;
- margin-left: .5em;
+ .user-manage__submit-wrapper {
+ width: 100%;
+ margin-top: 3em;
+ padding-top: 1em;
+ border-top: 1px solid $medgrey;
+ button {
+ float: right;
+ margin: .5em;
+ }
}
- .change-password__error
+ .user-manage__error
{
background: lighten($error-color, 20%);
padding: 1em;
@@ -49,9 +62,8 @@
color: $black;
font-family: "Courier New", Helvetica, Arial, sans-serif;
font-weight: 700;
- width: 325px;
}
- .change-password__success
+ .user-manage__success
{
color: $primebtn__bg;
padding: 1em;