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