[PORTAL-16 PORTAL-18] Widget ms; staging
[portal.git] / ecomp-portal-FE-common / client / app / views / users / new-user-dialogs / bulk-user.controller.js
index e3046b8..e73fe29 100644 (file)
-/*-\r
- * ================================================================================\r
- * ECOMP Portal\r
- * ================================================================================\r
- * Copyright (C) 2017 AT&T Intellectual Property\r
- * ================================================================================\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- * ================================================================================\r
- */\r
-/**\r
- * bulk user upload controller\r
- */\r
-'use strict';\r
-(function () {\r
-    class BulkUserModalCtrl {\r
-       constructor($scope, $log, $filter, $q, usersService, applicationsService, confirmBoxService, functionalMenuService, ngDialog) {\r
-               \r
-               // Set to true for copious console output\r
-               var debug = false;\r
-               // Roles fetched from app service\r
-               var appRolesResult = [];\r
-               // Users fetched from user service\r
-               var     userCheckResult = [];\r
-               // Requests for user-role assignment built by validator\r
-               var appUserRolesRequest = [];\r
-               \r
-               let init = () => {\r
-                       if (debug)\r
-                               $log.debug('BulkUserModalCtrl::init');\r
-                       // Angular insists on this.\r
-                       $scope.fileModel = {};\r
-                       // Model for drop-down\r
-                       $scope.adminApps = [];\r
-                       // Enable modal controls\r
-                       this.step1 = true;\r
-                       this.fileSelected = false;\r
-\r
-                       // Flag that indicates background work is proceeding\r
-                       $scope.isProcessing = true;\r
-\r
-                       // Load user's admin applications\r
-                       applicationsService.getAdminApps().promise().then(apps => {\r
-                               if (debug)\r
-                                       $log.debug('BulkUserModalCtrl::init: getAdminApps returned' + JSON.stringify(apps));\r
-                    if (!apps || typeof(apps) != 'object') {\r
-                        $log.error('BulkUserModalCtrl::init: getAdminApps returned unexpected data');\r
-                    }\r
-                    else {\r
-                       if (debug)\r
-                               $log.debug('BulkUserModalCtrl::init:  admin apps length is ', apps.length);\r
-                       \r
-                       // Sort app names and populate the drop-down model\r
-                        let sortedApps = apps.sort(getSortOrder('name', true));\r
-                        for (let i = 0; i < sortedApps.length; ++i) {\r
-                            $scope.adminApps.push({\r
-                                index: i,\r
-                                id: sortedApps[i].id,\r
-                                value: sortedApps[i].name,\r
-                                title: sortedApps[i].name\r
-                            });\r
-                        }\r
-                        // Pick the first one in the list\r
-                        $scope.selectedApplication = $scope.adminApps[0];\r
-                    }\r
-                               $scope.isProcessing = false;\r
-                }).catch(err => {\r
-                    $log.error('BulkUserModalCtrl::init: getAdminApps threw', err);\r
-                       $scope.isProcessing = false;\r
-                });\r
-                       \r
-               }; // init\r
-               \r
-               // Answers a function that compares properties with the specified name.\r
-               let getSortOrder = (prop, foldCase) => {\r
-                return function(a, b) {\r
-                       let aProp = foldCase ? a[prop].toLowerCase() : a[prop];\r
-                       let bProp = foldCase ? b[prop].toLowerCase() : b[prop];\r
-                    if (aProp > bProp)\r
-                        return 1;\r
-                    else if (aProp < bProp) \r
-                        return -1;\r
-                    else\r
-                       return 0;\r
-                }\r
-            }\r
-               \r
-               //This is a fix for dropdown selection, due to b2b dropdown only update value field\r
-               $scope.$watch('selectedApplication.value', (newVal, oldVal) => {\r
-                       for(var i=0;i<$scope.adminApps.length;i++){                     \r
-                               if($scope.adminApps[i].value==newVal){\r
-                                       $scope.selectedApplication=angular.copy($scope.adminApps[i]);;\r
-                               }\r
-                       }\r
-               });\r
-\r
-               // Invoked when user picks an app on the drop-down.\r
-               $scope.appSelected = () => {\r
-                       if (debug)\r
-                               $log.debug('BulkUserModalCtrl::appSelected: selectedApplication.id is ' + $scope.selectedApplication.id);\r
-                       this.appSelected = true;\r
-               }\r
-               \r
-               // Caches the file name supplied by the event handler.\r
-               $scope.fileChangeHandler = (event, files) => {\r
-                       this.fileSelected = true;\r
-                       this.fileToRead = files[0];\r
-                       if (debug)\r
-                               $log.debug("BulkUserModalCtrl::fileChangeHandler: file is ", this.fileToRead);\r
-               }; // file change handler\r
-               \r
-               /**\r
-                * Reads the contents of the file, calls portal endpoints\r
-                * to validate roles, userIds and existing role assignments;\r
-                * ultimately builds array of requests to be sent.\r
-                * Creates scope variable with input file contents for\r
-                * communication with functions.\r
-                * \r
-                * This function performs a synchronous step-by-step process\r
-                * using asynchronous promises. The code could all be inline\r
-                * here but the nesting becomes unwieldy.\r
-                */\r
-               $scope.readValidateFile = () => {\r
-                       $scope.isProcessing = true;\r
-                       $scope.progressMsg = 'Reading upload file..';\r
-                       var reader = new FileReader();\r
-                       reader.onload = function(event) {\r
-                               $scope.uploadFile = $filter('csvToObj')(reader.result);\r
-                               if (debug)\r
-                                       $log.debug('BulkUserModalCtrl::readValidateFile onload: data length is ' + $scope.uploadFile.length);\r
-                               // sort input by orgUserId\r
-                               $scope.uploadFile.sort(getSortOrder('orgUserId', true));\r
-                               \r
-                               let appid = $scope.selectedApplication.id;\r
-                               $scope.progressMsg = 'Fetching application roles..';\r
-                    functionalMenuService.getManagedRolesMenu(appid).then(function (rolesObj) {\r
-                       if (debug)\r
-                               $log.debug("BulkUserModalCtrl::readValidateFile: managedRolesMenu returned " + JSON.stringify(rolesObj));\r
-                                       appRolesResult = rolesObj;\r
-                                       $scope.progressMsg = 'Validating application roles..';\r
-                       $scope.verifyRoles();\r
-                               \r
-                       let userPromises = $scope.buildUserChecks();\r
-                       if (debug)\r
-                               $log.debug('BulkUserModalCtrl::readValidateFile: userPromises length is ' + userPromises.length);\r
-                       $scope.progressMsg = 'Validating Org Users..';\r
-                       $q.all(userPromises).then(function() {\r
-                               if (debug)\r
-                                       $log.debug('BulkUserModalCtrl::readValidateFile: userCheckResult length is ' + userCheckResult.length);\r
-                               $scope.evalUserCheckResults();\r
-                                       \r
-                               let appPromises = $scope.buildAppRoleChecks();\r
-                               if (debug)\r
-                                       $log.debug('BulkUserModalCtrl::readValidateFile: appPromises length is ' + appPromises.length);\r
-                               $scope.progressMsg = 'Querying application for user roles..';\r
-                               $q.all(appPromises).then( function() {\r
-                                       if (debug)\r
-                                               $log.debug('BulkUserModalCtrl::readValidateFile: appUserRolesRequest length is ' + appUserRolesRequest.length);\r
-                                       $scope.evalAppRoleCheckResults();\r
-                                       \r
-                                                       // Re sort by line for the confirmation dialog\r
-                                                       $scope.uploadFile.sort(getSortOrder('line', false));\r
-                                                       // We're done, confirm box may show the table\r
-                                                       if (debug)\r
-                                                               $log.debug('BulkUserModalCtrl::readValidateFile inner-then ends');\r
-                                                       $scope.progressMsg = 'Done.';\r
-                                                       $scope.isProcessing = false;\r
-                               },\r
-                               function(error) {\r
-                                       $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving user-app roles');\r
-                                                       $scope.isProcessing = false;\r
-                               }\r
-                               ); // then of app promises\r
-                       },\r
-                       function(error) {\r
-                               $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving user info');\r
-                               $scope.isProcessing = false;\r
-                       }\r
-                       ); // then of user promises\r
-                    },\r
-                    function(error) {\r
-                       $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving app role info');\r
-                       $scope.isProcessing = false;\r
-                    }\r
-                    ); // then of role promise\r
-           \r
-                       } // onload\r
-                       \r
-                       // Invoke the reader on the selected file\r
-                       reader.readAsText(this.fileToRead);\r
-               }; \r
-               \r
-               /**\r
-                * Evaluates the result set returned by the app role service.\r
-                * Sets an uploadFile array element status if a role is not defined.\r
-                * Reads and writes scope variable uploadFile.\r
-                * Reads closure variable appRolesResult.\r
-                */\r
-               $scope.verifyRoles = () => {\r
-                       if (debug)\r
-                               $log.debug('BulkUserModalCtrl::verifyRoles: appRoles is ' + JSON.stringify(appRolesResult));\r
-                       // check roles in upload file against defined app roles\r
-                       $scope.uploadFile.forEach( function (uploadRow) {\r
-                               // skip rows that already have a defined status: headers etc.\r
-                               if (uploadRow.status) {\r
-                                       if (debug)\r
-                                               $log.debug('BulkUserModalCtrl::verifyRoles: skip row ' + uploadRow.line);\r
-                                       return;\r
-                               }\r
-                               uploadRow.role = uploadRow.role.trim();\r
-                               var foundRole=false;\r
-                               for (var i=0; i < appRolesResult.length; i++) {\r
-                                       if (uploadRow.role.toUpperCase() === appRolesResult[i].rolename.trim().toUpperCase()) {\r
-                                               if (debug)\r
-                                                       $log.debug('BulkUserModalCtrl::verifyRoles: match on role ' + uploadRow.role);\r
-                                               foundRole=true;\r
-                                               break;\r
-                                       }\r
-                               };\r
-                               if (!foundRole) {\r
-                                       if (debug)\r
-                                               $log.debug('BulkUserModalCtrl::verifyRoles: NO match on role ' + uploadRow.role);\r
-                                       uploadRow.status = 'Invalid role';\r
-                               };\r
-                       }); // foreach\r
-               }; // verifyRoles\r
-               \r
-               /**\r
-                * Builds and returns an array of promises to invoke the \r
-                * searchUsers service for each unique Org User UID in the input.\r
-                * Reads and writes scope variable uploadFile, which must be sorted by Org User UID.\r
-                * The promise function writes to closure variable userCheckResult\r
-                */\r
-               $scope.buildUserChecks = () => {\r
-                       if (debug)\r
-                               $log.debug('BulkUserModalCtrl::buildUserChecks: uploadFile length is ' + $scope.uploadFile.length);\r
-                       userCheckResult = [];\r
-                       let promises = [];\r
-                       let prevRow = null;\r
-                       $scope.uploadFile.forEach(function (uploadRow) {\r
-                               if (uploadRow.status) {\r
-                                       if (debug)\r
-                                               $log.debug('BulkUserModalCtrl::buildUserChecks: skip row ' + uploadRow.line);\r
-                                       return;\r
-                               };\r
-                               // detect repeated UIDs\r
-                               if (prevRow == null || prevRow.orgUserId.toLowerCase() !== uploadRow.orgUserId.toLowerCase()) {\r
-                                       if (debug)\r
-                                               $log.debug('BulkUserModalCtrl::buildUserChecks: create request for orgUserId ' + uploadRow.orgUserId);\r
-                                       let userPromise = usersService.searchUsers(uploadRow.orgUserId).promise().then( (usersList) => {\r
-                                               if (typeof usersList[0] !== "undefined") {\r
-                                                       userCheckResult.push({ \r
-                                                               orgUserId:    usersList[0].orgUserId,\r
-                                                               firstName: usersList[0].firstName,\r
-                                                               lastName:  usersList[0].lastName,\r
-                                                               jobTitle:  usersList[0].jobTitle\r
-                                                       });\r
-                                               }\r
-                                               else {\r
-                                                       // User not found.\r
-                                                       if (debug)\r
-                                                               $log.debug('BulkUserModalCtrl::buildUserChecks: searchUsers returned null');\r
-                                               }\r
-                                       }, function(error){\r
-                                               $log.error('BulkUserModalCtrl::buildUserChecks: searchUsers failed ' + JSON.stringify(error));\r
-                                       }); \r
-                                       promises.push(userPromise);\r
-                               }\r
-                               else {\r
-                                       if (debug)\r
-                                               $log.debug('BulkUserModalCtrl::buildUserChecks: skip repeated orgUserId ' + uploadRow.orgUserId);                                       \r
-                               }\r
-                               prevRow = uploadRow;\r
-                       }); // foreach\r
-                       return promises;\r
-               }; // buildUserChecks\r
-               \r
-               /**\r
-                * Evaluates the result set returned by the user service to set\r
-                * the uploadFile array element status if the user was not found.\r
-                * Reads and writes scope variable uploadFile.\r
-                * Reads closure variable userCheckResult.\r
-                */\r
-               $scope.evalUserCheckResults = () => {\r
-                       if (debug)\r
-                               $log.debug('BulkUserModalCtrl::evalUserCheckResult: uploadFile length is ' + $scope.uploadFile.length);\r
-                       $scope.uploadFile.forEach(function (uploadRow) {\r
-                               if (uploadRow.status) {\r
-                                       if (debug)\r
-                                               $log.debug('BulkUserModalCtrl::evalUserCheckResults: skip row ' + uploadRow.line);\r
-                                       return;\r
-                               };\r
-                               let foundorgUserId = false;\r
-                               userCheckResult.forEach(function(userItem) {\r
-                                       if (uploadRow.orgUserId.toLowerCase() === userItem.orgUserId.toLowerCase()) {\r
-                                               if (debug)\r
-                                                       $log.debug('BulkUserModalCtrl::evalUserCheckResults: found orgUserId ' + uploadRow.orgUserId);\r
-                                               foundorgUserId=true;\r
-                                       };\r
-                               });\r
-                               if (!foundorgUserId) {\r
-                                       if (debug)\r
-                                               $log.debug('BulkUserModalCtrl::evalUserCheckResults: NO match on orgUserId ' + uploadRow.orgUserId);\r
-                                       uploadRow.status = 'Invalid orgUserId';\r
-                               }\r
-                       }); // foreach\r
-               }; // evalUserCheckResults\r
-\r
-            /**\r
-                * Builds and returns an array of promises to invoke the getUserAppRoles\r
-                * service for each unique Org User in the input file.\r
-                * Each promise creates an update to be sent to the remote application\r
-                * with all role names.\r
-                * Reads scope variable uploadFile, which must be sorted by Org User.\r
-                * The promise function writes to closure variable appUserRolesRequest\r
-                */\r
-               $scope.buildAppRoleChecks = () => {\r
-                       if (debug)\r
-                               $log.debug('BulkUserModalCtrl::buildAppRoleChecks: uploadFile length is ' + $scope.uploadFile.length); \r
-                       appUserRolesRequest = [];\r
-                       let appId = $scope.selectedApplication.id;\r
-                       let promises = [];\r
-                       let prevRow = null;\r
-                       $scope.uploadFile.forEach( function (uploadRow) {\r
-                               if (uploadRow.status) {\r
-                                       if (debug)\r
-                                               $log.debug('BulkUserModalCtrl::buildAppRoleChecks: skip row ' + uploadRow.line);\r
-                                       return;\r
-                               }\r
-                               // Because the input is sorted, generate only one request for each Org User\r
-                               if (prevRow == null || prevRow.orgUserId.toLowerCase() !== uploadRow.orgUserId.toLowerCase()) {\r
-                                if (debug)\r
-                                        $log.debug('BulkUserModalCtrl::buildAppRoleChecks: create request for orgUserId ' + uploadRow.orgUserId);\r
-                                let appPromise = usersService.getUserAppRoles(appId, uploadRow.orgUserId).promise().then( (userAppRolesResult) => {\r
-                                        // Reply for unknown user has all defined roles with isApplied=false on each.  \r
-                                        if (typeof userAppRolesResult[0] !== "undefined") {\r
-                                                if (debug)\r
-                                                        $log.debug('BulkUserModalCtrl::buildAppRoleChecks: adding result ' \r
-                                                                        + JSON.stringify(userAppRolesResult));\r
-                                                appUserRolesRequest.push({\r
-                                                        orgUserId: uploadRow.orgUserId,\r
-                                                        userAppRoles: userAppRolesResult                                                        \r
-                                                });\r
-                                        } else {\r
-                                                $log.error('BulkUserModalCtrl::buildAppRoleChecks: getUserAppRoles returned ' + JSON.stringify(userAppRolesResult));\r
-                                        };\r
-                                }, function(error){\r
-                                        $log.error('BulkUserModalCtrl::buildAppRoleChecks: getUserAppRoles failed ', error);\r
-                                });\r
-                                promises.push(appPromise);\r
-                               } else {\r
-                                if (debug)\r
-                                        $log.debug('BulkUserModalCtrl::buildAppRoleChecks: duplicate orgUserId, skip: '+ uploadRow.orgUserId);\r
-                        }\r
-                        prevRow = uploadRow;\r
-                }); // foreach\r
-                       return promises;\r
-               }; // buildAppRoleChecks\r
-               \r
-               /**\r
-                * Evaluates the result set returned by the app service and adjusts \r
-                * the list of updates to be sent to the remote application by setting\r
-                * isApplied=true for each role name found in the upload file.\r
-                * Reads and writes scope variable uploadFile.\r
-                * Reads closure variable appUserRolesRequest.\r
-                */\r
-               $scope.evalAppRoleCheckResults = () => {\r
-                       if (debug)\r
-                               $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: uploadFile length is ' + $scope.uploadFile.length);\r
-                       $scope.uploadFile.forEach(function (uploadRow) {\r
-                               if (uploadRow.status) {\r
-                                       if (debug)\r
-                                               $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: skip row ' + uploadRow.line);\r
-                                       return;\r
-                               }\r
-                               // Search for the match in the app-user-roles array\r
-                               appUserRolesRequest.forEach( function (appUserRoleObj) {\r
-                                       if (uploadRow.orgUserId.toLowerCase() === appUserRoleObj.orgUserId.toLowerCase()) {\r
-                                               if (debug)\r
-                                                       $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: match on orgUserId ' + uploadRow.orgUserId);\r
-                                               let roles = appUserRoleObj.userAppRoles;\r
-                                               roles.forEach(function (appRoleItem) {\r
-                                                       //if (debug)\r
-                                                       //      $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: checking uploadRow.role='\r
-                                                       //                      + uploadRow.role + ', appRoleItem.roleName= ' + appRoleItem.roleName);\r
-                                                       if (uploadRow.role === appRoleItem.roleName) {\r
-                                                               if (appRoleItem.isApplied) {\r
-                                                                       if (debug)\r
-                                                                               $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: existing role ' \r
-                                                                                       + appRoleItem.roleName);\r
-                                                                       uploadRow.status = 'Role exists';\r
-                                                               }\r
-                                                               else {\r
-                                                                       if (debug)\r
-                                                                               $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: new role ' \r
-                                                                                       + appRoleItem.roleName);\r
-                                                                       // After much back-and-forth I decided a clear indicator\r
-                                                                       // is better than blank in the table status column.\r
-                                                                       uploadRow.status = 'OK';\r
-                                                                       appRoleItem.isApplied = true;\r
-                                                               }\r
-                                                               // This count is not especially interesting.\r
-                                                               // numberUserRolesSucceeded++;\r
-                                                       }\r
-                                               }); // for each role\r
-                                       }\r
-                               }); // for each result          \r
-                       }); // for each row\r
-               }; // evalAppRoleCheckResults\r
-             \r
-               /**\r
-                * Sends requests to Portal requesting user role assignment.\r
-                * That endpoint handles creation of the user at the remote app if necessary.\r
-                * Reads closure variable appUserRolesRequest.\r
-                * Invoked by the Next button on the confirmation dialog.\r
-                */\r
-               $scope.updateDB = () => {\r
-                       $scope.isProcessing = true;\r
-                       $scope.progressMsg = 'Sending requests to application..';\r
-                       if (debug)\r
-                               $log.debug('BulkUserModalCtrl::updateDB: request length is ' + appUserRolesRequest.length);\r
-                       var numberUsersSucceeded = 0;\r
-                       let promises = [];\r
-                       appUserRolesRequest.forEach(function(appUserRoleObj) {\r
-                               if (debug) \r
-                                       $log.debug('BulkUserModalCtrl::updateDB: appUserRoleObj is ' + JSON.stringify(appUserRoleObj));\r
-                     let updateRequest = {\r
-                                orgUserId: appUserRoleObj.orgUserId, \r
-                                appId: $scope.selectedApplication.id, \r
-                                appRoles: appUserRoleObj.userAppRoles\r
-                     };\r
-                     if (debug)\r
-                        $log.debug('BulkUserModalCtrl::updateDB: updateRequest is ' + JSON.stringify(updateRequest));\r
-                     let updatePromise = usersService.updateUserAppRoles(updateRequest).promise().then(res => {\r
-                        if (debug)\r
-                                $log.debug('BulkUserModalCtrl::updateDB: updated successfully: ' + JSON.stringify(res));\r
-                        numberUsersSucceeded++;\r
-                     }).catch(err => {\r
-                        // What to do if one of many fails??\r
-                        $log.error('BulkUserModalCtrl::updateDB failed: ', err);\r
-                        confirmBoxService.showInformation(\r
-                                        'Failed to update the user application roles. ' +\r
-                                        'Error: ' + err.status).then(isConfirmed => { });\r
-                     }).finally( () => {\r
-                        // $log.debug('BulkUserModalCtrl::updateDB: finally()');\r
-                     });\r
-                     promises.push(updatePromise);\r
-                }); // for each\r
-                       \r
-                // Run all the promises\r
-                $q.all(promises).then(function(){\r
-                        $scope.isProcessing = false;\r
-                        confirmBoxService.showInformation('Processed ' + numberUsersSucceeded + ' users.').then(isConfirmed => {\r
-                                // Close the upload-confirm dialog\r
-                                ngDialog.close();\r
-                        });\r
-                });\r
-             }; // updateDb\r
-             \r
-               // Sets the variable that hides/reveals the user controls\r
-               $scope.step2 = () => {\r
-                       this.fileSelected = false;\r
-                       $scope.selectedFile = null;\r
-                       $scope.fileModel = null;\r
-                       this.step1 = false;                     \r
-               }\r
-               \r
-             // Navigate between dialog screens using step number: 1,2,...\r
-             $scope.navigateBack = () => {\r
-                this.step1 = true;\r
-                 this.fileSelected = false;\r
-             };\r
-             \r
-             // Opens a dialog to show the data to be uploaded.\r
-             // Invoked by the upload button on the bulk user dialog.\r
-             $scope.confirmUpload = () => {\r
-               // Start the process\r
-               $scope.readValidateFile();\r
-               // Dialog shows progress\r
-               ngDialog.open({\r
-                       templateUrl: 'app/views/users/new-user-dialogs/bulk-user.confirm.html',\r
-                       scope: $scope\r
-               });\r
-             };\r
-\r
-             // Invoked by the Cancel button on the confirmation dialog.\r
-             $scope.cancelUpload = () => {\r
-                ngDialog.close();\r
-             };\r
-             \r
-             init();\r
-       } // constructor\r
-    } // class\r
-    BulkUserModalCtrl.$inject = ['$scope', '$log', '$filter', '$q', 'usersService', 'applicationsService', 'confirmBoxService', 'functionalMenuService', 'ngDialog'];    \r
-    angular.module('ecompApp').controller('BulkUserModalCtrl', BulkUserModalCtrl);\r
-\r
-    angular.module('ecompApp').directive('fileChange', ['$parse', function($parse){\r
-       return {\r
-               require: 'ngModel',\r
-           restrict: 'A',\r
-           link : function($scope, element, attrs, ngModel) {\r
-               var attrHandler = $parse(attrs['fileChange']);\r
-               var handler=function(e) {\r
-                       $scope.$apply(function() {\r
-                               attrHandler($scope, { $event:e, files:e.target.files } );\r
-                               $scope.selectedFile = e.target.files[0].name;\r
-                       });\r
-               };\r
-               element[0].addEventListener('change',handler,false);\r
-          }\r
-       }\r
-    }]);\r
-\r
-    angular.module('ecompApp').filter('csvToObj',function() {\r
-       return function(input) {\r
-           var result = [];\r
-           var len, i, line, o;\r
-               var lines = input.split('\n');\r
-           // Need 1-based index below\r
-           for (len = lines.length, i = 1; i <= len; ++i) {\r
-               // Use 0-based index for array\r
-               line = lines[i - 1].trim();\r
-                       if (line.length == 0) {\r
-                               // console.log("Skipping blank line");\r
-                               result.push({\r
-                                       line: i,\r
-                                       orgUserId: '',\r
-                                       role: '',\r
-                                       status: 'Blank line'\r
-                               });\r
-                               continue;\r
-                       }\r
-                       o = line.split(',');\r
-                       if (o.length !== 2) {\r
-                               // other lengths not valid for upload\r
-                               result.push({\r
-                                       line: i,\r
-                                       orgUserId: line,   \r
-                                       role: '',\r
-                                       status: 'Failed to find 2 comma-separated values'\r
-                               });\r
-                       }\r
-                       else {\r
-                               // console.log("Valid line: ", val);\r
-                               let entry = {\r
-                                               line: i,\r
-                                               orgUserId: o[0],\r
-                                               role: o[1]\r
-                                               // leave status undefined, this could be valid.\r
-                               };\r
-                               if (o[0].toLowerCase() === 'orgUserId') {\r
-                                       // not valid for upload, so set status\r
-                                       entry.status = 'Header';\r
-                               }\r
-                               else if (o[0].trim() == '' || o[1].trim() == '') {\r
-                                       // defend against line with only a single comma etc.\r
-                                       entry.status = 'Failed to find 2 non-empty values';                                     \r
-                               }\r
-                               result.push(entry);\r
-                       } // len 2\r
-           } // for\r
-           return result;\r
-       };\r
-    });\r
-    \r
-  \r
-        \r
-})();\r
+/*-
+ * ================================================================================
+ * ECOMP Portal
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ================================================================================
+ */
+/**
+ * bulk user upload controller
+ */
+'use strict';
+(function () {
+    class BulkUserModalCtrl {
+       constructor($scope, $log, $filter, $q, usersService, applicationsService, confirmBoxService, functionalMenuService, ngDialog) {
+               
+               // Set to true for copious console output
+               var debug = false;
+               // Roles fetched from app service
+               var appRolesResult = [];
+               // Users fetched from user service
+               var     userCheckResult = [];
+               // Requests for user-role assignment built by validator
+               var appUserRolesRequest = [];
+               
+               let init = () => {
+                       if (debug)
+                               $log.debug('BulkUserModalCtrl::init');
+                       // Angular insists on this.
+                       $scope.fileModel = {};
+                       // Model for drop-down
+                       $scope.adminApps = [];
+                       // Enable modal controls
+                       this.step1 = true;
+                       this.fileSelected = false;
+
+                       // Flag that indicates background work is proceeding
+                       $scope.isProcessing = true;
+
+                       // Load user's admin applications
+                       applicationsService.getAdminApps().promise().then(apps => {
+                               if (debug)
+                                       $log.debug('BulkUserModalCtrl::init: getAdminApps returned' + JSON.stringify(apps));
+                    if (!apps || typeof(apps) != 'object') {
+                        $log.error('BulkUserModalCtrl::init: getAdminApps returned unexpected data');
+                    }
+                    else {
+                       if (debug)
+                               $log.debug('BulkUserModalCtrl::init:  admin apps length is ', apps.length);
+                       
+                       // Sort app names and populate the drop-down model
+                        let sortedApps = apps.sort(getSortOrder('name', true));
+                        for (let i = 0; i < sortedApps.length; ++i) {
+                            $scope.adminApps.push({
+                                index: i,
+                                id: sortedApps[i].id,
+                                value: sortedApps[i].name,
+                                title: sortedApps[i].name
+                            });
+                        }
+                        // Pick the first one in the list
+                        $scope.selectedApplication = $scope.adminApps[0];
+                    }
+                               $scope.isProcessing = false;
+                }).catch(err => {
+                    $log.error('BulkUserModalCtrl::init: getAdminApps threw', err);
+                       $scope.isProcessing = false;
+                });
+                       
+               }; // init
+               
+               // Answers a function that compares properties with the specified name.
+               let getSortOrder = (prop, foldCase) => {
+                return function(a, b) {
+                       let aProp = foldCase ? a[prop].toLowerCase() : a[prop];
+                       let bProp = foldCase ? b[prop].toLowerCase() : b[prop];
+                    if (aProp > bProp)
+                        return 1;
+                    else if (aProp < bProp) 
+                        return -1;
+                    else
+                       return 0;
+                }
+            }
+               
+               //This is a fix for dropdown selection, due to b2b dropdown only update value field
+               $scope.$watch('selectedApplication.value', (newVal, oldVal) => {
+                       for(var i=0;i<$scope.adminApps.length;i++){                     
+                               if($scope.adminApps[i].value==newVal){
+                                       $scope.selectedApplication=angular.copy($scope.adminApps[i]);;
+                               }
+                       }
+               });
+
+               // Invoked when user picks an app on the drop-down.
+               $scope.appSelected = () => {
+                       if (debug)
+                               $log.debug('BulkUserModalCtrl::appSelected: selectedApplication.id is ' + $scope.selectedApplication.id);
+                       this.appSelected = true;
+               }
+               
+               // Caches the file name supplied by the event handler.
+               $scope.fileChangeHandler = (event, files) => {
+                       this.fileSelected = true;
+                       this.fileToRead = files[0];
+                       if (debug)
+                               $log.debug("BulkUserModalCtrl::fileChangeHandler: file is ", this.fileToRead);
+               }; // file change handler
+               
+               /**
+                * Reads the contents of the file, calls portal endpoints
+                * to validate roles, userIds and existing role assignments;
+                * ultimately builds array of requests to be sent.
+                * Creates scope variable with input file contents for
+                * communication with functions.
+                * 
+                * This function performs a synchronous step-by-step process
+                * using asynchronous promises. The code could all be inline
+                * here but the nesting becomes unwieldy.
+                */
+               $scope.readValidateFile = () => {
+                       $scope.isProcessing = true;
+                       $scope.progressMsg = 'Reading upload file..';
+                       var reader = new FileReader();
+                       reader.onload = function(event) {
+                               $scope.uploadFile = $filter('csvToObj')(reader.result);
+                               if (debug)
+                                       $log.debug('BulkUserModalCtrl::readValidateFile onload: data length is ' + $scope.uploadFile.length);
+                               // sort input by orgUserId
+                               $scope.uploadFile.sort(getSortOrder('orgUserId', true));
+                               
+                               let appid = $scope.selectedApplication.id;
+                               $scope.progressMsg = 'Fetching application roles..';
+                    functionalMenuService.getManagedRolesMenu(appid).then(function (rolesObj) {
+                       if (debug)
+                               $log.debug("BulkUserModalCtrl::readValidateFile: managedRolesMenu returned " + JSON.stringify(rolesObj));
+                                       appRolesResult = rolesObj;
+                                       $scope.progressMsg = 'Validating application roles..';
+                       $scope.verifyRoles();
+                               
+                       let userPromises = $scope.buildUserChecks();
+                       if (debug)
+                               $log.debug('BulkUserModalCtrl::readValidateFile: userPromises length is ' + userPromises.length);
+                       $scope.progressMsg = 'Validating Org Users..';
+                       $q.all(userPromises).then(function() {
+                               if (debug)
+                                       $log.debug('BulkUserModalCtrl::readValidateFile: userCheckResult length is ' + userCheckResult.length);
+                               $scope.evalUserCheckResults();
+                                       
+                               let appPromises = $scope.buildAppRoleChecks();
+                               if (debug)
+                                       $log.debug('BulkUserModalCtrl::readValidateFile: appPromises length is ' + appPromises.length);
+                               $scope.progressMsg = 'Querying application for user roles..';
+                               $q.all(appPromises).then( function() {
+                                       if (debug)
+                                               $log.debug('BulkUserModalCtrl::readValidateFile: appUserRolesRequest length is ' + appUserRolesRequest.length);
+                                       $scope.evalAppRoleCheckResults();
+                                       
+                                                       // Re sort by line for the confirmation dialog
+                                                       $scope.uploadFile.sort(getSortOrder('line', false));
+                                                       // We're done, confirm box may show the table
+                                                       if (debug)
+                                                               $log.debug('BulkUserModalCtrl::readValidateFile inner-then ends');
+                                                       $scope.progressMsg = 'Done.';
+                                                       $scope.isProcessing = false;
+                               },
+                               function(error) {
+                                       $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving user-app roles');
+                                                       $scope.isProcessing = false;
+                               }
+                               ); // then of app promises
+                       },
+                       function(error) {
+                               $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving user info');
+                               $scope.isProcessing = false;
+                       }
+                       ); // then of user promises
+                    },
+                    function(error) {
+                       $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving app role info');
+                       $scope.isProcessing = false;
+                    }
+                    ); // then of role promise
+           
+                       } // onload
+                       
+                       // Invoke the reader on the selected file
+                       reader.readAsText(this.fileToRead);
+               }; 
+               
+               /**
+                * Evaluates the result set returned by the app role service.
+                * Sets an uploadFile array element status if a role is not defined.
+                * Reads and writes scope variable uploadFile.
+                * Reads closure variable appRolesResult.
+                */
+               $scope.verifyRoles = () => {
+                       if (debug)
+                               $log.debug('BulkUserModalCtrl::verifyRoles: appRoles is ' + JSON.stringify(appRolesResult));
+                       // check roles in upload file against defined app roles
+                       $scope.uploadFile.forEach( function (uploadRow) {
+                               // skip rows that already have a defined status: headers etc.
+                               if (uploadRow.status) {
+                                       if (debug)
+                                               $log.debug('BulkUserModalCtrl::verifyRoles: skip row ' + uploadRow.line);
+                                       return;
+                               }
+                               uploadRow.role = uploadRow.role.trim();
+                               var foundRole=false;
+                               for (var i=0; i < appRolesResult.length; i++) {
+                                       if (uploadRow.role.toUpperCase() === appRolesResult[i].rolename.trim().toUpperCase()) {
+                                               if (debug)
+                                                       $log.debug('BulkUserModalCtrl::verifyRoles: match on role ' + uploadRow.role);
+                                               foundRole=true;
+                                               break;
+                                       }
+                               };
+                               if (!foundRole) {
+                                       if (debug)
+                                               $log.debug('BulkUserModalCtrl::verifyRoles: NO match on role ' + uploadRow.role);
+                                       uploadRow.status = 'Invalid role';
+                               };
+                       }); // foreach
+               }; // verifyRoles
+               
+               /**
+                * Builds and returns an array of promises to invoke the 
+                * searchUsers service for each unique Org User UID in the input.
+                * Reads and writes scope variable uploadFile, which must be sorted by Org User UID.
+                * The promise function writes to closure variable userCheckResult
+                */
+               $scope.buildUserChecks = () => {
+                       if (debug)
+                               $log.debug('BulkUserModalCtrl::buildUserChecks: uploadFile length is ' + $scope.uploadFile.length);
+                       userCheckResult = [];
+                       let promises = [];
+                       let prevRow = null;
+                       $scope.uploadFile.forEach(function (uploadRow) {
+                               if (uploadRow.status) {
+                                       if (debug)
+                                               $log.debug('BulkUserModalCtrl::buildUserChecks: skip row ' + uploadRow.line);
+                                       return;
+                               };
+                               // detect repeated UIDs
+                               if (prevRow == null || prevRow.orgUserId.toLowerCase() !== uploadRow.orgUserId.toLowerCase()) {
+                                       if (debug)
+                                               $log.debug('BulkUserModalCtrl::buildUserChecks: create request for orgUserId ' + uploadRow.orgUserId);
+                                       let userPromise = usersService.searchUsers(uploadRow.orgUserId).promise().then( (usersList) => {
+                                               if (typeof usersList[0] !== "undefined") {
+                                                       userCheckResult.push({ 
+                                                               orgUserId:    usersList[0].orgUserId,
+                                                               firstName: usersList[0].firstName,
+                                                               lastName:  usersList[0].lastName,
+                                                               jobTitle:  usersList[0].jobTitle
+                                                       });
+                                               }
+                                               else {
+                                                       // User not found.
+                                                       if (debug)
+                                                               $log.debug('BulkUserModalCtrl::buildUserChecks: searchUsers returned null');
+                                               }
+                                       }, function(error){
+                                               $log.error('BulkUserModalCtrl::buildUserChecks: searchUsers failed ' + JSON.stringify(error));
+                                       }); 
+                                       promises.push(userPromise);
+                               }
+                               else {
+                                       if (debug)
+                                               $log.debug('BulkUserModalCtrl::buildUserChecks: skip repeated orgUserId ' + uploadRow.orgUserId);                                       
+                               }
+                               prevRow = uploadRow;
+                       }); // foreach
+                       return promises;
+               }; // buildUserChecks
+               
+               /**
+                * Evaluates the result set returned by the user service to set
+                * the uploadFile array element status if the user was not found.
+                * Reads and writes scope variable uploadFile.
+                * Reads closure variable userCheckResult.
+                */
+               $scope.evalUserCheckResults = () => {
+                       if (debug)
+                               $log.debug('BulkUserModalCtrl::evalUserCheckResult: uploadFile length is ' + $scope.uploadFile.length);
+                       $scope.uploadFile.forEach(function (uploadRow) {
+                               if (uploadRow.status) {
+                                       if (debug)
+                                               $log.debug('BulkUserModalCtrl::evalUserCheckResults: skip row ' + uploadRow.line);
+                                       return;
+                               };
+                               let foundorgUserId = false;
+                               userCheckResult.forEach(function(userItem) {
+                                       if (uploadRow.orgUserId.toLowerCase() === userItem.orgUserId.toLowerCase()) {
+                                               if (debug)
+                                                       $log.debug('BulkUserModalCtrl::evalUserCheckResults: found orgUserId ' + uploadRow.orgUserId);
+                                               foundorgUserId=true;
+                                       };
+                               });
+                               if (!foundorgUserId) {
+                                       if (debug)
+                                               $log.debug('BulkUserModalCtrl::evalUserCheckResults: NO match on orgUserId ' + uploadRow.orgUserId);
+                                       uploadRow.status = 'Invalid orgUserId';
+                               }
+                       }); // foreach
+               }; // evalUserCheckResults
+
+            /**
+                * Builds and returns an array of promises to invoke the getUserAppRoles
+                * service for each unique Org User in the input file.
+                * Each promise creates an update to be sent to the remote application
+                * with all role names.
+                * Reads scope variable uploadFile, which must be sorted by Org User.
+                * The promise function writes to closure variable appUserRolesRequest
+                */
+               $scope.buildAppRoleChecks = () => {
+                       if (debug)
+                               $log.debug('BulkUserModalCtrl::buildAppRoleChecks: uploadFile length is ' + $scope.uploadFile.length); 
+                       appUserRolesRequest = [];
+                       let appId = $scope.selectedApplication.id;
+                       let promises = [];
+                       let prevRow = null;
+                       $scope.uploadFile.forEach( function (uploadRow) {
+                               if (uploadRow.status) {
+                                       if (debug)
+                                               $log.debug('BulkUserModalCtrl::buildAppRoleChecks: skip row ' + uploadRow.line);
+                                       return;
+                               }
+                               // Because the input is sorted, generate only one request for each Org User
+                               if (prevRow == null || prevRow.orgUserId.toLowerCase() !== uploadRow.orgUserId.toLowerCase()) {
+                                if (debug)
+                                        $log.debug('BulkUserModalCtrl::buildAppRoleChecks: create request for orgUserId ' + uploadRow.orgUserId);
+                                let appPromise = usersService.getUserAppRoles(appId, uploadRow.orgUserId).promise().then( (userAppRolesResult) => {
+                                        // Reply for unknown user has all defined roles with isApplied=false on each.  
+                                        if (typeof userAppRolesResult[0] !== "undefined") {
+                                                if (debug)
+                                                        $log.debug('BulkUserModalCtrl::buildAppRoleChecks: adding result ' 
+                                                                        + JSON.stringify(userAppRolesResult));
+                                                appUserRolesRequest.push({
+                                                        orgUserId: uploadRow.orgUserId,
+                                                        userAppRoles: userAppRolesResult                                                        
+                                                });
+                                        } else {
+                                                $log.error('BulkUserModalCtrl::buildAppRoleChecks: getUserAppRoles returned ' + JSON.stringify(userAppRolesResult));
+                                        };
+                                }, function(error){
+                                        $log.error('BulkUserModalCtrl::buildAppRoleChecks: getUserAppRoles failed ', error);
+                                });
+                                promises.push(appPromise);
+                               } else {
+                                if (debug)
+                                        $log.debug('BulkUserModalCtrl::buildAppRoleChecks: duplicate orgUserId, skip: '+ uploadRow.orgUserId);
+                        }
+                        prevRow = uploadRow;
+                }); // foreach
+                       return promises;
+               }; // buildAppRoleChecks
+               
+               /**
+                * Evaluates the result set returned by the app service and adjusts 
+                * the list of updates to be sent to the remote application by setting
+                * isApplied=true for each role name found in the upload file.
+                * Reads and writes scope variable uploadFile.
+                * Reads closure variable appUserRolesRequest.
+                */
+               $scope.evalAppRoleCheckResults = () => {
+                       if (debug)
+                               $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: uploadFile length is ' + $scope.uploadFile.length);
+                       $scope.uploadFile.forEach(function (uploadRow) {
+                               if (uploadRow.status) {
+                                       if (debug)
+                                               $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: skip row ' + uploadRow.line);
+                                       return;
+                               }
+                               // Search for the match in the app-user-roles array
+                               appUserRolesRequest.forEach( function (appUserRoleObj) {
+                                       if (uploadRow.orgUserId.toLowerCase() === appUserRoleObj.orgUserId.toLowerCase()) {
+                                               if (debug)
+                                                       $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: match on orgUserId ' + uploadRow.orgUserId);
+                                               let roles = appUserRoleObj.userAppRoles;
+                                               roles.forEach(function (appRoleItem) {
+                                                       //if (debug)
+                                                       //      $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: checking uploadRow.role='
+                                                       //                      + uploadRow.role + ', appRoleItem.roleName= ' + appRoleItem.roleName);
+                                                       if (uploadRow.role === appRoleItem.roleName) {
+                                                               if (appRoleItem.isApplied) {
+                                                                       if (debug)
+                                                                               $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: existing role ' 
+                                                                                       + appRoleItem.roleName);
+                                                                       uploadRow.status = 'Role exists';
+                                                               }
+                                                               else {
+                                                                       if (debug)
+                                                                               $log.debug('BulkUserModalCtrl::evalAppRoleCheckResults: new role ' 
+                                                                                       + appRoleItem.roleName);
+                                                                       // After much back-and-forth I decided a clear indicator
+                                                                       // is better than blank in the table status column.
+                                                                       uploadRow.status = 'OK';
+                                                                       appRoleItem.isApplied = true;
+                                                               }
+                                                               // This count is not especially interesting.
+                                                               // numberUserRolesSucceeded++;
+                                                       }
+                                               }); // for each role
+                                       }
+                               }); // for each result          
+                       }); // for each row
+               }; // evalAppRoleCheckResults
+             
+               /**
+                * Sends requests to Portal requesting user role assignment.
+                * That endpoint handles creation of the user at the remote app if necessary.
+                * Reads closure variable appUserRolesRequest.
+                * Invoked by the Next button on the confirmation dialog.
+                */
+               $scope.updateDB = () => {
+                       $scope.isProcessing = true;
+                       $scope.progressMsg = 'Sending requests to application..';
+                       if (debug)
+                               $log.debug('BulkUserModalCtrl::updateDB: request length is ' + appUserRolesRequest.length);
+                       var numberUsersSucceeded = 0;
+                       let promises = [];
+                       appUserRolesRequest.forEach(function(appUserRoleObj) {
+                               if (debug) 
+                                       $log.debug('BulkUserModalCtrl::updateDB: appUserRoleObj is ' + JSON.stringify(appUserRoleObj));
+                     let updateRequest = {
+                                orgUserId: appUserRoleObj.orgUserId, 
+                                appId: $scope.selectedApplication.id, 
+                                appRoles: appUserRoleObj.userAppRoles
+                     };
+                     if (debug)
+                        $log.debug('BulkUserModalCtrl::updateDB: updateRequest is ' + JSON.stringify(updateRequest));
+                     let updatePromise = usersService.updateUserAppRoles(updateRequest).promise().then(res => {
+                        if (debug)
+                                $log.debug('BulkUserModalCtrl::updateDB: updated successfully: ' + JSON.stringify(res));
+                        numberUsersSucceeded++;
+                     }).catch(err => {
+                        // What to do if one of many fails??
+                        $log.error('BulkUserModalCtrl::updateDB failed: ', err);
+                        confirmBoxService.showInformation(
+                                        'Failed to update the user application roles. ' +
+                                        'Error: ' + err.status).then(isConfirmed => { });
+                     }).finally( () => {
+                        // $log.debug('BulkUserModalCtrl::updateDB: finally()');
+                     });
+                     promises.push(updatePromise);
+                }); // for each
+                       
+                // Run all the promises
+                $q.all(promises).then(function(){
+                        $scope.isProcessing = false;
+                        confirmBoxService.showInformation('Processed ' + numberUsersSucceeded + ' users.').then(isConfirmed => {
+                                // Close the upload-confirm dialog
+                                ngDialog.close();
+                        });
+                });
+             }; // updateDb
+             
+               // Sets the variable that hides/reveals the user controls
+               $scope.step2 = () => {
+                       this.fileSelected = false;
+                       $scope.selectedFile = null;
+                       $scope.fileModel = null;
+                       this.step1 = false;                     
+               }
+               
+             // Navigate between dialog screens using step number: 1,2,...
+             $scope.navigateBack = () => {
+                this.step1 = true;
+                 this.fileSelected = false;
+             };
+             
+             // Opens a dialog to show the data to be uploaded.
+             // Invoked by the upload button on the bulk user dialog.
+             $scope.confirmUpload = () => {
+               // Start the process
+               $scope.readValidateFile();
+               // Dialog shows progress
+               ngDialog.open({
+                       templateUrl: 'app/views/users/new-user-dialogs/bulk-user.confirm.html',
+                       scope: $scope
+               });
+             };
+
+             // Invoked by the Cancel button on the confirmation dialog.
+             $scope.cancelUpload = () => {
+                ngDialog.close();
+             };
+             
+             init();
+       } // constructor
+    } // class
+    BulkUserModalCtrl.$inject = ['$scope', '$log', '$filter', '$q', 'usersService', 'applicationsService', 'confirmBoxService', 'functionalMenuService', 'ngDialog'];    
+    angular.module('ecompApp').controller('BulkUserModalCtrl', BulkUserModalCtrl);
+
+    angular.module('ecompApp').directive('fileChange', ['$parse', function($parse){
+       return {
+               require: 'ngModel',
+           restrict: 'A',
+           link : function($scope, element, attrs, ngModel) {
+               var attrHandler = $parse(attrs['fileChange']);
+               var handler=function(e) {
+                       $scope.$apply(function() {
+                               attrHandler($scope, { $event:e, files:e.target.files } );
+                               $scope.selectedFile = e.target.files[0].name;
+                       });
+               };
+               element[0].addEventListener('change',handler,false);
+          }
+       }
+    }]);
+
+    angular.module('ecompApp').filter('csvToObj',function() {
+       return function(input) {
+           var result = [];
+           var len, i, line, o;
+               var lines = input.split('\n');
+           // Need 1-based index below
+           for (len = lines.length, i = 1; i <= len; ++i) {
+               // Use 0-based index for array
+               line = lines[i - 1].trim();
+                       if (line.length == 0) {
+                               // console.log("Skipping blank line");
+                               result.push({
+                                       line: i,
+                                       orgUserId: '',
+                                       role: '',
+                                       status: 'Blank line'
+                               });
+                               continue;
+                       }
+                       o = line.split(',');
+                       if (o.length !== 2) {
+                               // other lengths not valid for upload
+                               result.push({
+                                       line: i,
+                                       orgUserId: line,   
+                                       role: '',
+                                       status: 'Failed to find 2 comma-separated values'
+                               });
+                       }
+                       else {
+                               // console.log("Valid line: ", val);
+                               let entry = {
+                                               line: i,
+                                               orgUserId: o[0],
+                                               role: o[1]
+                                               // leave status undefined, this could be valid.
+                               };
+                               if (o[0].toLowerCase() === 'orgUserId') {
+                                       // not valid for upload, so set status
+                                       entry.status = 'Header';
+                               }
+                               else if (o[0].trim() == '' || o[1].trim() == '') {
+                                       // defend against line with only a single comma etc.
+                                       entry.status = 'Failed to find 2 non-empty values';                                     
+                               }
+                               result.push(entry);
+                       } // len 2
+           } // for
+           return result;
+       };
+    });
+    
+  
+        
+})();