Replace ecomp references
[portal.git] / ecomp-portal-FE-common / client / app / views / users / new-user-dialogs / bulk-user.controller.js
1 /*-
2  * ============LICENSE_START==========================================
3  * ONAP Portal
4  * ===================================================================
5  * Copyright (C) 2017 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 user upload controller
40  */
41 'use strict';
42 (function () {
43     class BulkUserModalCtrl {
44         constructor($scope, $log, $filter, $q, usersService, applicationsService, confirmBoxService, functionalMenuService, ngDialog,$modal) {
45                 
46                 // Set to true for copious console output
47                 var debug = false;
48                 // Roles fetched from app service
49                 var appRolesResult = [];
50                 // Users fetched from user service
51                 var     userCheckResult = [];
52                 // Requests for user-role assignment built by validator
53                 var appUserRolesRequest = [];
54                 
55                 let init = () => {
56                         if (debug)
57                                 $log.debug('BulkUserModalCtrl::init');
58                         // Angular insists on this.
59                         $scope.fileModel = {};
60                         // Model for drop-down
61                         $scope.adminApps = [];
62                         // Enable modal controls
63                         this.step1 = true;
64                         this.fileSelected = false;
65
66                         // Flag that indicates background work is proceeding
67                         $scope.isProcessing = true;
68
69                         // Load user's admin applications
70                         applicationsService.getAdminApps().promise().then(apps => {
71                                 if (debug)
72                                         $log.debug('BulkUserModalCtrl::init: getAdminApps returned' + JSON.stringify(apps));
73                     if (!apps || typeof(apps) != 'object') {
74                         $log.error('BulkUserModalCtrl::init: getAdminApps returned unexpected data');
75                     }
76                     else {
77                         if (debug)
78                                 $log.debug('BulkUserModalCtrl::init:  admin apps length is ', apps.length);
79                         
80                         // Sort app names and populate the drop-down model
81                         let sortedApps = apps.sort(getSortOrder('name', true));
82                         for (let i = 0; i < sortedApps.length; ++i) {
83                             $scope.adminApps.push({
84                                 index: i,
85                                 id: sortedApps[i].id,
86                                 value: sortedApps[i].name,
87                                 title: sortedApps[i].name
88                             });
89                         }
90                         // Pick the first one in the list
91                         $scope.selectedApplication = $scope.adminApps[0];
92                     }
93                                 $scope.isProcessing = false;
94                 }).catch(err => {
95                     $log.error('BulkUserModalCtrl::init: getAdminApps threw', err);
96                         $scope.isProcessing = false;
97                 });
98                         
99                 }; // init
100                 
101                 // Answers a function that compares properties with the specified name.
102                 let getSortOrder = (prop, foldCase) => {
103                 return function(a, b) {
104                         let aProp = foldCase ? a[prop].toLowerCase() : a[prop];
105                         let bProp = foldCase ? b[prop].toLowerCase() : b[prop];
106                     if (aProp > bProp)
107                         return 1;
108                     else if (aProp < bProp) 
109                         return -1;
110                     else
111                         return 0;
112                 }
113             }
114                 
115                 //This is a fix for dropdown selection, due to b2b dropdown only update value field
116                 $scope.$watch('selectedApplication.value', (newVal, oldVal) => {
117                         for(var i=0;i<$scope.adminApps.length;i++){                     
118                                 if($scope.adminApps[i].value==newVal){
119                                         $scope.selectedApplication=angular.copy($scope.adminApps[i]);;
120                                 }
121                         }
122                 });
123
124                 // Invoked when user picks an app on the drop-down.
125                 $scope.appSelected = () => {
126                         if (debug)
127                                 $log.debug('BulkUserModalCtrl::appSelected: selectedApplication.id is ' + $scope.selectedApplication.id);
128                         this.appSelected = true;
129                 }
130                 
131                 // Caches the file name supplied by the event handler.
132                 $scope.fileChangeHandler = (event, files) => {
133                         this.fileSelected = true;
134                         this.fileToRead = files[0];
135                         if (debug)
136                                 $log.debug("BulkUserModalCtrl::fileChangeHandler: file is ", this.fileToRead);
137                 }; // file change handler
138                 
139                 /**
140                  * Reads the contents of the file, calls portal endpoints
141                  * to validate roles, userIds and existing role assignments;
142                  * ultimately builds array of requests to be sent.
143                  * Creates scope variable with input file contents for
144                  * communication with functions.
145                  * 
146                  * This function performs a synchronous step-by-step process
147                  * using asynchronous promises. The code could all be inline
148                  * here but the nesting becomes unwieldy.
149                  */
150                 $scope.readValidateFile = () => {
151                         $scope.isProcessing = true;
152                         $scope.progressMsg = 'Reading upload file..';
153                         var reader = new FileReader();
154                         reader.onload = function(event) {
155                                 $scope.uploadFile = $filter('csvToObj')(reader.result);
156                                 if (debug)
157                                         $log.debug('BulkUserModalCtrl::readValidateFile onload: data length is ' + $scope.uploadFile.length);
158                                 // sort input by orgUserId
159                                 $scope.uploadFile.sort(getSortOrder('orgUserId', true));
160                                 
161                                 let appid = $scope.selectedApplication.id;
162                                 $scope.progressMsg = 'Fetching application roles..';
163                     functionalMenuService.getManagedRolesMenu(appid).then(function (rolesObj) {
164                         if (debug)
165                                 $log.debug("BulkUserModalCtrl::readValidateFile: managedRolesMenu returned " + JSON.stringify(rolesObj));
166                                         appRolesResult = rolesObj;
167                                         $scope.progressMsg = 'Validating application roles..';
168                         $scope.verifyRoles();
169                                 
170                         let userPromises = $scope.buildUserChecks();
171                         if (debug)
172                                 $log.debug('BulkUserModalCtrl::readValidateFile: userPromises length is ' + userPromises.length);
173                         $scope.progressMsg = 'Validating Org Users..';
174                         $q.all(userPromises).then(function() {
175                                 if (debug)
176                                         $log.debug('BulkUserModalCtrl::readValidateFile: userCheckResult length is ' + userCheckResult.length);
177                                 $scope.evalUserCheckResults();
178                                         
179                                 let appPromises = $scope.buildAppRoleChecks();
180                                 if (debug)
181                                         $log.debug('BulkUserModalCtrl::readValidateFile: appPromises length is ' + appPromises.length);
182                                 $scope.progressMsg = 'Querying application for user roles..';
183                                 $q.all(appPromises).then( function() {
184                                         if (debug)
185                                                 $log.debug('BulkUserModalCtrl::readValidateFile: appUserRolesRequest length is ' + appUserRolesRequest.length);
186                                         $scope.evalAppRoleCheckResults();
187                                         
188                                                         // Re sort by line for the confirmation dialog
189                                                         $scope.uploadFile.sort(getSortOrder('line', false));
190                                                         // We're done, confirm box may show the table
191                                                         if (debug)
192                                                                 $log.debug('BulkUserModalCtrl::readValidateFile inner-then ends');
193                                                         $scope.progressMsg = 'Done.';
194                                                         $scope.isProcessing = false;
195                                 },
196                                 function(error) {
197                                         $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving user-app roles');
198                                                         $scope.isProcessing = false;
199                                 }
200                                 ); // then of app promises
201                         },
202                         function(error) {
203                                 $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving user info');
204                                 $scope.isProcessing = false;
205                         }
206                         ); // then of user promises
207                     },
208                     function(error) {
209                         $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving app role info');
210                         $scope.isProcessing = false;
211                     }
212                     ); // then of role promise
213            
214                         } // onload
215                         
216                         // Invoke the reader on the selected file
217                         reader.readAsText(this.fileToRead);
218                 }; 
219                 
220                 /**
221                  * Evaluates the result set returned by the app role service.
222                  * Sets an uploadFile array element status if a role is not defined.
223                  * Reads and writes scope variable uploadFile.
224                  * Reads closure variable appRolesResult.
225                  */
226                 $scope.verifyRoles = () => {
227                         if (debug)
228                                 $log.debug('BulkUserModalCtrl::verifyRoles: appRoles is ' + JSON.stringify(appRolesResult));
229                         // check roles in upload file against defined app roles
230                         $scope.uploadFile.forEach( function (uploadRow) {
231                                 // skip rows that already have a defined status: headers etc.
232                                 if (uploadRow.status) {
233                                         if (debug)
234                                                 $log.debug('BulkUserModalCtrl::verifyRoles: skip row ' + uploadRow.line);
235                                         return;
236                                 }
237                                 uploadRow.role = uploadRow.role.trim();
238                                 var foundRole=false;
239                                 for (var i=0; i < appRolesResult.length; i++) {
240                                         if (uploadRow.role.toUpperCase() === appRolesResult[i].rolename.trim().toUpperCase()) {
241                                                 if (debug)
242                                                         $log.debug('BulkUserModalCtrl::verifyRoles: match on role ' + uploadRow.role);
243                                                 foundRole=true;
244                                                 break;
245                                         }
246                                 };
247                                 if (!foundRole) {
248                                         if (debug)
249                                                 $log.debug('BulkUserModalCtrl::verifyRoles: NO match on role ' + uploadRow.role);
250                                         uploadRow.status = 'Invalid role';
251                                 };
252                         }); // foreach
253                 }; // verifyRoles
254                 
255                 /**
256                  * Builds and returns an array of promises to invoke the 
257                  * searchUsers service for each unique Org User UID in the input.
258                  * Reads and writes scope variable uploadFile, which must be sorted by Org User UID.
259                  * The promise function writes to closure variable userCheckResult
260                  */
261                 $scope.buildUserChecks = () => {
262                         if (debug)
263                                 $log.debug('BulkUserModalCtrl::buildUserChecks: uploadFile length is ' + $scope.uploadFile.length);
264                         userCheckResult = [];
265                         let promises = [];
266                         let prevRow = null;
267                         $scope.uploadFile.forEach(function (uploadRow) {
268                                 if (uploadRow.status) {
269                                         if (debug)
270                                                 $log.debug('BulkUserModalCtrl::buildUserChecks: skip row ' + uploadRow.line);
271                                         return;
272                                 };
273                                 // detect repeated UIDs
274                                 if (prevRow == null || prevRow.orgUserId.toLowerCase() !== uploadRow.orgUserId.toLowerCase()) {
275                                         if (debug)
276                                                 $log.debug('BulkUserModalCtrl::buildUserChecks: create request for orgUserId ' + uploadRow.orgUserId);
277                                         let userPromise = usersService.searchUsers(uploadRow.orgUserId).promise().then( (usersList) => {
278                                                 if (typeof usersList[0] !== "undefined") {
279                                                         userCheckResult.push({ 
280                                                                 orgUserId:    usersList[0].orgUserId,
281                                                                 firstName: usersList[0].firstName,
282                                                                 lastName:  usersList[0].lastName,
283                                                                 jobTitle:  usersList[0].jobTitle
284                                                         });
285                                                 }
286                                                 else {
287                                                         // User not found.
288                                                         if (debug)
289                                                                 $log.debug('BulkUserModalCtrl::buildUserChecks: searchUsers returned null');
290                                                 }
291                                         }, function(error){
292                                                 $log.error('BulkUserModalCtrl::buildUserChecks: searchUsers failed ' + JSON.stringify(error));
293                                         }); 
294                                         promises.push(userPromise);
295                                 }
296                                 else {
297                                         if (debug)
298                                                 $log.debug('BulkUserModalCtrl::buildUserChecks: skip repeated orgUserId ' + uploadRow.orgUserId);                                       
299                                 }
300                                 prevRow = uploadRow;
301                         }); // foreach
302                         return promises;
303                 }; // buildUserChecks
304                 
305                 /**
306                  * Evaluates the result set returned by the user service to set
307                  * the uploadFile array element status if the user was not found.
308                  * Reads and writes scope variable uploadFile.
309                  * Reads closure variable userCheckResult.
310                  */
311                 $scope.evalUserCheckResults = () => {
312                         if (debug)
313                                 $log.debug('BulkUserModalCtrl::evalUserCheckResult: uploadFile length is ' + $scope.uploadFile.length);
314                         $scope.uploadFile.forEach(function (uploadRow) {
315                                 if (uploadRow.status) {
316                                         if (debug)
317                                                 $log.debug('BulkUserModalCtrl::evalUserCheckResults: skip row ' + uploadRow.line);
318                                         return;
319                                 };
320                                 let foundorgUserId = false;
321                                 userCheckResult.forEach(function(userItem) {
322                                         if (uploadRow.orgUserId.toLowerCase() === userItem.orgUserId.toLowerCase()) {
323                                                 if (debug)
324                                                         $log.debug('BulkUserModalCtrl::evalUserCheckResults: found orgUserId ' + uploadRow.orgUserId);
325                                                 foundorgUserId=true;
326                                         };
327                                 });
328                                 if (!foundorgUserId) {
329                                         if (debug)
330                                                 $log.debug('BulkUserModalCtrl::evalUserCheckResults: NO match on orgUserId ' + uploadRow.orgUserId);
331                                         uploadRow.status = 'Invalid orgUserId';
332                                 }
333                         }); // foreach
334                 }; // evalUserCheckResults
335
336             /**
337                  * Builds and returns an array of promises to invoke the getUserAppRoles
338                  * service for each unique Org User in the input file.
339                  * Each promise creates an update to be sent to the remote application
340                  * with all role names.
341                  * Reads scope variable uploadFile, which must be sorted by Org User.
342                  * The promise function writes to closure variable appUserRolesRequest
343                  */
344                 $scope.buildAppRoleChecks = () => {
345                         if (debug)
346                                 $log.debug('BulkUserModalCtrl::buildAppRoleChecks: uploadFile length is ' + $scope.uploadFile.length); 
347                         appUserRolesRequest = [];
348                         let appId = $scope.selectedApplication.id;
349                         let promises = [];
350                         let prevRow = null;
351                         $scope.uploadFile.forEach( function (uploadRow) {
352                                 if (uploadRow.status) {
353                                         if (debug)
354                                                 $log.debug('BulkUserModalCtrl::buildAppRoleChecks: skip row ' + uploadRow.line);
355                                         return;
356                                 }
357                                 // Because the input is sorted, generate only one request for each Org User
358                                 if (prevRow == null || prevRow.orgUserId.toLowerCase() !== uploadRow.orgUserId.toLowerCase()) {
359                                  if (debug)
360                                          $log.debug('BulkUserModalCtrl::buildAppRoleChecks: create request for orgUserId ' + uploadRow.orgUserId);
361                                  let appPromise = usersService.getUserAppRoles(appId, uploadRow.orgUserId,true).promise().then( (userAppRolesResult) => {
362                                          // Reply for unknown user has all defined roles with isApplied=false on each.  
363                                          if (typeof userAppRolesResult[0] !== "undefined") {
364                                                  if (debug)
365                                                          $log.debug('BulkUserModalCtrl::buildAppRoleChecks: adding result ' 
366                                                                          + JSON.stringify(userAppRolesResult));
367                                                  appUserRolesRequest.push({
368                                                          orgUserId: uploadRow.orgUserId,
369                                                          userAppRoles: userAppRolesResult                                                        
370                                                  });
371                                          } else {
372                                                  $log.error('BulkUserModalCtrl::buildAppRoleChecks: getUserAppRoles returned ' + JSON.stringify(userAppRolesResult));
373                                          };
374                                  }, function(error){
375                                          $log.error('BulkUserModalCtrl::buildAppRoleChecks: getUserAppRoles failed ', error);
376                                  });
377                                  promises.push(appPromise);
378                                 } else {
379                                  if (debug)
380                                          $log.debug('BulkUserModalCtrl::buildAppRoleChecks: duplicate orgUserId, skip: '+ uploadRow.orgUserId);
381                          }
382                          prevRow = uploadRow;
383                  }); // foreach
384                         return promises;
385                 }; // buildAppRoleChecks
386                 
387                 /**
388                  * Evaluates the result set returned by the app service and adjusts 
389                  * the list of updates to be sent to the remote application by setting
390                  * isApplied=true for each role name found in the upload file.
391                  * Reads and writes scope variable uploadFile.
392                  * Reads closure variable appUserRolesRequest.
393                  */
394                 $scope.evalAppRoleCheckResults = () => {
395                         if (debug)
396                                 $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: uploadFile length is ' + $scope.uploadFile.length);
397                         $scope.uploadFile.forEach(function (uploadRow) {
398                                 if (uploadRow.status) {
399                                         if (debug)
400                                                 $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: skip row ' + uploadRow.line);
401                                         return;
402                                 }
403                                 // Search for the match in the app-user-roles array
404                                 appUserRolesRequest.forEach( function (appUserRoleObj) {
405                                         if (uploadRow.orgUserId.toLowerCase() === appUserRoleObj.orgUserId.toLowerCase()) {
406                                                 if (debug)
407                                                         $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: match on orgUserId ' + uploadRow.orgUserId);
408                                                 let roles = appUserRoleObj.userAppRoles;
409                                                 roles.forEach(function (appRoleItem) {
410                                                         //if (debug)
411                                                         //      $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: checking uploadRow.role='
412                                                         //                      + uploadRow.role + ', appRoleItem.roleName= ' + appRoleItem.roleName);
413                                                         if (uploadRow.role === appRoleItem.roleName) {
414                                                                 if (appRoleItem.isApplied) {
415                                                                         if (debug)
416                                                                                 $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: existing role ' 
417                                                                                         + appRoleItem.roleName);
418                                                                         uploadRow.status = 'Role exists';
419                                                                 }
420                                                                 else {
421                                                                         if (debug)
422                                                                                 $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: new role ' 
423                                                                                         + appRoleItem.roleName);
424                                                                         // After much back-and-forth I decided a clear indicator
425                                                                         // is better than blank in the table status column.
426                                                                         uploadRow.status = 'OK';
427                                                                         appRoleItem.isApplied = true;
428                                                                 }
429                                                                 // This count is not especially interesting.
430                                                                 // numberUserRolesSucceeded++;
431                                                         }
432                                                 }); // for each role
433                                         }
434                                 }); // for each result          
435                         }); // for each row
436                 }; // evalAppRoleCheckResults
437              
438                 /**
439                  * Sends requests to Portal requesting user role assignment.
440                  * That endpoint handles creation of the user at the remote app if necessary.
441                  * Reads closure variable appUserRolesRequest.
442                  * Invoked by the Next button on the confirmation dialog.
443                  */
444                 $scope.updateDB = () => {
445                         $scope.isProcessing = true;
446                         $scope.progressMsg = 'Sending requests to application..';
447                         if (debug)
448                                 $log.debug('BulkUserModalCtrl::updateDB: request length is ' + appUserRolesRequest.length);
449                         var numberUsersSucceeded = 0;
450                         let promises = [];
451                         appUserRolesRequest.forEach(function(appUserRoleObj) {
452                                 if (debug) 
453                                         $log.debug('BulkUserModalCtrl::updateDB: appUserRoleObj is ' + JSON.stringify(appUserRoleObj));
454                      let updateRequest = {
455                                  orgUserId: appUserRoleObj.orgUserId, 
456                                  appId: $scope.selectedApplication.id, 
457                                  appRoles: appUserRoleObj.userAppRoles
458                      };
459                      if (debug)
460                          $log.debug('BulkUserModalCtrl::updateDB: updateRequest is ' + JSON.stringify(updateRequest));
461                      let updatePromise = usersService.updateUserAppRoles(updateRequest).promise().then(res => {
462                          if (debug)
463                                  $log.debug('BulkUserModalCtrl::updateDB: updated successfully: ' + JSON.stringify(res));
464                          numberUsersSucceeded++;
465                      }).catch(err => {
466                          // What to do if one of many fails??
467                          $log.error('BulkUserModalCtrl::updateDB failed: ', err);
468                          confirmBoxService.showInformation(
469                                          'Failed to update the user application roles. ' +
470                                          'Error: ' + err.status).then(isConfirmed => { });
471                      }).finally( () => {
472                          // $log.debug('BulkUserModalCtrl::updateDB: finally()');
473                      });
474                      promises.push(updatePromise);
475                  }); // for each
476                         
477                  // Run all the promises
478                  $q.all(promises).then(function(){
479                          $scope.isProcessing = false;
480                          confirmBoxService.showInformation('Processed ' + numberUsersSucceeded + ' users.').then(isConfirmed => {
481                                  // Close the upload-confirm dialog
482                                  ngDialog.close();
483                          });
484                  });
485              }; // updateDb
486              
487                 // Sets the variable that hides/reveals the user controls
488                 $scope.step2 = () => {
489                         this.fileSelected = false;
490                         $scope.selectedFile = null;
491                         $scope.fileModel = null;
492                         this.step1 = false;                     
493                 }
494                 
495              // Navigate between dialog screens using step number: 1,2,...
496              $scope.navigateBack = () => {
497                  this.step1 = true;
498                  this.fileSelected = false;
499              };
500              
501              // Opens a dialog to show the data to be uploaded.
502              // Invoked by the upload button on the bulk user dialog.
503              $scope.confirmUpload = () => {
504                 // Start the process
505                 $scope.readValidateFile();
506                 // Dialog shows progress
507                 $modal.open({
508                         templateUrl: 'app/views/users/new-user-dialogs/bulk-user.confirm.html',
509                     controller: '',
510                     sizeClass: 'modal-medium', 
511                     resolve:'',
512                     scope: $scope
513                 })
514              };
515
516              // Invoked by the Cancel button on the confirmation dialog.
517              $scope.cancelUpload = () => {
518                  ngDialog.close();
519              };
520              
521              init();
522         } // constructor
523     } // class
524     BulkUserModalCtrl.$inject = ['$scope', '$log', '$filter', '$q', 'usersService', 'applicationsService', 'confirmBoxService', 'functionalMenuService', 'ngDialog','$modal'];    
525     angular.module('ecompApp').controller('BulkUserModalCtrl', BulkUserModalCtrl);
526
527     angular.module('ecompApp').directive('fileChange', ['$parse', function($parse){
528         return {
529                 require: 'ngModel',
530             restrict: 'A',
531             link : function($scope, element, attrs, ngModel) {
532                 var attrHandler = $parse(attrs['fileChange']);
533                 var handler=function(e) {
534                         $scope.$apply(function() {
535                                 attrHandler($scope, { $event:e, files:e.target.files } );
536                                 $scope.selectedFile = e.target.files[0].name;
537                         });
538                 };
539                 element[0].addEventListener('change',handler,false);
540            }
541         }
542     }]);
543
544     angular.module('ecompApp').filter('csvToObj',function() {
545         return function(input) {
546             var result = [];
547             var len, i, line, o;
548                 var lines = input.split('\n');
549             // Need 1-based index below
550             for (len = lines.length, i = 1; i <= len; ++i) {
551                 // Use 0-based index for array
552                 line = lines[i - 1].trim();
553                         if (line.length == 0) {
554                                 // console.log("Skipping blank line");
555                                 result.push({
556                                         line: i,
557                                         orgUserId: '',
558                                         role: '',
559                                         status: 'Blank line'
560                                 });
561                                 continue;
562                         }
563                         o = line.split(',');
564                         if (o.length !== 2) {
565                                 // other lengths not valid for upload
566                                 result.push({
567                                         line: i,
568                                         orgUserId: line,   
569                                         role: '',
570                                         status: 'Failed to find 2 comma-separated values'
571                                 });
572                         }
573                         else {
574                                 // console.log("Valid line: ", val);
575                                 let entry = {
576                                                 line: i,
577                                                 orgUserId: o[0],
578                                                 role: o[1]
579                                                 // leave status undefined, this could be valid.
580                                 };
581                                 if (o[0].toLowerCase() === 'orgUserId') {
582                                         // not valid for upload, so set status
583                                         entry.status = 'Header';
584                                 }
585                                 else if (o[0].trim() == '' || o[1].trim() == '') {
586                                         // defend against line with only a single comma etc.
587                                         entry.status = 'Failed to find 2 non-empty values';                                     
588                                 }
589                                 result.push(entry);
590                         } // len 2
591             } // for
592             return result;
593         };
594     });
595     
596   
597         
598 })();