1/** 2 * Controller for user Accounts 3 * 4 * @module app/access-control 5 * @exports userController 6 * @name userController 7 */ 8 9window.angular && (function(angular) { 10 'use strict'; 11 12 angular.module('app.accessControl').controller('userController', [ 13 '$scope', 'APIUtils', 'toastService', '$uibModal', '$q', 14 function($scope, APIUtils, toastService, $uibModal, $q) { 15 $scope.loading; 16 $scope.accountSettings; 17 $scope.userRoles; 18 $scope.localUsers; 19 20 $scope.tableData = []; 21 $scope.tableHeader = [ 22 {label: 'Username'}, {label: 'Privilege'}, {label: 'Account status'} 23 ]; 24 $scope.tableBatchActions = [ 25 {type: 'delete', label: 'Remove'}, 26 {type: 'enable', label: 'Enable'}, 27 {type: 'disable', label: 'Disable'}, 28 ]; 29 30 /** 31 * Returns true if username is 'root' 32 * @param {*} user 33 */ 34 function checkIfRoot(user) { 35 return user.UserName === 'root' ? true : false; 36 } 37 38 /** 39 * Data table mapper 40 * @param {*} user 41 * @returns user 42 */ 43 function mapTableData(user) { 44 const accountStatus = 45 user.Locked ? 'Locked' : user.Enabled ? 'Enabled' : 'Disabled'; 46 const editAction = {type: 'Edit', enabled: true, file: 'icon-edit.svg'}; 47 const deleteAction = { 48 type: 'Delete', 49 enabled: checkIfRoot(user) ? false : true, 50 file: 'icon-trashcan.svg' 51 }; 52 user.selectable = checkIfRoot(user) ? false : true; 53 user.actions = [editAction, deleteAction]; 54 user.uiData = [user.UserName, user.RoleId, accountStatus]; 55 return user; 56 } 57 58 /** 59 * Returns lockout method based on the lockout duration property 60 * If the lockoutDuration is greater than 0 the lockout method 61 * is automatic otherwise the lockout method is manual 62 * @param {number} lockoutDuration 63 * @returns {number} : returns the account lockout method 64 * 1(automatic) / 0(manual) 65 */ 66 function mapLockoutMethod(lockoutDuration) { 67 return lockoutDuration > 0 ? 1 : 0; 68 } 69 70 /** 71 * API call to get all user accounts 72 */ 73 function getLocalUsers() { 74 $scope.loading = true; 75 APIUtils.getAllUserAccounts() 76 .then((users) => { 77 $scope.localUsers = users; 78 $scope.tableData = users.map(mapTableData); 79 }) 80 .catch((error) => { 81 console.log(JSON.stringify(error)); 82 toastService.error('Failed to load users.'); 83 }) 84 .finally(() => { 85 $scope.loading = false; 86 }) 87 } 88 89 /** 90 * API call to get current Account settings 91 */ 92 function getAccountSettings() { 93 APIUtils.getAllUserAccountProperties() 94 .then((settings) => { 95 $scope.accountSettings = settings; 96 }) 97 .catch((error) => { 98 console.log(JSON.stringify(error)); 99 $scope.accountSettings = null; 100 }) 101 } 102 103 /** 104 * API call to get local user roles 105 */ 106 function getUserRoles() { 107 APIUtils.getAccountServiceRoles() 108 .then((roles) => { 109 $scope.userRoles = roles; 110 }) 111 .catch((error) => { 112 console.log(JSON.stringify(error)); 113 $scope.userRoles = null; 114 }) 115 } 116 117 /** 118 * API call to create new user 119 * @param {*} user 120 */ 121 function createUser(username, password, role, enabled) { 122 $scope.loading = true; 123 APIUtils.createUser(username, password, role, enabled) 124 .then(() => { 125 getLocalUsers(); 126 toastService.success(`User '${username}' has been created.`); 127 }) 128 .catch((error) => { 129 console.log(JSON.stringify(error)); 130 toastService.error(`Failed to create new user '${username}'.`); 131 }) 132 .finally(() => { 133 $scope.loading = false; 134 }); 135 } 136 137 /** 138 * API call to update existing user 139 */ 140 function updateUser( 141 originalUsername, username, password, role, enabled, locked) { 142 $scope.loading = true; 143 APIUtils 144 .updateUser( 145 originalUsername, username, password, role, enabled, locked) 146 .then(() => { 147 getLocalUsers(); 148 toastService.success('User has been updated successfully.') 149 }) 150 .catch((error) => { 151 console.log(JSON.stringify(error)); 152 toastService.error(`Unable to update user '${originalUsername}'.`) 153 }) 154 .finally(() => { 155 $scope.loading = false; 156 }) 157 } 158 159 /** 160 * API call to delete users 161 * @param {*} users : Array of users to delete 162 */ 163 function deleteUsers(users = []) { 164 $scope.loading = true; 165 const promises = 166 users.map((user) => APIUtils.deleteUser(user.UserName)); 167 $q.all(promises) 168 .then(() => { 169 let message; 170 if (users.length > 1) { 171 message = 'Users have been removed.' 172 } else { 173 message = `User '${users[0].UserName}' has been removed.` 174 } 175 toastService.success(message); 176 }) 177 .catch((error) => { 178 console.log(JSON.stringify(error)); 179 let message; 180 if (users.length > 1) { 181 message = 'Failed to remove users.' 182 } else { 183 message = `Failed to remove user '${users[0].UserName}'.` 184 } 185 toastService.error(message); 186 }) 187 .finally(() => { 188 getLocalUsers(); 189 $scope.loading = false; 190 }); 191 } 192 193 /** 194 * API call to update user status enabled/disabled 195 * @param {*} users : Array of users to update 196 * @param {boolean} enabled : status 197 */ 198 function updateUserStatus(users = [], enabled = true) { 199 $scope.loading = true; 200 const promises = users.map( 201 (user) => APIUtils.updateUser( 202 user.UserName, null, null, null, enabled, null)); 203 $q.all(promises) 204 .then(() => { 205 let message; 206 let statusLabel = enabled ? 'enabled' : 'disabled'; 207 if (users.length > 1) { 208 message = `Users ${statusLabel}.` 209 } else { 210 message = `User '${users[0].UserName}' ${statusLabel}.`; 211 } 212 toastService.success(message); 213 }) 214 .catch((error) => { 215 console.log(JSON.stringify(error)); 216 let message; 217 let statusLabel = enabled ? 'enable' : 'disable'; 218 if (users.length > 1) { 219 message = `Failed to ${statusLabel} users.` 220 } else { 221 message = 222 `Failed to ${statusLabel} user '${users[0].UserName}'.` 223 } 224 toastService.error(message); 225 }) 226 .finally(() => { 227 getLocalUsers(); 228 $scope.loading = false; 229 }); 230 } 231 232 /** 233 * API call to save account policy settings 234 * @param {number} lockoutDuration 235 * @param {number} lockoutThreshold 236 */ 237 function updateAccountSettings(lockoutDuration, lockoutThreshold) { 238 $scope.loading = true; 239 APIUtils.saveUserAccountProperties(lockoutDuration, lockoutThreshold) 240 .then(() => { 241 $scope.accountSettings['AccountLockoutDuration'] = 242 lockoutDuration; 243 $scope.accountSettings['AccountLockoutThreshold'] = 244 lockoutThreshold; 245 toastService.success( 246 'Account policy settings have been updated.'); 247 }) 248 .catch((error) => { 249 console.log(JSON.stringify(error)); 250 toastService.error('Failed to update account policy settings.'); 251 }) 252 .finally(() => { 253 $scope.loading = false; 254 }); 255 } 256 257 /** 258 * Initiate account settings modal 259 */ 260 function initAccountSettingsModal() { 261 const template = require('./user-accounts-modal-settings.html'); 262 $uibModal 263 .open({ 264 template, 265 windowTopClass: 'uib-modal', 266 ariaLabelledBy: 'dialog_label', 267 controllerAs: 'modalCtrl', 268 controller: function() { 269 const lockoutMethod = mapLockoutMethod( 270 $scope.accountSettings.AccountLockoutDuration); 271 272 this.settings = {}; 273 this.settings.maxLogin = 274 $scope.accountSettings.AccountLockoutThreshold; 275 this.settings.lockoutMethod = lockoutMethod; 276 this.settings.timeoutDuration = !lockoutMethod ? 277 null : 278 $scope.accountSettings.AccountLockoutDuration; 279 } 280 }) 281 .result 282 .then((form) => { 283 if (form.$valid) { 284 const lockoutDuration = form.lockoutMethod.$modelValue ? 285 form.timeoutDuration.$modelValue : 286 0; 287 const lockoutThreshold = form.maxLogin.$modelValue; 288 updateAccountSettings(lockoutDuration, lockoutThreshold); 289 } 290 }) 291 .catch( 292 () => { 293 // do nothing 294 }) 295 } 296 297 /** 298 * Initiate user modal 299 * Can be triggered by clicking edit in table or 'Add user' button 300 * If triggered from the table, user parameter will be provided 301 * If triggered by add user button, user parameter will be undefined 302 * @optional @param {*} user 303 */ 304 function initUserModal(user) { 305 if ($scope.userRoles === null || $scope.userRoles === undefined) { 306 // If userRoles failed to load, do not allow add/edit 307 // functionality 308 return; 309 } 310 const newUser = user ? false : true; 311 const originalUsername = user ? angular.copy(user.UserName) : null; 312 const template = require('./user-accounts-modal-user.html'); 313 $uibModal 314 .open({ 315 template, 316 windowTopClass: 'uib-modal', 317 ariaLabelledBy: 'dialog_label', 318 controllerAs: 'modalCtrl', 319 controller: function() { 320 // Set default status to Enabled 321 const status = newUser ? true : user.Enabled; 322 // Check if UserName is root 323 // Some form controls will be disabled for root users: 324 // edit enabled status, edit username, edit role 325 const isRoot = 326 newUser ? false : checkIfRoot(user) ? true : false; 327 // Array of existing usernames (excluding current user instance) 328 const existingUsernames = 329 $scope.localUsers.reduce((acc, val) => { 330 if (user && (val.UserName === user.UserName)) { 331 return acc; 332 } 333 acc.push(val.UserName); 334 return acc; 335 }, []); 336 337 this.user = {}; 338 this.user.isRoot = isRoot; 339 this.user.new = newUser; 340 this.user.accountStatus = status; 341 this.user.username = newUser ? '' : user.UserName; 342 this.user.privilege = newUser ? '' : user.RoleId; 343 this.user.locked = newUser ? null : user.Locked; 344 345 this.manualUnlockProperty = false; 346 this.automaticLockout = mapLockoutMethod( 347 $scope.accountSettings.AccountLockoutDuration); 348 this.privilegeRoles = $scope.userRoles; 349 this.existingUsernames = existingUsernames; 350 this.minPasswordLength = $scope.accountSettings ? 351 $scope.accountSettings.MinPasswordLength : 352 null; 353 this.maxPasswordLength = $scope.accountSettings ? 354 $scope.accountSettings.MaxPasswordLength : 355 null; 356 } 357 }) 358 .result 359 .then((form) => { 360 if (form.$valid) { 361 // If form control is pristine set property to null 362 // this will make sure only changed values are updated when 363 // modifying existing users 364 // API utils checks for null values 365 const username = 366 form.username.$pristine ? null : form.username.$modelValue; 367 const password = 368 form.password.$pristine ? null : form.password.$modelValue; 369 const role = form.privilege.$pristine ? 370 null : 371 form.privilege.$modelValue; 372 const enabled = (form.accountStatus.$pristine && 373 form.accountStatus1.$pristine) ? 374 null : 375 form.accountStatus.$modelValue; 376 const locked = (form.lock && form.lock.$dirty) ? 377 form.lock.$modelValue : 378 null; 379 380 if (!newUser) { 381 updateUser( 382 originalUsername, username, password, role, enabled, 383 locked); 384 } else { 385 createUser( 386 username, password, role, form.accountStatus.$modelValue); 387 } 388 } 389 }) 390 .catch( 391 () => { 392 // do nothing 393 }) 394 } 395 396 /** 397 * Intiate remove users modal 398 * @param {*} users 399 */ 400 function initRemoveModal(users) { 401 const template = require('./user-accounts-modal-remove.html'); 402 $uibModal 403 .open({ 404 template, 405 windowTopClass: 'uib-modal', 406 ariaLabelledBy: 'dialog_label', 407 controllerAs: 'modalCtrl', 408 controller: function() { 409 this.users = users; 410 } 411 }) 412 .result 413 .then(() => { 414 deleteUsers(users); 415 }) 416 .catch( 417 () => { 418 // do nothing 419 }) 420 } 421 422 /** 423 * Callback when action emitted from table 424 * @param {*} value 425 */ 426 $scope.onEmitRowAction = (value) => { 427 switch (value.action) { 428 case 'Edit': 429 initUserModal(value.row); 430 break; 431 case 'Delete': 432 initRemoveModal([value.row]); 433 break; 434 default: 435 } 436 }; 437 438 /** 439 * Callback when batch action emitted from table 440 */ 441 $scope.onEmitBatchAction = (value) => { 442 switch (value.action) { 443 case 'delete': 444 initRemoveModal(value.filteredRows); 445 break; 446 case 'enable': 447 updateUserStatus(value.filteredRows, true) 448 break; 449 case 'disable': 450 updateUserStatus(value.filteredRows, false) 451 break; 452 default: 453 break; 454 } 455 }; 456 457 /** 458 * Callback when 'Account settings policy' button clicked 459 */ 460 $scope.onClickAccountSettingsPolicy = () => { 461 initAccountSettingsModal(); 462 }; 463 464 /** 465 * Callback when 'Add user' button clicked 466 */ 467 $scope.onClickAddUser = () => { 468 initUserModal(); 469 }; 470 471 /** 472 * Callback when controller view initially loaded 473 */ 474 $scope.$on('$viewContentLoaded', () => { 475 getLocalUsers(); 476 getUserRoles(); 477 getAccountSettings(); 478 }) 479 } 480 ]); 481})(angular); 482