From 627badaf69987c01811c477219fd943757a635f5 Mon Sep 17 00:00:00 2001 From: "Christopher Lott (Christopher) (cl778h)" Date: Mon, 12 Jun 2017 09:49:00 -0400 Subject: [PORTAL-16 PORTAL-18] Widget ms; staging Remove staging repositories from poms. Add widget microservice code base. Add portal unit tests. Repair defects. Normalize line endings. Change-Id: Ia5e48da2a3141b352439ecd548cddf918f4df585 Signed-off-by: Christopher Lott (cl778h) --- .../users/new-user-dialogs/bulk-user.ack.html | 64 +- .../users/new-user-dialogs/bulk-user.confirm.html | 166 +-- .../users/new-user-dialogs/bulk-user.controller.js | 1154 ++++++++++---------- .../users/new-user-dialogs/bulk-user.modal.html | 146 +-- .../users/new-user-dialogs/new-user.controller.js | 433 ++++---- .../new-user-dialogs/new-user.controller.spec.js | 510 ++++----- .../users/new-user-dialogs/new-user.modal.html | 174 +-- 7 files changed, 1330 insertions(+), 1317 deletions(-) (limited to 'ecomp-portal-FE-common/client/app/views/users/new-user-dialogs') diff --git a/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/bulk-user.ack.html b/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/bulk-user.ack.html index 9527c750..e3bcf0a4 100644 --- a/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/bulk-user.ack.html +++ b/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/bulk-user.ack.html @@ -1,32 +1,32 @@ - -
-
-
Bulk User Upload Acknowledgement
-
-

The valid entries have been uploaded.

- -
-
OK
-
-
-
-
+ +
+
+
Bulk User Upload Acknowledgement
+
+

The valid entries have been uploaded.

