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