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