diff options
Diffstat (limited to 'ecomp-portal-FE-common/client/app/views')
15 files changed, 1714 insertions, 19 deletions
diff --git a/ecomp-portal-FE-common/client/app/views/account-onboarding/account-add-details/account-add-details.html b/ecomp-portal-FE-common/client/app/views/account-onboarding/account-add-details/account-add-details.html index 394971ce..03d7d1c4 100644 --- a/ecomp-portal-FE-common/client/app/views/account-onboarding/account-add-details/account-add-details.html +++ b/ecomp-portal-FE-common/client/app/views/account-onboarding/account-add-details/account-add-details.html @@ -194,7 +194,7 @@ padding-top:10px; <div class="b2b-modal-footer"> <div class="cta-button-group cta-modal-footer-flex"> <div class="item"> - <div id="account-details-next-button" class="btn btn-alt btn-small" ng-click="$dismiss('cancel')">Cancel</div> + <div id="account-details-next-cancel" class="btn btn-alt btn-small" ng-click="$dismiss('cancel')">Cancel</div> <div id="account-details-next-button" class="btn btn-alt btn-small" ng-click="accountAddDetails.saveChanges()">Save</div> </div> </div> diff --git a/ecomp-portal-FE-common/client/app/views/role/bulk-upload-dialogs/bulk-upload-functions-confirm.html b/ecomp-portal-FE-common/client/app/views/role/bulk-upload-dialogs/bulk-upload-functions-confirm.html new file mode 100644 index 00000000..cf24e9f5 --- /dev/null +++ b/ecomp-portal-FE-common/client/app/views/role/bulk-upload-dialogs/bulk-upload-functions-confirm.html @@ -0,0 +1,135 @@ +<!-- + ============LICENSE_START========================================== + ONAP Portal + =================================================================== + Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + =================================================================== + + Unless otherwise specified, all software contained herein is licensed + under the Apache License, Version 2.0 (the "License"); + you may not use this software 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. + + Unless otherwise specified, all documentation contained herein is licensed + under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + you may not use this documentation except in compliance with the License. + You may obtain a copy of the License at + + https://creativecommons.org/licenses/by/4.0/ + + Unless required by applicable law or agreed to in writing, documentation + 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. + + ============LICENSE_END============================================ + + ECOMP is a trademark and service mark of AT&T Intellectual Property. + --> +<div> + <div class="b2b-modal-header"> + <h2 class="heading-medium" id="newAdmin">Bulk Upload Functions + Confirmation</h2> + <div class="corner-button in"> + <button type="button" class="close" aria-label="Close" + id="bulk-user-button-close" ng-click="$dismiss('cancel')"></button> + </div> + </div> + <div class="b2b-modal-body"> + + <!-- progress indicator --> + <div class="upload-instructions" ng-show="isProcessing"> + {{progressMsg}} <br> <br> <span class="ecomp-spinner"></span> + </div> + + <div ng-hide="isProcessing"> + <div class="upload-instructions">Click OK to upload the valid + functions. Invalid or existing functions will be ignored.</div> + <p> + <span id="required" style="color: Red; font-size: 180%;" + visible="false">*</span>Type can only contain alphanumeric + characters, dots(.) and underscores(_) + </p> + <p> + <span id="required" style="color: Red; font-size: 180%;" + visible="false">*</span>Action can only contain alphanumeric + characters, hyphens(-), dots(.) and underscores(_) and single + asterisk character(*) + </p> + <p> + <span id="required" style="color: Red; font-size: 180%;" + visible="false">*</span>Instance/Code can only contain alphanumeric + characters, hyphens(-), dots(.), colons(:), forwardSlash(/) , + asterisk(*) and underscores(_) + </p> + <p> + <span id="required" style="color: Red; font-size: 180%;" + visible="false">*</span>Name can only contain alphanumeric + characters, spaces, hyphens(-), dots(.) and underscores(_) + </p> + </div> + <div class="c-ecomp-portal-abs-table default" + style="height: 250px !important"> + <table b2b-table table-data="uploadFile" + search-string="bulkRoleAndFunctions.searchString" + view-per-page="bulkRoleAndFunctions.viewPerPageIgnored" + current-page="bulkRoleAndFunctions.currentPageIgnored" + total-page="bulkRoleAndFunctions.totalPageIgnored"> + <thead b2b-table-row type="header"> + <tr> + <th id="th-line" b2b-table-header sortable="false">Line</th> + <th id="th-type" b2b-table-header sortable="false">Type</th> + <th id="th-instance" b2b-table-header sortable="false">Instance/Code</th> + <th id="th-action" b2b-table-header sortable="false">Action</th> + <th id="th-name" b2b-table-header sortable="false">Name</th> + <th id="th-status" b2b-table-header sortable="false">Status</th> + </tr> + </thead> + <!-- Use track-by="UNIQUE KEY HERE" or leave out if no unique keys in data --> + <tbody b2b-table-row type="body" class="table-body" + row-repeat="rowData in uploadFile"> + <tr id="tr-rowData"> + <td class="td-first" b2b-table-body> + <div ng-bind="rowData.line"></div> + </td> + <td b2b-table-body> + <div ng-bind="rowData.type"></div> + </td> + <td b2b-table-body> + <div ng-bind="rowData.instance"></div> + </td> + <td b2b-table-body> + <div ng-bind="rowData.action"></div> + </td> + <td b2b-table-body> + <div ng-bind="rowData.name"></div> + </td> + <td b2b-table-body> + <div ng-bind="rowData.status"></div> + </td> + </tr> + </tbody> + </table> + </div> + + </div> + +</div> +<div class="b2b-modal-footer"> + <div class="cta-button-group in"> + <button id="bulk-user-ok-button" class="btn btn-alt btn-small" + ng-class="{disabled: isValidating}" ng-click="updateFunctionsInDB()">Ok</button> + <button id="bulk-user-cancel-button" class="btn btn-alt btn-small" + ng-click="$dismiss('cancel')">Cancel</button> + </div> +</div> +</div> diff --git a/ecomp-portal-FE-common/client/app/views/role/bulk-upload-dialogs/bulk-upload-global-role-functions-confirm.html b/ecomp-portal-FE-common/client/app/views/role/bulk-upload-dialogs/bulk-upload-global-role-functions-confirm.html new file mode 100644 index 00000000..4b173fd3 --- /dev/null +++ b/ecomp-portal-FE-common/client/app/views/role/bulk-upload-dialogs/bulk-upload-global-role-functions-confirm.html @@ -0,0 +1,117 @@ +<!-- + ============LICENSE_START========================================== + ONAP Portal + =================================================================== + Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + =================================================================== + + Unless otherwise specified, all software contained herein is licensed + under the Apache License, Version 2.0 (the "License"); + you may not use this software 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. + + Unless otherwise specified, all documentation contained herein is licensed + under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + you may not use this documentation except in compliance with the License. + You may obtain a copy of the License at + + https://creativecommons.org/licenses/by/4.0/ + + Unless required by applicable law or agreed to in writing, documentation + 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. + + ============LICENSE_END============================================ + + ECOMP is a trademark and service mark of AT&T Intellectual Property. + --> +<div> + <div class="b2b-modal-header"> + <h2 class="heading-medium" id="newAdmin">Bulk Upload + Global-Role-Functions Confirmation</h2> + <div class="corner-button in"> + <button type="button" class="close" aria-label="Close" + id="bulk-user-button-close" ng-click="$dismiss('cancel')"></button> + </div> + </div> + <div class="b2b-modal-body"> + + <!-- progress indicator --> + <div class="upload-instructions" ng-show="isProcessing"> + {{progressMsg}} <br> <br> <span class="ecomp-spinner"></span> + </div> + + <div ng-hide="isProcessing"> + <div class="upload-instructions">Click OK to upload the valid + requests. Invalid requests will be ignored.</div> + <div class="c-ecomp-portal-abs-table default" + style="height: 250px !important"> + <table b2b-table table-data="uploadFile" + search-string="bulkRoleAndFunctions.searchString" + view-per-page="bulkRoleAndFunctions.viewPerPageIgnored" + current-page="bulkRoleAndFunctions.currentPageIgnored" + total-page="bulkRoleAndFunctions.totalPageIgnored"> + <thead b2b-table-row type="header"> + <tr> + <th id="th-line" b2b-table-header sortable="false">Line</th> + <th id="th-approle" b2b-table-header sortable="false">Global Role Name</th> + <th id="th-type" b2b-table-header sortable="false">Function Type</th> + <th id="th-instance" b2b-table-header sortable="false">Function Instance</th> + <th id="th-action" b2b-table-header sortable="false">Function Action</th> + <th id="th-delete" b2b-table-header sortable="false">Function Name</th> + <th id="th-status" b2b-table-header sortable="false">Status</th> + </tr> + </thead> + <!-- Use track-by="UNIQUE KEY HERE" or leave out if no unique keys in data --> + <tbody b2b-table-row type="body" class="table-body" + row-repeat="rowData in uploadFile"> + <tr id="tr-rowData"> + <td class="td-first" b2b-table-body> + <div ng-bind="rowData.line"></div> + </td> + <td b2b-table-body> + <div ng-bind="rowData.role"></div> + </td> + <td b2b-table-body> + <div ng-bind="rowData.type"></div> + </td> + <td b2b-table-body> + <div ng-bind="rowData.instance"></div> + </td> + <td b2b-table-body> + <div ng-bind="rowData.action"></div> + </td> + <td b2b-table-body> + <div ng-bind="rowData.name"></div> + </td> + <td b2b-table-body> + <div ng-bind="rowData.status"></div> + </td> + </tr> + </tbody> + </table> + </div> + + </div> + + </div> + <div class="b2b-modal-footer"> + <div class="cta-button-group in"> + <button id="bulk-user-ok-button" class="btn btn-alt btn-small" + ng-class="{disabled: isValidating}" + ng-click="updateGlobalRoleFunctionsInDB()">Ok</button> + <button id="bulk-user-cancel-button" class="btn btn-alt btn-small" + ng-click="$dismiss('cancel')">Cancel</button> + </div> + </div> +</div> diff --git a/ecomp-portal-FE-common/client/app/views/role/bulk-upload-dialogs/bulk-upload-role-functions-confirm.html b/ecomp-portal-FE-common/client/app/views/role/bulk-upload-dialogs/bulk-upload-role-functions-confirm.html new file mode 100644 index 00000000..dce8e99e --- /dev/null +++ b/ecomp-portal-FE-common/client/app/views/role/bulk-upload-dialogs/bulk-upload-role-functions-confirm.html @@ -0,0 +1,122 @@ +<!-- + ============LICENSE_START========================================== + ONAP Portal + =================================================================== + Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + =================================================================== + + Unless otherwise specified, all software contained herein is licensed + under the Apache License, Version 2.0 (the "License"); + you may not use this software 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. + + Unless otherwise specified, all documentation contained herein is licensed + under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + you may not use this documentation except in compliance with the License. + You may obtain a copy of the License at + + https://creativecommons.org/licenses/by/4.0/ + + Unless required by applicable law or agreed to in writing, documentation + 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. + + ============LICENSE_END============================================ + + ECOMP is a trademark and service mark of AT&T Intellectual Property. + --> +<div> + <div class="b2b-modal-header"> + <h2 class="heading-medium" id="newAdmin">Bulk Upload + Role-Functions Confirmation</h2> + <div class="corner-button in"> + <button type="button" class="close" aria-label="Close" + id="bulk-user-button-close" ng-click="$dismiss('cancel')"></button> + </div> + </div> + <div class="b2b-modal-body"> + + <!-- progress indicator --> + <div class="upload-instructions" ng-show="isProcessing"> + {{progressMsg}} <br> <br> <span class="ecomp-spinner"></span> + </div> + + <div ng-hide="isProcessing"> + <div class="upload-instructions">Click OK to upload the valid + requests. Invalid requests will be ignored.</div> + <div class="c-ecomp-portal-abs-table default" + style="height: 250px !important"> + <table b2b-table table-data="uploadFile" + search-string="bulkRoleAndFunctions.searchString" + view-per-page="bulkRoleAndFunctions.viewPerPageIgnored" + current-page="bulkRoleAndFunctions.currentPageIgnored" + total-page="bulkRoleAndFunctions.totalPageIgnored"> + <thead b2b-table-row type="header"> + <tr> + <th id="th-line" b2b-table-header sortable="false">Line</th> + <th id="th-approle" b2b-table-header sortable="false">Role + Name</th> + <th id="th-type" b2b-table-header sortable="false">Function + Type</th> + <th id="th-instance" b2b-table-header sortable="false">Function + Instance</th> + <th id="th-action" b2b-table-header sortable="false">Function + Action</th> + <th id="th-delete" b2b-table-header sortable="false">Function + Name</th> + <th id="th-status" b2b-table-header sortable="false">Status</th> + </tr> + </thead> + <!-- Use track-by="UNIQUE KEY HERE" or leave out if no unique keys in data --> + <tbody b2b-table-row type="body" class="table-body" + row-repeat="rowData in uploadFile"> + <tr id="tr-rowData"> + <td class="td-first" b2b-table-body> + <div ng-bind="rowData.line"></div> + </td> + <td b2b-table-body> + <div ng-bind="rowData.role"></div> + </td> + <td b2b-table-body> + <div ng-bind="rowData.type"></div> + </td> + <td b2b-table-body> + <div ng-bind="rowData.instance"></div> + </td> + <td b2b-table-body> + <div ng-bind="rowData.action"></div> + </td> + <td b2b-table-body> + <div ng-bind="rowData.name"></div> + </td> + <td b2b-table-body> + <div ng-bind="rowData.status"></div> + </td> + </tr> + </tbody> + </table> + </div> + + </div> + + </div> + <div class="b2b-modal-footer"> + <div class="cta-button-group in"> + <button id="bulk-user-ok-button" class="btn btn-alt btn-small" + ng-class="{disabled: isValidating}" + ng-click="updateRoleFunctionsInDB()">Ok</button> + <button id="bulk-user-cancel-button" class="btn btn-alt btn-small" + ng-click="$dismiss('cancel')">Cancel</button> + </div> + </div> +</div> diff --git a/ecomp-portal-FE-common/client/app/views/role/bulk-upload-dialogs/bulk-upload-role-functions-controller.js b/ecomp-portal-FE-common/client/app/views/role/bulk-upload-dialogs/bulk-upload-role-functions-controller.js new file mode 100644 index 00000000..41af0bc6 --- /dev/null +++ b/ecomp-portal-FE-common/client/app/views/role/bulk-upload-dialogs/bulk-upload-role-functions-controller.js @@ -0,0 +1,987 @@ +/*- + * ============LICENSE_START========================================== + * ONAP Portal + * =================================================================== + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * =================================================================== + * + * Unless otherwise specified, all software contained herein is licensed + * under the Apache License, Version 2.0 (the "License"); + * you may not use this software 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. + * + * Unless otherwise specified, all documentation contained herein is licensed + * under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + * you may not use this documentation except in compliance with the License. + * You may obtain a copy of the License at + * + * https://creativecommons.org/licenses/by/4.0/ + * + * Unless required by applicable law or agreed to in writing, documentation + * 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. + * + * ============LICENSE_END============================================ + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +/** + * bulk upload role-functions controller + */ +'use strict'; +(function () { + class BulkRoleAndFunctionsModalCtrl { + constructor($scope, $log, $filter, $q, $modalInstance, $modal, ngDialog, message, confirmBoxService, usersService, applicationsService, functionalMenuService, RoleService) { + // Set to true for copious console output + var debug = false; + // Roles fetched from Role service + var appRoleFuncsResult = []; + // Functions fetched from Role service + var appFunctionsResult = []; + // Global roles fetched from Role service + var appGlobalRolesResult = []; + + var appId = message.appid; + + $scope.ngRepeatBulkUploadOptions = [ + {id: '1', title: 'Functions', value: 'functions'}, + {id: '2', title: 'Roles', value: 'roles'}, + {id: '3', title: 'Role Functions', value: 'roleFunctions'}, + {id: '4', title: 'Global Role Functions', value: 'globalRoleFunctions'} + ]; + + $scope.selectedUploadType = $scope.ngRepeatBulkUploadOptions[0]; + $scope.UploadTypeInstruction = "Function Type, Function Instance, Function Action, Function Name"; + $scope.changeUploadTypeInstruction = function(typeInstrc){ + switch(typeInstrc) { + case 'functions': + $scope.UploadTypeInstruction = "Function Type, Function Instance, Function Action, Function Name"; + break; + case 'roles': + $scope.UploadTypeInstruction = "Role Name, Priority (Optional)"; + break; + case 'roleFunctions': + $scope.UploadTypeInstruction = "Role Name, Function Type, Function Instance, Function Action, Function Name"; + break; + default: + $scope.UploadTypeInstruction = "Global Role Name, Function Type, Function Instance, Function Action, Function Name"; + } + }; + + let init = () => { + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::init'); + // Angular insists on this. + $scope.fileModel = {}; + // Enable modal controls + this.step1 = true; + + this.fileSelected = 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; + } + } + + // Caches the file name supplied by the event handler. + $scope.fileChangeHandler = (event, files) => { + this.fileSelected = true; + this.fileToRead = files[0]; + if (debug) + $log.debug("BulkRoleAndFunctionsModalCtrl::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 = (typeUpload) => { + $scope.isProcessing = true; + $scope.progressMsg = 'Reading upload file...'; + var reader = new FileReader(); + reader.onload = function(event) { + if(typeUpload === 'roles'){ + $scope.uploadFile = $filter('csvToRoleObj')(reader.result); + if (debug){ + $log.debug('BulkRoleAndFunctionsModalCtrl::readValidateFile onload: data length is ' + $scope.uploadFile.length); + } + $scope.progressMsg = 'Fetching & validating application roles...'; + // fetch app roles + RoleService.getRoles(appId).then(function (appRoles){ + if (debug){ + $log.debug("BulkRoleAndFunctionsModalCtrl::readValidateFile: getRoles returned " + JSON.stringify(appFunctions.data)); + } + let availableRolesList = JSON.parse(appRoles.data); + appRoleFuncsResult = availableRolesList.availableRoles; + $scope.evalAppRolesCheckResults(); + // 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('BulkRoleAndFunctionsModalCtrl::readValidateFile inner-then ends'); + $scope.progressMsg = 'Done.'; + $scope.isProcessing = false; + }, function(error) { + $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving app roles info'); + $scope.isProcessing = false; + }); + } else if (typeUpload === 'roleFunctions'){ + $scope.uploadFile = $filter('csvToRoleFuncObj')(reader.result); + if (debug){ + $log.debug('BulkRoleAndFunctionsModalCtrl::readValidateFile onload: data length is ' + $scope.uploadFile.length); + } + $scope.progressMsg = 'Fetching & validating application role functions...'; + //fetch app functions + RoleService.getRoleFunctionList(appId).then(function (appFunctions){ + if (debug) + $log.debug("BulkRoleAndFunctionsModalCtrl::readValidateFile: getRoleFunctionList returned " + JSON.stringify(appFunctions.data)); + let availableRoleFunctionsList = JSON.parse(appFunctions.data); + appFunctionsResult = availableRoleFunctionsList.availableRoleFunctions; + // fetch app roles + RoleService.getRoles(appId).then(function (appRoles){ + if (debug){ + $log.debug("BulkRoleAndFunctionsModalCtrl::readValidateFile: getRoles returned " + JSON.stringify(appFunctions.data)); + } + let availableRolesList = JSON.parse(appRoles.data); + appRoleFuncsResult = availableRolesList.availableRoles; + $scope.evalAppRoleFuncsCheckResults(); + // 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('BulkRoleAndFunctionsModalCtrl::readValidateFile inner-then ends'); + $scope.progressMsg = 'Done.'; + $scope.isProcessing = false; + }, function(error) { + $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving app roles info'); + $scope.isProcessing = false; + }); + }, + function(error) { + $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving app functions info'); + $scope.isProcessing = false; + } + ); + } else if(typeUpload === 'functions'){ + $scope.uploadFile = $filter('csvToFuncObj')(reader.result); + if (debug){ + $log.debug('BulkRoleAndFunctionsModalCtrl::readValidateFile onload: data length is ' + $scope.uploadFile.length); + } + $scope.progressMsg = 'Fetching & validating the application functions...'; + // fetch app functions + RoleService.getRoleFunctionList(appId).then(function (appFunctions){ + if (debug) + $log.debug("BulkRoleAndFunctionsModalCtrl::readValidateFile: getRoleFunctionList returned " + JSON.stringify(appFunctions.data)); + let availableRoleFunctionsList = JSON.parse(appFunctions.data); + appFunctionsResult = availableRoleFunctionsList.availableRoleFunctions; + $scope.verifyFunctions(); + $scope.evalAppFunctionsCheckResults(); + // 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('BulkRoleAndFunctionsModalCtrl::readValidateFile inner-then ends'); + $scope.progressMsg = 'Done.'; + $scope.isProcessing = false; + }, + function(error) { + $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving app functions info'); + $scope.isProcessing = false; + } + ); + } else if(typeUpload === 'globalRoleFunctions'){ + $scope.uploadFile = $filter('csvToRoleFuncObj')(reader.result); + if (debug){ + $log.debug('BulkRoleAndFunctionsModalCtrl::readValidateFile onload: data length is ' + $scope.uploadFile.length); + } + $scope.progressMsg = 'Fetching application global role functions...'; + //fetch app functions + RoleService.getRoleFunctionList(appId).then(function (appFunctions){ + if (debug) + $log.debug("BulkRoleAndFunctionsModalCtrl::readValidateFile: getRoleFunctionList returned " + JSON.stringify(appFunctions.data)); + let availableRoleFunctionsList = JSON.parse(appFunctions.data); + appFunctionsResult = availableRoleFunctionsList.availableRoleFunctions; + // fetch app roles + RoleService.getRoles(appId).then(function (appRoles){ + if (debug){ + $log.debug("BulkRoleAndFunctionsModalCtrl::readValidateFile: getRoles returned " + JSON.stringify(appFunctions.data)); + } + let availableRolesList = JSON.parse(appRoles.data); + appRoleFuncsResult = availableRolesList.availableRoles; + appRoleFuncsResult.forEach(function(appRole) { + if(appRole.name.toLowerCase().startsWith("global_")){ + appGlobalRolesResult.push(appRole); + } + }); + $scope.evalAppRoleFuncsCheckResults(typeUpload); + // 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('BulkRoleAndFunctionsModalCtrl::readValidateFile inner-then ends'); + $scope.progressMsg = 'Done.'; + $scope.isProcessing = false; + }, function(error) { + $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving app roles info'); + $scope.isProcessing = false; + }); + }, + function(error) { + $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving app functions info'); + $scope.isProcessing = false; + } + ); + } + + } // onload + + // Invoke the reader on the selected file + reader.readAsText(this.fileToRead); + }; + + /** + * Evaluates the result set returned by the role service. + * Sets an uploadFile array element status if a functions is not + * defined. Reads and writes scope variable uploadFile. Reads + * closure variable appFunctionsResult. + */ + $scope.verifyFunctions = () => { + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::verifyFunctions: appFunctions is ' + JSON.stringify(appFunctionsResult)); + // check functions in upload file against defined app functions + $scope.uploadFile.forEach( function (uploadRow) { + // skip rows that already have a defined status: headers etc. + if (uploadRow.status) { + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::verifyFunctions: skip row ' + uploadRow.line); + return; + } + for (var i=0; i < appFunctionsResult.length; i++) { + if (uploadRow.type.toUpperCase() === appFunctionsResult[i].type.toUpperCase() + && uploadRow.instance.toUpperCase() === appFunctionsResult[i].code.toUpperCase() + && uploadRow.action.toUpperCase() === appFunctionsResult[i].action.toUpperCase()) { + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::verifyFunctions: match on function ' + uploadRow.type, + uploadRow.instance, uploadRow.type, uploadRow.type); + break; + } + } + }); // foreach + }; // verifyFunctions + + /** + * Evaluates the result set of existing functions returned by + * the Roleservice and list of functions found in the upload file. + * Reads and writes scope variable uploadFile. + * Reads closure variable appFunctionsResult. + */ + $scope.evalAppFunctionsCheckResults = () => { + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppFunctionsCheckResults: uploadFile length is ' + $scope.uploadFile.length); + $scope.uploadFile.forEach(function (uploadRow) { + if (uploadRow.status) { + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppFunctionsCheckResults: skip row ' + uploadRow.line); + return; + } + // Search for the match in the app-functions + // array + let isFunctionExist = false; + appFunctionsResult.forEach( function (exixtingFuncObj) { + if (uploadRow.type.toUpperCase() === exixtingFuncObj.type.toUpperCase() + && uploadRow.instance.toUpperCase() === exixtingFuncObj.code.toUpperCase() + && uploadRow.action.toUpperCase() === exixtingFuncObj.action.toUpperCase()) { + uploadRow.status = 'Function exits!'; + uploadRow.isCreate = false; + isFunctionExist = true; + } + }); // for each result + if(!isFunctionExist) { + if(/[^a-zA-Z0-9\-\.\_]/.test(uploadRow.type) + || (uploadRow.action !== '*' + && /[^a-zA-Z0-9\-\.\_]/.test(uploadRow.action)) + || /[^a-zA-Z0-9\-\:\_\./*]/.test(uploadRow.instance) + || /[^a-zA-Z0-9\-\_ \.]/.test(uploadRow.name)){ + uploadRow.status = 'Invalid function'; + uploadRow.isCreate = false; + } else { + if (debug){ + $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppFunctionsCheckResults: new function ' + + uploadRow); + } + // After much back-and-forth I decided a clear indicator is better than blank in the table status column. + uploadRow.status = 'Create'; + uploadRow.isCreate = true; + } + } + }); // for each row + }; // evalAppFunctionsCheckResults + + /** + * Evaluates the result set of existing roles returned by + * the Roleservice and list of roles found in the upload file. + * Reads and writes scope variable uploadFile. + * Reads closure variable appRolesResult. + */ + $scope.evalAppRolesCheckResults = () => { + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppRolesCheckResults: uploadFile length is ' + $scope.uploadFile.length); + $scope.uploadFile.forEach(function (uploadRow) { + if (uploadRow.status) { + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppRolesCheckResults: skip row ' + uploadRow.line); + return; + } + // Search for the match in the app-roles + // array + let isRoleExist = false; + appRoleFuncsResult.forEach( function (existingRoleObj) { + if (uploadRow.role.toUpperCase() === existingRoleObj.name.toUpperCase()) { + uploadRow.status = 'Role exits!'; + uploadRow.isCreate = false; + isRoleExist = true; + } + }); // for each result + if(!isRoleExist) { + if(/[^a-zA-Z0-9\-\_ \.\/]/.test(uploadRow.role) || + uploadRow.role.toLowerCase().startsWith("global_")){ + uploadRow.status = 'Invalid role!'; + uploadRow.isCreate = false; + } else { + if (debug){ + $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppRolesCheckResults: new function ' + + uploadRow); + } + // After much back-and-forth I decided a clear indicator is better than blank in the table status column. + uploadRow.status = 'Create'; + uploadRow.isCreate = true; + } + } + }); // for each row + }; // evalAppRolesCheckResults + + /** + * Evaluates the result set of existing roles returned by + * the Roleservice and list of roles found in the upload file. + * Reads and writes scope variable uploadFile. + * Reads closure variable appRolesResult. + */ + $scope.evalAppRoleFuncsCheckResults = (typeUpload) => { + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppRoleFuncsCheckResults: uploadFile length is ' + $scope.uploadFile.length); + $scope.uploadFile.forEach(function (uploadRow) { + if (uploadRow.status) { + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppRoleFuncsCheckResults: skip row ' + uploadRow.line); + return; + } + // Search for the match in the app-functions array + let isValidFunc = false; + appFunctionsResult.forEach(function (existingFuncObj){ + if(uploadRow.type.toUpperCase() === existingFuncObj.type.toUpperCase() + && uploadRow.instance.toUpperCase() === existingFuncObj.code.toUpperCase() + && uploadRow.action.toUpperCase() === existingFuncObj.action.toUpperCase() + && uploadRow.name.toUpperCase() === existingFuncObj.name.toUpperCase()){ + isValidFunc = true; + } + }); + + let isValidRole = false; + let isRoleFuncExist = false; + if(typeUpload === 'globalRoleFunctions'){ + // Search for the match in the app-role array + appGlobalRolesResult.forEach( function (existingRoleObj) { + if (uploadRow.role.toUpperCase() === existingRoleObj.name.toUpperCase()) { + isValidRole = true; + if(isValidFunc){ + existingRoleObj.roleFunctions.forEach(function (existingRoleFuncObj){ + if(uploadRow.type.toUpperCase() === existingRoleFuncObj.type.toUpperCase() + && uploadRow.instance.toUpperCase() === existingRoleFuncObj.code.toUpperCase() + && uploadRow.action.toUpperCase() === existingRoleFuncObj.action.toUpperCase()){ + isRoleFuncExist = true; + } + }); + } + } + }); // for each result + } else { + // Search for the match in the app-role array + appRoleFuncsResult.forEach( function (existingRoleObj) { + if (uploadRow.role.toUpperCase() === existingRoleObj.name.toUpperCase()) { + isValidRole = true; + if(isValidFunc){ + existingRoleObj.roleFunctions.forEach(function (existingRoleFuncObj){ + if(uploadRow.type.toUpperCase() === existingRoleFuncObj.type.toUpperCase() + && uploadRow.instance.toUpperCase() === existingRoleFuncObj.code.toUpperCase() + && uploadRow.action.toUpperCase() === existingRoleFuncObj.action.toUpperCase()){ + isRoleFuncExist = true; + } + }); + } + } + }); // for each result + } + + uploadRow.isCreate = false; + if(typeUpload === 'globalRoleFunctions' && (!isValidRole || !isValidFunc)){ + uploadRow.status = 'Invalid global role function!'; + } else if(typeUpload !== 'globalRoleFunctions' && (!isValidRole || !isValidFunc)){ + uploadRow.status = 'Invalid role function!'; + } else if(typeUpload === 'globalRoleFunctions' && !isRoleFuncExist) { + uploadRow.status = 'Add global role function!'; + uploadRow.isCreate = true; + } else if(typeUpload !== 'globalRoleFunctions' && !isRoleFuncExist){ + uploadRow.status = 'Add role function!'; + uploadRow.isCreate = true; + } else if(typeUpload === 'globalRoleFunctions'){ + uploadRow.status = 'Global role function exists!'; + } else { + uploadRow.status = 'Role function exists!'; + } + + }); // for each row + }; // evalAppRolesCheckResults + + + /** + * Sends requests to Portal BE requesting application functions assignment. + * That endpoint handles creation of the application functions in the + * external auth system if necessary. Reads closure variable appFunctionsResult. + * Invoked by the Next button on the confirmation dialog. + */ + $scope.updateFunctionsInDB = () => { + $scope.isProcessing = true; + $scope.progressMsg = 'Sending requests to application..'; + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::updateFunctionsInDB: request length is ' + appUserRolesRequest.length); + var numberFunctionsSucceeded = 0; + let promises = []; + $scope.uploadFile.forEach(function(appFuncPostData) { + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::updateFunctionsInDB: appFuncPostData is ' + JSON.stringify(appFuncPostData)); + let updateFunctionsFinalPostData = { + type: appFuncPostData.type, + code: appFuncPostData.instance, + action: appFuncPostData.action, + name: appFuncPostData.name + }; + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::updateFunctionsInDB: updateFunctionsFinalPostData is ' + JSON.stringify(updateFunctionsFinalPostData)); + let updatePromise = {}; + if(appFuncPostData.isCreate){ + updatePromise = functionalMenuService.saveBulkFunction(appId, updateFunctionsFinalPostData).promise().then(res => { + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::updateFunctionsInDB: updated successfully: ' + JSON.stringify(res)); + numberFunctionsSucceeded++; + }).catch(err => { + // What to do if one of many fails?? + $log.error('BulkRoleAndFunctionsModalCtrl::updateFunctionsInDB failed: ', err); + confirmBoxService.showInformation( + 'Failed to update the application functions. ' + + 'Error: ' + err.status).then(isConfirmed => { }); + }).finally( () => { + }); + } + promises.push(updatePromise); + }); // for each + + // Run all the promises + $q.all(promises).then(function(){ + $scope.isProcessing = false; + confirmBoxService.showInformation('Processed ' + numberFunctionsSucceeded + ' records.').then(isConfirmed => { + // Close the upload-confirm dialog + ngDialog.close(); + }); + }); + }; // updateFunctionsInDB + + /** + * Sends requests to Portal BE requesting application functions assignment. + * That endpoint handles creation of the application role in the + * external auth system if necessary. Reads closure variable appRoleFuncResult. + * Invoked by the Next button on the confirmation dialog. + */ + $scope.updateRolesInDB = () => { + $scope.isProcessing = true; + $scope.progressMsg = 'Sending requests to application..'; + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::updateRolesInDB: request length is ' + appUserRolesRequest.length); + var numberRolesSucceeded = 0; + let promises = []; + $scope.uploadFile.forEach(function(appRolePostData) { + let priority = parseInt(appRolePostData.priority); + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::updateRolesInDB: appRolePostData is ' + JSON.stringify(appFuncPostData)); + let uplaodRolePostData = ""; + if(isNaN(priority)){ + uplaodRolePostData = { + name: appRolePostData.role, + active: true, + } + } else { + uplaodRolePostData = { + name: appRolePostData.role, + priority: appRolePostData.priority, + active: true, + } + } + var postData = { + role: uplaodRolePostData, + roleFunctions: [], + childRoles: [] + } + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::updateRolesInDB: uplaodRoleFinalPostData is ' + JSON.stringify(uplaodRoleFinalPostData)); + let updatePromise = {}; + if(appRolePostData.isCreate){ + updatePromise = functionalMenuService.saveBulkRole(appId, JSON.stringify(postData)).promise().then(res => { + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::updateRolesInDB: updated successfully: ' + JSON.stringify(res)); + numberRolesSucceeded++; + }).catch(err => { + // What to do if one of many fails?? + $log.error('BulkRoleAndFunctionsModalCtrl::updateRolesInDB failed: ', err); + confirmBoxService.showInformation( + 'Failed to update the application role. ' + + 'Error: ' + err.status).then(isConfirmed => { }); + }).finally( () => { + }); + } + promises.push(updatePromise); + }); // for each + + // Run all the promises + $q.all(promises).then(function(){ + $scope.isProcessing = false; + confirmBoxService.showInformation('Processed ' + numberRolesSucceeded + ' records. Please sync roles').then(isConfirmed => { + // Close the upload-confirm dialog + ngDialog.close(); + }); + }); + }; // updateRolesInDB + + /** + * Sends requests to Portal BE requesting role function assignment. + * That endpoint handles adding role function in the external auth system + * if necessary.Invoked by the Next button on the confirmation dialog. + */ + $scope.updateRoleFunctionsInDB = () => { + $scope.isProcessing = true; + $scope.progressMsg = 'Sending requests to application..'; + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::updateRoleFunctionsInDB: request length is ' + appUserRolesRequest.length); + var numberRoleFunctionSucceeded = 0; + let promises = []; + $scope.uploadFile.forEach(function(appRoleFuncPostData) { + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::updateRoleFunctionsInDB: appRoleFuncPostData is ' + JSON.stringify(appFuncPostData)); + let updateRoleFunctionFinalPostData = { + roleName: appRoleFuncPostData.role, + type: appRoleFuncPostData.type, + instance: appRoleFuncPostData.instance, + action: appRoleFuncPostData.action, + name: appRoleFuncPostData.name, + isGlobalRolePartnerFunc: false + }; + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::updateRoleFunctionsInDB: updateRoleFunctionFinalPostData is ' + JSON.stringify(updateFunctionsFinalPostData)); + let updatePromise = {}; + if(appRoleFuncPostData.isCreate){ + updatePromise = functionalMenuService.updateBulkRoleFunction(appId, updateRoleFunctionFinalPostData).promise().then(res => { + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::updateRoleFunctionsInDB: updated successfully: ' + JSON.stringify(res)); + numberRoleFunctionSucceeded++; + }).catch(err => { + // What to do if one of many fails?? + $log.error('BulkRoleAndFunctionsModalCtrl::updateRoleFunctionsInDB failed: ', err); + confirmBoxService.showInformation( + 'Failed to update the application role function. ' + + 'Error: ' + err.status).then(isConfirmed => { }); + }).finally( () => { + }); + } + promises.push(updatePromise); + }); // for each + + // Run all the promises + $q.all(promises).then(function(){ + $scope.isProcessing = false; + confirmBoxService.showInformation('Processed ' + numberRoleFunctionSucceeded + ' records. Please sync roles to reflect in portal').then(isConfirmed => { + // Close the upload-confirm dialog + ngDialog.close(); + }); + }); + }; // updateRoleFunctionsInDB + + /** + * Sends requests to Portal requesting global role functions assignment. + * That endpoint handles updating global role functions in the external auth system + * if necessary. Invoked by the Next button on the confirmation dialog. + */ + $scope.updateGlobalRoleFunctionsInDB = () => { + $scope.isProcessing = true; + $scope.progressMsg = 'Sending requests to application..'; + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::updateGlobalRoleFunctionsInDB: request length is ' + appUserRolesRequest.length); + var numberGlobalRoleFunctionSucceeded = 0; + let promises = []; + $scope.uploadFile.forEach(function(appRoleFuncPostData) { + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::updateGlobalRoleFunctionsInDB: appRoleFuncPostData is ' + JSON.stringify(appFuncPostData)); + let updateGlobalRoleFunctionFinalPostData = { + roleName: appRoleFuncPostData.role, + type: appRoleFuncPostData.type, + instance: appRoleFuncPostData.instance, + action: appRoleFuncPostData.action, + name: appRoleFuncPostData.name, + isGlobalRolePartnerFunc: true + }; + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::updateGlobalRoleFunctionsInDB: updateRoleFunctionFinalPostData is ' + JSON.stringify(updateFunctionsFinalPostData)); + let updatePromise = {}; + if(appRoleFuncPostData.isCreate){ + updatePromise = functionalMenuService.updateBulkRoleFunction(appId, updateGlobalRoleFunctionFinalPostData).promise().then(res => { + if (debug) + $log.debug('BulkRoleAndFunctionsModalCtrl::updateGlobalRoleFunctionsInDB: updated successfully: ' + JSON.stringify(res)); + numberGlobalRoleFunctionSucceeded++; + }).catch(err => { + // What to do if one of many fails?? + $log.error('BulkRoleAndFunctionsModalCtrl::updateGlobalRoleFunctionsInDB failed: ', err); + confirmBoxService.showInformation( + 'Failed to update the global role partner function. ' + + 'Error: ' + err.status).then(isConfirmed => { }); + }).finally( () => { + }); + } + promises.push(updatePromise); + }); // for each + + // Run all the promises + $q.all(promises).then(function(){ + $scope.isProcessing = false; + confirmBoxService.showInformation('Processed ' + numberGlobalRoleFunctionSucceeded + ' records. Please sync roles to reflect in portal').then(isConfirmed => { + // Close the upload-confirm dialog + ngDialog.close(); + }); + }); + }; // updateGlobalRoleFunctionsInDB + + // 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 = (typeUpload) => { + // Start the process + $scope.readValidateFile(typeUpload); + // Dialog shows progress + if(typeUpload === 'functions'){ + $modal.open({ + templateUrl: 'app/views/role/bulk-upload-dialogs/bulk-upload-functions-confirm.html', + controller: '', + sizeClass: 'modal-medium', + resolve:'', + scope: $scope + }) + } else if(typeUpload === 'roleFunctions'){ + $modal.open({ + templateUrl: 'app/views/role/bulk-upload-dialogs/bulk-upload-role-functions-confirm.html', + controller: '', + sizeClass: 'modal-medium', + resolve:'', + scope: $scope + }) + + } else if(typeUpload === 'roles'){ + $modal.open({ + templateUrl: 'app/views/role/bulk-upload-dialogs/bulk-upload-roles-confirm.html', + controller: '', + sizeClass: 'modal-medium', + resolve:'', + scope: $scope + }) + } else if(typeUpload === 'globalRoleFunctions'){ + $modal.open({ + templateUrl: 'app/views/role/bulk-upload-dialogs/bulk-upload-global-role-functions-confirm.html', + controller: '', + sizeClass: 'modal-medium', + resolve:'', + scope: $scope + }) + } + }; + + // Invoked by the Cancel button on the confirmation dialog. + $scope.cancelUpload = () => { + ngDialog.close(); + }; + + init(); + } // constructor + } // class + BulkRoleAndFunctionsModalCtrl.$inject = ['$scope', '$log', '$filter', '$q', '$modalInstance', '$modal', 'ngDialog', 'message', 'confirmBoxService', 'usersService', 'applicationsService', 'functionalMenuService', 'RoleService']; + angular.module('ecompApp').controller('BulkRoleAndFunctionsModalCtrl', BulkRoleAndFunctionsModalCtrl); + + 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('csvToFuncObj',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, + type: '', + instance: '', + action: '', + name: '', + status: 'Blank line' + }); + continue; + } + o = line.split(','); + if (o.length !== 4) { + // other lengths not valid for upload + result.push({ + line: i, + type: o[0], + instance: o[1], + action: o[2], + name: '', + status: 'Failed to find 4 comma-separated values' + }); + } + else { + // console.log("Valid line: ", val); + let entry = { + line: i, + type: o[0], + instance: o[1], + action: o[2], + name: o[3] + // leave status undefined, this + // could be valid. + }; + if (o[0].toLowerCase() === 'type') { + // not valid for upload, so set status + entry.status = 'Header'; + } + else if (o[0].toLowerCase() === 'instance') { + // not valid for upload, so set status + entry.status = 'Header'; + } + else if (o[0].toLowerCase() === 'action') { + // not valid for upload, so set status + entry.status = 'Header'; + } + else if (o[0].toLowerCase() === 'name') { + // not valid for upload, so set status + entry.status = 'Header'; + } + else if (o[0].trim() == '' || o[1].trim() == '' || o[2].trim() == '' || o[3].trim() == '') { + // defend against line with only a + // single comma etc. + entry.status = 'Failed to find non-empty values'; + } + result.push(entry); + } // len 2 + } // for + return result; + }; + }); + + angular.module('ecompApp').filter('csvToRoleFuncObj',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, + role:'', + type: '', + instance: '', + action: '', + name: '', + status: 'Blank line' + }); + continue; + } + o = line.split(','); + if (o.length !== 5) { + // other lengths not valid for upload + result.push({ + line: i, + role: o[0], + type: o[1], + instance: o[2], + action: o[3], + name: '', + status: 'Failed to find 4 comma-separated values' + }); + } + else { + // console.log("Valid line: ", val); + let entry = { + line: i, + role: o[0], + type: o[1], + instance: o[2], + action: o[3], + name: o[4] + // leave status undefined, this + // could be valid. + }; + if (o[0].toLowerCase() === 'role') { + // not valid for upload, so set status + entry.status = 'Header'; + } else if (o[0].toLowerCase() === 'type') { + // not valid for upload, so set status + entry.status = 'Header'; + } + else if (o[0].toLowerCase() === 'instance') { + // not valid for upload, so set status + entry.status = 'Header'; + } + else if (o[0].toLowerCase() === 'action') { + // not valid for upload, so set status + entry.status = 'Header'; + } + else if (o[0].toLowerCase() === 'name') { + // not valid for upload, so set status + entry.status = 'Header'; + } + else if (o[0].trim() == '' || o[1].trim() == '' || o[2].trim() == '' || o[3].trim() == '' || o[4].trim() == '') { + // defend against line with only a + // single comma etc. + entry.status = 'Failed to find non-empty values'; + } + result.push(entry); + } // len 2 + } // for + return result; + }; + }); + + angular.module('ecompApp').filter('csvToRoleObj',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, + role:'', + priority: '', + status: 'Blank line' + }); + continue; + } + o = line.split(','); + if (o.length === 0 && line.length !== 0) { + // other lengths not valid for upload + result.push({ + line: i, + role: o[0], + priority:null + }); + } + else { + // console.log("Valid line: ", val); + let entry = { + line: i, + role: o[0], + priority: o[1] + // leave status undefined, this + // could be valid. + }; + if (o[0].toLowerCase() === 'role') { + // not valid for upload, so set status + entry.status = 'Header'; + } + if (o[0].toLowerCase() === 'priority') { + // not valid for upload, so set status + entry.status = 'Header'; + } + else if (o[0].trim() == '') { + // defend against line with only a + // single comma etc. + entry.status = 'Failed to find non-empty values'; + } + result.push(entry); + } // len 2 + } // for + return result; + }; + }); + +})(); diff --git a/ecomp-portal-FE-common/client/app/views/role/bulk-upload-dialogs/bulk-upload-role-functions-modal.html b/ecomp-portal-FE-common/client/app/views/role/bulk-upload-dialogs/bulk-upload-role-functions-modal.html new file mode 100644 index 00000000..6c6a4e73 --- /dev/null +++ b/ecomp-portal-FE-common/client/app/views/role/bulk-upload-dialogs/bulk-upload-role-functions-modal.html @@ -0,0 +1,105 @@ +<!-- + ============LICENSE_START========================================== + ONAP Portal + =================================================================== + Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + =================================================================== + + Unless otherwise specified, all software contained herein is licensed + under the Apache License, Version 2.0 (the "License"); + you may not use this software 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. + + Unless otherwise specified, all documentation contained herein is licensed + under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + you may not use this documentation except in compliance with the License. + You may obtain a copy of the License at + + https://creativecommons.org/licenses/by/4.0/ + + Unless required by applicable law or agreed to in writing, documentation + 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. + + ============LICENSE_END============================================ + + ECOMP is a trademark and service mark of AT&T Intellectual Property. + --> +<div> + <div class="b2b-modal-header"> + <h2 class="heading-medium" id="newAdmin">Bulk Upload Role-Function</h2> + <div class="corner-button in"> + <button type="button" class="close" aria-label="Close" + id="bulkuser-button-close" ng-click="$dismiss('cancel')"></button> + </div> + </div> + <div class="b2b-modal-body"> + <div class="b2b-modal-body-div"> + <div ng-show="bulkRoleAndFunctions.step1"> + <div class="upload-instructions">Select Upload Type:</div> + <div class="c-ecomp-portal-abs-select default"> + + <select id="bulk-user-dropdown-apps" name="dropdown1" b2b-dropdown + ng-model="selectedUploadType.value" ng-change="changeUploadTypeInstruction(selectedUploadType.value)"> + <option b2b-dropdown-list + option-repeat="d in ngRepeatBulkUploadOptions" + value="{{d.value}}">{{d.title}}</option> + </select> + + </div> + </div> + + <div ng-hide="bulkRoleAndFunctions.step1"> + <div class="upload-instructions">Select Upload File:</div> + <!-- input type=file is difficult to style. + Instead use a label styled as a button. --> + <label class="file-label"> <input type="file" + file-change="fileChangeHandler($event,files)" ng-model="fileModel" /> + <span></span> + </label>{{selectedFile}} + <div class="upload-instructions"> + File must be .csv or .txt and one entry per line with this format: + <p>{{UploadTypeInstruction}}</p> + </div> + </div> + + <!-- progress indicator in middle --> + <div ng-show="isProcessing"> + <span class="ecomp-spinner"></span> + </div> + <br> + </div> + </div> + <div class="b2b-modal-footer"> + <div class="cta-button-group in"> + <button id="bulk-user-back-button" class="btn btn-alt btn-small" + ng-hide="bulkRoleAndFunctions.step1" ng-click="navigateBack()">Back</button> + <button id="bulk-user-next-button" class="btn btn-alt btn-small" + ng-hide="!bulkRoleAndFunctions.step1" + ng-click="!isProcessing && step2()" + ng-class="{disabled: isProcessing}">Next</button> + <button id="bulk-user-upload-button" class="btn btn-alt btn-small" + ng-hide="bulkRoleAndFunctions.step1" + ng-click="bulkRoleAndFunctions.fileSelected && confirmUpload(selectedUploadType.value)" + ng-class="{disabled: !bulkRoleAndFunctions.fileSelected}">Upload</button> + <button id="bulk-user-cancel-button" class="btn btn-alt btn-small" + ng-click="$dismiss('cancel')">Cancel</button> + </div> + </div> +</div> + +<script> +$(document).ready(function(){ + $(".ngdialog-close").attr('id','dialog-close'); +}); +</script> diff --git a/ecomp-portal-FE-common/client/app/views/role/bulk-upload-dialogs/bulk-upload-role-functions-modal.less b/ecomp-portal-FE-common/client/app/views/role/bulk-upload-dialogs/bulk-upload-role-functions-modal.less new file mode 100644 index 00000000..8ab5603f --- /dev/null +++ b/ecomp-portal-FE-common/client/app/views/role/bulk-upload-dialogs/bulk-upload-role-functions-modal.less @@ -0,0 +1,100 @@ +/*- + * ============LICENSE_START========================================== + * ONAP Portal + * =================================================================== + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * =================================================================== + * + * Unless otherwise specified, all software contained herein is licensed + * under the Apache License, Version 2.0 (the "License"); + * you may not use this software 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. + * + * Unless otherwise specified, all documentation contained herein is licensed + * under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + * you may not use this documentation except in compliance with the License. + * You may obtain a copy of the License at + * + * https://creativecommons.org/licenses/by/4.0/ + * + * Unless required by applicable law or agreed to in writing, documentation + * 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. + * + * ============LICENSE_END============================================ + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +.bulk-user-modal { + height: 430px; + + .title { + .dGray18r; + border-bottom: @blue-active 3px solid; + } + + .main { + margin: 16px; + + .upload-instructions { + .dGray14r; + } + + // http://stackoverflow.com/questions/572768/styling-an-input-type-file-button + + .file-label { + border: 1px solid #ffffff; + border-radius: 6px; + margin-top: 4px; + margin-bottom: 4px; + margin-left: 0px; + margin-right: 8px; + color: #ffffff; + background: #067ab4; + display: inline-block; + text-align: center; + font-family: Omnes-ECOMP-W02-Medium,Arial; + font-size: 14px; + height: 29px; + line-height: 29px; + width: 90px; + + input[type="file"] { + // Hide the browser's control + display: none; + } + + } + + .file-label:hover { + background: #009fdb; + } + + .file-label:active { + background: #009fdb; + } + + .file-label:invalid+span { + color: #ffffff; + } + + .file-label:valid+span { + color: #ffffff; + } + + } + +} +.b2b-modal-body-div{ + height:250px; +} diff --git a/ecomp-portal-FE-common/client/app/views/role/bulk-upload-dialogs/bulk-upload-roles-confirm.html b/ecomp-portal-FE-common/client/app/views/role/bulk-upload-dialogs/bulk-upload-roles-confirm.html new file mode 100644 index 00000000..e5e4a86b --- /dev/null +++ b/ecomp-portal-FE-common/client/app/views/role/bulk-upload-dialogs/bulk-upload-roles-confirm.html @@ -0,0 +1,109 @@ +<!-- + ============LICENSE_START========================================== + ONAP Portal + =================================================================== + Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + =================================================================== + + Unless otherwise specified, all software contained herein is licensed + under the Apache License, Version 2.0 (the "License"); + you may not use this software 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. + + Unless otherwise specified, all documentation contained herein is licensed + under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + you may not use this documentation except in compliance with the License. + You may obtain a copy of the License at + + https://creativecommons.org/licenses/by/4.0/ + + Unless required by applicable law or agreed to in writing, documentation + 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. + + ============LICENSE_END============================================ + + ECOMP is a trademark and service mark of AT&T Intellectual Property. + --> +<div> + <div class="b2b-modal-header"> + <h2 class="heading-medium" id="newAdmin">Bulk Upload Roles + Confirmation</h2> + <div class="corner-button in"> + <button type="button" class="close" aria-label="Close" + id="bulk-user-button-close" ng-click="$dismiss('cancel')"></button> + </div> + </div> + <div class="b2b-modal-body"> + + <!-- progress indicator --> + <div class="upload-instructions" ng-show="isProcessing"> + {{progressMsg}} <br> <br> <span class="ecomp-spinner"></span> + </div> + + <div ng-hide="isProcessing"> + <div class="upload-instructions">Click OK to upload the valid + roles. Invalid or existing roles will be ignored.</div> + <p> + <span id="required" style="color: Red; font-size: 180%;" + visible="false">*</span>Name can only contain alphanumeric + characters, dots(.), forward slashes(/), and underscores(_) + </p> + </div> + <div class="c-ecomp-portal-abs-table default" + style="height: 250px !important"> + <table b2b-table table-data="uploadFile" + search-string="bulkRoleAndFunctions.searchString" + view-per-page="bulkRoleAndFunctions.viewPerPageIgnored" + current-page="bulkRoleAndFunctions.currentPageIgnored" + total-page="bulkRoleAndFunctions.totalPageIgnored"> + <thead b2b-table-row type="header"> + <tr> + <th id="th-line" b2b-table-header sortable="false">Line</th> + <th id="th-name" b2b-table-header sortable="false">Name</th> + <th id="th-priority" b2b-table-header sortable="false">Priority</th> + <th id="th-status" b2b-table-header sortable="false">Status</th> + </tr> + </thead> + <!-- Use track-by="UNIQUE KEY HERE" or leave out if no unique keys in data --> + <tbody b2b-table-row type="body" class="table-body" + row-repeat="rowData in uploadFile"> + <tr id="tr-rowData"> + <td class="td-first" b2b-table-body> + <div ng-bind="rowData.line"></div> + </td> + <td b2b-table-body> + <div ng-bind="rowData.role"></div> + </td> + <td b2b-table-body> + <div ng-bind="rowData.priority"></div> + </td> + <td b2b-table-body> + <div ng-bind="rowData.status"></div> + </td> + </tr> + </tbody> + </table> + </div> + + </div> + +</div> +<div class="b2b-modal-footer"> + <div class="cta-button-group in"> + <button id="bulk-user-ok-button" class="btn btn-alt btn-small" + ng-class="{disabled: isValidating}" ng-click="updateRolesInDB()">Ok</button> + <button id="bulk-user-cancel-button" class="btn btn-alt btn-small" + ng-click="$dismiss('cancel')">Cancel</button> + </div> +</div> diff --git a/ecomp-portal-FE-common/client/app/views/role/role-create-edit-popup-controller.js b/ecomp-portal-FE-common/client/app/views/role/role-create-edit-popup-controller.js index 2c531262..2b49d9ab 100644 --- a/ecomp-portal-FE-common/client/app/views/role/role-create-edit-popup-controller.js +++ b/ecomp-portal-FE-common/client/app/views/role/role-create-edit-popup-controller.js @@ -63,9 +63,9 @@ app.controller('roleCreateEditController',function($scope, conf, $http, $modalIn availableRoleFunction.selected = true; console.log(availableRoleFunction.selected); } - }; + } $scope.availableRoleFunctions.push(availableRoleFunction); - }; + } $scope.toggleRoleFunction = function(selected,selectedRoleFunction){ if($scope.roleFunctions){ diff --git a/ecomp-portal-FE-common/client/app/views/role/role-list-controller.js b/ecomp-portal-FE-common/client/app/views/role/role-list-controller.js index 46ff0d73..acfb25e0 100644 --- a/ecomp-portal-FE-common/client/app/views/role/role-list-controller.js +++ b/ecomp-portal-FE-common/client/app/views/role/role-list-controller.js @@ -44,6 +44,7 @@ app.controller('roleListController', function ($scope,RoleService, applicationsS $scope.goToUrl = function(roleIdVal) { $state.go("root.role", {"roleId":roleIdVal}); } + $scope.toggleRole = function(appId, selected, availableRole) { var toggleType = null; if(selected) { @@ -122,8 +123,29 @@ app.controller('roleListController', function ($scope,RoleService, applicationsS }); } }; + + $scope.openBulkUploadRolesAndFunctionsModal = function(appId) { + var modalInstance = $modal.open({ + templateUrl: 'app/views/role/bulk-upload-dialogs/bulk-upload-role-functions-modal.html', + controller: 'BulkRoleAndFunctionsModalCtrl as bulkRoleAndFunctions', + sizeClass: 'modal-medium', + resolve: { + message: function () { + var message = { + appid: appId + }; + return message; + } + } + }); + modalInstance.result.then(function (confirmed) { + if(confirmed == 'confirmed'){ + // update role list table + } + }); + }; - //getCentalizedApps + // getCentalizedApps $scope.getCentralizedApps = function(userId) { RoleService.getCentralizedApps(userId).then(res=> { if (res.length>0) { @@ -193,7 +215,7 @@ app.controller('roleListController', function ($scope,RoleService, applicationsS init(); - //edit Role + // edit Role $scope.editRoleModalPopup = function(appId, availableRole) { $scope.editRole = availableRole; if(appId != undefined && availableRole.id != undefined){ @@ -215,7 +237,7 @@ app.controller('roleListController', function ($scope,RoleService, applicationsS availableRoleFunctions: availableRoleFunctions, appId: $scope.apps.selectedCentralizedApp, role: role - }; + }; return message; } } @@ -232,7 +254,7 @@ app.controller('roleListController', function ($scope,RoleService, applicationsS }; - //add Role + // add Role $scope.addRoleModalPopup = function(appId) { if(appId){ var roleId = 0; diff --git a/ecomp-portal-FE-common/client/app/views/role/role_list.html b/ecomp-portal-FE-common/client/app/views/role/role_list.html index ae07c203..b082c3ea 100644 --- a/ecomp-portal-FE-common/client/app/views/role/role_list.html +++ b/ecomp-portal-FE-common/client/app/views/role/role_list.html @@ -60,6 +60,7 @@ <div id="button-create-role" align="left" class="admins-table-btn-create" > <button id="button-create-role" ng-click="addRoleModalPopup(apps.selectedCentralizedApp)" class = "btn btn-alt btn-small">Create</button> <button id="button-sync-role" ng-show="syncRolesApplied" ng-click="syncRolesFromExternalAuthSystem(apps.selectedCentralizedApp)" class = "btn btn-alt btn-small"><i class="icon-arrows-update-refresh-syncL" aria-hidden="true"></i> Sync Roles</button> + <button id="button-bulk-upload" ng-show="syncRolesApplied" ng-click="openBulkUploadRolesAndFunctionsModal(apps.selectedCentralizedApp)" class = "btn btn-alt btn-small"><i class="icon-arrows-upload" aria-hidden="true"></i> Bulk Upload</button> </div> <br> <div class="property-label"> diff --git a/ecomp-portal-FE-common/client/app/views/users/users.controller.js b/ecomp-portal-FE-common/client/app/views/users/users.controller.js index 0a05d702..dfe1da6c 100644 --- a/ecomp-portal-FE-common/client/app/views/users/users.controller.js +++ b/ecomp-portal-FE-common/client/app/views/users/users.controller.js @@ -253,16 +253,6 @@ }); }; - this.syncRolesFromExternalAuthSystem = (appId) =>{ - applicationsService.syncRolesEcompFromExtAuthSystem(appId).then(function(res){ - if(res.status == 200){ - confirmBoxService.showInformation('Sync operation completed successfully!').then(isConfirmed => {}); - } else{ - confirmBoxService.showInformation('Sync operation failed for '+app).then(isConfirmed => {}); - } - }); - }; - $scope.$watch('users.selectedApp.value', (newVal, oldVal) => { if(typeof(newVal) != 'undefined' && !newVal.includes("Select")){ applicationsService.getSingleAppInfo(newVal).then(function(res) { diff --git a/ecomp-portal-FE-common/client/app/views/users/users.tpl.html b/ecomp-portal-FE-common/client/app/views/users/users.tpl.html index 14371236..ef08e50b 100644 --- a/ecomp-portal-FE-common/client/app/views/users/users.tpl.html +++ b/ecomp-portal-FE-common/client/app/views/users/users.tpl.html @@ -54,7 +54,6 @@ </div> <button class="btn btn-alt btn-small" id="users-button-add" ng-click="users.openAddNewUserModal()"><i class="icon-people-userbookmark" aria-hidden="true"></i> Add User</button> <button class="btn btn-alt btn-small" id="users-bulk-upload-button-add" ng-click="users.openBulkUserUploadModal()"><i class="icon-arrows-upload" aria-hidden="true"></i> Bulk Upload</button> - <button class="btn btn-alt btn-small" id="users-button-sync" ng-show="syncRolesApplied" ng-click="users.syncRolesFromExternalAuthSystem(app.appId)"><i class="icon-arrows-update-refresh-syncL" aria-hidden="true"></i> Sync Roles</button> </div> </div> <div ng-hide="users.isLoadingTable"> diff --git a/ecomp-portal-FE-common/client/app/views/widget-onboarding/widget-details-dialog/widget-details.controller.js b/ecomp-portal-FE-common/client/app/views/widget-onboarding/widget-details-dialog/widget-details.controller.js index 377d5c80..b6429015 100644 --- a/ecomp-portal-FE-common/client/app/views/widget-onboarding/widget-details-dialog/widget-details.controller.js +++ b/ecomp-portal-FE-common/client/app/views/widget-onboarding/widget-details-dialog/widget-details.controller.js @@ -242,6 +242,14 @@ }).finally(()=> { this.isLoadingTable = false; }); + + widgetsCatalogService.getUploadFlag().then(res => { + this.uploadFlag=res; + }).catch(err => { + $log.error('WidgetOnboardingDetailsModalCtrl::init error: ' + err); + }).finally(()=> { + }); + getAvailableApps(); getAvailableServices(); }; diff --git a/ecomp-portal-FE-common/client/app/views/widget-onboarding/widget-details-dialog/widget-details.modal.html b/ecomp-portal-FE-common/client/app/views/widget-onboarding/widget-details-dialog/widget-details.modal.html index fd3a1248..ade07b95 100644 --- a/ecomp-portal-FE-common/client/app/views/widget-onboarding/widget-details-dialog/widget-details.modal.html +++ b/ecomp-portal-FE-common/client/app/views/widget-onboarding/widget-details-dialog/widget-details.modal.html @@ -145,7 +145,7 @@ </div> </div> - <div class="item required"> + <div ng-show=" widgetOnboardingDetails.uploadFlag"> <div class="item-label">Upload Widget</div> <div> <input id="widget-onboarding-details-upload-file" |