+ +
+
OK
+
+
+
+
diff --git a/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/bulk-user.confirm.html b/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/bulk-user.confirm.html index a3c0b534..6df7d240 100644 --- a/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/bulk-user.confirm.html +++ b/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/bulk-user.confirm.html @@ -1,83 +1,83 @@ - -
-
Bulk User Upload Confirmation
-
- - -
- {{progressMsg}} -
-
- -
- -
-
- Click OK to upload the valid requests. - Invalid requests will be ignored.
-
- - - - - - - - - - - - - - - - - - -
LineOrg User ID - App - RoleStatus
-
-
-
-
-
-
-
-
-
- -
-
- - - -
-
-
+ +
+
Bulk User Upload Confirmation
+
+ + +
+ {{progressMsg}} +
+
+ +
+ +
+
+ Click OK to upload the valid requests. + Invalid requests will be ignored.
+
+ + + + + + + + + + + + + + + + + + +
LineOrg User ID + App + RoleStatus
+
+
+
+
+
+
+
+
+
+ +
+
+ + + +
+
+
diff --git a/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/bulk-user.controller.js b/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/bulk-user.controller.js index e3046b86..e73fe290 100644 --- a/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/bulk-user.controller.js +++ b/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/bulk-user.controller.js @@ -1,577 +1,577 @@ -/*- - * ================================================================================ - * ECOMP Portal - * ================================================================================ - * Copyright (C) 2017 AT&T Intellectual Property - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ================================================================================ - */ -/** - * bulk user upload controller - */ -'use strict'; -(function () { - class BulkUserModalCtrl { - constructor($scope, $log, $filter, $q, usersService, applicationsService, confirmBoxService, functionalMenuService, ngDialog) { - - // Set to true for copious console output - var debug = false; - // Roles fetched from app service - var appRolesResult = []; - // Users fetched from user service - var userCheckResult = []; - // Requests for user-role assignment built by validator - var appUserRolesRequest = []; - - let init = () => { - if (debug) - $log.debug('BulkUserModalCtrl::init'); - // Angular insists on this. - $scope.fileModel = {}; - // Model for drop-down - $scope.adminApps = []; - // Enable modal controls - this.step1 = true; - this.fileSelected = false; - - // Flag that indicates background work is proceeding - $scope.isProcessing = true; - - // Load user's admin applications - applicationsService.getAdminApps().promise().then(apps => { - if (debug) - $log.debug('BulkUserModalCtrl::init: getAdminApps returned' + JSON.stringify(apps)); - if (!apps || typeof(apps) != 'object') { - $log.error('BulkUserModalCtrl::init: getAdminApps returned unexpected data'); - } - else { - if (debug) - $log.debug('BulkUserModalCtrl::init: admin apps length is ', apps.length); - - // Sort app names and populate the drop-down model - let sortedApps = apps.sort(getSortOrder('name', true)); - for (let i = 0; i < sortedApps.length; ++i) { - $scope.adminApps.push({ - index: i, - id: sortedApps[i].id, - value: sortedApps[i].name, - title: sortedApps[i].name - }); - } - // Pick the first one in the list - $scope.selectedApplication = $scope.adminApps[0]; - } - $scope.isProcessing = false; - }).catch(err => { - $log.error('BulkUserModalCtrl::init: getAdminApps threw', err); - $scope.isProcessing = false; - }); - - }; // init - - // Answers a function that compares properties with the specified name. - let getSortOrder = (prop, foldCase) => { - return function(a, b) { - let aProp = foldCase ? a[prop].toLowerCase() : a[prop]; - let bProp = foldCase ? b[prop].toLowerCase() : b[prop]; - if (aProp > bProp) - return 1; - else if (aProp < bProp) - return -1; - else - return 0; - } - } - - //This is a fix for dropdown selection, due to b2b dropdown only update value field - $scope.$watch('selectedApplication.value', (newVal, oldVal) => { - for(var i=0;i<$scope.adminApps.length;i++){ - if($scope.adminApps[i].value==newVal){ - $scope.selectedApplication=angular.copy($scope.adminApps[i]);; - } - } - }); - - // Invoked when user picks an app on the drop-down. - $scope.appSelected = () => { - if (debug) - $log.debug('BulkUserModalCtrl::appSelected: selectedApplication.id is ' + $scope.selectedApplication.id); - this.appSelected = true; - } - - // Caches the file name supplied by the event handler. - $scope.fileChangeHandler = (event, files) => { - this.fileSelected = true; - this.fileToRead = files[0]; - if (debug) - $log.debug("BulkUserModalCtrl::fileChangeHandler: file is ", this.fileToRead); - }; // file change handler - - /** - * Reads the contents of the file, calls portal endpoints - * to validate roles, userIds and existing role assignments; - * ultimately builds array of requests to be sent. - * Creates scope variable with input file contents for - * communication with functions. - * - * This function performs a synchronous step-by-step process - * using asynchronous promises. The code could all be inline - * here but the nesting becomes unwieldy. - */ - $scope.readValidateFile = () => { - $scope.isProcessing = true; - $scope.progressMsg = 'Reading upload file..'; - var reader = new FileReader(); - reader.onload = function(event) { - $scope.uploadFile = $filter('csvToObj')(reader.result); - if (debug) - $log.debug('BulkUserModalCtrl::readValidateFile onload: data length is ' + $scope.uploadFile.length); - // sort input by orgUserId - $scope.uploadFile.sort(getSortOrder('orgUserId', true)); - - let appid = $scope.selectedApplication.id; - $scope.progressMsg = 'Fetching application roles..'; - functionalMenuService.getManagedRolesMenu(appid).then(function (rolesObj) { - if (debug) - $log.debug("BulkUserModalCtrl::readValidateFile: managedRolesMenu returned " + JSON.stringify(rolesObj)); - appRolesResult = rolesObj; - $scope.progressMsg = 'Validating application roles..'; - $scope.verifyRoles(); - - let userPromises = $scope.buildUserChecks(); - if (debug) - $log.debug('BulkUserModalCtrl::readValidateFile: userPromises length is ' + userPromises.length); - $scope.progressMsg = 'Validating Org Users..'; - $q.all(userPromises).then(function() { - if (debug) - $log.debug('BulkUserModalCtrl::readValidateFile: userCheckResult length is ' + userCheckResult.length); - $scope.evalUserCheckResults(); - - let appPromises = $scope.buildAppRoleChecks(); - if (debug) - $log.debug('BulkUserModalCtrl::readValidateFile: appPromises length is ' + appPromises.length); - $scope.progressMsg = 'Querying application for user roles..'; - $q.all(appPromises).then( function() { - if (debug) - $log.debug('BulkUserModalCtrl::readValidateFile: appUserRolesRequest length is ' + appUserRolesRequest.length); - $scope.evalAppRoleCheckResults(); - - // Re sort by line for the confirmation dialog - $scope.uploadFile.sort(getSortOrder('line', false)); - // We're done, confirm box may show the table - if (debug) - $log.debug('BulkUserModalCtrl::readValidateFile inner-then ends'); - $scope.progressMsg = 'Done.'; - $scope.isProcessing = false; - }, - function(error) { - $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving user-app roles'); - $scope.isProcessing = false; - } - ); // then of app promises - }, - function(error) { - $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving user info'); - $scope.isProcessing = false; - } - ); // then of user promises - }, - function(error) { - $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving app role info'); - $scope.isProcessing = false; - } - ); // then of role promise - - } // onload - - // Invoke the reader on the selected file - reader.readAsText(this.fileToRead); - }; - - /** - * Evaluates the result set returned by the app role service. - * Sets an uploadFile array element status if a role is not defined. - * Reads and writes scope variable uploadFile. - * Reads closure variable appRolesResult. - */ - $scope.verifyRoles = () => { - if (debug) - $log.debug('BulkUserModalCtrl::verifyRoles: appRoles is ' + JSON.stringify(appRolesResult)); - // check roles in upload file against defined app roles - $scope.uploadFile.forEach( function (uploadRow) { - // skip rows that already have a defined status: headers etc. - if (uploadRow.status) { - if (debug) - $log.debug('BulkUserModalCtrl::verifyRoles: skip row ' + uploadRow.line); - return; - } - uploadRow.role = uploadRow.role.trim(); - var foundRole=false; - for (var i=0; i < appRolesResult.length; i++) { - if (uploadRow.role.toUpperCase() === appRolesResult[i].rolename.trim().toUpperCase()) { - if (debug) - $log.debug('BulkUserModalCtrl::verifyRoles: match on role ' + uploadRow.role); - foundRole=true; - break; - } - }; - if (!foundRole) { - if (debug) - $log.debug('BulkUserModalCtrl::verifyRoles: NO match on role ' + uploadRow.role); - uploadRow.status = 'Invalid role'; - }; - }); // foreach - }; // verifyRoles - - /** - * Builds and returns an array of promises to invoke the - * searchUsers service for each unique Org User UID in the input. - * Reads and writes scope variable uploadFile, which must be sorted by Org User UID. - * The promise function writes to closure variable userCheckResult - */ - $scope.buildUserChecks = () => { - if (debug) - $log.debug('BulkUserModalCtrl::buildUserChecks: uploadFile length is ' + $scope.uploadFile.length); - userCheckResult = []; - let promises = []; - let prevRow = null; - $scope.uploadFile.forEach(function (uploadRow) { - if (uploadRow.status) { - if (debug) - $log.debug('BulkUserModalCtrl::buildUserChecks: skip row ' + uploadRow.line); - return; - }; - // detect repeated UIDs - if (prevRow == null || prevRow.orgUserId.toLowerCase() !== uploadRow.orgUserId.toLowerCase()) { - if (debug) - $log.debug('BulkUserModalCtrl::buildUserChecks: create request for orgUserId ' + uploadRow.orgUserId); - let userPromise = usersService.searchUsers(uploadRow.orgUserId).promise().then( (usersList) => { - if (typeof usersList[0] !== "undefined") { - userCheckResult.push({ - orgUserId: usersList[0].orgUserId, - firstName: usersList[0].firstName, - lastName: usersList[0].lastName, - jobTitle: usersList[0].jobTitle - }); - } - else { - // User not found. - if (debug) - $log.debug('BulkUserModalCtrl::buildUserChecks: searchUsers returned null'); - } - }, function(error){ - $log.error('BulkUserModalCtrl::buildUserChecks: searchUsers failed ' + JSON.stringify(error)); - }); - promises.push(userPromise); - } - else { - if (debug) - $log.debug('BulkUserModalCtrl::buildUserChecks: skip repeated orgUserId ' + uploadRow.orgUserId); - } - prevRow = uploadRow; - }); // foreach - return promises; - }; // buildUserChecks - - /** - * Evaluates the result set returned by the user service to set - * the uploadFile array element status if the user was not found. - * Reads and writes scope variable uploadFile. - * Reads closure variable userCheckResult. - */ - $scope.evalUserCheckResults = () => { - if (debug) - $log.debug('BulkUserModalCtrl::evalUserCheckResult: uploadFile length is ' + $scope.uploadFile.length); - $scope.uploadFile.forEach(function (uploadRow) { - if (uploadRow.status) { - if (debug) - $log.debug('BulkUserModalCtrl::evalUserCheckResults: skip row ' + uploadRow.line); - return; - }; - let foundorgUserId = false; - userCheckResult.forEach(function(userItem) { - if (uploadRow.orgUserId.toLowerCase() === userItem.orgUserId.toLowerCase()) { - if (debug) - $log.debug('BulkUserModalCtrl::evalUserCheckResults: found orgUserId ' + uploadRow.orgUserId); - foundorgUserId=true; - }; - }); - if (!foundorgUserId) { - if (debug) - $log.debug('BulkUserModalCtrl::evalUserCheckResults: NO match on orgUserId ' + uploadRow.orgUserId); - uploadRow.status = 'Invalid orgUserId'; - } - }); // foreach - }; // evalUserCheckResults - - /** - * Builds and returns an array of promises to invoke the getUserAppRoles - * service for each unique Org User in the input file. - * Each promise creates an update to be sent to the remote application - * with all role names. - * Reads scope variable uploadFile, which must be sorted by Org User. - * The promise function writes to closure variable appUserRolesRequest - */ - $scope.buildAppRoleChecks = () => { - if (debug) - $log.debug('BulkUserModalCtrl::buildAppRoleChecks: uploadFile length is ' + $scope.uploadFile.length); - appUserRolesRequest = []; - let appId = $scope.selectedApplication.id; - let promises = []; - let prevRow = null; - $scope.uploadFile.forEach( function (uploadRow) { - if (uploadRow.status) { - if (debug) - $log.debug('BulkUserModalCtrl::buildAppRoleChecks: skip row ' + uploadRow.line); - return; - } - // Because the input is sorted, generate only one request for each Org User - if (prevRow == null || prevRow.orgUserId.toLowerCase() !== uploadRow.orgUserId.toLowerCase()) { - if (debug) - $log.debug('BulkUserModalCtrl::buildAppRoleChecks: create request for orgUserId ' + uploadRow.orgUserId); - let appPromise = usersService.getUserAppRoles(appId, uploadRow.orgUserId).promise().then( (userAppRolesResult) => { - // Reply for unknown user has all defined roles with isApplied=false on each. - if (typeof userAppRolesResult[0] !== "undefined") { - if (debug) - $log.debug('BulkUserModalCtrl::buildAppRoleChecks: adding result ' - + JSON.stringify(userAppRolesResult)); - appUserRolesRequest.push({ - orgUserId: uploadRow.orgUserId, - userAppRoles: userAppRolesResult - }); - } else { - $log.error('BulkUserModalCtrl::buildAppRoleChecks: getUserAppRoles returned ' + JSON.stringify(userAppRolesResult)); - }; - }, function(error){ - $log.error('BulkUserModalCtrl::buildAppRoleChecks: getUserAppRoles failed ', error); - }); - promises.push(appPromise); - } else { - if (debug) - $log.debug('BulkUserModalCtrl::buildAppRoleChecks: duplicate orgUserId, skip: '+ uploadRow.orgUserId); - } - prevRow = uploadRow; - }); // foreach - return promises; - }; // buildAppRoleChecks - - /** - * Evaluates the result set returned by the app service and adjusts - * the list of updates to be sent to the remote application by setting - * isApplied=true for each role name found in the upload file. - * Reads and writes scope variable uploadFile. - * Reads closure variable appUserRolesRequest. - */ - $scope.evalAppRoleCheckResults = () => { - if (debug) - $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: uploadFile length is ' + $scope.uploadFile.length); - $scope.uploadFile.forEach(function (uploadRow) { - if (uploadRow.status) { - if (debug) - $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: skip row ' + uploadRow.line); - return; - } - // Search for the match in the app-user-roles array - appUserRolesRequest.forEach( function (appUserRoleObj) { - if (uploadRow.orgUserId.toLowerCase() === appUserRoleObj.orgUserId.toLowerCase()) { - if (debug) - $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: match on orgUserId ' + uploadRow.orgUserId); - let roles = appUserRoleObj.userAppRoles; - roles.forEach(function (appRoleItem) { - //if (debug) - // $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: checking uploadRow.role=' - // + uploadRow.role + ', appRoleItem.roleName= ' + appRoleItem.roleName); - if (uploadRow.role === appRoleItem.roleName) { - if (appRoleItem.isApplied) { - if (debug) - $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: existing role ' - + appRoleItem.roleName); - uploadRow.status = 'Role exists'; - } - else { - if (debug) - $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: new role ' - + appRoleItem.roleName); - // After much back-and-forth I decided a clear indicator - // is better than blank in the table status column. - uploadRow.status = 'OK'; - appRoleItem.isApplied = true; - } - // This count is not especially interesting. - // numberUserRolesSucceeded++; - } - }); // for each role - } - }); // for each result - }); // for each row - }; // evalAppRoleCheckResults - - /** - * Sends requests to Portal requesting user role assignment. - * That endpoint handles creation of the user at the remote app if necessary. - * Reads closure variable appUserRolesRequest. - * Invoked by the Next button on the confirmation dialog. - */ - $scope.updateDB = () => { - $scope.isProcessing = true; - $scope.progressMsg = 'Sending requests to application..'; - if (debug) - $log.debug('BulkUserModalCtrl::updateDB: request length is ' + appUserRolesRequest.length); - var numberUsersSucceeded = 0; - let promises = []; - appUserRolesRequest.forEach(function(appUserRoleObj) { - if (debug) - $log.debug('BulkUserModalCtrl::updateDB: appUserRoleObj is ' + JSON.stringify(appUserRoleObj)); - let updateRequest = { - orgUserId: appUserRoleObj.orgUserId, - appId: $scope.selectedApplication.id, - appRoles: appUserRoleObj.userAppRoles - }; - if (debug) - $log.debug('BulkUserModalCtrl::updateDB: updateRequest is ' + JSON.stringify(updateRequest)); - let updatePromise = usersService.updateUserAppRoles(updateRequest).promise().then(res => { - if (debug) - $log.debug('BulkUserModalCtrl::updateDB: updated successfully: ' + JSON.stringify(res)); - numberUsersSucceeded++; - }).catch(err => { - // What to do if one of many fails?? - $log.error('BulkUserModalCtrl::updateDB failed: ', err); - confirmBoxService.showInformation( - 'Failed to update the user application roles. ' + - 'Error: ' + err.status).then(isConfirmed => { }); - }).finally( () => { - // $log.debug('BulkUserModalCtrl::updateDB: finally()'); - }); - promises.push(updatePromise); - }); // for each - - // Run all the promises - $q.all(promises).then(function(){ - $scope.isProcessing = false; - confirmBoxService.showInformation('Processed ' + numberUsersSucceeded + ' users.').then(isConfirmed => { - // Close the upload-confirm dialog - ngDialog.close(); - }); - }); - }; // updateDb - - // Sets the variable that hides/reveals the user controls - $scope.step2 = () => { - this.fileSelected = false; - $scope.selectedFile = null; - $scope.fileModel = null; - this.step1 = false; - } - - // Navigate between dialog screens using step number: 1,2,... - $scope.navigateBack = () => { - this.step1 = true; - this.fileSelected = false; - }; - - // Opens a dialog to show the data to be uploaded. - // Invoked by the upload button on the bulk user dialog. - $scope.confirmUpload = () => { - // Start the process - $scope.readValidateFile(); - // Dialog shows progress - ngDialog.open({ - templateUrl: 'app/views/users/new-user-dialogs/bulk-user.confirm.html', - scope: $scope - }); - }; - - // Invoked by the Cancel button on the confirmation dialog. - $scope.cancelUpload = () => { - ngDialog.close(); - }; - - init(); - } // constructor - } // class - BulkUserModalCtrl.$inject = ['$scope', '$log', '$filter', '$q', 'usersService', 'applicationsService', 'confirmBoxService', 'functionalMenuService', 'ngDialog']; - angular.module('ecompApp').controller('BulkUserModalCtrl', BulkUserModalCtrl); - - angular.module('ecompApp').directive('fileChange', ['$parse', function($parse){ - return { - require: 'ngModel', - restrict: 'A', - link : function($scope, element, attrs, ngModel) { - var attrHandler = $parse(attrs['fileChange']); - var handler=function(e) { - $scope.$apply(function() { - attrHandler($scope, { $event:e, files:e.target.files } ); - $scope.selectedFile = e.target.files[0].name; - }); - }; - element[0].addEventListener('change',handler,false); - } - } - }]); - - angular.module('ecompApp').filter('csvToObj',function() { - return function(input) { - var result = []; - var len, i, line, o; - var lines = input.split('\n'); - // Need 1-based index below - for (len = lines.length, i = 1; i <= len; ++i) { - // Use 0-based index for array - line = lines[i - 1].trim(); - if (line.length == 0) { - // console.log("Skipping blank line"); - result.push({ - line: i, - orgUserId: '', - role: '', - status: 'Blank line' - }); - continue; - } - o = line.split(','); - if (o.length !== 2) { - // other lengths not valid for upload - result.push({ - line: i, - orgUserId: line, - role: '', - status: 'Failed to find 2 comma-separated values' - }); - } - else { - // console.log("Valid line: ", val); - let entry = { - line: i, - orgUserId: o[0], - role: o[1] - // leave status undefined, this could be valid. - }; - if (o[0].toLowerCase() === 'orgUserId') { - // not valid for upload, so set status - entry.status = 'Header'; - } - else if (o[0].trim() == '' || o[1].trim() == '') { - // defend against line with only a single comma etc. - entry.status = 'Failed to find 2 non-empty values'; - } - result.push(entry); - } // len 2 - } // for - return result; - }; - }); - - - -})(); +/*- + * ================================================================================ + * ECOMP Portal + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ================================================================================ + */ +/** + * bulk user upload controller + */ +'use strict'; +(function () { + class BulkUserModalCtrl { + constructor($scope, $log, $filter, $q, usersService, applicationsService, confirmBoxService, functionalMenuService, ngDialog) { + + // Set to true for copious console output + var debug = false; + // Roles fetched from app service + var appRolesResult = []; + // Users fetched from user service + var userCheckResult = []; + // Requests for user-role assignment built by validator + var appUserRolesRequest = []; + + let init = () => { + if (debug) + $log.debug('BulkUserModalCtrl::init'); + // Angular insists on this. + $scope.fileModel = {}; + // Model for drop-down + $scope.adminApps = []; + // Enable modal controls + this.step1 = true; + this.fileSelected = false; + + // Flag that indicates background work is proceeding + $scope.isProcessing = true; + + // Load user's admin applications + applicationsService.getAdminApps().promise().then(apps => { + if (debug) + $log.debug('BulkUserModalCtrl::init: getAdminApps returned' + JSON.stringify(apps)); + if (!apps || typeof(apps) != 'object') { + $log.error('BulkUserModalCtrl::init: getAdminApps returned unexpected data'); + } + else { + if (debug) + $log.debug('BulkUserModalCtrl::init: admin apps length is ', apps.length); + + // Sort app names and populate the drop-down model + let sortedApps = apps.sort(getSortOrder('name', true)); + for (let i = 0; i < sortedApps.length; ++i) { + $scope.adminApps.push({ + index: i, + id: sortedApps[i].id, + value: sortedApps[i].name, + title: sortedApps[i].name + }); + } + // Pick the first one in the list + $scope.selectedApplication = $scope.adminApps[0]; + } + $scope.isProcessing = false; + }).catch(err => { + $log.error('BulkUserModalCtrl::init: getAdminApps threw', err); + $scope.isProcessing = false; + }); + + }; // init + + // Answers a function that compares properties with the specified name. + let getSortOrder = (prop, foldCase) => { + return function(a, b) { + let aProp = foldCase ? a[prop].toLowerCase() : a[prop]; + let bProp = foldCase ? b[prop].toLowerCase() : b[prop]; + if (aProp > bProp) + return 1; + else if (aProp < bProp) + return -1; + else + return 0; + } + } + + //This is a fix for dropdown selection, due to b2b dropdown only update value field + $scope.$watch('selectedApplication.value', (newVal, oldVal) => { + for(var i=0;i<$scope.adminApps.length;i++){ + if($scope.adminApps[i].value==newVal){ + $scope.selectedApplication=angular.copy($scope.adminApps[i]);; + } + } + }); + + // Invoked when user picks an app on the drop-down. + $scope.appSelected = () => { + if (debug) + $log.debug('BulkUserModalCtrl::appSelected: selectedApplication.id is ' + $scope.selectedApplication.id); + this.appSelected = true; + } + + // Caches the file name supplied by the event handler. + $scope.fileChangeHandler = (event, files) => { + this.fileSelected = true; + this.fileToRead = files[0]; + if (debug) + $log.debug("BulkUserModalCtrl::fileChangeHandler: file is ", this.fileToRead); + }; // file change handler + + /** + * Reads the contents of the file, calls portal endpoints + * to validate roles, userIds and existing role assignments; + * ultimately builds array of requests to be sent. + * Creates scope variable with input file contents for + * communication with functions. + * + * This function performs a synchronous step-by-step process + * using asynchronous promises. The code could all be inline + * here but the nesting becomes unwieldy. + */ + $scope.readValidateFile = () => { + $scope.isProcessing = true; + $scope.progressMsg = 'Reading upload file..'; + var reader = new FileReader(); + reader.onload = function(event) { + $scope.uploadFile = $filter('csvToObj')(reader.result); + if (debug) + $log.debug('BulkUserModalCtrl::readValidateFile onload: data length is ' + $scope.uploadFile.length); + // sort input by orgUserId + $scope.uploadFile.sort(getSortOrder('orgUserId', true)); + + let appid = $scope.selectedApplication.id; + $scope.progressMsg = 'Fetching application roles..'; + functionalMenuService.getManagedRolesMenu(appid).then(function (rolesObj) { + if (debug) + $log.debug("BulkUserModalCtrl::readValidateFile: managedRolesMenu returned " + JSON.stringify(rolesObj)); + appRolesResult = rolesObj; + $scope.progressMsg = 'Validating application roles..'; + $scope.verifyRoles(); + + let userPromises = $scope.buildUserChecks(); + if (debug) + $log.debug('BulkUserModalCtrl::readValidateFile: userPromises length is ' + userPromises.length); + $scope.progressMsg = 'Validating Org Users..'; + $q.all(userPromises).then(function() { + if (debug) + $log.debug('BulkUserModalCtrl::readValidateFile: userCheckResult length is ' + userCheckResult.length); + $scope.evalUserCheckResults(); + + let appPromises = $scope.buildAppRoleChecks(); + if (debug) + $log.debug('BulkUserModalCtrl::readValidateFile: appPromises length is ' + appPromises.length); + $scope.progressMsg = 'Querying application for user roles..'; + $q.all(appPromises).then( function() { + if (debug) + $log.debug('BulkUserModalCtrl::readValidateFile: appUserRolesRequest length is ' + appUserRolesRequest.length); + $scope.evalAppRoleCheckResults(); + + // Re sort by line for the confirmation dialog + $scope.uploadFile.sort(getSortOrder('line', false)); + // We're done, confirm box may show the table + if (debug) + $log.debug('BulkUserModalCtrl::readValidateFile inner-then ends'); + $scope.progressMsg = 'Done.'; + $scope.isProcessing = false; + }, + function(error) { + $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving user-app roles'); + $scope.isProcessing = false; + } + ); // then of app promises + }, + function(error) { + $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving user info'); + $scope.isProcessing = false; + } + ); // then of user promises + }, + function(error) { + $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving app role info'); + $scope.isProcessing = false; + } + ); // then of role promise + + } // onload + + // Invoke the reader on the selected file + reader.readAsText(this.fileToRead); + }; + + /** + * Evaluates the result set returned by the app role service. + * Sets an uploadFile array element status if a role is not defined. + * Reads and writes scope variable uploadFile. + * Reads closure variable appRolesResult. + */ + $scope.verifyRoles = () => { + if (debug) + $log.debug('BulkUserModalCtrl::verifyRoles: appRoles is ' + JSON.stringify(appRolesResult)); + // check roles in upload file against defined app roles + $scope.uploadFile.forEach( function (uploadRow) { + // skip rows that already have a defined status: headers etc. + if (uploadRow.status) { + if (debug) + $log.debug('BulkUserModalCtrl::verifyRoles: skip row ' + uploadRow.line); + return; + } + uploadRow.role = uploadRow.role.trim(); + var foundRole=false; + for (var i=0; i < appRolesResult.length; i++) { + if (uploadRow.role.toUpperCase() === appRolesResult[i].rolename.trim().toUpperCase()) { + if (debug) + $log.debug('BulkUserModalCtrl::verifyRoles: match on role ' + uploadRow.role); + foundRole=true; + break; + } + }; + if (!foundRole) { + if (debug) + $log.debug('BulkUserModalCtrl::verifyRoles: NO match on role ' + uploadRow.role); + uploadRow.status = 'Invalid role'; + }; + }); // foreach + }; // verifyRoles + + /** + * Builds and returns an array of promises to invoke the + * searchUsers service for each unique Org User UID in the input. + * Reads and writes scope variable uploadFile, which must be sorted by Org User UID. + * The promise function writes to closure variable userCheckResult + */ + $scope.buildUserChecks = () => { + if (debug) + $log.debug('BulkUserModalCtrl::buildUserChecks: uploadFile length is ' + $scope.uploadFile.length); + userCheckResult = []; + let promises = []; + let prevRow = null; + $scope.uploadFile.forEach(function (uploadRow) { + if (uploadRow.status) { + if (debug) + $log.debug('BulkUserModalCtrl::buildUserChecks: skip row ' + uploadRow.line); + return; + }; + // detect repeated UIDs + if (prevRow == null || prevRow.orgUserId.toLowerCase() !== uploadRow.orgUserId.toLowerCase()) { + if (debug) + $log.debug('BulkUserModalCtrl::buildUserChecks: create request for orgUserId ' + uploadRow.orgUserId); + let userPromise = usersService.searchUsers(uploadRow.orgUserId).promise().then( (usersList) => { + if (typeof usersList[0] !== "undefined") { + userCheckResult.push({ + orgUserId: usersList[0].orgUserId, + firstName: usersList[0].firstName, + lastName: usersList[0].lastName, + jobTitle: usersList[0].jobTitle + }); + } + else { + // User not found. + if (debug) + $log.debug('BulkUserModalCtrl::buildUserChecks: searchUsers returned null'); + } + }, function(error){ + $log.error('BulkUserModalCtrl::buildUserChecks: searchUsers failed ' + JSON.stringify(error)); + }); + promises.push(userPromise); + } + else { + if (debug) + $log.debug('BulkUserModalCtrl::buildUserChecks: skip repeated orgUserId ' + uploadRow.orgUserId); + } + prevRow = uploadRow; + }); // foreach + return promises; + }; // buildUserChecks + + /** + * Evaluates the result set returned by the user service to set + * the uploadFile array element status if the user was not found. + * Reads and writes scope variable uploadFile. + * Reads closure variable userCheckResult. + */ + $scope.evalUserCheckResults = () => { + if (debug) + $log.debug('BulkUserModalCtrl::evalUserCheckResult: uploadFile length is ' + $scope.uploadFile.length); + $scope.uploadFile.forEach(function (uploadRow) { + if (uploadRow.status) { + if (debug) + $log.debug('BulkUserModalCtrl::evalUserCheckResults: skip row ' + uploadRow.line); + return; + }; + let foundorgUserId = false; + userCheckResult.forEach(function(userItem) { + if (uploadRow.orgUserId.toLowerCase() === userItem.orgUserId.toLowerCase()) { + if (debug) + $log.debug('BulkUserModalCtrl::evalUserCheckResults: found orgUserId ' + uploadRow.orgUserId); + foundorgUserId=true; + }; + }); + if (!foundorgUserId) { + if (debug) + $log.debug('BulkUserModalCtrl::evalUserCheckResults: NO match on orgUserId ' + uploadRow.orgUserId); + uploadRow.status = 'Invalid orgUserId'; + } + }); // foreach + }; // evalUserCheckResults + + /** + * Builds and returns an array of promises to invoke the getUserAppRoles + * service for each unique Org User in the input file. + * Each promise creates an update to be sent to the remote application + * with all role names. + * Reads scope variable uploadFile, which must be sorted by Org User. + * The promise function writes to closure variable appUserRolesRequest + */ + $scope.buildAppRoleChecks = () => { + if (debug) + $log.debug('BulkUserModalCtrl::buildAppRoleChecks: uploadFile length is ' + $scope.uploadFile.length); + appUserRolesRequest = []; + let appId = $scope.selectedApplication.id; + let promises = []; + let prevRow = null; + $scope.uploadFile.forEach( function (uploadRow) { + if (uploadRow.status) { + if (debug) + $log.debug('BulkUserModalCtrl::buildAppRoleChecks: skip row ' + uploadRow.line); + return; + } + // Because the input is sorted, generate only one request for each Org User + if (prevRow == null || prevRow.orgUserId.toLowerCase() !== uploadRow.orgUserId.toLowerCase()) { + if (debug) + $log.debug('BulkUserModalCtrl::buildAppRoleChecks: create request for orgUserId ' + uploadRow.orgUserId); + let appPromise = usersService.getUserAppRoles(appId, uploadRow.orgUserId).promise().then( (userAppRolesResult) => { + // Reply for unknown user has all defined roles with isApplied=false on each. + if (typeof userAppRolesResult[0] !== "undefined") { + if (debug) + $log.debug('BulkUserModalCtrl::buildAppRoleChecks: adding result ' + + JSON.stringify(userAppRolesResult)); + appUserRolesRequest.push({ + orgUserId: uploadRow.orgUserId, + userAppRoles: userAppRolesResult + }); + } else { + $log.error('BulkUserModalCtrl::buildAppRoleChecks: getUserAppRoles returned ' + JSON.stringify(userAppRolesResult)); + }; + }, function(error){ + $log.error('BulkUserModalCtrl::buildAppRoleChecks: getUserAppRoles failed ', error); + }); + promises.push(appPromise); + } else { + if (debug) + $log.debug('BulkUserModalCtrl::buildAppRoleChecks: duplicate orgUserId, skip: '+ uploadRow.orgUserId); + } + prevRow = uploadRow; + }); // foreach + return promises; + }; // buildAppRoleChecks + + /** + * Evaluates the result set returned by the app service and adjusts + * the list of updates to be sent to the remote application by setting + * isApplied=true for each role name found in the upload file. + * Reads and writes scope variable uploadFile. + * Reads closure variable appUserRolesRequest. + */ + $scope.evalAppRoleCheckResults = () => { + if (debug) + $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: uploadFile length is ' + $scope.uploadFile.length); + $scope.uploadFile.forEach(function (uploadRow) { + if (uploadRow.status) { + if (debug) + $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: skip row ' + uploadRow.line); + return; + } + // Search for the match in the app-user-roles array + appUserRolesRequest.forEach( function (appUserRoleObj) { + if (uploadRow.orgUserId.toLowerCase() === appUserRoleObj.orgUserId.toLowerCase()) { + if (debug) + $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: match on orgUserId ' + uploadRow.orgUserId); + let roles = appUserRoleObj.userAppRoles; + roles.forEach(function (appRoleItem) { + //if (debug) + // $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: checking uploadRow.role=' + // + uploadRow.role + ', appRoleItem.roleName= ' + appRoleItem.roleName); + if (uploadRow.role === appRoleItem.roleName) { + if (appRoleItem.isApplied) { + if (debug) + $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: existing role ' + + appRoleItem.roleName); + uploadRow.status = 'Role exists'; + } + else { + if (debug) + $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: new role ' + + appRoleItem.roleName); + // After much back-and-forth I decided a clear indicator + // is better than blank in the table status column. + uploadRow.status = 'OK'; + appRoleItem.isApplied = true; + } + // This count is not especially interesting. + // numberUserRolesSucceeded++; + } + }); // for each role + } + }); // for each result + }); // for each row + }; // evalAppRoleCheckResults + + /** + * Sends requests to Portal requesting user role assignment. + * That endpoint handles creation of the user at the remote app if necessary. + * Reads closure variable appUserRolesRequest. + * Invoked by the Next button on the confirmation dialog. + */ + $scope.updateDB = () => { + $scope.isProcessing = true; + $scope.progressMsg = 'Sending requests to application..'; + if (debug) + $log.debug('BulkUserModalCtrl::updateDB: request length is ' + appUserRolesRequest.length); + var numberUsersSucceeded = 0; + let promises = []; + appUserRolesRequest.forEach(function(appUserRoleObj) { + if (debug) + $log.debug('BulkUserModalCtrl::updateDB: appUserRoleObj is ' + JSON.stringify(appUserRoleObj)); + let updateRequest = { + orgUserId: appUserRoleObj.orgUserId, + appId: $scope.selectedApplication.id, + appRoles: appUserRoleObj.userAppRoles + }; + if (debug) + $log.debug('BulkUserModalCtrl::updateDB: updateRequest is ' + JSON.stringify(updateRequest)); + let updatePromise = usersService.updateUserAppRoles(updateRequest).promise().then(res => { + if (debug) + $log.debug('BulkUserModalCtrl::updateDB: updated successfully: ' + JSON.stringify(res)); + numberUsersSucceeded++; + }).catch(err => { + // What to do if one of many fails?? + $log.error('BulkUserModalCtrl::updateDB failed: ', err); + confirmBoxService.showInformation( + 'Failed to update the user application roles. ' + + 'Error: ' + err.status).then(isConfirmed => { }); + }).finally( () => { + // $log.debug('BulkUserModalCtrl::updateDB: finally()'); + }); + promises.push(updatePromise); + }); // for each + + // Run all the promises + $q.all(promises).then(function(){ + $scope.isProcessing = false; + confirmBoxService.showInformation('Processed ' + numberUsersSucceeded + ' users.').then(isConfirmed => { + // Close the upload-confirm dialog + ngDialog.close(); + }); + }); + }; // updateDb + + // Sets the variable that hides/reveals the user controls + $scope.step2 = () => { + this.fileSelected = false; + $scope.selectedFile = null; + $scope.fileModel = null; + this.step1 = false; + } + + // Navigate between dialog screens using step number: 1,2,... + $scope.navigateBack = () => { + this.step1 = true; + this.fileSelected = false; + }; + + // Opens a dialog to show the data to be uploaded. + // Invoked by the upload button on the bulk user dialog. + $scope.confirmUpload = () => { + // Start the process + $scope.readValidateFile(); + // Dialog shows progress + ngDialog.open({ + templateUrl: 'app/views/users/new-user-dialogs/bulk-user.confirm.html', + scope: $scope + }); + }; + + // Invoked by the Cancel button on the confirmation dialog. + $scope.cancelUpload = () => { + ngDialog.close(); + }; + + init(); + } // constructor + } // class + BulkUserModalCtrl.$inject = ['$scope', '$log', '$filter', '$q', 'usersService', 'applicationsService', 'confirmBoxService', 'functionalMenuService', 'ngDialog']; + angular.module('ecompApp').controller('BulkUserModalCtrl', BulkUserModalCtrl); + + angular.module('ecompApp').directive('fileChange', ['$parse', function($parse){ + return { + require: 'ngModel', + restrict: 'A', + link : function($scope, element, attrs, ngModel) { + var attrHandler = $parse(attrs['fileChange']); + var handler=function(e) { + $scope.$apply(function() { + attrHandler($scope, { $event:e, files:e.target.files } ); + $scope.selectedFile = e.target.files[0].name; + }); + }; + element[0].addEventListener('change',handler,false); + } + } + }]); + + angular.module('ecompApp').filter('csvToObj',function() { + return function(input) { + var result = []; + var len, i, line, o; + var lines = input.split('\n'); + // Need 1-based index below + for (len = lines.length, i = 1; i <= len; ++i) { + // Use 0-based index for array + line = lines[i - 1].trim(); + if (line.length == 0) { + // console.log("Skipping blank line"); + result.push({ + line: i, + orgUserId: '', + role: '', + status: 'Blank line' + }); + continue; + } + o = line.split(','); + if (o.length !== 2) { + // other lengths not valid for upload + result.push({ + line: i, + orgUserId: line, + role: '', + status: 'Failed to find 2 comma-separated values' + }); + } + else { + // console.log("Valid line: ", val); + let entry = { + line: i, + orgUserId: o[0], + role: o[1] + // leave status undefined, this could be valid. + }; + if (o[0].toLowerCase() === 'orgUserId') { + // not valid for upload, so set status + entry.status = 'Header'; + } + else if (o[0].trim() == '' || o[1].trim() == '') { + // defend against line with only a single comma etc. + entry.status = 'Failed to find 2 non-empty values'; + } + result.push(entry); + } // len 2 + } // for + return result; + }; + }); + + + +})(); diff --git a/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/bulk-user.modal.html b/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/bulk-user.modal.html index 3d479cb9..7945e54a 100644 --- a/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/bulk-user.modal.html +++ b/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/bulk-user.modal.html @@ -1,70 +1,76 @@ - -
-
Bulk User Upload
-
-
-
Select Application:
-
- - - -
-
- -
-
Select Upload File:
- - - {{selectedFile}} -
File must have one entry per line with this format: -
orgUserId, role name
-
-
- - -
- -
- -
- - - - - -
-
-
+ +
+
Bulk User Upload
+
+
+
Select Application:
+
+ + + +
+
+ +
+
Select Upload File:
+ + + {{selectedFile}} +
File must have one entry per line with this format: +
orgUserId, role name
+
+
+ + +
+ +
+ +
+ + + + + +
+
+
+ + diff --git a/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/new-user.controller.js b/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/new-user.controller.js index 882f1e8f..6550a1ee 100644 --- a/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/new-user.controller.js +++ b/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/new-user.controller.js @@ -1,216 +1,217 @@ -/*- - * ================================================================================ - * ECOMP Portal - * ================================================================================ - * Copyright (C) 2017 AT&T Intellectual Property - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ================================================================================ - */ -/** - * Created by nnaffar on 12/20/15. - */ -'use strict'; -(function () { - class NewUserModalCtrl { - constructor($scope, $log, usersService, applicationsService, confirmBoxService) { - let init = () => { - //$log.info('NewUserModalCtrl::init'); - this.isSaving = false; - this.anyChanges = false; - this.adminApps = []; - this.isGettingAdminApps = false; - if($scope.ngDialogData && $scope.ngDialogData.selectedUser && $scope.ngDialogData.dialogState){ - this.selectedUser = $scope.ngDialogData.selectedUser; - this.dialogState = $scope.ngDialogData.dialogState; - this.isShowBack = false; - if(this.dialogState === 3){ - this.getUserAppsRoles(); - } - }else{ - this.isShowBack = true; - this.selectedUser = null; - this.dialogState = 1; - } - }; - - this.appChanged = (index) => { - let myApp = this.adminApps[index]; - //$log.debug('NewUserModalCtrl::appChanged: index: ', index, '; app id: ', myApp.id, 'app name: ',myApp.name); - myApp.isChanged = true; - this.anyChanges = true; - } - - this.deleteApp = (app) => { - let appMessage = this.selectedUser.firstName + ' ' + this.selectedUser.lastName; - confirmBoxService.deleteItem(appMessage).then(isConfirmed => { - if(isConfirmed){ - this.anyChanges = true; - app.isChanged = true; - app.isDeleted = true; // use this to hide the app in the display - app.appRoles.forEach(function(role){ - role.isApplied = false; - }); - } - }).catch(err => { - $log.error('NewUserModalCtrl::deleteApp error: ',err); - confirmBoxService.showInformation('There was a problem deleting the the applications. ' + - 'Please try again later. Error: ' + err.status).then(isConfirmed => {}); - }); - }; - - this.getUserAppsRoles = () => { - if (!this.selectedUser || !this.selectedUser.orgUserId) { - $log.error('NewUserModalCtrl::getUserAppsRoles error: No user is selected'); - this.dialogState = 1; - return; - } - //$log.debug('NewUserModalCtrl::getUserAppsRoles: about to call getAdminAppsSimpler'); - this.isGettingAdminApps = true; - applicationsService.getAdminAppsSimpler().then((apps) => { - //$log.debug('NewUserModalCtrl::getUserAppsRoles: beginning of then for getAdminAppsSimpler'); - this.isGettingAdminApps = false; - if (!apps || !apps.length) { - $log.error('NewUserModalCtrl::getUserAppsRoles error: no admin apps found'); - return null; - } - //$log.debug('NewUserModalCtrl::getUserAppsRoles: then for getAdminAppsSimpler: step 2'); - //$log.debug('NewUserModalCtrl::getUserAppsRoles: admin apps: ', apps); - this.adminApps = apps; - this.dialogState = 3; - this.userAppRoles = {}; - this.numberAppsProcessed = 0; - this.isLoading = true; - apps.forEach(app => { - //$log.debug('NewUserModalCtrl::getUserAppsRoles: app: id: ', app.id, 'name: ',app.name); - // Keep track of which app has changed, so we know which apps to update using a BE API - app.isChanged = false; - // Each of these specifies a state, which corresponds to a different message and style that gets displayed - app.isLoading = true; - app.isError = false; - app.isDeleted = false; - app.printNoChanges = false; - app.isUpdating = false; - app.isErrorUpdating = false; - app.isDoneUpdating = false; - app.errorMessage = ""; - usersService.getUserAppRoles(app.id, this.selectedUser.orgUserId).promise().then((userAppRolesResult) => { - //$log.debug('NewUserModalCtrl::getUserAppsRoles: got a result for app: ',app.id,': ',app.name,': ',userAppRolesResult); - app.appRoles = userAppRolesResult; - app.isLoading = false; - - }).catch(err => { - $log.error(err); - app.isError = true; - app.isLoading = false; - app.errorMessage = err.headers('FEErrorString'); - //$log.debug('NewUserModalCtrl::getUserAppsRoles: in new-user.controller: response header: '+err.headers('FEErrorString')); - }).finally(()=>{ - this.numberAppsProcessed++; - if (this.numberAppsProcessed === this.adminApps.length) { - this.isLoading = false; - } - }); - }) - return; - }).catch(err => { - $log.error(err); - }) - - } - - /** - * Update the selected user apps with the new roles. - * If no roles remain, set the user to inactive. - */ - this.updateUserAppsRoles = () => { - // $log.debug('NewUserModalCtrl::updateUserAppsRoles: entering updateUserAppsRoles'); - if(!this.selectedUser || !this.selectedUser.orgUserId || !this.adminApps){ - $log.error('NewUserModalCtrl::updateUserAppsRoles: mmissing arguments'); - return; - } - this.isSaving = true; - //$log.debug('NewUserModalCtrl::updateUserAppsRoles: going to update user: ' + this.selectedUser.orgUserId); - this.numberAppsProcessed = 0; - this.numberAppsSucceeded = 0; - this.adminApps.forEach(app => { - if (app.isChanged) { - //$log.debug('NewUserModalCtrl::updateUserAppsRoles: app roles have changed; going to update: id: ', app.id, '; name: ', app.name); - app.isUpdating = true; - var newUserAppRoles = { - orgUserId: this.selectedUser.orgUserId, - appId: app.id, - appRoles: app.appRoles, - appName: app.name - }; - usersService.updateUserAppRoles(newUserAppRoles).promise() - .then(res => { - //$log.debug('NewUserModalCtrl::updateUserAppsRoles: User app roles updated successfully on app: ',app.id); - app.isUpdating = false; - app.isDoneUpdating = true; - this.numberAppsSucceeded++; - }).catch(err => { - $log.error(err); - app.isErrorUpdating = true; - confirmBoxService.showInformation( - 'Failed to update the user application roles: ' + err.status) - .then(isConfirmed => {}); - }).finally(()=>{ - this.numberAppsProcessed++; - if (this.numberAppsProcessed === this.adminApps.length) { - this.isSaving = false; // hide the spinner - } - if (this.numberAppsSucceeded === this.adminApps.length) { - $scope.closeThisDialog(true);//close and resolve dialog promise with true (to update the table) - } - }) - } else { - //$log.debug('NewUserModalCtrl::updateUserAppsRoles: app roles have NOT changed; NOT going to update: id: ', app.id, '; name: ', app.name); - app.noChanges = true; - app.isError = false; //remove the error message; just show the No Changes messages - this.numberAppsProcessed++; - this.numberAppsSucceeded++; - if (this.numberAppsProcessed === this.adminApps.length) { - this.isSaving = false; // hide the spinner - } - if (this.numberAppsSucceeded === this.adminApps.length) { - $scope.closeThisDialog(true);//close and resolve dialog promise with true (to update the table) - } - } - }); - }; - - /** - * Navigate between dialog screens using step number: 1,2,... - */ - this.navigateBack = () => { - if (this.dialogState === 1) { - //back from 1st screen? - } - if (this.dialogState === 3) { - this.dialogState = 1; - } - }; - - init(); - - $scope.$on('$stateChangeStart', e => { - //Disable navigation when modal is opened - //**Nabil - note: this will cause the history back state to be replaced with current state - e.preventDefault(); - }); - } - } - NewUserModalCtrl.$inject = ['$scope', '$log', 'usersService', 'applicationsService', 'confirmBoxService']; - angular.module('ecompApp').controller('NewUserModalCtrl', NewUserModalCtrl); -})(); +/*- + * ================================================================================ + * ECOMP Portal + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ================================================================================ + */ +/** + * Created by nnaffar on 12/20/15. + */ +'use strict'; +(function () { + class NewUserModalCtrl { + constructor($scope, $log, usersService, applicationsService, confirmBoxService) { + var extRequestValue = false; + let init = () => { + //$log.info('NewUserModalCtrl::init'); + this.isSaving = false; + this.anyChanges = false; + this.adminApps = []; + this.isGettingAdminApps = false; + if($scope.ngDialogData && $scope.ngDialogData.selectedUser && $scope.ngDialogData.dialogState){ + this.selectedUser = $scope.ngDialogData.selectedUser; + this.dialogState = $scope.ngDialogData.dialogState; + this.isShowBack = false; + if(this.dialogState === 3){ + this.getUserAppsRoles(); + } + }else{ + this.isShowBack = true; + this.selectedUser = null; + this.dialogState = 1; + } + }; + + this.appChanged = (index) => { + let myApp = this.adminApps[index]; + //$log.debug('NewUserModalCtrl::appChanged: index: ', index, '; app id: ', myApp.id, 'app name: ',myApp.name); + myApp.isChanged = true; + this.anyChanges = true; + } + + this.deleteApp = (app) => { + let appMessage = this.selectedUser.firstName + ' ' + this.selectedUser.lastName; + confirmBoxService.deleteItem(appMessage).then(isConfirmed => { + if(isConfirmed){ + this.anyChanges = true; + app.isChanged = true; + app.isDeleted = true; // use this to hide the app in the display + app.appRoles.forEach(function(role){ + role.isApplied = false; + }); + } + }).catch(err => { + $log.error('NewUserModalCtrl::deleteApp error: ',err); + confirmBoxService.showInformation('There was a problem deleting the the applications. ' + + 'Please try again later. Error: ' + err.status).then(isConfirmed => {}); + }); + }; + + this.getUserAppsRoles = () => { + if (!this.selectedUser || !this.selectedUser.orgUserId) { + $log.error('NewUserModalCtrl::getUserAppsRoles error: No user is selected'); + this.dialogState = 1; + return; + } + //$log.debug('NewUserModalCtrl::getUserAppsRoles: about to call getAdminAppsSimpler'); + this.isGettingAdminApps = true; + applicationsService.getAdminAppsSimpler().then((apps) => { + //$log.debug('NewUserModalCtrl::getUserAppsRoles: beginning of then for getAdminAppsSimpler'); + this.isGettingAdminApps = false; + if (!apps || !apps.length) { + $log.error('NewUserModalCtrl::getUserAppsRoles error: no admin apps found'); + return null; + } + //$log.debug('NewUserModalCtrl::getUserAppsRoles: then for getAdminAppsSimpler: step 2'); + //$log.debug('NewUserModalCtrl::getUserAppsRoles: admin apps: ', apps); + this.adminApps = apps; + this.dialogState = 3; + this.userAppRoles = {}; + this.numberAppsProcessed = 0; + this.isLoading = true; + apps.forEach(app => { + //$log.debug('NewUserModalCtrl::getUserAppsRoles: app: id: ', app.id, 'name: ',app.name); + // Keep track of which app has changed, so we know which apps to update using a BE API + app.isChanged = false; + // Each of these specifies a state, which corresponds to a different message and style that gets displayed + app.isLoading = true; + app.isError = false; + app.isDeleted = false; + app.printNoChanges = false; + app.isUpdating = false; + app.isErrorUpdating = false; + app.isDoneUpdating = false; + app.errorMessage = ""; + usersService.getUserAppRoles(app.id, this.selectedUser.orgUserId, extRequestValue).promise().then((userAppRolesResult) => { + //$log.debug('NewUserModalCtrl::getUserAppsRoles: got a result for app: ',app.id,': ',app.name,': ',userAppRolesResult); + app.appRoles = userAppRolesResult; + app.isLoading = false; + + }).catch(err => { + $log.error(err); + app.isError = true; + app.isLoading = false; + app.errorMessage = err.headers('FEErrorString'); + //$log.debug('NewUserModalCtrl::getUserAppsRoles: in new-user.controller: response header: '+err.headers('FEErrorString')); + }).finally(()=>{ + this.numberAppsProcessed++; + if (this.numberAppsProcessed === this.adminApps.length) { + this.isLoading = false; + } + }); + }) + return; + }).catch(err => { + $log.error(err); + }) + + } + + /** + * Update the selected user apps with the new roles. + * If no roles remain, set the user to inactive. + */ + this.updateUserAppsRoles = () => { + // $log.debug('NewUserModalCtrl::updateUserAppsRoles: entering updateUserAppsRoles'); + if(!this.selectedUser || !this.selectedUser.orgUserId || !this.adminApps){ + $log.error('NewUserModalCtrl::updateUserAppsRoles: mmissing arguments'); + return; + } + this.isSaving = true; + //$log.debug('NewUserModalCtrl::updateUserAppsRoles: going to update user: ' + this.selectedUser.orgUserId); + this.numberAppsProcessed = 0; + this.numberAppsSucceeded = 0; + this.adminApps.forEach(app => { + if (app.isChanged) { + //$log.debug('NewUserModalCtrl::updateUserAppsRoles: app roles have changed; going to update: id: ', app.id, '; name: ', app.name); + app.isUpdating = true; + var newUserAppRoles = { + orgUserId: this.selectedUser.orgUserId, + appId: app.id, + appRoles: app.appRoles, + appName: app.name + }; + usersService.updateUserAppRoles(newUserAppRoles).promise() + .then(res => { + //$log.debug('NewUserModalCtrl::updateUserAppsRoles: User app roles updated successfully on app: ',app.id); + app.isUpdating = false; + app.isDoneUpdating = true; + this.numberAppsSucceeded++; + }).catch(err => { + $log.error(err); + app.isErrorUpdating = true; + confirmBoxService.showInformation( + 'Failed to update the user application roles: ' + err.status) + .then(isConfirmed => {}); + }).finally(()=>{ + this.numberAppsProcessed++; + if (this.numberAppsProcessed === this.adminApps.length) { + this.isSaving = false; // hide the spinner + } + if (this.numberAppsSucceeded === this.adminApps.length) { + $scope.closeThisDialog(true);//close and resolve dialog promise with true (to update the table) + } + }) + } else { + //$log.debug('NewUserModalCtrl::updateUserAppsRoles: app roles have NOT changed; NOT going to update: id: ', app.id, '; name: ', app.name); + app.noChanges = true; + app.isError = false; //remove the error message; just show the No Changes messages + this.numberAppsProcessed++; + this.numberAppsSucceeded++; + if (this.numberAppsProcessed === this.adminApps.length) { + this.isSaving = false; // hide the spinner + } + if (this.numberAppsSucceeded === this.adminApps.length) { + $scope.closeThisDialog(true);//close and resolve dialog promise with true (to update the table) + } + } + }); + }; + + /** + * Navigate between dialog screens using step number: 1,2,... + */ + this.navigateBack = () => { + if (this.dialogState === 1) { + //back from 1st screen? + } + if (this.dialogState === 3) { + this.dialogState = 1; + } + }; + + init(); + + $scope.$on('$stateChangeStart', e => { + //Disable navigation when modal is opened + //**Nabil - note: this will cause the history back state to be replaced with current state + e.preventDefault(); + }); + } + } + NewUserModalCtrl.$inject = ['$scope', '$log', 'usersService', 'applicationsService', 'confirmBoxService']; + angular.module('ecompApp').controller('NewUserModalCtrl', NewUserModalCtrl); +})(); diff --git a/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/new-user.controller.spec.js b/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/new-user.controller.spec.js index 8d5ac749..bdc29583 100644 --- a/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/new-user.controller.spec.js +++ b/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/new-user.controller.spec.js @@ -1,255 +1,255 @@ -/*- - * ================================================================================ - * ECOMP Portal - * ================================================================================ - * Copyright (C) 2017 AT&T Intellectual Property - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ================================================================================ - */ -/** - * Created by nnaffar on 12/20/15. - */ -'use strict'; - -describe('Controller: NewUserModalCtrl ', () => { - beforeEach(module('testUtils')); - beforeEach(module('ecompApp')); - - let promisesTestUtils; - //destroy $http default cache before starting to prevent the error 'default cache already exists' - //_promisesTestUtils_ comes from testUtils for promises resolve/reject - beforeEach(inject((_CacheFactory_, _promisesTestUtils_)=> { - _CacheFactory_.destroyAll(); - promisesTestUtils = _promisesTestUtils_; - })); - - let newUser, $controller, $q, $rootScope, $log, $scope; - - let applicationsServiceMock, usersServiceMock, confirmBoxServiceMock; - let deferredAdminApps, deferredUsersAccounts, deferredUsersAppRoles, deferredUsersAppRoleUpdate; - - beforeEach(inject((_$controller_, _$q_, _$rootScope_, _$log_)=> { - $rootScope = _$rootScope_; - $q = _$q_; - $controller = _$controller_; - $log = _$log_; - })); - - beforeEach(()=> { - [deferredAdminApps, deferredUsersAccounts, deferredUsersAppRoles, deferredUsersAppRoleUpdate] = [$q.defer(),$q.defer(), $q.defer(), $q.defer()]; - - /*applicationsServiceMock = { - getAdminApps: () => { - var promise = () => {return deferredAdminApps.promise}; - var cancel = jasmine.createSpy(); - return { - promise: promise, - cancel: cancel - } - } - };*/ - - confirmBoxServiceMock = { - deleteItem: () => { - var promise = () => {return deferredAdminApps.promise}; - var cancel = jasmine.createSpy(); - return { - promise: promise, - cancel: cancel - } - } - }; - - applicationsServiceMock = jasmine.createSpyObj('applicationsServiceMock', ['getAdminAppsSimpler']); - applicationsServiceMock.getAdminAppsSimpler.and.returnValue(deferredAdminApps.promise); - - usersServiceMock = jasmine.createSpyObj('usersServiceMock', ['getAccountUsers','getUserAppRoles','updateUserAppsRoles']); - - //applicationsServiceMock.getAdminApps().promise().and.returnValue(deferredAdminApps.promise); - usersServiceMock.getAccountUsers.and.returnValue(deferredUsersAccounts.promise); - usersServiceMock.getUserAppRoles.and.returnValue(deferredUsersAppRoles.promise); - usersServiceMock.updateUserAppsRoles.and.returnValue(deferredUsersAppRoleUpdate.promise); - - $scope = $rootScope.$new(); - newUser = $controller('NewUserModalCtrl', { - $scope: $scope, - $log: $log, - usersService: usersServiceMock, - applicationsService: applicationsServiceMock, - confirmBoxService: confirmBoxServiceMock - }); - //$scope.users = users; - }); - - /*beforeEach(()=> { - scope = $rootScope.$new(); - newUser = $controller('NewUserModalCtrl', { - $scope: scope, - $log: $log, - usersService: usersService, - applicationsService: applicationsService, - confirmBoxService: confirmBoxService - }); - });*/ - - - it('should open modal window without user when no user is selected', ()=> { - expect(newUser.selectedUser).toBe(null); - }); - - it('should open modal window with selectedUser apps roles when user is selected', ()=> { - let roles = {apps: [{id: 1, appRoles: [{id: 3, isApplied: true}]}]}; - let someUser = {orgUserId: 'asdfjl'}; - - deferredUsersAppRoles.resolve(roles); - deferredAdminApps.resolve(roles.apps); - - $scope.ngDialogData = { - selectedUser: someUser, - dialogState: 2 - }; - - //inject ngDialogData to the scope controller - newUser = $controller('NewUserModalCtrl', { - $scope: $scope, - $log: $log, - usersService: usersServiceMock, - applicationsService: applicationsServiceMock, - confirmBoxService: confirmBoxServiceMock - }); - - newUser.getUserAppsRoles(); - $scope.$apply(); - - expect(newUser.selectedUser).toBe(someUser); - expect(newUser.adminApps).toEqual(roles.apps); - }); - - it('should push to apps order list only apps that has applied roles when initializing', () => { - let roles = {apps: [{appId: 13, appRoles: [{id: 3, isApplied: true}]},{appId: 20, appRoles: [{id: 3, isApplied: false}]}]}; - let someUser = {orgUserId: 'asdfjl'}; - - deferredUsersAppRoles.resolve(roles); - //deferredAdminApps.resolve(roles.apps); - - $scope.ngDialogData = { - selectedUser: someUser, - dialogState: 2 - }; - - //inject ngDialogData to the scope controller - newUser = $controller('NewUserModalCtrl', { - $scope: $scope, - $log: $log, - usersService: usersServiceMock, - applicationsService: applicationsServiceMock, - confirmBoxService: confirmBoxServiceMock - }); - - $scope.$apply(); - - // expect(newUser.appsOrder).toEqual([13]); - }); - - it('should push app to apps order list when applying at least one role to user from app', () => { - let roles = {apps: [{appId: 13, appRoles: [{id: 3, isApplied: true}]},{appId: 20, appRoles: [{id: 3, isApplied: false}]}]}; - let someUser = {orgUserId: 'asdfjl'}; - - // promisesTestUtils.resolvePromise(usersService, 'getUserAppsRoles', roles); - deferredUsersAppRoles.resolve(roles); - - $scope.ngDialogData = { - selectedUser: someUser, - dialogState: 2 - }; - - //inject ngDialogData to the scope controller - newUser = $controller('NewUserModalCtrl', { - $scope: $scope, - $log: $log, - usersService: usersServiceMock, - applicationsService: applicationsServiceMock, - confirmBoxService: confirmBoxServiceMock - }); - - //$scope.$apply(); - //newUser.updateAppsOrder({appId: 39, appRoles: [{id: 13, isApplied: true}]}); - $scope.$apply(); - - // expect(newUser.appsOrder).toEqual([13, 39]); - }); - - - it('should remove app from list when removing all user roles in it', () => { - let roles = {apps: [{appName: 'aaa', appId: 13, appRoles: [{id: 3, isApplied: true}]},{appName: 'vvv', appId: 20, appRoles: [{id: 3, isApplied: true}]}]}; - let someUser = {orgUserId: 'asdfjl'}; - - // promisesTestUtils.resolvePromise(usersService, 'getUserAppsRoles', roles); - promisesTestUtils.resolvePromise(confirmBoxServiceMock, 'deleteItem', true); - - deferredUsersAppRoles.resolve(roles); - - $scope.ngDialogData = { - selectedUser: someUser, - dialogState: 2 - }; - - //inject ngDialogData to the scope controller - newUser = $controller('NewUserModalCtrl', { - $scope: $scope, - $log: $log, - usersService: usersServiceMock, - applicationsService: applicationsServiceMock, - confirmBoxService: confirmBoxServiceMock - }); - - $scope.$apply(); - newUser.deleteApp(roles.apps[0]); - $scope.$apply(); - - // expect(newUser.appsOrder).toEqual([20]); - }); - - it('should close the modal when update changes succeeded', () => { - let roles = {apps: [{appName: 'aaa', appId: 13, appRoles: [{id: 3, isApplied: true}]},{appName: 'vvv', appId: 20, appRoles: [{id: 3, isApplied: true}]}]}; - let someUser = {orgUserId: 'asdfjl'}; - //promisesTestUtils.resolvePromise(usersServiceMock, 'getUserAppsRoles', roles); - //promisesTestUtils.resolvePromise(usersServiceMock, 'updateUserAppsRoles'); - deferredUsersAppRoles.resolve(roles); - deferredUsersAppRoleUpdate.resolve(); - deferredAdminApps.resolve(roles.apps); - - $scope.ngDialogData = { - selectedUser: someUser, - dialogState: 2 - }; - - //inject ngDialogData to the scope controller - newUser = $controller('NewUserModalCtrl', { - $scope: $scope, - $log: $log, - usersService: usersServiceMock, - applicationsService: applicationsServiceMock, - confirmBoxService: confirmBoxServiceMock - }); - $scope.closeThisDialog = function(){}; - spyOn($scope, 'closeThisDialog'); - - newUser.getUserAppsRoles(); - $scope.$apply(); - newUser.updateUserAppsRoles(); - $scope.$apply(); - expect($scope.closeThisDialog).toHaveBeenCalledWith(true); - }); - }); +/*- + * ================================================================================ + * ECOMP Portal + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ================================================================================ + */ +/** + * Created by nnaffar on 12/20/15. + */ +'use strict'; + +describe('Controller: NewUserModalCtrl ', () => { + beforeEach(module('testUtils')); + beforeEach(module('ecompApp')); + + let promisesTestUtils; + //destroy $http default cache before starting to prevent the error 'default cache already exists' + //_promisesTestUtils_ comes from testUtils for promises resolve/reject + beforeEach(inject((_CacheFactory_, _promisesTestUtils_)=> { + _CacheFactory_.destroyAll(); + promisesTestUtils = _promisesTestUtils_; + })); + + let newUser, $controller, $q, $rootScope, $log, $scope; + + let applicationsServiceMock, usersServiceMock, confirmBoxServiceMock; + let deferredAdminApps, deferredUsersAccounts, deferredUsersAppRoles, deferredUsersAppRoleUpdate; + + beforeEach(inject((_$controller_, _$q_, _$rootScope_, _$log_)=> { + $rootScope = _$rootScope_; + $q = _$q_; + $controller = _$controller_; + $log = _$log_; + })); + + beforeEach(()=> { + [deferredAdminApps, deferredUsersAccounts, deferredUsersAppRoles, deferredUsersAppRoleUpdate] = [$q.defer(),$q.defer(), $q.defer(), $q.defer()]; + + /*applicationsServiceMock = { + getAdminApps: () => { + var promise = () => {return deferredAdminApps.promise}; + var cancel = jasmine.createSpy(); + return { + promise: promise, + cancel: cancel + } + } + };*/ + + confirmBoxServiceMock = { + deleteItem: () => { + var promise = () => {return deferredAdminApps.promise}; + var cancel = jasmine.createSpy(); + return { + promise: promise, + cancel: cancel + } + } + }; + + applicationsServiceMock = jasmine.createSpyObj('applicationsServiceMock', ['getAdminAppsSimpler']); + applicationsServiceMock.getAdminAppsSimpler.and.returnValue(deferredAdminApps.promise); + + usersServiceMock = jasmine.createSpyObj('usersServiceMock', ['getAccountUsers','getUserAppRoles','updateUserAppsRoles']); + + //applicationsServiceMock.getAdminApps().promise().and.returnValue(deferredAdminApps.promise); + usersServiceMock.getAccountUsers.and.returnValue(deferredUsersAccounts.promise); + usersServiceMock.getUserAppRoles.and.returnValue(deferredUsersAppRoles.promise); + usersServiceMock.updateUserAppsRoles.and.returnValue(deferredUsersAppRoleUpdate.promise); + + $scope = $rootScope.$new(); + newUser = $controller('NewUserModalCtrl', { + $scope: $scope, + $log: $log, + usersService: usersServiceMock, + applicationsService: applicationsServiceMock, + confirmBoxService: confirmBoxServiceMock + }); + //$scope.users = users; + }); + + /*beforeEach(()=> { + scope = $rootScope.$new(); + newUser = $controller('NewUserModalCtrl', { + $scope: scope, + $log: $log, + usersService: usersService, + applicationsService: applicationsService, + confirmBoxService: confirmBoxService + }); + });*/ + + + it('should open modal window without user when no user is selected', ()=> { + expect(newUser.selectedUser).toBe(null); + }); + + it('should open modal window with selectedUser apps roles when user is selected', ()=> { + let roles = {apps: [{id: 1, appRoles: [{id: 3, isApplied: true}]}]}; + let someUser = {orgUserId: 'asdfjl'}; + + deferredUsersAppRoles.resolve(roles); + deferredAdminApps.resolve(roles.apps); + + $scope.ngDialogData = { + selectedUser: someUser, + dialogState: 2 + }; + + //inject ngDialogData to the scope controller + newUser = $controller('NewUserModalCtrl', { + $scope: $scope, + $log: $log, + usersService: usersServiceMock, + applicationsService: applicationsServiceMock, + confirmBoxService: confirmBoxServiceMock + }); + + newUser.getUserAppsRoles(); + $scope.$apply(); + + expect(newUser.selectedUser).toBe(someUser); + expect(newUser.adminApps).toEqual(roles.apps); + }); + + it('should push to apps order list only apps that has applied roles when initializing', () => { + let roles = {apps: [{appId: 13, appRoles: [{id: 3, isApplied: true}]},{appId: 20, appRoles: [{id: 3, isApplied: false}]}]}; + let someUser = {orgUserId: 'asdfjl'}; + + deferredUsersAppRoles.resolve(roles); + //deferredAdminApps.resolve(roles.apps); + + $scope.ngDialogData = { + selectedUser: someUser, + dialogState: 2 + }; + + //inject ngDialogData to the scope controller + newUser = $controller('NewUserModalCtrl', { + $scope: $scope, + $log: $log, + usersService: usersServiceMock, + applicationsService: applicationsServiceMock, + confirmBoxService: confirmBoxServiceMock + }); + + $scope.$apply(); + + // expect(newUser.appsOrder).toEqual([13]); + }); + + it('should push app to apps order list when applying at least one role to user from app', () => { + let roles = {apps: [{appId: 13, appRoles: [{id: 3, isApplied: true}]},{appId: 20, appRoles: [{id: 3, isApplied: false}]}]}; + let someUser = {orgUserId: 'asdfjl'}; + + // promisesTestUtils.resolvePromise(usersService, 'getUserAppsRoles', roles); + deferredUsersAppRoles.resolve(roles); + + $scope.ngDialogData = { + selectedUser: someUser, + dialogState: 2 + }; + + //inject ngDialogData to the scope controller + newUser = $controller('NewUserModalCtrl', { + $scope: $scope, + $log: $log, + usersService: usersServiceMock, + applicationsService: applicationsServiceMock, + confirmBoxService: confirmBoxServiceMock + }); + + //$scope.$apply(); + //newUser.updateAppsOrder({appId: 39, appRoles: [{id: 13, isApplied: true}]}); + $scope.$apply(); + + // expect(newUser.appsOrder).toEqual([13, 39]); + }); + + + it('should remove app from list when removing all user roles in it', () => { + let roles = {apps: [{appName: 'aaa', appId: 13, appRoles: [{id: 3, isApplied: true}]},{appName: 'vvv', appId: 20, appRoles: [{id: 3, isApplied: true}]}]}; + let someUser = {orgUserId: 'asdfjl'}; + + // promisesTestUtils.resolvePromise(usersService, 'getUserAppsRoles', roles); + promisesTestUtils.resolvePromise(confirmBoxServiceMock, 'deleteItem', true); + + deferredUsersAppRoles.resolve(roles); + + $scope.ngDialogData = { + selectedUser: someUser, + dialogState: 2 + }; + + //inject ngDialogData to the scope controller + newUser = $controller('NewUserModalCtrl', { + $scope: $scope, + $log: $log, + usersService: usersServiceMock, + applicationsService: applicationsServiceMock, + confirmBoxService: confirmBoxServiceMock + }); + + $scope.$apply(); + newUser.deleteApp(roles.apps[0]); + $scope.$apply(); + + // expect(newUser.appsOrder).toEqual([20]); + }); + + it('should close the modal when update changes succeeded', () => { + let roles = {apps: [{appName: 'aaa', appId: 13, appRoles: [{id: 3, isApplied: true}]},{appName: 'vvv', appId: 20, appRoles: [{id: 3, isApplied: true}]}]}; + let someUser = {orgUserId: 'asdfjl'}; + //promisesTestUtils.resolvePromise(usersServiceMock, 'getUserAppsRoles', roles); + //promisesTestUtils.resolvePromise(usersServiceMock, 'updateUserAppsRoles'); + deferredUsersAppRoles.resolve(roles); + deferredUsersAppRoleUpdate.resolve(); + deferredAdminApps.resolve(roles.apps); + + $scope.ngDialogData = { + selectedUser: someUser, + dialogState: 2 + }; + + //inject ngDialogData to the scope controller + newUser = $controller('NewUserModalCtrl', { + $scope: $scope, + $log: $log, + usersService: usersServiceMock, + applicationsService: applicationsServiceMock, + confirmBoxService: confirmBoxServiceMock + }); + $scope.closeThisDialog = function(){}; + spyOn($scope, 'closeThisDialog'); + + newUser.getUserAppsRoles(); + $scope.$apply(); + newUser.updateUserAppsRoles(); + $scope.$apply(); + expect($scope.closeThisDialog).toHaveBeenCalledWith(true); + }); + }); diff --git a/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/new-user.modal.html b/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/new-user.modal.html index 5f26152b..5fec021a 100644 --- a/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/new-user.modal.html +++ b/ecomp-portal-FE-common/client/app/views/users/new-user-dialogs/new-user.modal.html @@ -1,84 +1,90 @@ - -
- -
- - - -
- - - -
-
- -
-
- - -
-
- Access and roles: -
- -
-
-
{{app.name | elipsis: 27}}
-
- -
-
{{app.errorMessage}}
-
Contacting application...
-
No changes
-
Updating application...
-
Finished updating application
-
Could not update application...
-
-
-
-
- -
- - - - -
- -
- -
- - - -
+ +
+ +
+ + + +
+ + + +
+
+ +
+
+ + +
+
+ Access and roles: +
+ +
+
+
{{app.name | elipsis: 27}}
+
+ +
+
{{app.errorMessage}}
+
Contacting application...
+
No changes
+
Updating application...
+
Finished updating application
+
Could not update application...
+
+
+
+
+ +
+ + + + +
+ +
+ +
+ + + +
+ + -- cgit 1.2.3-korg