CADI AAF Integration and merging the code
[portal.git] / ecomp-portal-FE-common / client / app / views / role / bulk-upload-dialogs / bulk-upload-role-functions-controller.js
1 /*-
2  * ============LICENSE_START==========================================
3  * ONAP Portal
4  * ===================================================================
5  * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * ===================================================================
7  *
8  * Unless otherwise specified, all software contained herein is licensed
9  * under the Apache License, Version 2.0 (the "License");
10  * you may not use this software except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *             http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  * Unless otherwise specified, all documentation contained herein is licensed
22  * under the Creative Commons License, Attribution 4.0 Intl. (the "License");
23  * you may not use this documentation except in compliance with the License.
24  * You may obtain a copy of the License at
25  *
26  *             https://creativecommons.org/licenses/by/4.0/
27  *
28  * Unless required by applicable law or agreed to in writing, documentation
29  * distributed under the License is distributed on an "AS IS" BASIS,
30  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31  * See the License for the specific language governing permissions and
32  * limitations under the License.
33  *
34  * ============LICENSE_END============================================
35  *
36  * 
37  */
38 /**
39  * bulk upload role-functions controller
40  */
41 'use strict';
42 (function () {
43     class BulkRoleAndFunctionsModalCtrl {
44         constructor($scope, $log, $filter, $q, $modalInstance, $modal, ngDialog, message, confirmBoxService, usersService, applicationsService, functionalMenuService, RoleService) {
45                 // Set to true for copious console output
46                 var debug = false;
47                 // Roles fetched from Role service
48                 var appRoleFuncsResult = [];
49                 // Functions fetched from Role service
50                 var appFunctionsResult = [];
51                 // Global  roles fetched from Role service
52                 var appGlobalRolesResult = [];
53                 
54                 var appId = message.appid;
55                 
56                  $scope.ngRepeatBulkUploadOptions = [
57                         {id: '1', title: 'Functions', value: 'functions'},
58                         {id: '2', title: 'Roles', value: 'roles'},
59                         {id: '3', title: 'Role Functions', value: 'roleFunctions'},
60                         {id: '4', title: 'Global Role Functions', value: 'globalRoleFunctions'}
61                     ];
62                  
63                  $scope.selectedUploadType =   $scope.ngRepeatBulkUploadOptions[0];
64                  $scope.UploadTypeInstruction = "Function Type, Function Instance, Function Action, Function Name";
65                  $scope.changeUploadTypeInstruction = function(typeInstrc){
66                          switch(typeInstrc) {
67                             case 'functions':
68                                 $scope.UploadTypeInstruction = "Function Type, Function Instance, Function Action, Function Name";
69                                 break;
70                             case 'roles':
71                                 $scope.UploadTypeInstruction = "Role Name, Priority (Optional)";
72                                 break;
73                             case 'roleFunctions':
74                                 $scope.UploadTypeInstruction = "Role Name, Function Type, Function Instance, Function Action, Function Name";
75                                 break;
76                             default:
77                                 $scope.UploadTypeInstruction = "Global Role Name, Function Type, Function Instance, Function Action, Function Name";
78                         }
79                  };
80                 
81                 let init = () => {
82                         if (debug)
83                                 $log.debug('BulkRoleAndFunctionsModalCtrl::init');
84                         // Angular insists on this.
85                         $scope.fileModel = {};
86                         // Enable modal controls
87                         this.step1 = true;
88                         
89                         this.fileSelected = false;      
90                         
91                         $scope.isProcessedRecords = false;
92                 }; // init
93                 
94                 // Answers a function that compares properties with the specified name.
95                 let getSortOrder = (prop, foldCase) => {
96                 return function(a, b) {
97                         let aProp = foldCase ? a[prop].toLowerCase() : a[prop];
98                         let bProp = foldCase ? b[prop].toLowerCase() : b[prop];
99                     if (aProp > bProp)
100                         return 1;
101                     else if (aProp < bProp) 
102                         return -1;
103                     else
104                         return 0;
105                 }
106             }
107                 
108                 // Caches the file name supplied by the event handler.
109                 $scope.fileChangeHandler = (event, files) => {
110                         var fileName = files[0].name;
111                     var validFormats = ['csv', 'txt'];
112                     //Get file extension
113                     var ext = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase(); 
114                     //Check for valid format
115                     if(validFormats.indexOf(ext) == -1){
116                         this.fileSelected = false;
117                     }else{
118                         this.fileSelected = true;
119                         this.fileToRead = files[0];
120                     }
121                         if (debug)
122                                 $log.debug("BulkRoleAndFunctionsModalCtrl::fileChangeHandler: file is ", this.fileToRead);
123                 }; // file change handler
124                 
125                 /**
126                  * Reads the contents of the file, calls portal endpoints to
127                  * validate roles, userIds and existing role assignments;
128                  * ultimately builds array of requests to be sent. Creates scope
129                  * variable with input file contents for communication with
130                  * functions.
131                  * 
132                  * This function performs a synchronous step-by-step process
133                  * using asynchronous promises. The code could all be inline
134                  * here but the nesting becomes unwieldy.
135                  */
136                 $scope.readValidateFile = (typeUpload) => {
137                         $scope.isProcessing = true;
138                         $scope.conformMsg = '';
139                         $scope.isProcessedRecords = true;
140                         $scope.progressMsg = 'Reading upload file...';
141                         var reader = new FileReader();
142                         reader.onload = function(event) {
143                                 if(typeUpload === 'roles'){
144                                         $scope.uploadFile = $filter('csvToRoleObj')(reader.result);
145                                         if (debug){
146                                                 $log.debug('BulkRoleAndFunctionsModalCtrl::readValidateFile onload: data length is ' + $scope.uploadFile.length);
147                                         }
148                                         $scope.progressMsg = 'Fetching & validating application roles...';
149                                                                 // fetch app roles
150                                                         RoleService.getRoles(appId).then(function (appRoles){
151                                                                 if (debug){
152                                                         $log.debug("BulkRoleAndFunctionsModalCtrl::readValidateFile: getRoles returned " + JSON.stringify(appFunctions.data));
153                                                                 }
154                                                                         let availableRolesList = JSON.parse(appRoles.data);
155                                                                         appRoleFuncsResult = availableRolesList.availableRoles;
156                                                                 $scope.evalAppRolesCheckResults();
157                                                                 // Re sort by line for the confirmation dialog
158                                                         $scope.uploadFile.sort(getSortOrder('line', false));
159                                                         // We're done, confirm box may show the  table
160                                                         if (debug)
161                                                                         $log.debug('BulkRoleAndFunctionsModalCtrl::readValidateFile inner-then ends');
162                                                         $scope.progressMsg = 'Done.';
163                                                         $scope.isProcessing = false;
164                                                         $scope.isProcessedRecords = false;
165                                                         }, function(error) {
166                                                 $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving app roles info');
167                                                 $scope.isProcessing = false;
168                                                 $scope.isProcessedRecords = false;
169                                         });
170                                 } else if (typeUpload === 'roleFunctions'){
171                                         $scope.uploadFile = $filter('csvToRoleFuncObj')(reader.result);
172                                         if (debug){
173                                                 $log.debug('BulkRoleAndFunctionsModalCtrl::readValidateFile onload: data length is ' + $scope.uploadFile.length);
174                                         }
175                                         $scope.progressMsg = 'Fetching & validating application role functions...';
176                                         //fetch app functions
177                                         RoleService.getRoleFunctionList(appId).then(function (appFunctions){
178                                                 if (debug)
179                                         $log.debug("BulkRoleAndFunctionsModalCtrl::readValidateFile: getRoleFunctionList returned " + JSON.stringify(appFunctions.data));
180                                                                 let availableRoleFunctionsList = JSON.parse(appFunctions.data);
181                                                                 appFunctionsResult = availableRoleFunctionsList.availableRoleFunctions;
182                                                                 // fetch app roles
183                                                         RoleService.getRoles(appId).then(function (appRoles){
184                                                                 if (debug){
185                                                         $log.debug("BulkRoleAndFunctionsModalCtrl::readValidateFile: getRoles returned " + JSON.stringify(appFunctions.data));
186                                                                 }
187                                                                         let availableRolesList = JSON.parse(appRoles.data);
188                                                                         appRoleFuncsResult = availableRolesList.availableRoles;
189                                                                 $scope.evalAppRoleFuncsCheckResults();
190                                                                 // Re sort by line for the confirmation dialog
191                                                         $scope.uploadFile.sort(getSortOrder('line', false));
192                                                         // We're done, confirm box may show the  table
193                                                         if (debug)
194                                                                         $log.debug('BulkRoleAndFunctionsModalCtrl::readValidateFile inner-then ends');
195                                                         $scope.progressMsg = 'Done.';
196                                                         $scope.isProcessing = false;
197                                                         $scope.isProcessedRecords = false;
198                                                         }, function(error) {
199                                                 $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving app roles info');
200                                                 $scope.isProcessing = false;
201                                                 $scope.isProcessedRecords = false;
202                                         });
203                                         },
204                         function(error) {
205                                 $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving app functions info');
206                                 $scope.isProcessing = false;
207                         }
208                         );
209                                 } else if(typeUpload === 'functions'){
210                                         $scope.uploadFile = $filter('csvToFuncObj')(reader.result);
211                                         if (debug){
212                                                 $log.debug('BulkRoleAndFunctionsModalCtrl::readValidateFile onload: data length is ' + $scope.uploadFile.length);
213                                         }
214                                         $scope.progressMsg = 'Fetching & validating the application functions...';
215                                         // fetch app functions
216                                         RoleService.getRoleFunctionList(appId).then(function (appFunctions){
217                                                 if (debug)
218                                         $log.debug("BulkRoleAndFunctionsModalCtrl::readValidateFile: getRoleFunctionList returned " + JSON.stringify(appFunctions.data));
219                                                                 let availableRoleFunctionsList = JSON.parse(appFunctions.data);
220                                                                 appFunctionsResult = availableRoleFunctionsList.availableRoleFunctions;
221                                                 $scope.verifyFunctions();
222                                                 $scope.evalAppFunctionsCheckResults();
223                                         // Re sort by line for the confirmation dialog
224                                         $scope.uploadFile.sort(getSortOrder('line', false));
225                                         // We're done, confirm box may show the  table
226                                         if (debug)
227                                                         $log.debug('BulkRoleAndFunctionsModalCtrl::readValidateFile inner-then ends');
228                                         $scope.progressMsg = 'Done.';
229                                         $scope.isProcessing = false;
230                                         $scope.isProcessedRecords = false;
231                                         },
232                         function(error) {
233                                 $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving app functions info');
234                                 $scope.isProcessing = false;
235                                 $scope.isProcessedRecords = false;
236                         }
237                         );
238                                 } else if(typeUpload === 'globalRoleFunctions'){
239                                         $scope.uploadFile = $filter('csvToRoleFuncObj')(reader.result);
240                                         if (debug){
241                                                 $log.debug('BulkRoleAndFunctionsModalCtrl::readValidateFile onload: data length is ' + $scope.uploadFile.length);
242                                         }
243                                         $scope.progressMsg = 'Fetching application global role functions...';
244                                         //fetch app functions
245                                         RoleService.getRoleFunctionList(appId).then(function (appFunctions){
246                                                         if (debug)
247                                         $log.debug("BulkRoleAndFunctionsModalCtrl::readValidateFile: getRoleFunctionList returned " + JSON.stringify(appFunctions.data));
248                                                                 let availableRoleFunctionsList = JSON.parse(appFunctions.data);
249                                                                 appFunctionsResult = availableRoleFunctionsList.availableRoleFunctions;
250                                                                 // fetch app roles
251                                                         RoleService.getRoles(appId).then(function (appRoles){
252                                                                 if (debug){
253                                                         $log.debug("BulkRoleAndFunctionsModalCtrl::readValidateFile: getRoles returned " + JSON.stringify(appFunctions.data));
254                                                                 }
255                                                                         let availableRolesList = JSON.parse(appRoles.data);
256                                                                         appRoleFuncsResult = availableRolesList.availableRoles;
257                                                                         appRoleFuncsResult.forEach(function(appRole) {
258                                                                                 if(appRole.name.toLowerCase().startsWith("global_")){
259                                                                                         appGlobalRolesResult.push(appRole);
260                                                                                 }
261                                                                                 });
262                                                                 $scope.evalAppRoleFuncsCheckResults(typeUpload);
263                                                                 // Re sort by line for the confirmation dialog
264                                                         $scope.uploadFile.sort(getSortOrder('line', false));
265                                                         // We're done, confirm box may show the  table
266                                                         if (debug)
267                                                                         $log.debug('BulkRoleAndFunctionsModalCtrl::readValidateFile inner-then ends');
268                                                         $scope.progressMsg = 'Done.';
269                                                         $scope.isProcessing = false;
270                                                         $scope.isProcessedRecords = false;
271                                                         }, function(error) {
272                                                 $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving app roles info');
273                                                 $scope.isProcessing = false;
274                                                 $scope.isProcessedRecords = false;
275                                         });
276                                                 },
277                             function(error) {
278                                 $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving app functions info');
279                                 $scope.isProcessing = false;
280                             }
281                             );
282                                 }
283
284                         } // onload
285                         
286                         // Invoke the reader on the selected file
287                         reader.readAsText(this.fileToRead);
288                 }; 
289                 
290                 /**
291                  * Evaluates the result set returned by the role service.
292                  * Sets an uploadFile array element status if a functions is not
293                  * defined. Reads and writes scope variable uploadFile. Reads
294                  * closure variable appFunctionsResult.
295                  */
296                 $scope.verifyFunctions = () => {
297                         if (debug)
298                                 $log.debug('BulkRoleAndFunctionsModalCtrl::verifyFunctions: appFunctions is ' + JSON.stringify(appFunctionsResult));
299                         // check functions in upload file against defined app functions
300                         $scope.uploadFile.forEach( function (uploadRow) {
301                                 // skip rows that already have a defined status: headers etc.
302                                 if (uploadRow.status) {
303                                         if (debug)
304                                                 $log.debug('BulkRoleAndFunctionsModalCtrl::verifyFunctions: skip row ' + uploadRow.line);
305                                         return;
306                                 }
307                                 for (var i=0; i < appFunctionsResult.length; i++) {
308                                         if (uploadRow.type.toUpperCase() === appFunctionsResult[i].type.toUpperCase()
309                                                 && uploadRow.instance.toUpperCase() === appFunctionsResult[i].code.toUpperCase()
310                                                 && uploadRow.action.toUpperCase() === appFunctionsResult[i].action.toUpperCase()) {
311                                                 if (debug)
312                                                         $log.debug('BulkRoleAndFunctionsModalCtrl::verifyFunctions: match on function ' + uploadRow.type,
313                                                                 uploadRow.instance, uploadRow.type,  uploadRow.type);
314                                                 break;
315                                         }
316                                 }
317                         }); // foreach
318                 }; // verifyFunctions
319                 
320         /**
321                  * Evaluates the result set of existing functions returned by 
322                  * the Roleservice and list of functions found in the upload file. 
323                  * Reads and writes scope variable uploadFile. 
324                  * Reads closure variable appFunctionsResult.
325                  */
326                 $scope.evalAppFunctionsCheckResults = () => {
327                         if (debug)
328                                 $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppFunctionsCheckResults: uploadFile length is ' + $scope.uploadFile.length);
329                         $scope.uploadFile.forEach(function (uploadRow) {
330                                 if (uploadRow.status) {
331                                         if (debug)
332                                                 $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppFunctionsCheckResults: skip row ' + uploadRow.line);
333                                         return;
334                                 }
335                                 // Search for the match in the app-functions
336                                 // array
337                                 let isFunctionExist = false;
338                                 appFunctionsResult.forEach( function (exixtingFuncObj) {
339                                                         if (uploadRow.type.toUpperCase() === exixtingFuncObj.type.toUpperCase()
340                                                                 && uploadRow.instance.toUpperCase() === exixtingFuncObj.code.toUpperCase()
341                                                                 && uploadRow.action.toUpperCase() === exixtingFuncObj.action.toUpperCase()) {
342                                                                 uploadRow.status = 'Function exits!';
343                                                                 uploadRow.isCreate = false;
344                                                                 isFunctionExist = true;
345                                                         }
346                                 }); // for each result
347                                 if(!isFunctionExist) {
348                                         if(/[^a-zA-Z0-9\-\.\_]/.test(uploadRow.type) 
349                                                         || (uploadRow.action !== '*' 
350                                                         && /[^a-zA-Z0-9\-\.\_]/.test(uploadRow.action))
351                                                         || /[^a-zA-Z0-9\-\:\_\./*]/.test(uploadRow.instance)
352                                                         || /[^a-zA-Z0-9\-\_ \.]/.test(uploadRow.name)){
353                                                 uploadRow.status = 'Invalid function';
354                                                 uploadRow.isCreate = false;
355                                         } else {
356                                                 if (debug){
357                                                         $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppFunctionsCheckResults: new function ' 
358                                                                         + uploadRow);
359                                                 }
360                                                         // After much back-and-forth I decided a clear  indicator is better than blank in the table  status column.
361                                                 uploadRow.status = 'Create';
362                                                 uploadRow.isCreate = true;
363                                         }
364                                         }
365                         }); // for each row
366                 }; // evalAppFunctionsCheckResults
367                 
368                 /**
369                  * Evaluates the result set of existing roles returned by 
370                  * the Roleservice and list of roles found in the upload file. 
371                  * Reads and writes scope variable uploadFile. 
372                  * Reads closure variable appRolesResult.
373                  */
374                         $scope.evalAppRolesCheckResults = () => {
375                                 if (debug)
376                                         $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppRolesCheckResults: uploadFile length is ' + $scope.uploadFile.length);
377                                 $scope.uploadFile.forEach(function (uploadRow) {
378                                         if (uploadRow.status) {
379                                                 if (debug)
380                                                         $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppRolesCheckResults: skip row ' + uploadRow.line);
381                                                 return;
382                                         }
383                                         // Search for the match in the app-roles
384                                 // array
385                                         let isRoleExist = false;
386                                         appRoleFuncsResult.forEach( function (existingRoleObj) {
387                                                                 if (uploadRow.role.toUpperCase() === existingRoleObj.name.toUpperCase()) {
388                                                                 uploadRow.status = 'Role exits!';
389                                                                 uploadRow.isCreate = false;
390                                                                 isRoleExist = true;
391                                                                 }
392                                         }); // for each result
393                                         if(!isRoleExist) {
394                                                 if(/[^a-zA-Z0-9\-\_ \.\/]/.test(uploadRow.role) ||
395                                                                 uploadRow.role.toLowerCase().startsWith("global_")){
396                                                         uploadRow.status = 'Invalid role!';
397                                                         uploadRow.isCreate = false;
398                                                 } else {
399                                                         if (debug){
400                                                                 $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppRolesCheckResults: new function ' 
401                                                                         + uploadRow);
402                                                         }
403                                                         // After much back-and-forth I decided a clear  indicator is better than blank in the table  status column.
404                                                         uploadRow.status = 'Create';
405                                                         uploadRow.isCreate = true;
406                                                 }
407                                         }
408                                 }); // for each row
409                         }; // evalAppRolesCheckResults
410                         
411                         /**
412                          * Evaluates the result set of existing roles returned by 
413                          * the Roleservice and list of roles found in the upload file. 
414                          * Reads and writes scope variable uploadFile. 
415                          * Reads closure variable appRolesResult.
416                          */
417                         $scope.evalAppRoleFuncsCheckResults = (typeUpload) => {
418                                 if (debug)
419                                         $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppRoleFuncsCheckResults: uploadFile length is ' + $scope.uploadFile.length);
420                                 $scope.uploadFile.forEach(function (uploadRow) {
421                                         if (uploadRow.status) {
422                                                 if (debug)
423                                                         $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppRoleFuncsCheckResults: skip row ' + uploadRow.line);
424                                                 return;
425                                         }
426                                         // Search for the match in the app-functions array
427                                         let isValidFunc = false;
428                                         appFunctionsResult.forEach(function (existingFuncObj){
429                                                 if(uploadRow.type.toUpperCase() === existingFuncObj.type.toUpperCase()
430                                                                         && uploadRow.instance.toUpperCase() === existingFuncObj.code.toUpperCase()
431                                                                         && uploadRow.action.toUpperCase() === existingFuncObj.action.toUpperCase()
432                                                                         && uploadRow.name.toUpperCase() === existingFuncObj.name.toUpperCase()){
433                                                         isValidFunc = true;
434                                                         }
435                                         });
436                                         
437                                         let isValidRole = false;
438                                         let isRoleFuncExist = false;
439                                         if(typeUpload === 'globalRoleFunctions'){
440                                                 // Search for the match in the app-role array
441                                                 appGlobalRolesResult.forEach( function (existingRoleObj) {
442                                                                         if (uploadRow.role.toUpperCase() === existingRoleObj.name.toUpperCase()) {
443                                                                                 isValidRole = true;
444                                                                                 if(isValidFunc){
445                                                                                         existingRoleObj.roleFunctions.forEach(function (existingRoleFuncObj){
446                                                                                                 if(uploadRow.type.toUpperCase() === existingRoleFuncObj.type.toUpperCase()
447                                                                                                 && uploadRow.instance.toUpperCase() === existingRoleFuncObj.code.toUpperCase()
448                                                                                                 && uploadRow.action.toUpperCase() === existingRoleFuncObj.action.toUpperCase()){
449                                                                                                         isRoleFuncExist = true;
450                                                                                         }
451                                                                                         });
452                                                                                 }
453                                                                         }
454                                                 }); // for each result
455                                         } else {
456                                                 // Search for the match in the app-role array
457                                                 appRoleFuncsResult.forEach( function (existingRoleObj) {
458                                                                         if (uploadRow.role.toUpperCase() === existingRoleObj.name.toUpperCase()) {
459                                                                                 isValidRole = true;
460                                                                                 if(isValidFunc){
461                                                                                         existingRoleObj.roleFunctions.forEach(function (existingRoleFuncObj){
462                                                                                                 if(uploadRow.type.toUpperCase() === existingRoleFuncObj.type.toUpperCase()
463                                                                                                 && uploadRow.instance.toUpperCase() === existingRoleFuncObj.code.toUpperCase()
464                                                                                                 && uploadRow.action.toUpperCase() === existingRoleFuncObj.action.toUpperCase()){
465                                                                                                         isRoleFuncExist = true;
466                                                                                         }
467                                                                                         });
468                                                                                 }       
469                                                                         }
470                                                 }); // for each result
471                                         }
472                                         
473                                 uploadRow.isCreate = false;
474                                 if(typeUpload === 'globalRoleFunctions' && (!isValidRole || !isValidFunc)){
475                                         uploadRow.status = 'Invalid global role function!';
476                                 } else if(typeUpload !== 'globalRoleFunctions' && (!isValidRole || !isValidFunc)){
477                                         uploadRow.status = 'Invalid role function!';
478                                 } else if(typeUpload === 'globalRoleFunctions' && !isRoleFuncExist) {
479                                         uploadRow.status = 'Add global role function!';
480                                                 uploadRow.isCreate = true;
481                                 } else if(typeUpload !== 'globalRoleFunctions' && !isRoleFuncExist){
482                                         uploadRow.status = 'Add role function!';
483                                         uploadRow.isCreate = true;
484                                 } else if(typeUpload === 'globalRoleFunctions'){
485                                         uploadRow.status = 'Global role function exists!';
486                                 } else {
487                                         uploadRow.status = 'Role function exists!';
488                                 }
489                                         
490                                 }); // for each row
491                         }; // evalAppRolesCheckResults
492                         
493                 
494         /**
495          * Sends requests to Portal BE requesting application functions assignment.
496                  * That endpoint handles creation of the application functions in the 
497                  * external auth system if necessary. Reads closure variable appFunctionsResult.
498                  * Invoked by the Next button on the confirmation dialog.
499                  */
500                 $scope.updateFunctionsInDB = () => {
501                         $scope.isProcessing = true;
502                         $scope.conformMsg = '';
503                         $scope.isProcessedRecords = true;
504                         $scope.progressMsg = 'Sending requests to application..';
505                         if (debug)
506                                 $log.debug('BulkRoleAndFunctionsModalCtrl::updateFunctionsInDB: request length is ' + appUserRolesRequest.length);
507                         var numberFunctionsSucceeded = 0;
508                         let promises = [];
509                         $scope.uploadFile.forEach(function(appFuncPostData) {
510                                 if (debug) 
511                                         $log.debug('BulkRoleAndFunctionsModalCtrl::updateFunctionsInDB: appFuncPostData is ' + JSON.stringify(appFuncPostData));
512                                 let updateFunctionsFinalPostData = {
513                                          type: appFuncPostData.type, 
514                                          code: appFuncPostData.instance, 
515                                          action: appFuncPostData.action,
516                                          name: appFuncPostData.name
517                         };
518                      if (debug)
519                          $log.debug('BulkRoleAndFunctionsModalCtrl::updateFunctionsInDB: updateFunctionsFinalPostData is ' + JSON.stringify(updateFunctionsFinalPostData));
520                      let updatePromise = {};
521                      if(appFuncPostData.isCreate){
522                      updatePromise = functionalMenuService.saveBulkFunction(appId, updateFunctionsFinalPostData).promise().then(res => {
523                          if (debug)
524                                  $log.debug('BulkRoleAndFunctionsModalCtrl::updateFunctionsInDB: updated successfully: ' + JSON.stringify(res));
525                          numberFunctionsSucceeded++;
526                      }).catch(err => {
527                          // What to do if one of many fails??
528                          $log.error('BulkRoleAndFunctionsModalCtrl::updateFunctionsInDB failed: ', err);
529                          confirmBoxService.showInformation(
530                                          'Failed to update the application functions. ' +
531                                          'Error: ' + err.status).then(isConfirmed => { });
532                      }).finally( () => {
533                      });
534                         }
535                     promises.push(updatePromise);
536                  }); // for each
537                         
538                  // Run all the promises
539                  $q.all(promises).then(function(){
540                          $scope.conformMsg  = 'Processed ' + numberFunctionsSucceeded + ' records.';
541                          $scope.isProcessing = false;
542                          $scope.isProcessedRecords = true;
543                          $scope.uploadFile = [];
544                  });
545              }; // updateFunctionsInDB
546              
547              /**
548                  * Sends requests to Portal BE requesting application functions assignment.
549                  * That endpoint handles creation of the application role in the 
550                  * external auth system if necessary. Reads closure variable appRoleFuncResult.
551                  * Invoked by the Next button on the confirmation dialog.
552                  */
553                         $scope.updateRolesInDB = () => {
554                                 $scope.isProcessing = true;
555                                 $scope.conformMsg = '';
556                                 $scope.isProcessedRecords = true;
557                                 $scope.progressMsg = 'Sending requests to application..';
558                                 if (debug)
559                                         $log.debug('BulkRoleAndFunctionsModalCtrl::updateRolesInDB: request length is ' + appUserRolesRequest.length);
560                                 var numberRolesSucceeded = 0;
561                                 let promises = [];
562                                 $scope.uploadFile.forEach(function(appRolePostData) {
563                                         let priority = parseInt(appRolePostData.priority);
564                                         if (debug) 
565                                                 $log.debug('BulkRoleAndFunctionsModalCtrl::updateRolesInDB: appRolePostData is ' + JSON.stringify(appFuncPostData));
566                                         let uplaodRolePostData = "";
567                                         if(isNaN(priority)){
568                                         uplaodRolePostData = {
569                                                  name: appRolePostData.role,
570                                                  active: true,
571                                                         }
572                                         } else {
573                                                 uplaodRolePostData = {
574                                          name: appRolePostData.role, 
575                                          priority: appRolePostData.priority, 
576                                          active: true,
577                                                 }
578                                         }
579                                                 var postData = {
580                                                                 role: uplaodRolePostData,
581                                                                 roleFunctions: [],
582                                                                 childRoles: []
583                                                         }
584                           if (debug)
585                                  $log.debug('BulkRoleAndFunctionsModalCtrl::updateRolesInDB: uplaodRoleFinalPostData is ' + JSON.stringify(uplaodRoleFinalPostData));
586                           let updatePromise = {};
587                           if(appRolePostData.isCreate){
588                           updatePromise = functionalMenuService.saveBulkRole(appId, JSON.stringify(postData)).promise().then(res => {
589                                  if (debug)
590                                          $log.debug('BulkRoleAndFunctionsModalCtrl::updateRolesInDB: updated successfully: ' + JSON.stringify(res));
591                                 numberRolesSucceeded++;
592                           }).catch(err => {
593                                  // What to do if one of many fails??
594                                  $log.error('BulkRoleAndFunctionsModalCtrl::updateRolesInDB failed: ', err);
595                                  confirmBoxService.showInformation(
596                                                  'Failed to update the application role. ' +
597                                                  'Error: ' + err.status).then(isConfirmed => { });
598                           }).finally( () => {
599                           });
600                         }
601                          promises.push(updatePromise);
602                          }); // for each
603                                 
604                          // Run all the promises
605                          $q.all(promises).then(function(){
606                                 if(numberRolesSucceeded == 0){
607                                  $scope.conformMsg  = 'Processed ' + numberRolesSucceeded + ' records';
608                                  }else{
609                                  $scope.conformMsg  = 'Processed ' + numberRolesSucceeded + ' records. Please sync roles to reflect in portal';
610                                  }                               $scope.isProcessing = false;
611                                  $scope.isProcessedRecords = true;
612                                  $scope.uploadFile = [];
613                          });
614                   }; // updateRolesInDB
615                   
616                 /**
617                  * Sends requests to Portal BE requesting role function assignment.
618                  * That endpoint handles adding role function in the external auth system
619                  * if necessary.Invoked by the Next button on the confirmation dialog.
620                  */
621                         $scope.updateRoleFunctionsInDB = () => {
622                                 $scope.isProcessing = true;
623                                 $scope.conformMsg = '';
624                                 $scope.isProcessedRecords = true;
625                                 $scope.progressMsg = 'Sending requests to application..';
626                                 if (debug)
627                                         $log.debug('BulkRoleAndFunctionsModalCtrl::updateRoleFunctionsInDB: request length is ' + appUserRolesRequest.length);
628                                 var numberRoleFunctionSucceeded = 0;
629                                 let promises = [];
630                                 $scope.uploadFile.forEach(function(appRoleFuncPostData) {
631                                         if (debug) 
632                                                 $log.debug('BulkRoleAndFunctionsModalCtrl::updateRoleFunctionsInDB: appRoleFuncPostData is ' + JSON.stringify(appFuncPostData));
633                                         let updateRoleFunctionFinalPostData = {
634                                                  roleName: appRoleFuncPostData.role,
635                                                  type: appRoleFuncPostData.type, 
636                                                  instance: appRoleFuncPostData.instance, 
637                                                  action: appRoleFuncPostData.action,
638                                                  name: appRoleFuncPostData.name,
639                                                  isGlobalRolePartnerFunc: false
640                             };
641                          if (debug)
642                                  $log.debug('BulkRoleAndFunctionsModalCtrl::updateRoleFunctionsInDB: updateRoleFunctionFinalPostData is ' + JSON.stringify(updateFunctionsFinalPostData));
643                          let updatePromise = {};
644                          if(appRoleFuncPostData.isCreate){
645                          updatePromise = functionalMenuService.updateBulkRoleFunction(appId, updateRoleFunctionFinalPostData).promise().then(res => {
646                                  if (debug)
647                                          $log.debug('BulkRoleAndFunctionsModalCtrl::updateRoleFunctionsInDB: updated successfully: ' + JSON.stringify(res));
648                                  numberRoleFunctionSucceeded++;
649                          }).catch(err => {
650                                  // What to do if one of many fails??
651                                  $log.error('BulkRoleAndFunctionsModalCtrl::updateRoleFunctionsInDB failed: ', err);
652                                  confirmBoxService.showInformation(
653                                                  'Failed to update the application role function. ' +
654                                                  'Error: ' + err.status).then(isConfirmed => { });
655                          }).finally( () => {
656                          });
657                         }
658                         promises.push(updatePromise);
659                          }); // for each
660                                 
661                          // Run all the promises
662                          $q.all(promises).then(function(){
663                                  if(numberRoleFunctionSucceeded == 0){
664                                  $scope.conformMsg  = 'Processed ' + numberRoleFunctionSucceeded + ' records';
665                                  }else{
666                                  $scope.conformMsg  = 'Processed ' + numberRoleFunctionSucceeded + ' records. Please sync roles to reflect in portal';
667                                  }                               $scope.isProcessing = false;
668                                  $scope.isProcessedRecords = true;
669                                  $scope.uploadFile = [];
670                          });
671                   }; // updateRoleFunctionsInDB
672                   
673                 /**
674                          * Sends requests to Portal requesting global role functions assignment.
675                          * That endpoint handles updating global role functions in the external auth system
676                          * if necessary. Invoked by the Next button on the confirmation dialog.
677                          */
678                         $scope.updateGlobalRoleFunctionsInDB = () => {
679                                 $scope.isProcessing = true;
680                                 $scope.conformMsg = '';
681                                 $scope.isProcessedRecords = true;
682                                 $scope.progressMsg = 'Sending requests to application..';
683                                 if (debug)
684                                         $log.debug('BulkRoleAndFunctionsModalCtrl::updateGlobalRoleFunctionsInDB: request length is ' + appUserRolesRequest.length);
685                                 var numberGlobalRoleFunctionSucceeded = 0;
686                                 let promises = [];
687                                 $scope.uploadFile.forEach(function(appRoleFuncPostData) {
688                                         if (debug) 
689                                                 $log.debug('BulkRoleAndFunctionsModalCtrl::updateGlobalRoleFunctionsInDB: appRoleFuncPostData is ' + JSON.stringify(appFuncPostData));
690                                         let updateGlobalRoleFunctionFinalPostData = {
691                                                  roleName: appRoleFuncPostData.role,
692                                                  type: appRoleFuncPostData.type, 
693                                                  instance: appRoleFuncPostData.instance, 
694                                                  action: appRoleFuncPostData.action,
695                                                  name: appRoleFuncPostData.name,
696                                                  isGlobalRolePartnerFunc: true
697                                 };
698                              if (debug)
699                                  $log.debug('BulkRoleAndFunctionsModalCtrl::updateGlobalRoleFunctionsInDB: updateRoleFunctionFinalPostData is ' + JSON.stringify(updateFunctionsFinalPostData));
700                              let updatePromise = {};
701                              if(appRoleFuncPostData.isCreate){
702                              updatePromise = functionalMenuService.updateBulkRoleFunction(appId, updateGlobalRoleFunctionFinalPostData).promise().then(res => {
703                                  if (debug)
704                                          $log.debug('BulkRoleAndFunctionsModalCtrl::updateGlobalRoleFunctionsInDB: updated successfully: ' + JSON.stringify(res));
705                                  numberGlobalRoleFunctionSucceeded++;
706                              }).catch(err => {
707                                  // What to do if one of many fails??
708                                  $log.error('BulkRoleAndFunctionsModalCtrl::updateGlobalRoleFunctionsInDB failed: ', err);
709                                  confirmBoxService.showInformation(
710                                                  'Failed to update the global role partner function. ' +
711                                                  'Error: ' + err.status).then(isConfirmed => { });
712                              }).finally( () => {
713                              });
714                                 }
715                             promises.push(updatePromise);
716                          }); // for each
717                                 
718                          // Run all the promises
719                          $q.all(promises).then(function(){
720                                  if(numberGlobalRoleFunctionSucceeded == 0){
721                                          $scope.conformMsg  = 'Processed ' + numberGlobalRoleFunctionSucceeded + ' records';
722                                  }else{
723                                          $scope.conformMsg  = 'Processed ' + numberGlobalRoleFunctionSucceeded + ' records. Please sync roles to reflect in portal';
724                                  }
725                                  $scope.isProcessing = false;
726                                  $scope.isProcessedRecords = true;
727                                  $scope.uploadFile = [];
728                          });
729                        }; // updateGlobalRoleFunctionsInDB
730                        
731                 // Sets the variable that hides/reveals the user controls
732                 $scope.step2 = () => {
733                         this.fileSelected = false;
734                         $scope.selectedFile = null;
735                         $scope.fileModel = null;
736                         this.step1 = false;                     
737                 }
738                 
739              // Navigate between dialog screens using step number: 1,2,...
740              $scope.navigateBack = () => {
741                  this.step1 = true;
742                  this.fileSelected = false;
743              };
744              
745              // Opens a dialog to show the data to be uploaded.
746              // Invoked by the upload button on the bulk user dialog.
747              $scope.confirmUpload = (typeUpload) => {
748                 // Start the process
749                 $scope.readValidateFile(typeUpload);
750                 // Dialog shows progress
751                 if(typeUpload === 'functions'){
752                         $modal.open({
753                         templateUrl: 'app/views/role/bulk-upload-dialogs/bulk-upload-functions-confirm.html',
754                         controller: '',
755                         sizeClass: 'modal-medium', 
756                         resolve:'',
757                         scope: $scope
758                     })
759                 } else if(typeUpload === 'roleFunctions'){
760                         $modal.open({
761                                 templateUrl: 'app/views/role/bulk-upload-dialogs/bulk-upload-role-functions-confirm.html',
762                         controller: '',
763                         sizeClass: 'modal-medium', 
764                         resolve:'',
765                         scope: $scope
766                     })
767                         
768                 } else if(typeUpload === 'roles'){
769                         $modal.open({
770                         templateUrl: 'app/views/role/bulk-upload-dialogs/bulk-upload-roles-confirm.html',
771                         controller: '',
772                         sizeClass: 'modal-medium', 
773                         resolve:'',
774                         scope: $scope
775                     })
776                 } else if(typeUpload === 'globalRoleFunctions'){
777                         $modal.open({
778                         templateUrl: 'app/views/role/bulk-upload-dialogs/bulk-upload-global-role-functions-confirm.html',
779                         controller: '',
780                         sizeClass: 'modal-medium', 
781                         resolve:'',
782                         scope: $scope
783                     })
784                 }
785              };
786
787              // Invoked by the Cancel button on the confirmation dialog.
788              $scope.cancelUpload = () => {
789                  ngDialog.close();
790              };
791              
792              init();
793         } // constructor
794     } // class
795     BulkRoleAndFunctionsModalCtrl.$inject = ['$scope', '$log', '$filter', '$q',  '$modalInstance', '$modal', 'ngDialog', 'message', 'confirmBoxService', 'usersService', 'applicationsService', 'functionalMenuService', 'RoleService'];    
796     angular.module('ecompApp').controller('BulkRoleAndFunctionsModalCtrl', BulkRoleAndFunctionsModalCtrl);
797
798     angular.module('ecompApp').directive('fileChange', ['$parse', function($parse){
799         return {
800                 require: 'ngModel',
801             restrict: 'A',
802             link : function($scope, element, attrs, ngModel) {
803                 var attrHandler = $parse(attrs['fileChange']);
804                 var handler=function(e) {
805                         $scope.$apply(function() {
806                                 attrHandler($scope, { $event:e, files:e.target.files } );
807                                 $scope.selectedFile = e.target.files[0].name;
808                         });
809                 };
810                 element[0].addEventListener('change',handler,false);
811            }
812         }
813     }]);
814     
815     angular.module('ecompApp').filter('csvToFuncObj',function() {
816         return function(input) {
817             var result = [];
818             var len, i, line, o;
819                 var lines = input.split('\n');
820             // Need 1-based index below
821             for (len = lines.length, i = 1; i <= len; ++i) {
822                 // Use 0-based index for array
823                 line = lines[i - 1].trim();
824                         if (line.length == 0) {
825                                 // console.log("Skipping blank line");
826                                 result.push({
827                                         line: i,
828                                         type: '',
829                                         instance: '',
830                                         action: '',
831                                         name: '',
832                                         status: 'Blank line'
833                                 });
834                                 continue;
835                         }
836                         o = line.split(',');
837                         if (o.length !== 4) {
838                                 // other lengths not valid for upload
839                                 result.push({
840                                         line: i,
841                                         type: o[0],
842                                         instance: o[1],
843                                         action: o[2],
844                                         name: '',
845                                         status: 'Failed to find 4 comma-separated values'
846                                 });
847                         }
848                         else {
849                                 // console.log("Valid line: ", val);
850                                 let entry = {
851                                                 line: i,
852                                                 type: o[0],
853                                                 instance: o[1],
854                                                 action: o[2],
855                                                 name: o[3]
856                                                 // leave status undefined, this
857                                                 // could be valid.
858                                 };
859                                 if (o[0].toLowerCase() === 'type') {
860                                         // not valid for upload, so set status
861                                         entry.status = 'Header';
862                                 }
863                                 else if (o[0].toLowerCase() === 'instance') {
864                                         // not valid for upload, so set status
865                                         entry.status = 'Header';
866                                 }
867                                 else if (o[0].toLowerCase() === 'action') {
868                                         // not valid for upload, so set status
869                                         entry.status = 'Header';
870                                 }
871                                 else if (o[0].toLowerCase() === 'name') {
872                                         // not valid for upload, so set status
873                                         entry.status = 'Header';
874                                 }
875                                 else if (o[0].trim() == '' || o[1].trim() == '' ||  o[2].trim() == '' ||  o[3].trim() == '') {
876                                         // defend against line with only a
877                                         // single comma etc.
878                                         entry.status = 'Failed to find non-empty values';                                       
879                                 }
880                                 result.push(entry);
881                         } // len 2
882             } // for
883             return result;
884         };
885     });
886     
887     angular.module('ecompApp').filter('csvToRoleFuncObj',function() {
888         return function(input) {
889             var result = [];
890             var len, i, line, o;
891                 var lines = input.split('\n');
892             // Need 1-based index below
893             for (len = lines.length, i = 1; i <= len; ++i) {
894                 // Use 0-based index for array
895                 line = lines[i - 1].trim();
896                         if (line.length == 0) {
897                                 // console.log("Skipping blank line");
898                                 result.push({
899                                         line: i,
900                                         role:'',
901                                         type: '',
902                                         instance: '',
903                                         action: '',
904                                         name: '',
905                                         status: 'Blank line'
906                                 });
907                                 continue;
908                         }
909                         o = line.split(',');
910                         if (o.length !== 5) {
911                                 // other lengths not valid for upload
912                                 result.push({
913                                         line: i,
914                                         role: o[0],
915                                         type: o[1],
916                                         instance: o[2],
917                                         action: o[3],
918                                         name: '',
919                                         status: 'Failed to find 4 comma-separated values'
920                                 });
921                         }
922                         else {
923                                 // console.log("Valid line: ", val);
924                                 let entry = {
925                                                 line: i,
926                                                 role: o[0],
927                                                 type: o[1],
928                                                 instance: o[2],
929                                                 action: o[3],
930                                                 name: o[4]
931                                                 // leave status undefined, this
932                                                 // could be valid.
933                                 };
934                                 if (o[0].toLowerCase() === 'role') {
935                                         // not valid for upload, so set status
936                                         entry.status = 'Header';
937                                 } else if (o[0].toLowerCase() === 'type') {
938                                         // not valid for upload, so set status
939                                         entry.status = 'Header';
940                                 }
941                                 else if (o[0].toLowerCase() === 'instance') {
942                                         // not valid for upload, so set status
943                                         entry.status = 'Header';
944                                 }
945                                 else if (o[0].toLowerCase() === 'action') {
946                                         // not valid for upload, so set status
947                                         entry.status = 'Header';
948                                 }
949                                 else if (o[0].toLowerCase() === 'name') {
950                                         // not valid for upload, so set status
951                                         entry.status = 'Header';
952                                 }
953                                 else if (o[0].trim() == '' || o[1].trim() == '' ||  o[2].trim() == '' ||  o[3].trim() == '' || o[4].trim() == '') {
954                                         // defend against line with only a
955                                         // single comma etc.
956                                         entry.status = 'Failed to find non-empty values';                                       
957                                 }
958                                 result.push(entry);
959                         } // len 2
960             } // for
961             return result;
962         };
963     });
964     
965     angular.module('ecompApp').filter('csvToRoleObj',function() {
966         return function(input) {
967             var result = [];
968             var len, i, line, o;
969                 var lines = input.split('\n');
970             // Need 1-based index below
971             for (len = lines.length, i = 1; i <= len; ++i) {
972                 // Use 0-based index for array
973                 line = lines[i - 1].trim();
974                         if (line.length == 0) {
975                                 // console.log("Skipping blank line");
976                                 result.push({
977                                         line: i,
978                                         role:'',
979                                         priority: '',
980                                         status: 'Blank line'
981                                 });
982                                 continue;
983                         }
984                         o = line.split(',');
985                         if (o.length === 0 && line.length !== 0) {
986                                 // other lengths not valid for upload
987                                 result.push({
988                                         line: i,
989                                         role: o[0],
990                                         priority:null
991                                 });
992                         }
993                         else {
994                                 // console.log("Valid line: ", val);
995                                 let entry = {
996                                                 line: i,
997                                                 role: o[0],
998                                                 priority: o[1]
999                                                 // leave status undefined, this
1000                                                 // could be valid.
1001                                 };
1002                                 if (o[0].toLowerCase() === 'role') {
1003                                         // not valid for upload, so set status
1004                                         entry.status = 'Header';
1005                                 }
1006                                 if (o[0].toLowerCase() === 'priority') {
1007                                         // not valid for upload, so set status
1008                                         entry.status = 'Header';
1009                                 }
1010                                 else if (o[0].trim() == '') {
1011                                         // defend against line with only a
1012                                         // single comma etc.
1013                                         entry.status = 'Failed to find non-empty values';                                       
1014                                 }
1015                                 result.push(entry);
1016                         } // len 2
1017             } // for
1018             return result;
1019         };
1020     });
1021     
1022 })();