From 978dbcf0a196acbafad72fe1e2478ec0e384f02f Mon Sep 17 00:00:00 2001 From: "Christopher Lott (cl778h)" Date: Wed, 23 Aug 2017 18:27:19 -0400 Subject: [PATCH] Deliver centralized role management feature Repair multiple defects also. Revise deployment to use docker-compose. Remove all zip archives. Issue: PORTAL-21, PORTAL-25, PORTAL-28, PORTAL-52, PORTAL-69, PORTAL-74, PORTAL-76, PORTAL-80, PORTAL-82 Change-Id: Ie72fec7d35ba78beb162bba6ed27b2caee340c61 Signed-off-by: Christopher Lott (cl778h) --- deliveries/.env | 17 + deliveries/.gitignore | 2 +- deliveries/Apps_Users_OnBoarding_Script.sql | 6 +- deliveries/Dockerfile.mariadb | 36 +- deliveries/Dockerfile.portalapps | 33 +- deliveries/Dockerfile.widgetms | 18 + deliveries/README.md | 7 +- deliveries/build_portalapps_dockers.sh | 147 +- deliveries/createMaria.sh | 9 - deliveries/dbstart.sh | 9 - deliveries/dbstop.sh | 9 - deliveries/docker-compose.yml | 83 + deliveries/etc.zip | Bin 11426 -> 0 bytes deliveries/new_start.sh | 29 - deliveries/new_stop.sh | 9 - deliveries/os_Dockerfile | 84 - deliveries/os_build_febe.sh | 84 - deliveries/os_docker_base.sh | 49 + deliveries/os_docker_push.sh | 41 +- deliveries/os_docker_release.sh | 41 +- deliveries/os_settings.sh | 30 - deliveries/portal_vm_init.sh | 81 +- .../ECOMPDBCAPP/dbcapp.properties | 8 + .../ECOMPDBCAPP/fusion.properties | 33 + .../ECOMPDBCAPP/portal.properties | 25 + .../ECOMPDBCAPP/system.properties | 63 + .../ECOMPPORTALAPP/fusion.properties | 46 + .../ECOMPPORTALAPP/logback.xml | 285 + .../ECOMPPORTALAPP/openid-connect.properties | 3 + .../ECOMPPORTALAPP/portal.properties | 23 + .../ECOMPPORTALAPP/system.properties | 97 + .../ECOMPSDKAPP/fusion.properties | 35 + .../ECOMPSDKAPP/portal.properties | 44 + .../ECOMPSDKAPP/system.properties | 65 + .../ECOMPWIDGETMS/application.properties | 35 + deliveries/run.sh | 10 - .../{configure-and-run.sh => start-apps-cmd.sh} | 2 +- deliveries/start-wms-cmd.sh | 2 + deliveries/wait-for.sh | 82 + deliveries/widget_ms_start.sh | 10 - deliveries/widget_ms_stop.sh | 9 - ecomp-portal-BE-common-test/pom.xml | 6 +- ecomp-portal-BE-common/pom.xml | 16 +- .../config/PortalCentralAccessConfiguration.java | 29 + .../controller/AppsControllerExternalRequest.java | 4 +- .../controller/ExternalAccessRolesController.java | 330 + .../portal/controller/RoleManageController.java | 19 +- .../controller/RolesApprovalSystemController.java | 17 +- .../controller/SharedContextRestController.java | 6 +- .../portal/controller/TicketEventController.java | 27 +- .../portal/domain/CentralRoleFunction.java | 100 + .../openecomp/portalapp/portal/domain/EPApp.java | 25 +- .../portalapp/portal/domain/EPAppRoleFunction.java | 50 + .../{EpUserAppRoles.java => EPUserAppRoles.java} | 2 +- .../portalapp/portal/domain/EcompApp.java | 22 + .../portal/domain/ExternalRoleDetails.java | 78 + .../portal/logging/aop/EPEELFLoggerAdvice.java | 2 + .../portal/logging/format/EPAppMessagesEnum.java | 1 - .../portal/logging/format/EPErrorCodesEnum.java | 1 - .../portal/service/AdminRolesServiceImpl.java | 160 +- .../portal/service/EPAppCommonServiceImpl.java | 79 +- .../portalapp/portal/service/EPAppService.java | 10 +- .../portal/service/EPLeftMenuServiceImpl.java | 2 +- .../portal/service/EPRoleFunctionService.java | 31 + .../EPRoleFunctionServiceCentralizedImpl.java | 70 + .../portal/service/EPRoleFunctionServiceImpl.java | 79 + .../portal/service/ExternalAccessRolesService.java | 190 + .../service/ExternalAccessRolesServiceImpl.java | 1678 ++ .../portal/service/PortalAdminServiceImpl.java | 92 +- .../portal/service/SharedContextServiceImpl.java | 4 +- .../portal/service/UserRolesCommonServiceImpl.java | 564 +- .../portal/service/WidgetParameterServiceImpl.java | 4 +- .../portal/transport/BulkUploadRoleFunction.java | 68 + .../portal/transport/BulkUploadUserRoles.java | 83 + .../portalapp/portal/transport/CentralApp.java | 210 + .../portalapp/portal/transport/CentralRole.java | 159 + .../portalapp/portal/transport/CentralUser.java | 139 + .../portalapp/portal/transport/CentralUserApp.java | 70 + .../portal/transport/EPUserAppCurrentRoles.java | 98 + .../portal/transport/EcompUserAppRoles.java | 66 + .../portal/transport/EpNotificationItem.java | 11 + .../portal/transport/EpNotificationItemVO.java | 12 + .../portalapp/portal/transport/EventWidget.java | 1 - .../portal/transport/ExternalAccessPerms.java | 96 + .../transport/ExternalAccessPermsDetail.java | 90 + .../portal/transport/ExternalAccessRole.java | 39 + .../portal/transport/ExternalAccessRolePerms.java | 29 + .../portal/transport/ExternalAccessUser.java | 28 + .../transport/ExternalAccessUserRoleDetail.java | 36 + .../portal/transport/ExternalRoleDescription.java | 50 + .../portalapp/portal/transport/OnboardingApp.java | 4 + .../portalapp/portal/ueb/EPUebHelper.java | 2 +- .../portal/utils/EPCommonSystemProperties.java | 9 +- .../portalapp/portal/utils/EcompPortalUtils.java | 44 + .../portalapp/portal/utils/PortalConstants.java | 3 +- .../org/openecomp/portalapp/util/EPUserUtils.java | 67 +- .../src/main/webapp/WEB-INF/fusion/orm/EP.hbm.xml | 281 +- .../src/main/webapp/WEB-INF/jsp/login.jsp | 120 - .../src/main/webapp/WEB-INF/jsp/login_external.jsp | 162 - .../src/main/webapp/static/ebz/angular_js/app.js | 3 - .../static/fusion/images/onap-portal-logo.png | Bin 71199 -> 58332 bytes ecomp-portal-BE-os/README.md | 9 +- ecomp-portal-BE-os/pom.xml | 192 +- .../authentication/OpenIdConnectLoginStrategy.java | 2 +- .../authentication/SimpleLoginStrategy.java | 6 +- .../portalapp/conf/ExternalAppConfig.java | 2 +- .../portalapp/controller/LoginController.java | 9 +- .../portalapp/portal/transport/OnboardingApp.java | 4 + .../src/main/resources/portal.properties | 5 + .../src/main/webapp/WEB-INF/conf/raptor.properties | 2 +- .../src/main/webapp/WEB-INF/conf/system.properties | 5 +- .../src/main/webapp/WEB-INF/jsp/login.jsp | 3 +- .../portalapp/portal/framework/MockTestSuite.java | 68 + .../EcompPortalDDLMySql_1710_Common.sql | 1769 ++ .../EcompPortalDMLMySql_1707_Common.sql | 22 +- .../EcompPortalDMLMySql_1710_Common.sql | 280 + ecomp-portal-DB-common/README.md | 2 + ecomp-portal-DB-os/EcompPortalDDLMySql_1710_OS.sql | 12 + ecomp-portal-DB-os/EcompPortalDMLMySql_1710_OS.sql | 79 + ecomp-portal-DB-os/README.md | 16 +- .../client/app/directives/left-menu/left-menu.less | 6 + .../multiple-select/multiple-select.less | 4 + .../multiple-select/multiple-select.tpl.html | 4 +- .../services/confirm-box/confirm-box.service.js | 389 +- .../client/app/services/utils/utils.service.js | 8 + .../client/app/styles/appDS2.less | 7 + .../account-add-details/account-add-details.html | 81 +- .../account-add-details/account-add-details.js | 27 +- .../account-add-details/account-add-details.less | 13 +- .../account-onboarding.controller.js | 28 +- .../add-admin-dialogs/new-admin.controller.js | 15 +- .../admins/add-admin-dialogs/new-admin.modal.html | 131 +- .../admins/add-admin-dialogs/new-admin.modal.less | 51 +- .../client/app/views/admins/admins.controller.js | 48 +- .../client/app/views/admins/admins.tpl.html | 4 +- .../application-details.modal.less | 13 +- .../add-catalog-dialogs/new-catalog.modal.less | 132 + .../client/app/views/catalog/catalog.less | 23 +- .../client/app/views/catalog/catalog.tpl.html | 66 +- .../admin-confirmation-box.tpl.html | 27 +- .../confirmation-box.controller.js | 22 +- .../confirmation-box/confirmation-box.tpl.html | 26 +- .../dragdrop-confirmation-box.tpl.html | 27 +- .../confirmation-box/information-box.tpl.html | 22 +- .../confirmation-box/reload-page-confirm.html | 36 + .../views/dashboard/dashboard-widget-manage.html | 78 +- .../dashboard-widget-parameter-manage.html | 28 +- .../dashboard-widget-parameters.controller.js | 8 +- .../dashboard/dashboard-widget.controller.less | 57 +- .../app/views/dashboard/dashboard.controller.js | 43 +- .../client/app/views/dashboard/dashboard.less | 43 +- .../client/app/views/dashboard/dashboard.tpl.html | 33 +- .../menu-details.controller.js | 178 +- .../functionalMenu-dialog/menu-details.modal.html | 83 +- .../functionalMenu-dialog/modal-details.modal.less | 28 +- .../app/views/functionalMenu/functionalMenu.less | 48 +- .../client/app/views/header/header.controller.js | 71 +- .../client/app/views/header/header.less | 31 + .../client/app/views/header/header.tpl.html | 36 +- .../microservice-add-details.html | 60 +- .../microservice-add-details.js | 13 +- .../microservice-add-details.less | 48 +- .../microservice-onboarding.controller.js | 25 +- .../notificationhistory.controller.js | 55 +- .../notification-history/notificationhistory.less | 11 + .../notificationhistory.tpl.html | 6 +- .../new-portal-admin.controller.js | 8 +- .../new-portal-admin/new-portal-admin.modal.html | 42 +- .../new-portal-admin/new-portal-admin.modal.less | 2 +- .../views/portal-admin/portal-admin-controller.js | 24 +- .../app/views/portal-admin/portal-admin.tpl.html | 12 +- .../app/views/role/popup_modal_rolefunction.html | 95 +- .../client/app/views/role/role-controller.js | 212 +- .../views/role/role-function-list-controller.js | 165 +- .../client/app/views/role/role-list-controller.js | 72 +- .../client/app/views/role/role.html | 37 +- .../client/app/views/role/role.less | 25 +- .../app/views/role/role_childrole_popup.html | 19 +- .../client/app/views/role/role_function_list.html | 11 +- .../app/views/role/role_functions_popup.html | 38 +- .../client/app/views/role/role_list.html | 27 +- .../app/views/role/rolefunctionpopupController.js | 156 +- .../app/views/role/rolepopupmodelController.js | 33 +- .../client/app/views/search/search.less | 8 + .../contact-us-manage.controller.less | 46 + .../contact-us-manage/contact-us-manage.html | 255 +- .../support/contact-us/contact-us.controller.js | 33 +- .../app/views/support/contact-us/contact-us.less | 40 + .../views/support/contact-us/contact-us.tpl.html | 22 +- .../client/app/views/tabs/tabframe.html | 2 +- .../client/app/views/tabs/tabs.less | 31 +- .../user.notifications.Json.details.controller.js | 13 +- ...user.notifications.Json.details.modal.page.html | 76 +- .../user.notifications.controller.js | 123 +- ...user.notifications.json.details.modal.page.less | 37 +- .../user.notifications.less | 16 + .../user.notifications.modal.controller.js | 1085 +- .../user.notifications.modal.less | 32 +- .../user.notifications.modal.page.html | 181 +- .../user.notifications.tpl.html | 17 +- .../users/new-user-dialogs/bulk-user.ack.html | 2 +- .../users/new-user-dialogs/bulk-user.confirm.html | 22 +- .../users/new-user-dialogs/bulk-user.controller.js | 15 +- .../users/new-user-dialogs/bulk-user.modal.html | 81 +- .../users/new-user-dialogs/bulk-user.modal.less | 5 +- .../users/new-user-dialogs/new-user.controller.js | 27 +- .../users/new-user-dialogs/new-user.modal.html | 143 +- .../users/new-user-dialogs/new-user.modal.less | 62 +- .../client/app/views/users/users.controller.js | 56 +- .../client/app/views/users/users.tpl.html | 14 +- .../widget-details.controller.js | 18 +- .../widget-details.modal.html | 85 +- .../widget-details.modal.less | 13 +- .../widget-onboarding.controller.js | 27 +- .../widget-details.modal.html | 4 +- .../widget-details.modal.less | 7 +- .../b2b/css/b2b-angular/README.md | 7 +- .../b2b/css/b2b-angular/b2b-angular.css | 577 +- .../b2b/js/b2b-angular/README.md | 2 + .../b2b/js/b2b-angular/b2b-library.min.js | 18634 ++++++++++--------- ecomp-portal-FE-common/pom.xml | 4 +- .../client/assets/images/onap-logo.png | Bin 29116 -> 52523 bytes .../ionicons-2.0.1/css/ecomp-ionicons.css | 27 +- ecomp-portal-FE-os/client/index.html | 6 +- ecomp-portal-FE-os/client/src/app.less | 17 +- .../src/directives/search-users/search-users.less | 2 +- .../directives/search-users/search-users.tpl.html | 4 +- ecomp-portal-FE-os/client/src/router.js | 9 + .../services/userProfile/userProfile.service.js | 4 +- .../src/styles/{att-abs.less => ecomp-abs.less} | 0 .../application-details.controller.js | 31 +- .../application-details.modal.html | 78 +- .../views/applications/applications.controller.js | 34 +- .../src/views/applications/applications.tpl.html | 6 +- .../menu-details.controller.js | 415 - .../functionalMenu-dialog/menu-details.modal.html | 103 - .../functionalMenu/functionalMenu.controller.js | 52 +- ecomp-portal-FE-os/pom.xml | 2 +- ecomp-portal-widget-ms/.gitignore | 36 +- .../1702-widgets/approx-portal-usage.zip | Bin 90114 -> 0 bytes .../1702-widgets/daily-app-usage-count.zip | Bin 52363 -> 0 bytes .../1702-widgets/daily-app-usage-count2.zip | Bin 90872 -> 0 bytes .../1702-widgets/widget_events.zip | Bin 1504004 -> 0 bytes .../1702-widgets/widget_news.zip | Bin 1503954 -> 0 bytes .../1702-widgets/widget_resources.zip | Bin 1504661 -> 0 bytes ecomp-portal-widget-ms/README.md | 223 +- ecomp-portal-widget-ms/common-widgets/.gitignore | 5 + .../common-widgets/assembly-descriptor-events.xml | 23 + .../common-widgets/assembly-descriptor-news.xml | 23 + .../assembly-descriptor-resources.xml | 23 + .../common-widgets/events-widget/js/controller.js | 64 + .../events-widget/markup/markup.html | 49 + .../events-widget/styles/app-widget-1-by-3.css | 43 + .../events-widget/styles/images/generic.png | Bin 0 -> 208 bytes .../events-widget/styles/images/grips.png | Bin 0 -> 951 bytes .../common-widgets/events-widget/styles/styles.css | 43 + .../common-widgets/news-widget/js/controller.js | 60 + .../common-widgets/news-widget/markup/markup.html | 21 + .../news-widget/styles/app-widget-1-by-3.css | 43 + .../news-widget/styles/app-widget.css | 43 + .../news-widget/styles/images/generic.png | Bin 0 -> 208 bytes .../news-widget/styles/images/grips.png | Bin 0 -> 951 bytes .../common-widgets/news-widget/styles/style.css | 43 + .../common-widgets/news-widget/styles/styles.css | 43 + ecomp-portal-widget-ms/common-widgets/pom.xml | 79 + .../resources-widget/js/controller.js | 60 + .../resources-widget/markup/markup.html | 21 + .../resources-widget/styles/app-widget-1-by-3.css | 43 + .../resources-widget/styles/app-widget.css | 43 + .../resources-widget/styles/images/generic.png | Bin 0 -> 208 bytes .../resources-widget/styles/images/grips.png | Bin 0 -> 951 bytes .../resources-widget/styles/style.css | 43 + .../resources-widget/styles/styles.css | 43 + .../dashboard-widgets/approx-portal-usage.zip | Bin 5017 -> 0 bytes .../dashboard-widgets/approx-portal-usage2.zip | Bin 5062 -> 0 bytes .../dashboard-widgets/ccd_widget.zip | Bin 1502265 -> 0 bytes .../dashboard-widgets/daily-app-usage-count.zip | Bin 4962 -> 0 bytes .../dashboard-widgets/events-widget.zip | Bin 1501585 -> 0 bytes .../dashboard-widgets/news-widget.zip | Bin 1502150 -> 0 bytes .../dashboard-widgets/resources-widget.zip | Bin 1502662 -> 0 bytes ecomp-portal-widget-ms/java | 0 ecomp-portal-widget-ms/pom.xml | 184 +- .../portalapp/widget/utils/UnzipUtil.java | 102 - .../src/main/resources/events-widget.zip | Bin 1501585 -> 0 bytes .../src/main/resources/news-widget.zip | Bin 1502150 -> 0 bytes .../src/main/resources/resources-widget.zip | Bin 1502662 -> 0 bytes ecomp-portal-widget-ms/widget-ms/.gitignore | 39 + ecomp-portal-widget-ms/widget-ms/README.md | 189 + ...ment Guide Portal Microservices and Consul.docx | Bin ecomp-portal-widget-ms/widget-ms/pom.xml | 170 + .../src/main/certificates/be1/widget-keystore.p12 | Bin .../src/main/certificates/be2/widget-keystore.p12 | Bin .../{ => widget-ms}/src/main/docker/Dockerfile | 0 .../portalapp/widget/MicroserviceApplication.java | 1 - .../portalapp/widget/constant/WidgetConstant.java | 2 - .../controller/DatabaseFileUploadController.java | 3 - .../widget/controller/HealthController.java | 0 .../controller/WidgetsCatalogController.java | 2 +- .../portalapp/widget/dao/WidgetDataSource.java | 0 .../org/openecomp/portalapp/widget/domain/App.java | 0 .../portalapp/widget/domain/MicroserviceData.java | 0 .../widget/domain/MicroserviceParameter.java | 0 .../openecomp/portalapp/widget/domain/RoleApp.java | 1 - .../portalapp/widget/domain/ValidationRespond.java | 0 .../portalapp/widget/domain/WidgetCatalog.java | 6 +- .../portalapp/widget/domain/WidgetFile.java | 0 .../widget/excetpion/StorageException.java | 0 .../excetpion/StorageFileNotFoundException.java | 0 .../widget/filters/CorsConfiguration.java | 0 .../widget/hibernate/HibernateConfiguration.java | 0 .../widget/listener/WidgetEventListener.java | 2 +- .../widget/service/InitializationService.java | 0 .../widget/service/MicroserviceService.java | 0 .../portalapp/widget/service/StorageService.java | 0 .../widget/service/WidgetCatalogService.java | 1 - .../service/impl/InitializationServiceImpl.java | 89 +- .../service/impl/MicroserviceServiceImpl.java | 1 - .../widget/service/impl/StorageServiceImpl.java | 242 +- .../service/impl/WidgetCatalogServiceImpl.java | 3 + .../portalapp/widget/utils/AuthorizationUtil.java | 0 .../portalapp/widget/utils/UnzipUtil.java | 110 + .../src/main/resources/application-properties | 0 .../resources/application.properties.templated | 0 .../src/main/resources/framework-template.js | 0 .../{ => widget-ms}/src/main/resources/logback.xml | 0 .../src/main/resources/templates/Upload.html | 0 .../src/main/resources/templates/widgetsPage.html | 0 .../src/main/resources/widget-keystore.p12 | Bin .../src/main/resources/widget_ms_start.sh | 0 .../src/main/resources/widget_ms_stop.sh | 0 .../test/controller/WidgetFileControllerTest.java | 0 .../controller/WidgetsCatalogControllerTest.java | 0 .../test/service/WidgetCatalogServiceTest.java | 0 ecomp-portal-widget-ms/{ => widget-ms}/testadd.txt | 0 ecomp-portal-widget-ms/{ => widget-ms}/website.url | Bin pom.xml | 1 + 336 files changed, 24091 insertions(+), 13823 deletions(-) create mode 100644 deliveries/.env create mode 100644 deliveries/Dockerfile.widgetms delete mode 100755 deliveries/createMaria.sh delete mode 100755 deliveries/dbstart.sh delete mode 100755 deliveries/dbstop.sh create mode 100644 deliveries/docker-compose.yml delete mode 100644 deliveries/etc.zip delete mode 100755 deliveries/new_start.sh delete mode 100755 deliveries/new_stop.sh delete mode 100644 deliveries/os_Dockerfile delete mode 100755 deliveries/os_build_febe.sh create mode 100755 deliveries/os_docker_base.sh delete mode 100755 deliveries/os_settings.sh create mode 100644 deliveries/properties_rackspace/ECOMPDBCAPP/dbcapp.properties create mode 100644 deliveries/properties_rackspace/ECOMPDBCAPP/fusion.properties create mode 100644 deliveries/properties_rackspace/ECOMPDBCAPP/portal.properties create mode 100644 deliveries/properties_rackspace/ECOMPDBCAPP/system.properties create mode 100644 deliveries/properties_rackspace/ECOMPPORTALAPP/fusion.properties create mode 100644 deliveries/properties_rackspace/ECOMPPORTALAPP/logback.xml create mode 100644 deliveries/properties_rackspace/ECOMPPORTALAPP/openid-connect.properties create mode 100644 deliveries/properties_rackspace/ECOMPPORTALAPP/portal.properties create mode 100644 deliveries/properties_rackspace/ECOMPPORTALAPP/system.properties create mode 100644 deliveries/properties_rackspace/ECOMPSDKAPP/fusion.properties create mode 100644 deliveries/properties_rackspace/ECOMPSDKAPP/portal.properties create mode 100644 deliveries/properties_rackspace/ECOMPSDKAPP/system.properties create mode 100644 deliveries/properties_rackspace/ECOMPWIDGETMS/application.properties delete mode 100755 deliveries/run.sh rename deliveries/{configure-and-run.sh => start-apps-cmd.sh} (94%) create mode 100755 deliveries/start-wms-cmd.sh create mode 100755 deliveries/wait-for.sh delete mode 100755 deliveries/widget_ms_start.sh delete mode 100755 deliveries/widget_ms_stop.sh create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/config/PortalCentralAccessConfiguration.java create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/ExternalAccessRolesController.java create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/CentralRoleFunction.java create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/EPAppRoleFunction.java rename ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/{EpUserAppRoles.java => EPUserAppRoles.java} (97%) create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/ExternalRoleDetails.java create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPRoleFunctionService.java create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPRoleFunctionServiceCentralizedImpl.java create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPRoleFunctionServiceImpl.java create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/ExternalAccessRolesService.java create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/ExternalAccessRolesServiceImpl.java create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/BulkUploadRoleFunction.java create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/BulkUploadUserRoles.java create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/CentralApp.java create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/CentralRole.java create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/CentralUser.java create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/CentralUserApp.java create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/EPUserAppCurrentRoles.java create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/EcompUserAppRoles.java create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessPerms.java create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessPermsDetail.java create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessRole.java create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessRolePerms.java create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessUser.java create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessUserRoleDetail.java create mode 100644 ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalRoleDescription.java delete mode 100644 ecomp-portal-BE-common/src/main/webapp/WEB-INF/jsp/login.jsp delete mode 100644 ecomp-portal-BE-common/src/main/webapp/WEB-INF/jsp/login_external.jsp delete mode 100644 ecomp-portal-BE-common/src/main/webapp/static/ebz/angular_js/app.js create mode 100644 ecomp-portal-BE-os/src/test/java/org/openecomp/portalapp/portal/framework/MockTestSuite.java create mode 100644 ecomp-portal-DB-common/EcompPortalDDLMySql_1710_Common.sql create mode 100644 ecomp-portal-DB-common/EcompPortalDMLMySql_1710_Common.sql create mode 100644 ecomp-portal-DB-os/EcompPortalDDLMySql_1710_OS.sql create mode 100644 ecomp-portal-DB-os/EcompPortalDMLMySql_1710_OS.sql create mode 100644 ecomp-portal-FE-common/client/app/styles/appDS2.less create mode 100644 ecomp-portal-FE-common/client/app/views/catalog/add-catalog-dialogs/new-catalog.modal.less create mode 100644 ecomp-portal-FE-common/client/app/views/confirmation-box/reload-page-confirm.html rename ecomp-portal-FE-os/client/src/styles/{att-abs.less => ecomp-abs.less} (100%) delete mode 100644 ecomp-portal-FE-os/client/src/views/functionalMenu/functionalMenu-dialog/menu-details.controller.js delete mode 100644 ecomp-portal-FE-os/client/src/views/functionalMenu/functionalMenu-dialog/menu-details.modal.html delete mode 100644 ecomp-portal-widget-ms/1702-widgets/approx-portal-usage.zip delete mode 100644 ecomp-portal-widget-ms/1702-widgets/daily-app-usage-count.zip delete mode 100644 ecomp-portal-widget-ms/1702-widgets/daily-app-usage-count2.zip delete mode 100644 ecomp-portal-widget-ms/1702-widgets/widget_events.zip delete mode 100644 ecomp-portal-widget-ms/1702-widgets/widget_news.zip delete mode 100644 ecomp-portal-widget-ms/1702-widgets/widget_resources.zip create mode 100644 ecomp-portal-widget-ms/common-widgets/.gitignore create mode 100644 ecomp-portal-widget-ms/common-widgets/assembly-descriptor-events.xml create mode 100644 ecomp-portal-widget-ms/common-widgets/assembly-descriptor-news.xml create mode 100644 ecomp-portal-widget-ms/common-widgets/assembly-descriptor-resources.xml create mode 100644 ecomp-portal-widget-ms/common-widgets/events-widget/js/controller.js create mode 100644 ecomp-portal-widget-ms/common-widgets/events-widget/markup/markup.html create mode 100644 ecomp-portal-widget-ms/common-widgets/events-widget/styles/app-widget-1-by-3.css create mode 100644 ecomp-portal-widget-ms/common-widgets/events-widget/styles/images/generic.png create mode 100644 ecomp-portal-widget-ms/common-widgets/events-widget/styles/images/grips.png create mode 100644 ecomp-portal-widget-ms/common-widgets/events-widget/styles/styles.css create mode 100644 ecomp-portal-widget-ms/common-widgets/news-widget/js/controller.js create mode 100644 ecomp-portal-widget-ms/common-widgets/news-widget/markup/markup.html create mode 100644 ecomp-portal-widget-ms/common-widgets/news-widget/styles/app-widget-1-by-3.css create mode 100644 ecomp-portal-widget-ms/common-widgets/news-widget/styles/app-widget.css create mode 100644 ecomp-portal-widget-ms/common-widgets/news-widget/styles/images/generic.png create mode 100644 ecomp-portal-widget-ms/common-widgets/news-widget/styles/images/grips.png create mode 100644 ecomp-portal-widget-ms/common-widgets/news-widget/styles/style.css create mode 100644 ecomp-portal-widget-ms/common-widgets/news-widget/styles/styles.css create mode 100644 ecomp-portal-widget-ms/common-widgets/pom.xml create mode 100644 ecomp-portal-widget-ms/common-widgets/resources-widget/js/controller.js create mode 100644 ecomp-portal-widget-ms/common-widgets/resources-widget/markup/markup.html create mode 100644 ecomp-portal-widget-ms/common-widgets/resources-widget/styles/app-widget-1-by-3.css create mode 100644 ecomp-portal-widget-ms/common-widgets/resources-widget/styles/app-widget.css create mode 100644 ecomp-portal-widget-ms/common-widgets/resources-widget/styles/images/generic.png create mode 100644 ecomp-portal-widget-ms/common-widgets/resources-widget/styles/images/grips.png create mode 100644 ecomp-portal-widget-ms/common-widgets/resources-widget/styles/style.css create mode 100644 ecomp-portal-widget-ms/common-widgets/resources-widget/styles/styles.css delete mode 100644 ecomp-portal-widget-ms/dashboard-widgets/approx-portal-usage.zip delete mode 100644 ecomp-portal-widget-ms/dashboard-widgets/approx-portal-usage2.zip delete mode 100644 ecomp-portal-widget-ms/dashboard-widgets/ccd_widget.zip delete mode 100644 ecomp-portal-widget-ms/dashboard-widgets/daily-app-usage-count.zip delete mode 100644 ecomp-portal-widget-ms/dashboard-widgets/events-widget.zip delete mode 100644 ecomp-portal-widget-ms/dashboard-widgets/news-widget.zip delete mode 100644 ecomp-portal-widget-ms/dashboard-widgets/resources-widget.zip delete mode 100644 ecomp-portal-widget-ms/java delete mode 100644 ecomp-portal-widget-ms/src/main/java/org/openecomp/portalapp/widget/utils/UnzipUtil.java delete mode 100644 ecomp-portal-widget-ms/src/main/resources/events-widget.zip delete mode 100644 ecomp-portal-widget-ms/src/main/resources/news-widget.zip delete mode 100644 ecomp-portal-widget-ms/src/main/resources/resources-widget.zip create mode 100644 ecomp-portal-widget-ms/widget-ms/.gitignore create mode 100644 ecomp-portal-widget-ms/widget-ms/README.md rename ecomp-portal-widget-ms/{ => widget-ms}/docs/Deployment Guide Portal Microservices and Consul.docx (100%) create mode 100644 ecomp-portal-widget-ms/widget-ms/pom.xml rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/certificates/be1/widget-keystore.p12 (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/certificates/be2/widget-keystore.p12 (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/docker/Dockerfile (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/MicroserviceApplication.java (88%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/constant/WidgetConstant.java (96%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/controller/DatabaseFileUploadController.java (95%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/controller/HealthController.java (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/controller/WidgetsCatalogController.java (99%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/dao/WidgetDataSource.java (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/domain/App.java (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/domain/MicroserviceData.java (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/domain/MicroserviceParameter.java (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/domain/RoleApp.java (98%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/domain/ValidationRespond.java (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/domain/WidgetCatalog.java (90%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/domain/WidgetFile.java (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/excetpion/StorageException.java (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/excetpion/StorageFileNotFoundException.java (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/filters/CorsConfiguration.java (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/hibernate/HibernateConfiguration.java (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/listener/WidgetEventListener.java (87%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/service/InitializationService.java (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/service/MicroserviceService.java (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/service/StorageService.java (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/service/WidgetCatalogService.java (92%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/service/impl/InitializationServiceImpl.java (73%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/service/impl/MicroserviceServiceImpl.java (97%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/service/impl/StorageServiceImpl.java (81%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/service/impl/WidgetCatalogServiceImpl.java (98%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/java/org/openecomp/portalapp/widget/utils/AuthorizationUtil.java (100%) create mode 100644 ecomp-portal-widget-ms/widget-ms/src/main/java/org/openecomp/portalapp/widget/utils/UnzipUtil.java rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/resources/application-properties (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/resources/application.properties.templated (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/resources/framework-template.js (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/resources/logback.xml (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/resources/templates/Upload.html (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/resources/templates/widgetsPage.html (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/resources/widget-keystore.p12 (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/resources/widget_ms_start.sh (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/main/resources/widget_ms_stop.sh (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/test/java/org/openecomp/portalapp/widget/test/controller/WidgetFileControllerTest.java (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/test/java/org/openecomp/portalapp/widget/test/controller/WidgetsCatalogControllerTest.java (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/src/test/java/org/openecomp/portalapp/widget/test/service/WidgetCatalogServiceTest.java (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/testadd.txt (100%) rename ecomp-portal-widget-ms/{ => widget-ms}/website.url (100%) diff --git a/deliveries/.env b/deliveries/.env new file mode 100644 index 00000000..fa307685 --- /dev/null +++ b/deliveries/.env @@ -0,0 +1,17 @@ +# Environment settings +# used by docker-compose AND by other shell scripts + +# Host directory with config files +PROJECT_DIR=/PROJECT/OpenSource/UbuntuEP + +# Directory within containers +WEBAPPS_DIR=/opt/apache-tomcat-8.0.37/webapps + +# Following are ALSO used in demo/boot/portal_vm_init.sh +EP_IMG_NAME=portal-apps +DB_IMG_NAME=portal-db +WMS_IMG_NAME=portal-wms +# Tag all images with this +PORTAL_TAG=1.1.0 + +NEXUS_REPO=nexus3.onap.org:10003 diff --git a/deliveries/.gitignore b/deliveries/.gitignore index f12ac3a0..796b96d1 100644 --- a/deliveries/.gitignore +++ b/deliveries/.gitignore @@ -1 +1 @@ -/PROJECT +/build diff --git a/deliveries/Apps_Users_OnBoarding_Script.sql b/deliveries/Apps_Users_OnBoarding_Script.sql index ff3d3e96..2d1adfb5 100644 --- a/deliveries/Apps_Users_OnBoarding_Script.sql +++ b/deliveries/Apps_Users_OnBoarding_Script.sql @@ -345,14 +345,14 @@ select * from fn_role where app_id = (select app_id from fn_app where app_name = ) b ); -- end new -INSERT INTO `fn_common_widget_data` (`id`,`CATEGORY`,`HREF`,`TITLE`,`content`,`event_date`,`SORT_ORDER`) VALUES (6,'NEWS','http://about.att.com/innovationblog/next_att_labs','What\s Next at AT&T Labs? AI Set to Revolutionize the Network',NULL,NULL,10); -INSERT INTO `fn_common_widget_data` (`id`,`CATEGORY`,`HREF`,`TITLE`,`content`,`event_date`,`SORT_ORDER`) VALUES (7,'NEWS','http://about.att.com/innovationblog/ecomp_code','Code, Community and Commitment – the 3 Cs of Open Source',NULL,NULL,20); +INSERT INTO `fn_common_widget_data` (`id`,`CATEGORY`,`HREF`,`TITLE`,`content`,`event_date`,`SORT_ORDER`) VALUES (6,'NEWS','http://about.att.com/innovationblog/next_att_labs','What\'s Next at AT&T Labs? AI Set to Revolutionize the Network',NULL,NULL,10); +INSERT INTO `fn_common_widget_data` (`id`,`CATEGORY`,`HREF`,`TITLE`,`content`,`event_date`,`SORT_ORDER`) VALUES (7,'NEWS','http://about.att.com/innovationblog/ecomp_code','Code, Community and Commitment - the 3 Cs of Open Source',NULL,NULL,20); INSERT INTO `fn_common_widget_data` (`id`,`CATEGORY`,`HREF`,`TITLE`,`content`,`event_date`,`SORT_ORDER`) VALUES (8,'NEWS','http://about.att.com/story/orange_testing_att_open_source_ecomp_platform.html','Orange Testing AT&Ts Open Source ECOMP Platform for Building Software-Defined Network Capabilities',NULL,NULL,30); INSERT INTO `fn_common_widget_data` (`id`,`CATEGORY`,`HREF`,`TITLE`,`content`,`event_date`,`SORT_ORDER`) VALUES (9,'NEWS', 'http://about.att.com/innovationblog/linux_foundation','Opening up ECOMP: Our Network Operating System for SDN',NULL,NULL,40); INSERT INTO `fn_common_widget_data` (`id`,`CATEGORY`,`HREF`,`TITLE`,`content`,`event_date`,`SORT_ORDER`) VALUES (10,'EVENTS',NULL,'OpenECOMP Launches into Open Source',NULL,'2017-02-14',1); INSERT INTO `fn_common_widget_data` (`id`,`CATEGORY`,`HREF`,`TITLE`,`content`,`event_date`,`SORT_ORDER`) VALUES (11,'IMPORTANTRESOURCES','http://about.att.com/content/dam/snrdocs/ecomp.pdf','ECOMP White Paper',NULL,NULL,1); INSERT INTO `fn_common_widget_data` (`id`,`CATEGORY`,`HREF`,`TITLE`,`content`,`event_date`,`SORT_ORDER`) VALUES (12,'IMPORTANTRESOURCES','https://wiki.onap.org/','ONAP Wiki',NULL,NULL,2); -INSERT INTO `fn_common_widget_data` (`id`,`CATEGORY`,`HREF`,`TITLE`,`content`,`event_date`,`SORT_ORDER`) VALUES (13,'IMPORTANTRESOURCES','https://wiki.onap.org/display/DW/Portal','ONAP Wiki, Portal',NULL,NULL,3); +INSERT INTO `fn_common_widget_data` (`id`,`CATEGORY`,`HREF`,`TITLE`,`content`,`event_date`,`SORT_ORDER`) VALUES (13,'IMPORTANTRESOURCES','https://wiki.onap.org/display/DW/Portal','ONAP Wiki for Portal',NULL,NULL,3); INSERT INTO `fn_common_widget_data` (`id`,`CATEGORY`,`HREF`,`TITLE`,`content`,`event_date`,`SORT_ORDER`) VALUES (14,'IMPORTANTRESOURCES','https://wiki.onap.org/display/DW/Development+Guides','ONAP User Guide',NULL,NULL,4); diff --git a/deliveries/Dockerfile.mariadb b/deliveries/Dockerfile.mariadb index 004e7af8..5b0abd51 100644 --- a/deliveries/Dockerfile.mariadb +++ b/deliveries/Dockerfile.mariadb @@ -1,34 +1,28 @@ FROM mariadb:latest -#Author -MAINTAINER Manoop talasila@research.att.com - -ARG SCRIPT_DIR=${SCRIPT_DIR} -ARG SCRIPT_COMMON_DIR=${SCRIPT_COMMON_DIR} +ARG PORTAL_SCRIPT_DIR=${PORTAL_SCRIPT_DIR} ARG SDK_SCRIPT_DIR=${SDK_SCRIPT_DIR} -ARG SDK_COMMON_SCRIPT_DIR=${SDK_COMMON_SCRIPT_DIR} -ARG DBC_COMMON_SCRIPT_DIR=${DBC_COMMON_SCRIPT_DIR} ARG DBC_SCRIPT_DIR=${DBC_SCRIPT_DIR} # constant #Add config file -ADD my.cnf /etc/mysql/my.cnf +COPY my.cnf /etc/mysql/my.cnf #ADD cluster.cnf /etc/mysql/conf.d # Scripts are executed in alphabetical order -# Portal DDL and DML -ADD ${SCRIPT_COMMON_DIR}/EcompPortalDDLMySql_1707_Common.sql docker-entrypoint-initdb.d -ADD ${SCRIPT_DIR}/EcompPortalDDLMySql_1707_OS.sql docker-entrypoint-initdb.d -ADD ${SCRIPT_COMMON_DIR}/EcompPortalDMLMySql_1707_Common.sql docker-entrypoint-initdb.d -ADD ${SCRIPT_DIR}/EcompPortalDMLMySql_1707_OS.sql docker-entrypoint-initdb.d -ADD Apps_Users_OnBoarding_Script.sql docker-entrypoint-initdb.d/EcompPortalDMLMySql_1707_z_apps_users.sql +# Portal DDL and DML at 1710 +COPY ${PORTAL_SCRIPT_DIR}/EcompPortalDDLMySql_1710_Common.sql /docker-entrypoint-initdb.d/ +COPY ${PORTAL_SCRIPT_DIR}/EcompPortalDDLMySql_1710_OS.sql /docker-entrypoint-initdb.d/ +COPY ${PORTAL_SCRIPT_DIR}/EcompPortalDMLMySql_1710_Common.sql /docker-entrypoint-initdb.d/ +COPY ${PORTAL_SCRIPT_DIR}/EcompPortalDMLMySql_1710_OS.sql /docker-entrypoint-initdb.d/ +COPY Apps_Users_OnBoarding_Script.sql /docker-entrypoint-initdb.d/EcompPortalDMLMySql_1710_z_apps_users.sql -# SDK App DDL and DML -ADD ${SDK_COMMON_SCRIPT_DIR}/EcompSdkDDLMySql_1707_Common.sql docker-entrypoint-initdb.d -ADD ${SDK_SCRIPT_DIR}/EcompSdkDDLMySql_1707_OS.sql docker-entrypoint-initdb.d -ADD ${SDK_COMMON_SCRIPT_DIR}/EcompSdkDMLMySql_1707_Common.sql docker-entrypoint-initdb.d -ADD ${SDK_SCRIPT_DIR}/EcompSdkDMLMySql_1707_OS.sql docker-entrypoint-initdb.d +# SDK App DDL and DML unchanged since 1707 +COPY ${SDK_SCRIPT_DIR}/EcompSdkDDLMySql_1707_Common.sql /docker-entrypoint-initdb.d/ +COPY ${SDK_SCRIPT_DIR}/EcompSdkDDLMySql_1707_OS.sql /docker-entrypoint-initdb.d/ +COPY ${SDK_SCRIPT_DIR}/EcompSdkDMLMySql_1707_Common.sql /docker-entrypoint-initdb.d/ +COPY ${SDK_SCRIPT_DIR}/EcompSdkDMLMySql_1707_OS.sql /docker-entrypoint-initdb.d/ -# DBC App combined DDL/DML, built by os_build_febe.sh -ADD ${DBC_SCRIPT_DIR}/dbca-complete-mysql-1707-os.sql docker-entrypoint-initdb.d +# DBC App combined DDL/DML, built by script +COPY ${DBC_SCRIPT_DIR}/dbca-complete-mysql-1707-os.sql /docker-entrypoint-initdb.d/ diff --git a/deliveries/Dockerfile.portalapps b/deliveries/Dockerfile.portalapps index 3e295e8f..c9fab4db 100644 --- a/deliveries/Dockerfile.portalapps +++ b/deliveries/Dockerfile.portalapps @@ -1,7 +1,10 @@ # Dockerfile for image with ONAP applications: # Portal app, Portal-SDK app, Portal-DBC app. -FROM openjdk:8-jdk +# Yields an image 823 MB +FROM frolvlad/alpine-oraclejdk8:slim +# Yields an image 1.4 GB +# FROM openjdk:8-jdk # Arguments are supplied by build.sh script # the defaults below only support testing @@ -12,21 +15,28 @@ ARG DBC_WAR=build/dmaap-bc-app-os.war ARG HTTP_PROXY ARG HTTPS_PROXY -# This is just a variable, never passed in -ARG TOMCATHOME=/opt/apache-tomcat-8.0.37 +# Just variables, never passed in +ARG TOMCAT=apache-tomcat-8.0.37 +ARG TOMCATTAR=${TOMCAT}.tar.gz +ARG TOMCATHOME=/opt/${TOMCAT} ENV http_proxy $HTTP_PROXY ENV https_proxy $HTTPS_PROXY RUN if [ ! -z ${HTTP_PROXY} ]; then echo "Acquire::http::proxy \"${HTTP_PROXY}\";" >> /etc/apt/apt.conf; fi && \ if [ ! -z ${HTTPS_PROXY} ]; then echo "Acquire::https::proxy \"${HTTPS_PROXY}\";" >> /etc/apt/apt.conf; fi -# Install Tomcat; curl is already part of this image +# Install the wait script +COPY wait-for.sh / + +# Install Tomcat. This image already has curl. WORKDIR /tmp -RUN curl -s -O https://archive.apache.org/dist/tomcat/tomcat-8/v8.0.37/bin/apache-tomcat-8.0.37.tar.gz -RUN tar -xzf apache-tomcat-8.0.37.tar.gz +RUN wget -q http://archive.apache.org/dist/tomcat/tomcat-8/v8.0.37/bin/apache-tomcat-8.0.37.tar.gz +RUN tar -xzf ${TOMCATTAR} +RUN rm ${TOMCATTAR} # Remove manager and sample apps -RUN rm -fr apache-tomcat-8.0.37/webapps/[a-z]* -RUN mv apache-tomcat-8.0.37 /opt +RUN rm -fr ${TOMCAT}/webapps/[a-z]* +RUN mkdir -p /opt +RUN mv ${TOMCAT} /opt WORKDIR ${TOMCATHOME}/webapps RUN mkdir ECOMPPORTAL && mkdir ECOMPSDKAPP && mkdir ECOMPDBCAPP @@ -46,9 +56,12 @@ RUN cd ECOMPDBCAPP && unzip -q *.war && rm *.war VOLUME ${TOMCATHOME}/logs +# Switch back to root +WORKDIR / + # Define commonly used ENV variables ENV PATH $PATH:$JAVA_HOME/bin:${TOMCATHOME}/bin -COPY configure-and-run.sh / +COPY start-apps-cmd.sh / # Define default command. -CMD ["/configure-and-run.sh"] +CMD /start-apps-cmd.sh diff --git a/deliveries/Dockerfile.widgetms b/deliveries/Dockerfile.widgetms new file mode 100644 index 00000000..16bf60b1 --- /dev/null +++ b/deliveries/Dockerfile.widgetms @@ -0,0 +1,18 @@ +# Large image +# FROM openjdk:8-jdk +# Very small image +FROM frolvlad/alpine-oraclejdk8:slim + +# Arguments are supplied by build script; +# the defaults below only support testing +ARG WMS_JAR=build/widget-ms.jar +# Launch script +COPY start-wms-cmd.sh / +# Wait script, which depends on nc +COPY wait-for.sh / +# Onejar +COPY ${WMS_JAR} /app.jar +RUN sh -c 'touch /app.jar' +VOLUME /tmp +ENV JAVA_OPTS="" +CMD /start-wms-cmd.sh diff --git a/deliveries/README.md b/deliveries/README.md index bc9bc3fe..99832c8e 100644 --- a/deliveries/README.md +++ b/deliveries/README.md @@ -1 +1,6 @@ - "moved insert statement to fn_common_widget_data table from EcompPortalDMLMySql_1707_OS.sql to Apps_Users_OnBoarding_Script.sql, the Onboard script in deliveries folder". +This directory has configuration files for building docker images, +and management files for starting and stopping docker containers. + +The Apps_Users_OnBoarding_Script.sql file has data for ONAP demo deployments: +it adds users and applications so the Portal app has meaningful content on +startup. These were moved from script EcompPortalDMLMySql_1707_OS.sql. diff --git a/deliveries/build_portalapps_dockers.sh b/deliveries/build_portalapps_dockers.sh index a45e55cc..ead31e82 100755 --- a/deliveries/build_portalapps_dockers.sh +++ b/deliveries/build_portalapps_dockers.sh @@ -8,16 +8,9 @@ # Stop on error; show output set -e -x -# For debugging only bcox the FE build takes a long time -SKIPFE=N -if [ $# -gt 0 -a "$1" == "skipfe" ] ; then - echo "Skipping Portal-FE build step" - SKIPFE=Y -fi - -# Establish environment variables -echo "Set variables" -source $(dirname $0)/os_settings.sh +# This reuses the docker-compose file +echo "Set image tag name variables" +source $(dirname $0)/.env # Work standalone AND in the ONAP Jenkins. # Pick up Jenkins settings for this script. @@ -25,70 +18,91 @@ source $(dirname $0)/os_settings.sh if [ -n "$MVN" ]; then export MVN="${MVN} -B -gs ${GLOBAL_SETTINGS_FILE} -s ${SETTINGS_FILE}" else - MVN=mvn + # Force refresh of snapshots + MVN="mvn -B -U" fi # This expects to start in the deliveries folder; make sure -DOCKERFILE=Dockerfile.portalapps -if [ ! -f $DOCKERFILE ] ; then - echo "Failed to find expected file; must start in deliveries folder" +PORTAL_DOCKERFILE=Dockerfile.portalapps +if [ ! -f $PORTAL_DOCKERFILE ] ; then + echo "Failed to find file ${PORTAL_DOCKERFILE}; must start in deliveries folder; exiting" exit 1 fi -# Establish directories and variables +# Store directory names as variables +# This is the Docker Project area. DELIV="$(pwd)" -# Relative path of temp directory -BUILD="build" -# Absolute path of temp directory -OUT=$DELIV/$BUILD -if [ $SKIPFE == "Y" ]; then - echo "Skipping clean/recreate of $OUT" -else - rm -fr $OUT - mkdir $OUT -fi -# parent directory +# parent directory, for finding source projects cd .. BASE="$(pwd)" - -# Copy DDL/DML to required directories (old scripts use long path /PROJECT/...) cd $DELIV -rm -fr PROJECT + +# Relative path of temp directory +BUILD_REL="build" +# Absolute path of temp directory +BUILD_ABS=$DELIV/$BUILD_REL +rm -fr $BUILD_REL +mkdir $BUILD_REL + +# Copy DDL/DML to required directories + +# RELATIVE PATHS to local directories with database scripts +# bcos Docker looks within this build area only +SCR_BASE=$BUILD_REL/scripts +PORTAL_SCRIPT_DIR=$SCR_BASE/ecomp-portal-DB-os +SDK_SCRIPT_DIR=$SCR_BASE/epsdk-app-os +DBC_SCRIPT_DIR=$SCR_BASE/dbca-os +mkdir -p ${PORTAL_SCRIPT_DIR} ${SDK_SCRIPT_DIR} ${DBC_SCRIPT_DIR} + # copy over DB scripts for the dockerfiles -# forgive the ugly trick with the .. at end. -mkdir -p ${SCRIPT_COMMON_DIR} && cp -r $BASE/ecomp-portal-DB-common ${SCRIPT_COMMON_DIR}/.. -mkdir -p ${SCRIPT_DIR} && cp -r $BASE/ecomp-portal-DB-os ${SCRIPT_DIR}/.. -mkdir -p ${SDK_COMMON_SCRIPT_DIR} && cp -r $BASE/sdk/ecomp-sdk/epsdk-app-common/db-scripts ${SDK_COMMON_SCRIPT_DIR}/.. -mkdir -p ${SDK_SCRIPT_DIR} && cp -r $BASE/sdk/ecomp-sdk/epsdk-app-os/db-scripts ${SDK_SCRIPT_DIR}/.. -# Build complete database script for DBC -DBCA_OPEN_SD=$BASE/dmaapbc/dcae_dmaapbc_webapp/dbca-os/db-scripts -DBCA_COMM_SD=$BASE/dmaapbc/dcae_dmaapbc_webapp/dbca-common/db-scripts -# Old scripts expect this path -mkdir -p $DBC_SCRIPT_DIR -cat $DBCA_OPEN_SD/dbca-create-mysql-1707-os.sql $DBCA_COMM_SD/dbca-ddl-mysql-1707-common.sql $DBCA_OPEN_SD/dbca-dml-mysql-1707-os.sql > $DBC_SCRIPT_DIR/dbca-complete-mysql-1707-os.sql - -cd $BASE/ecomp-portal-BE-common +# Portal +cp $BASE/ecomp-portal-DB-common/*.sql ${PORTAL_SCRIPT_DIR} +cp $BASE/ecomp-portal-DB-os/*.sql ${PORTAL_SCRIPT_DIR} +# SDK app +cp $BASE/sdk/ecomp-sdk/epsdk-app-common/db-scripts/*.sql ${SDK_SCRIPT_DIR} +cp $BASE/sdk/ecomp-sdk/epsdk-app-os/db-scripts/*.sql ${SDK_SCRIPT_DIR} +# DBC app +cp $BASE/dmaapbc/dcae_dmaapbc_webapp/dbca-common/db-scripts/*.sql ${DBC_SCRIPT_DIR} +cp $BASE/dmaapbc/dcae_dmaapbc_webapp/dbca-os/db-scripts/*.sql ${DBC_SCRIPT_DIR} +# Assemble a script with "use" at the top. +cat $DBC_SCRIPT_DIR/dbca-create-mysql-1707-os.sql $DBC_SCRIPT_DIR/dbca-ddl-mysql-1707-common.sql $DBC_SCRIPT_DIR/dbca-dml-mysql-1707-os.sql > $DBC_SCRIPT_DIR/dbca-complete-mysql-1707-os.sql + +# build database docker +DB_DOCKER_CMD=" + docker build -t ${DB_IMG_NAME}:${PORTAL_TAG} ${PROXY_ARGS} + --build-arg PORTAL_SCRIPT_DIR=${PORTAL_SCRIPT_DIR} + --build-arg SDK_SCRIPT_DIR=${SDK_SCRIPT_DIR} + --build-arg DBC_SCRIPT_DIR=${DBC_SCRIPT_DIR} + -f Dockerfile.mariadb . +" +echo "Build mariadb docker image" +$DB_DOCKER_CMD + +echo "Build all jar and war files in Portal" +cd $BASE ${MVN} clean install +echo "Copy Portal app BE" cd $BASE/ecomp-portal-BE-os -${MVN} clean package -cp target/ecompportal-be-os.war $OUT +cp target/ecompportal-be-os.war $BUILD_ABS +echo "Copy Portal app FE" cd $BASE/ecomp-portal-FE-os/ -if [ $SKIPFE == "Y" ]; then - echo "Skipping MVN in $(pwd)" -else - ${MVN} clean package - cp -r dist/public $OUT -fi +cp -r dist/public $BUILD_ABS + +echo "Copy Portal widget-ms" +cd $BASE/ecomp-portal-widget-ms +cp widget-ms/target/widget-ms.jar $BUILD_ABS +echo "Build and copy Portal-SDK app" cd $BASE/sdk/ecomp-sdk/epsdk-app-os ${MVN} clean package -cp target/epsdk-app-os.war $OUT +cp target/epsdk-app-os.war $BUILD_ABS +echo "Build and copy Portal-DBC app" cd $BASE/dmaapbc/dcae_dmaapbc_webapp ${MVN} clean package -cp dbca-os/target/dmaap-bc-app-os.war $OUT +cp dbca-os/target/dmaap-bc-app-os.war $BUILD_ABS PROXY_ARGS="" if [ $HTTP_PROXY ]; then @@ -98,19 +112,26 @@ if [ $HTTPS_PROXY ]; then PROXY_ARGS+=" --build-arg HTTPS_PROXY=${HTTPS_PROXY}" fi -# build portal docker +echo "Build portal docker image" cd $DELIV PORTAL_DOCKER_CMD=" - docker build -t ${EP_IMG_NAME} ${PROXY_ARGS} - --build-arg FE_DIR=$BUILD/public - --build-arg PORTAL_WAR=$BUILD/ecompportal-be-os.war - --build-arg SDK_WAR=$BUILD/epsdk-app-os.war - --build-arg DBC_WAR=$BUILD/dmaap-bc-app-os.war - -f $DOCKERFILE . + docker build -t ${EP_IMG_NAME}:${PORTAL_TAG} ${PROXY_ARGS} + --build-arg FE_DIR=$BUILD_REL/public + --build-arg PORTAL_WAR=$BUILD_REL/ecompportal-be-os.war + --build-arg SDK_WAR=$BUILD_REL/epsdk-app-os.war + --build-arg DBC_WAR=$BUILD_REL/dmaap-bc-app-os.war + -f $PORTAL_DOCKERFILE . " -echo "Invoking portal docker build" $PORTAL_DOCKER_CMD -# Build widget-ms docker -cd $BASE/ecomp-portal-widget-ms -${MVN} package docker:build +echo "Bbuild widget-ms docker image" +WMS_DOCKER_CMD=" + docker build -t ${WMS_IMG_NAME}:${PORTAL_TAG} ${PROXY_ARGS} + --build-arg WMS_JAR=$BUILD_REL/widget-ms.jar + -f Dockerfile.widgetms . +" +$WMS_DOCKER_CMD + +# For ease of debugging, leave the build dir +# echo "Cleaning up" +# rm -fr $BUILD_REL diff --git a/deliveries/createMaria.sh b/deliveries/createMaria.sh deleted file mode 100755 index 84e6bb38..00000000 --- a/deliveries/createMaria.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -# Stop on errors; show output -set -e -x - -source $(dirname $0)/os_settings.sh - -echo ${SCRIPT_DIR} - -docker build -t ${DB_IMG_NAME} --build-arg SCRIPT_DIR="${SCRIPT_DIR}" --build-arg SDK_SCRIPT_DIR="${SDK_SCRIPT_DIR}" --build-arg DBC_SCRIPT_DIR="${DBC_SCRIPT_DIR}" --build-arg SCRIPT_COMMON_DIR="${SCRIPT_COMMON_DIR}" --build-arg SDK_COMMON_SCRIPT_DIR="${SDK_COMMON_SCRIPT_DIR}" --build-arg DBC_COMMON_SCRIPT_DIR="${DBC_COMMON_SCRIPT_DIR}" -f ./Dockerfile.mariadb . diff --git a/deliveries/dbstart.sh b/deliveries/dbstart.sh deleted file mode 100755 index c76cb391..00000000 --- a/deliveries/dbstart.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -# Establish environment variables -source $(dirname $0)/os_settings.sh - -#docker create --name ${DB_VOL_NAME} -v /var/lib/mysql mariadb; - -echo "Running docker image ${DB_IMG_NAME} as name ${DB_CONT_NAME} with volume ${DB_VOL_NAME}" -docker run -d --volumes-from ${DB_VOL_NAME} -p 3306:3306 -e MYSQL_ROOT_PASSWORD=Aa123456 --net=host --name ${DB_CONT_NAME} ${DB_IMG_NAME}; diff --git a/deliveries/dbstop.sh b/deliveries/dbstop.sh deleted file mode 100755 index 9c5b73a7..00000000 --- a/deliveries/dbstop.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -# Establish environment variables -source $(dirname $0)/os_settings.sh - -echo "Stopping docker container named ${DB_CONT_NAME}" -docker stop ${DB_CONT_NAME} -echo "Removing docker container named ${DB_CONT_NAME}" -docker rm ${DB_CONT_NAME} diff --git a/deliveries/docker-compose.yml b/deliveries/docker-compose.yml new file mode 100644 index 00000000..1ea2bb67 --- /dev/null +++ b/deliveries/docker-compose.yml @@ -0,0 +1,83 @@ +# docker-compose for ONAP portal containers: database, microservice, portal apps. +# Only exposes the portal apps on host network, not the database or WMS. +# Works in multiple environments; does not pull from a Nexus repository. +# Relies on .env file in current directory. + +version: '2.0' + +services: + + # Config files may use hostname "portal-db" + portal-db: + image: ${DB_IMG_NAME}:${PORTAL_TAG} + environment: + MYSQL_ROOT_PASSWORD: 'Aa123456' + expose: + - 3306 + volumes: + # Just specify a path and let the Engine create a volume + - /var/lib/mysql + logging: + driver: json-file + + # An environment variable here CAN override the database URL; + # instead the value in the config file uses hostname from above + portal-wms: + image: ${WMS_IMG_NAME}:${PORTAL_TAG} + expose: + - 8082 + links: + - portal-db + depends_on: + - portal-db + volumes: + - ${PROJECT_DIR}/etc/ECOMPWIDGETMS/application.properties:/application.properties + command: + - /wait-for.sh + - -t + - "60" + - portal-db:3306 + - -- + - /start-wms-cmd.sh + logging: + driver: json-file + + # Environment variables here CANNOT override the database URL because + # two apps use identical configuration keys with different values + portal-apps: + image: ${EP_IMG_NAME}:${PORTAL_TAG} + expose: + - 8989 + ports: + - 8989:8080 + - 8010:8009 + - 8006:8005 + links: + - portal-db + - portal-wms + depends_on: + - portal-db + - portal-wms + volumes: + - ${PROJECT_DIR}/etc/ECOMPPORTALAPP/system.properties:${WEBAPPS_DIR}/ECOMPPORTAL/WEB-INF/conf/system.properties + - ${PROJECT_DIR}/etc/ECOMPPORTALAPP/fusion.properties:${WEBAPPS_DIR}/ECOMPPORTAL/WEB-INF/fusion/conf/fusion.properties + - ${PROJECT_DIR}/etc/ECOMPPORTALAPP/portal.properties:${WEBAPPS_DIR}/ECOMPPORTAL/WEB-INF/classes/portal.properties + - ${PROJECT_DIR}/etc/ECOMPPORTALAPP/openid-connect.properties:${WEBAPPS_DIR}/ECOMPPORTAL/WEB-INF/classes/openid-connect.properties + - ${PROJECT_DIR}/etc/ECOMPPORTALAPP/logback.xml:${WEBAPPS_DIR}/ECOMPPORTAL/WEB-INF/classes/logback.xml + - ${PROJECT_DIR}/etc/ECOMPSDKAPP/fusion.properties:${WEBAPPS_DIR}/ECOMPSDKAPP/WEB-INF/fusion/conf/fusion.properties + - ${PROJECT_DIR}/etc/ECOMPSDKAPP/system.properties:${WEBAPPS_DIR}/ECOMPSDKAPP/WEB-INF/conf/system.properties + - ${PROJECT_DIR}/etc/ECOMPSDKAPP/portal.properties:${WEBAPPS_DIR}/ECOMPSDKAPP/WEB-INF/classes/portal.properties + - ${PROJECT_DIR}/etc/ECOMPDBCAPP/system.properties:${WEBAPPS_DIR}/ECOMPDBCAPP/WEB-INF/conf/system.properties + - ${PROJECT_DIR}/etc/ECOMPDBCAPP/portal.properties:${WEBAPPS_DIR}/ECOMPDBCAPP/WEB-INF/classes/portal.properties + - ${PROJECT_DIR}/etc/ECOMPDBCAPP/dbcapp.properties:${WEBAPPS_DIR}/ECOMPDBCAPP/WEB-INF/dbcapp/dbcapp.properties + - ${PROJECT_DIR}/etc/ECOMPDBCAPP/fusion.properties:${WEBAPPS_DIR}/ECOMPDBCAPP/WEB-INF/fusion/conf/fusion.properties + - ${PROJECT_DIR}/portal-apps-logs:/opt/apache-tomcat-8.0.37/logs + command: + - /wait-for.sh + - -t + - "60" + - portal-db:3306 + - -- + - /start-apps-cmd.sh + logging: + driver: json-file diff --git a/deliveries/etc.zip b/deliveries/etc.zip deleted file mode 100644 index 67a65b27275d46fa02776b79b3d8eb3147d308cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11426 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 diff --git a/deliveries/new_start.sh b/deliveries/new_start.sh deleted file mode 100755 index cffcda9b..00000000 --- a/deliveries/new_start.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash - -# Establish environment variables -source $(dirname $0)/os_settings.sh - -BASEDIR=/PROJECT/OpenSource/UbuntuEP -PORTALDIR=/opt/apache-tomcat-8.0.37/webapps/ECOMPPORTAL -SDKAPPDIR=/opt/apache-tomcat-8.0.37/webapps/ECOMPSDKAPP -DBCAPPDIR=/opt/apache-tomcat-8.0.37/webapps/ECOMPDBCAPP -PORTALPROPDIR=ECOMPPORTALAPP -SDKAPPPROPDIR=ECOMPSDKAPP -DBCAPPPROPDIR=ECOMPDBCAPP -#docker rm ep_1610 -echo "Running docker image ${EP_IMG_NAME} as name ${EP_CONT_NAME}" -docker run -d --name ${EP_CONT_NAME} \ --p 8989:8080 -p 8010:8009 -p 8006:8005 \ --v ${BASEDIR}/etc/${PORTALPROPDIR}/system.properties:${PORTALDIR}/WEB-INF/conf/system.properties \ --v ${BASEDIR}/etc/${PORTALPROPDIR}/fusion.properties:${PORTALDIR}/WEB-INF/fusion/conf/fusion.properties \ --v ${BASEDIR}/etc/${PORTALPROPDIR}/portal.properties:${PORTALDIR}/WEB-INF/classes/portal.properties \ --v ${BASEDIR}/etc/${PORTALPROPDIR}/openid-connect.properties:${PORTALDIR}/WEB-INF/classes/openid-connect.properties \ --v ${BASEDIR}/etc/${SDKAPPPROPDIR}/fusion.properties:${SDKAPPDIR}/WEB-INF/fusion/conf/fusion.properties \ --v ${BASEDIR}/etc/${SDKAPPPROPDIR}/system.properties:${SDKAPPDIR}/WEB-INF/conf/system.properties \ --v ${BASEDIR}/etc/${SDKAPPPROPDIR}/portal.properties:${SDKAPPDIR}/WEB-INF/classes/portal.properties \ --v ${BASEDIR}/etc/${DBCAPPPROPDIR}/system.properties:${DBCAPPDIR}/WEB-INF/conf/system.properties \ --v ${BASEDIR}/etc/${DBCAPPPROPDIR}/portal.properties:${DBCAPPDIR}/WEB-INF/classes/portal.properties \ --v ${BASEDIR}/etc/${DBCAPPPROPDIR}/dbcapp.properties:${DBCAPPDIR}/WEB-INF/dbcapp/dbcapp.properties \ --v ${BASEDIR}/etc/${DBCAPPPROPDIR}/fusion.properties:${DBCAPPDIR}/WEB-INF/fusion/conf/fusion.properties \ --v ${BASEDIR}/log:/opt/apache-tomcat-8.0.37/logs \ -${EP_IMG_NAME} diff --git a/deliveries/new_stop.sh b/deliveries/new_stop.sh deleted file mode 100755 index 9193e285..00000000 --- a/deliveries/new_stop.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -# Establish environment variables -source $(dirname $0)/os_settings.sh - -echo "Stopping docker container named ${EP_CONT_NAME}" -docker stop ${EP_CONT_NAME} -echo "Removing docker container named ${EP_CONT_NAME}" -docker rm ${EP_CONT_NAME} diff --git a/deliveries/os_Dockerfile b/deliveries/os_Dockerfile deleted file mode 100644 index 130244da..00000000 --- a/deliveries/os_Dockerfile +++ /dev/null @@ -1,84 +0,0 @@ -# Pull base image. -#FROM ubuntu-openjdk-8-jdk - -FROM ubuntu:14.04 - -ARG HTTP_PROXY=${HTTP_PROXY} -ARG HTTPS_PROXY=${HTTPS_PROXY} - -ENV http_proxy $HTTP_PROXY -ENV https_proxy $HTTPS_PROXY - -RUN if [ ! -z ${HTTP_PROXY} ]; then echo "Acquire::http::proxy \"${HTTP_PROXY}\";" >> /etc/apt/apt.conf; fi && \ - if [ ! -z ${HTTPS_PROXY} ]; then echo "Acquire::https::proxy \"${HTTPS_PROXY}\";" >> /etc/apt/apt.conf; fi - -# Install the python script required for "add-apt-repository" -RUN apt-get update && apt-get install -y software-properties-common - -# Sets language to UTF8 : this works in pretty much all cases -ENV LANG en_US.UTF-8 -RUN locale-gen $LANG - -# Setup the openjdk 8 repo -RUN add-apt-repository ppa:openjdk-r/ppa - -# Install java8 -RUN apt-get update && apt-get install -y --force-yes openjdk-8-jdk - -# Setup JAVA_HOME, this is useful for docker commandline -ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64/ -RUN export JAVA_HOME - -# Show java version (for debugging) -# RUN java -version - -RUN apt-get update -RUN apt-get install -y curl -# Install Tomcat -RUN cd /tmp && curl -O https://archive.apache.org/dist/tomcat/tomcat-8/v8.0.37/bin/apache-tomcat-8.0.37.tar.gz -RUN tar -xzf /tmp/apache-tomcat-8.0.37.tar.gz -RUN mv apache-tomcat-8.0.37 /opt - -# Define working directory. -WORKDIR /opt/apache-tomcat-8.0.37/bin - -# Define commonly used ENV variables -ENV PATH $PATH:$JAVA_HOME/bin:/opt/apache-tomcat-8.0.37/bin - -VOLUME /opt/apache-tomcat-8.0.37/logs - -ARG VERSION=${VERSION:-1.1.0} -#LABEL Version=${VERSION} -ARG SDK_DIR=${SDK_DIR} -ARG FE_DIR=${FE_DIR} -ARG PORTAL_SDK_DIR=${PORTAL_SDK_DIR} -ARG PORTAL_DBC_DIR=${PORTAL_DBC_DIR} -# Set up variables: -ENV TOMCATHOME /opt/apache-tomcat-8.0.37 -ENV PORTALHOME /PROJECT/APPS/ECOMPPORTAL/ECOMPPORTALAPP -ENV PORTALSDKHOME /PROJECT/APPS/ECOMPPORTAL/ECOMPSDKAPP -ENV PORTALDBCHOME /PROJECT/APPS/ECOMPPORTAL/ECOMPDBCAPP -# Install Common Software,Git,Apache -RUN mkdir -p $PORTALHOME && mkdir -p $PORTALSDKHOME && mkdir -p $PORTALDBCHOME - -COPY ${SDK_DIR} ${PORTALHOME}/ -# step 33 -COPY ${PORTAL_SDK_DIR} ${PORTALSDKHOME}/ -COPY ${PORTAL_DBC_DIR} ${PORTALDBCHOME}/ - -RUN ln -s ${PORTALHOME} ${TOMCATHOME}/webapps/ECOMPPORTAL && ln -s ${PORTALSDKHOME} ${TOMCATHOME}/webapps/ECOMPSDKAPP && ln -s ${PORTALDBCHOME} ${TOMCATHOME}/webapps/ECOMPDBCAPP - - -# Define working directory. -WORKDIR ${TOMCATHOME}/bin -VOLUME ${TOMCATHOME}/logs -# Define commonly used ENV variables -ENV PATH $PATH:$JAVA_HOME/bin:${TOMCATHOME}/bin -COPY configure-and-run.sh /PROJECT/OpenSource/UbuntuEP/ - -#RUN cp -r ${FE_DIR}/dist/public ${PORTALHOME}/public - -COPY ${FE_DIR}/dist/public ${PORTALHOME}/public -# Define default command. -#CMD ["bash"] -CMD ["/PROJECT/OpenSource/UbuntuEP/configure-and-run.sh"] diff --git a/deliveries/os_build_febe.sh b/deliveries/os_build_febe.sh deleted file mode 100755 index d9a59bf1..00000000 --- a/deliveries/os_build_febe.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/bin/bash -# Builds docker with three webapps: portal app, portal-sdk app, dbc app -# Stop on error; show output -set -e -x - -source $(dirname $0)/os_settings.sh - -# Work standalone and in Jenkins. -# Pick up Jenkins settings for this script. -# Use -B for batch operation to skip download progress output -if [ -n "$MVN" ]; then - export MVN="${MVN} -gs ${GLOBAL_SETTINGS_FILE} -s ${SETTINGS_FILE} -B" -else - MVN=mvn -fi - -CURRENTDIR="$(pwd)" - -# install ecomp portal -rm -rf $CURRENTDIR/$WORKINGDIR -mkdir $CURRENTDIR/$WORKINGDIR -cd $CURRENTDIR/$WORKINGDIR -SOURCEDIR=$CURRENTDIR/$WORKINGDIR/Source -mkdir $SOURCEDIR -cd $SOURCEDIR -PROJECTDIR=$SOURCEDIR/ecomp-portal-core -mkdir $PROJECTDIR - -#create project dir -#copy FE and BE -cd $CURRENTDIR -cd .. - -cp -r ecomp-portal-FE-common $PROJECTDIR/ecomp-portal-FE-common -cp -r ecomp-portal-FE-os $PROJECTDIR/ecomp-portal-FE-os -cp -r ecomp-portal-BE-common $PROJECTDIR/ecomp-portal-BE-common -cp -r ecomp-portal-BE-os $PROJECTDIR/ecomp-portal-BE-os -cp -r ecomp-portal-DB-common $PROJECTDIR/ecomp-portal-DB-common -cp -r ecomp-portal-DB-os $PROJECTDIR/ecomp-portal-DB-os -cp -r sdk/ecomp-sdk $PROJECTDIR/ecomp-sdk - -cd $PROJECTDIR/ecomp-portal-BE-common -${MVN} install - -cd $PROJECTDIR/ecomp-portal-BE-os -${MVN} install - -cd $PROJECTDIR/ecomp-portal-FE-os/ -${MVN} install - -cd $PROJECTDIR/ecomp-sdk/epsdk-app-os -${MVN} install - -# now install DBC app -cd $SOURCEDIR -DBCDIR=$SOURCEDIR/ST_DBPA -mkdir $DBCDIR -#copy DBC project -cd $CURRENTDIR -cd .. -cp -r dmaapbc/dcae_dmaapbc_webapp $DBCDIR/dcae_dmaapbc_webapp -cd $DBCDIR/dcae_dmaapbc_webapp -${MVN} install -cd dbca-os/target -mv dmaap-bc-app-os ep-dbc-app - -# Build complete database script in the "OS" script area -cd ../db-scripts -cat dbca-create-mysql-1707-os.sql ../../dbca-common/db-scripts/dbca-ddl-mysql-1707-common.sql dbca-dml-mysql-1707-os.sql > dbca-complete-mysql-1707-os.sql - -# install into docker -cd $CURRENTDIR - -PROXY_ARGS="" -if [ $HTTP_PROXY ]; then - PROXY_ARGS+="--build-arg HTTP_PROXY=${HTTP_PROXY}" -fi -if [ $HTTPS_PROXY ]; then - PROXY_ARGS+=" --build-arg HTTPS_PROXY=${HTTPS_PROXY}" -fi - -EXEC_CMD="docker build -t ${IMGNAME} ${PROXY_ARGS} --build-arg VERSION=${VERSION} --build-arg PORTAL_SDK_DIR=${PORTAL_SDK_DIR} --build-arg SDK_DIR=${SDK_DIR} --build-arg FE_DIR=${FE_DIR} --build-arg PORTAL_DBC_DIR=${PORTAL_DBC_DIR} -f ./os_Dockerfile ." -echo $EXEC_CMD -$EXEC_CMD diff --git a/deliveries/os_docker_base.sh b/deliveries/os_docker_base.sh new file mode 100755 index 00000000..2bdfea68 --- /dev/null +++ b/deliveries/os_docker_base.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# Builds and pushes versions of Portal images +# Invoked by scripts that set VERSION and LATEST + +# be verbose +set -x + +if [ -z "$VERSION" ]; then + echo "VERSION not set" + exit 1 +fi +if [ -z "$LATEST" ]; then + echo "LATEST not set" + exit 1 +fi + +# Establish environment variables +source $(dirname $0)/.env + +# Build the containers +./build_portalapps_dockers.sh + +APPS_VERSION="${NEXUS_REPO}/openecomp/${EP_IMG_NAME}:${VERSION}" +DB_VERSION="${NEXUS_REPO}/openecomp/${DB_IMG_NAME}:${VERSION}" +WMS_VERSION="${NEXUS_REPO}/openecomp/${WMS_IMG_NAME}:${VERSION}" + +APPS_LATEST="${NEXUS_REPO}/openecomp/${EP_IMG_NAME}:${LATEST}" +DB_LATEST="${NEXUS_REPO}/openecomp/${DB_IMG_NAME}:${LATEST}" +WMS_LATEST="${NEXUS_REPO}/openecomp/${WMS_IMG_NAME}:${LATEST}" + +# tag versions +docker tag ${EP_IMG_NAME}:${PORTAL_TAG} ${APPS_VERSION} +docker tag ${EP_IMG_NAME}:${PORTAL_TAG} ${APPS_LATEST} + +docker tag ${DB_IMG_NAME}:${PORTAL_TAG} ${DB_VERSION} +docker tag ${DB_IMG_NAME}:${PORTAL_TAG} ${DB_LATEST} + +docker tag ${WMS_IMG_NAME}:${PORTAL_TAG} ${WMS_VERSION} +docker tag ${WMS_IMG_NAME}:${PORTAL_TAG} ${WMS_LATEST} + +# push +docker push ${APPS_VERSION} +docker push ${APPS_LATEST} + +docker push ${DB_VERSION} +docker push ${DB_LATEST} + +docker push ${WMS_VERSION} +docker push ${WMS_LATEST} diff --git a/deliveries/os_docker_push.sh b/deliveries/os_docker_push.sh index 2ec6de42..eb663b83 100755 --- a/deliveries/os_docker_push.sh +++ b/deliveries/os_docker_push.sh @@ -1,40 +1,11 @@ #!/bin/bash +# Builds and pushes SNAPSHOT versions of Portal images -# Establish environment variables -source $(dirname $0)/os_settings.sh - -./run.sh - -REPO="nexus3.onap.org:10003" +# be verbose +set -x TIMESTAMP=$(date +%C%y%m%dT%H%M%S) -VERSION="1.1.0-SNAPSHOT-${TIMESTAMP}" -LATEST="latest" - -APPS_VERSION="${REPO}/openecomp/${EP_TAG_NAME}:${VERSION}" -DB_VERSION="${REPO}/openecomp/${DB_TAG_NAME}:${VERSION}" -WMS_VERSION="${REPO}/openecomp/${WMS_TAG_NAME}:${VERSION}" - -APPS_LATEST="${REPO}/openecomp/${EP_TAG_NAME}:${LATEST}" -DB_LATEST="${REPO}/openecomp/${DB_TAG_NAME}:${LATEST}" -WMS_LATEST="${REPO}/openecomp/${WMS_TAG_NAME}:${LATEST}" - -# tag versions -docker tag ${EP_IMG_NAME} ${APPS_VERSION} -docker tag ${EP_IMG_NAME} ${APPS_LATEST} - -docker tag ${DB_IMG_NAME} ${DB_VERSION} -docker tag ${DB_IMG_NAME} ${DB_LATEST} - -docker tag ${WMS_IMG_NAME} ${WMS_VERSION} -docker tag ${WMS_IMG_NAME} ${WMS_LATEST} - -# push -docker push ${APPS_VERSION} -docker push ${APPS_LATEST} - -docker push ${DB_VERSION} -docker push ${DB_LATEST} +export VERSION="1.1.0-SNAPSHOT-${TIMESTAMP}" +export LATEST="latest" -docker push ${WMS_VERSION} -docker push ${WMS_LATEST} +exec ./os_docker_base.sh diff --git a/deliveries/os_docker_release.sh b/deliveries/os_docker_release.sh index 2bd2e20d..42825534 100755 --- a/deliveries/os_docker_release.sh +++ b/deliveries/os_docker_release.sh @@ -1,40 +1,11 @@ #!/bin/bash +# Builds and pushes STAGING versions of Portal images -# Establish environment variables -source $(dirname $0)/os_settings.sh - -./run.sh - -REPO="nexus3.onap.org:10003" +# be verbose +set -x TIMESTAMP=$(date +%C%y%m%dT%H%M%S) -VERSION="1.1.0-STAGING-${TIMESTAMP}" -LATEST="1.1-STAGING-latest" - -APPS_VERSION="${REPO}/openecomp/${EP_TAG_NAME}:${VERSION}" -DB_VERSION="${REPO}/openecomp/${DB_TAG_NAME}:${VERSION}" -WMS_VERSION="${REPO}/openecomp/${WMS_TAG_NAME}:${VERSION}" - -APPS_LATEST="${REPO}/openecomp/${EP_TAG_NAME}:${LATEST}" -DB_LATEST="${REPO}/openecomp/${DB_TAG_NAME}:${LATEST}" -WMS_LATEST="${REPO}/openecomp/${WMS_TAG_NAME}:${LATEST}" - -# tag version -docker tag ${EP_IMG_NAME} ${APPS_VERSION} -docker tag ${EP_IMG_NAME} ${APPS_LATEST} - -docker tag ${DB_IMG_NAME} ${DB_VERSION} -docker tag ${DB_IMG_NAME} ${DB_LATEST} - -docker tag ${WMS_IMG_NAME} ${WMS_VERSION} -docker tag ${WMS_IMG_NAME} ${WMS_LATEST} - -# push -docker push ${APPS_VERSION} -docker push ${APPS_LATEST} - -docker push ${DB_VERSION} -docker push ${DB_LATEST} +export VERSION="1.1.0-STAGING-${TIMESTAMP}" +export LATEST="1.1-STAGING-latest" -docker push ${WMS_VERSION} -docker push ${WMS_LATEST} +exec ./os_docker_base.sh diff --git a/deliveries/os_settings.sh b/deliveries/os_settings.sh deleted file mode 100755 index 19a1e0ef..00000000 --- a/deliveries/os_settings.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -# Establish constants for the management shell scripts. -# These variables are ALSO used in demo/boot/portal_vm_init.sh - -EP_TAG_NAME=portalapps -EP_IMG_NAME=portalapps:latest -EP_CONT_NAME=onap_portal - -DB_TAG_NAME=portaldb -DB_IMG_NAME=portaldb:latest -DB_CONT_NAME=onap_portal_db -DB_VOL_NAME=data_vol_portal - -WMS_TAG_NAME=portalwms -WMS_IMG_NAME=widget-ms -WMS_CONT_NAME=onap_portal_widget_ms - -VERSION=1.1.0 -ETCDIR=etc -WORKINGDIR=PROJECT -SDK_DIR=PROJECT/Source/ecomp-portal-core/ecomp-portal-BE-os/target/ecompportal-be-os -FE_DIR=PROJECT/Source/ecomp-portal-core/ecomp-portal-FE-os -SCRIPT_COMMON_DIR="PROJECT/Source/ecomp-portal-core/ecomp-portal-DB-common/" -SCRIPT_DIR="PROJECT/Source/ecomp-portal-core/ecomp-portal-DB-os/" -SDK_COMMON_SCRIPT_DIR=PROJECT/Source/ecomp-portal-core/ecomp-sdk/epsdk-app-common/db-scripts -SDK_SCRIPT_DIR=PROJECT/Source/ecomp-portal-core/ecomp-sdk/epsdk-app-os/db-scripts -DBC_COMMON_SCRIPT_DIR=PROJECT/Source/ST_DBPA/dcae_dmaapbc_webapp/dbca-common/db-scripts -DBC_SCRIPT_DIR=PROJECT/Source/ST_DBPA/dcae_dmaapbc_webapp/dbca-os/db-scripts -PORTAL_SDK_DIR=PROJECT/Source/ecomp-portal-core/ecomp-sdk/epsdk-app-os/target/epsdk-app-os -PORTAL_DBC_DIR=PROJECT/Source/ST_DBPA/dcae_dmaapbc_webapp/dbca-os/target/ep-dbc-app diff --git a/deliveries/portal_vm_init.sh b/deliveries/portal_vm_init.sh index 5f34aae8..5f4716ec 100755 --- a/deliveries/portal_vm_init.sh +++ b/deliveries/portal_vm_init.sh @@ -1,71 +1,42 @@ #!/bin/bash # Starts docker containers for ONAP Portal +# This version for Amsterdam/R1 of Portal, uses docker-compose. +# Temporarily maintained in portal/deliveries area; +# replicated from the ONAP demo/boot area due to release concerns. # be verbose set -x -# Refresh source area with start scripts -cd /opt/portal -git pull -cd /opt - # Establish environment variables NEXUS_USERNAME=$(cat /opt/config/nexus_username.txt) NEXUS_PASSWD=$(cat /opt/config/nexus_password.txt) NEXUS_DOCKER_REPO=$(cat /opt/config/nexus_docker_repo.txt) DOCKER_IMAGE_VERSION=$(cat /opt/config/docker_version.txt) -# Get container, image and tag names used below -source portal/deliveries/os_settings.sh +# Refresh configuration and scripts +cd /opt/portal +git pull +cd deliveries + +# Get image names used below from docker-compose environment file +source .env -# Unpack property files -unzip -o portal/deliveries/etc.zip -d /PROJECT/OpenSource/UbuntuEP/ +# Copy property files +ETC=/PROJECT/OpenSource/UbuntuEP/etc +mkdir -p $ETC +cp -r properties_rackspace/* $ETC # Refresh images docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO -docker pull $NEXUS_DOCKER_REPO/openecomp/${DB_TAG_NAME}:$DOCKER_IMAGE_VERSION -docker pull $NEXUS_DOCKER_REPO/openecomp/${EP_TAG_NAME}:$DOCKER_IMAGE_VERSION -docker pull $NEXUS_DOCKER_REPO/openecomp/${WMS_TAG_NAME}:$DOCKER_IMAGE_VERSION - -# Remove lingering containers; order matters. -docker rm -f $DB_CONT_NAME -docker rm -f $DB_VOL_NAME -docker rm -f $EP_CONT_NAME -docker rm -f $WMS_CONT_NAME - -docker create --name $DB_VOL_NAME -v /var/lib/mysql mariadb -docker tag $NEXUS_DOCKER_REPO/openecomp/${DB_TAG_NAME}:$DOCKER_IMAGE_VERSION $DB_IMG_NAME -docker tag $NEXUS_DOCKER_REPO/openecomp/${EP_TAG_NAME}:$DOCKER_IMAGE_VERSION $EP_IMG_NAME -# WMS image has no version in the registry -docker tag $NEXUS_DOCKER_REPO/openecomp/${WMS_TAG_NAME}:$DOCKER_IMAGE_VERSION ${WMS_IMG_NAME}:latest - -# Recreate the named containers -cd portal/deliveries -echo "Starting database" -./dbstart.sh -echo "Delaying for database" -sleep 10 -echo "Starting apps" -./new_start.sh -echo "Starting widget-ms" -./widget_ms_start.sh - -sleep 180 - -if [ ! -e /opt/config/boot.txt ] -then - if [ -e /opt/config/public_ip.txt ] - then - IP_ADDRESS=$(cat /opt/config/public_ip.txt) - else - IP_ADDRESS=$(ifconfig eth0 | grep "inet addr" | tr -s ' ' | cut -d' ' -f3 | cut -d':' -f2) - fi - # Wait until MySQL is running... - while [[ $(netstat -vulntp |grep -i mysql | awk '{print $4}') != ":::3306" ]] - do - sleep 1 - done - # no longer necessary; done at docker build time - # mysql -u root -p'Aa123456' -h $IP_ADDRESS < /opt/portal/deliveries/Apps_Users_OnBoarding_Script.sql - echo "yes" > /opt/config/boot.txt -fi +docker pull $NEXUS_DOCKER_REPO/openecomp/${DB_IMG_NAME}:$DOCKER_IMAGE_VERSION +docker pull $NEXUS_DOCKER_REPO/openecomp/${EP_IMG_NAME}:$DOCKER_IMAGE_VERSION +docker pull $NEXUS_DOCKER_REPO/openecomp/${WMS_IMG_NAME}:$DOCKER_IMAGE_VERSION + +# Tag them as expected by docker-compose file +docker tag $NEXUS_DOCKER_REPO/openecomp/${DB_IMG_NAME}:$DOCKER_IMAGE_VERSION $DB_IMG_NAME:$PORTAL_TAG +docker tag $NEXUS_DOCKER_REPO/openecomp/${EP_IMG_NAME}:$DOCKER_IMAGE_VERSION $EP_IMG_NAME:$PORTAL_TAG +docker tag $NEXUS_DOCKER_REPO/openecomp/${WMS_IMG_NAME}:$DOCKER_IMAGE_VERSION $WMS_IMG_NAME:$PORTAL_TAG + +# compose is not in /usr/bin +/opt/docker/docker-compose down +/opt/docker/docker-compose up -d diff --git a/deliveries/properties_rackspace/ECOMPDBCAPP/dbcapp.properties b/deliveries/properties_rackspace/ECOMPDBCAPP/dbcapp.properties new file mode 100644 index 00000000..1c13384d --- /dev/null +++ b/deliveries/properties_rackspace/ECOMPDBCAPP/dbcapp.properties @@ -0,0 +1,8 @@ +# Properties for the Data Bus Controller webapp +dmaap.rest.url.list = http://10.0.4.102:18080/webapi +# webapp's mechid is sent to DCAE for authorization +dmaap.mechid.name = m06672@dbcapp.dmaap.dcae.att.com +# encrypted with CipherUtil +dmaap.mechid.password = /F1vRhga1Ijw7yRFFj6R5A== +# Valid access methods are "dao" and "rest" +profile.access.method = dao diff --git a/deliveries/properties_rackspace/ECOMPDBCAPP/fusion.properties b/deliveries/properties_rackspace/ECOMPDBCAPP/fusion.properties new file mode 100644 index 00000000..4d4e17e9 --- /dev/null +++ b/deliveries/properties_rackspace/ECOMPDBCAPP/fusion.properties @@ -0,0 +1,33 @@ +# login settings +login_method_backdoor = backdoor +login_method_attribute_name = login_method +login_method_csp = csp +login_method_web_junction = web_junction + +#login message +login.error.hrid.empty = Login failed, please contact system administrator. +login.error.hrid.not-found = User not found, please contact system administrator. +login.error.user.inactive = Account is disabled, please contact system administrator. + +authentication_mechanism = DBAUTH + +# User Session settings +user_attribute_name = user +roles_attribute_name = roles +role_functions_attribute_name = role_functions + +# POST settings +post_initial_context_factory = com.sun.jndi.ldap.LdapCtxFactory +post_provider_url = todo_ldap +post_security_principal = ou=people,o=org,c=us +post_max_result_size = 499 + +# menu settings +menu_query_name = menuData +application_menu_set_name = APP +application_menu_attribute_name = applicationMenuData +business_direct_menu_set_name = BD +business_direct_menu_attribute_name = businessDirectMenuData + +# Role settings +sys_admin_role_id = 1 diff --git a/deliveries/properties_rackspace/ECOMPDBCAPP/portal.properties b/deliveries/properties_rackspace/ECOMPDBCAPP/portal.properties new file mode 100644 index 00000000..6dbbee84 --- /dev/null +++ b/deliveries/properties_rackspace/ECOMPDBCAPP/portal.properties @@ -0,0 +1,25 @@ +# Properties read by ECOMP Framework library, ecompFW.jar + +portal.api.impl.class = org.openecomp.portalapp.service.OnBoardingApiServiceImpl +portal.api.prefix = /api +max.idle.time = 5 +user.attribute.name = user_attribute + +# Legacy property TODO +ecomp_redirect_url = http://portal.api.simpledemo.openecomp.org:8989/ECOMPPORTAL/login.htm + +# URL of the ECOMP Portal REST API +ecomp_rest_url = http://portal.api.simpledemo.openecomp.org:8989/ECOMPPORTAL/auxapi + +#Use REST API instead of UEB to fetch the functional menu data +use_rest_for_functional_menu=true + +# Don't fetch functional menu via UEB in 1610. +ueb_listeners_enable = false + +# Application key is used by session management +ueb_app_key = MtRwsF16RdpHZ7eM + +# The inbox name property should not be required when the REST API is used, +# but in 1610 FuncMenuController logs ALARM if it cannot find this key. +ecomp_portal_inbox_name = ECOMP-PORTAL-INBOX-TEST diff --git a/deliveries/properties_rackspace/ECOMPDBCAPP/system.properties b/deliveries/properties_rackspace/ECOMPDBCAPP/system.properties new file mode 100644 index 00000000..019268b7 --- /dev/null +++ b/deliveries/properties_rackspace/ECOMPDBCAPP/system.properties @@ -0,0 +1,63 @@ +#Local +app_display_name = DMaaP Bus Ctlr + +db.driver = com.mysql.jdbc.Driver +db.connectionURL = jdbc:mysql://portal-db:3306/dbca_os +db.userName = root +db.password = Aa123456 +db.encrypt_flag = false +db.hib.dialect = org.hibernate.dialect.MySQLDialect +db.min_pool_size = 5 +db.max_pool_size = 10 +hb.dialect = org.hibernate.dialect.MySQLDialect +hb.show_sql = false +hb.db_reconnect = true +hb.idle_connection_test_period = 3600 + +# Directory with the Quantum.lic file +files_path = /opt/app/tomcat/webapps/dmaap-bc-app/WEB-INF/dbcapp + +application_user_id = 30000 +post_default_role_id = 16 +clustered = true + +#Enable Fusion Mobile capabilities for the application +mobile_enable = false + +# Cache config file is needed on the classpath +cache_config_file_path = /WEB-INF/classes/cache.ccf +cache_switch = 199 +cache_load_on_startup = false + +user_name = fullName +decryption_key = AGLDdG4D04BKm2IxIWEr8o== + +#element map files +element_map_file_path = /tmp +element_map_icon_path = app/fusionapp/icons/ + +# Quartz is not used by the DBC application +# log_cron = +# mylogins_feed_cron = +# sessiontimeout_feed_cron = +# my_login_feed_output_dir = + +# ECOMP Portal Shared Context REST API URL is not used by the DBC application +# ecomp_shared_context_rest_url = + +contact_us_link = https://todo_contact_us_link + +# An Unique 128-bit value defined to identify a specific version +# of an application deployed on a specific virtual machine. +# This value must be generated and updated by the application +# which is using the ECOMP SDK at the time of its deployment. +# Online Unique UUID generator - https://www.uuidgenerator.net/ +# ID generated for DBC to supply to EELF +# A bogus value is cached in SCM: 12345678-.. +instance_uuid = 12345678-90ab-cdef-1234-567890abcdef + +# R Cloud feature +guard_notebook_url=https://todo_rcloud_link + +# Application base URL is a proper prefix of the on-boarded URL. +app_base_url = http://portal.api.simpledemo.openecomp.org:8989/ECOMPDBCAPP/ diff --git a/deliveries/properties_rackspace/ECOMPPORTALAPP/fusion.properties b/deliveries/properties_rackspace/ECOMPPORTALAPP/fusion.properties new file mode 100644 index 00000000..c92a5739 --- /dev/null +++ b/deliveries/properties_rackspace/ECOMPPORTALAPP/fusion.properties @@ -0,0 +1,46 @@ +# domain settings +#domain_class_location = + +# validator settings +#default_error_message = Default error message + +login_url_no_ret_val = http://portal.api.simpledemo.openecomp.org:8989/ECOMPPORTAL/login.htm + +user_attribute_name = user + +# User Session settings +roles_attribute_name = roles +role_functions_attribute_name = role_functions + +# menu settings +menu_query_name = menuData +application_menu_set_name = APP +application_menu_attribute_name = applicationMenuData +business_direct_menu_set_name = BD +business_direct_menu_attribute_name = businessDirectMenuData + +# ECOMP settings +ecomp_app_id = 1 +# Role settings +sys_admin_role_id = 1 +account_admin_role_id = 999 +restricted_app_role_id = 900 + +# Home Page index html +home_page = /index.html + +authentication_mechanism =DBAUTH + +login.error.hrid.empty = Login failed, please contact system administrator. +login.error.hrid.not-found = User not found, please contact system administrator. +login.error.user.inactive = Account is disabled, please contact system administrator. + +# +# Number of seconds to poll health (database operational, etc.) +# +health_poll_interval_seconds = 5 +# +# If a component is down a log entry will be written that triggers an alert. This parameter specifies how often this alert should be triggered +# if the component remains down. For example a value of 30, would translate to 30 * 60 seconds = 1800 seconds, or every 30 minutes +# +health_fail_alert_every_x_intervals = 30 diff --git a/deliveries/properties_rackspace/ECOMPPORTALAPP/logback.xml b/deliveries/properties_rackspace/ECOMPPORTALAPP/logback.xml new file mode 100644 index 00000000..0c0d7647 --- /dev/null +++ b/deliveries/properties_rackspace/ECOMPPORTALAPP/logback.xml @@ -0,0 +1,285 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${applicationLoggerPattern} + + + + + + + + + + + + ${logDirectory}/${generalLogName}.log + + + ${logDirectory}/${generalLogName}.log.%d{yyyy-MM-dd}.zip + + 30 + + + ${applicationLoggerPattern} + + + + + + 256 + + true + + + + + + + + + + + + + + + + + + + ${logDirectory}/${auditLogName}.log + + + ${logDirectory}/${auditLogName}.log.%d{yyyy-MM-dd}.zip + + 30 + + + ${auditLoggerPattern} + + + + 256 + + + + + ${logDirectory}/${metricsLogName}.log + + + ${logDirectory}/${metricsLogName}.log.%d{yyyy-MM-dd}.zip + + 30 + + + ${metricsLoggerPattern} + + + + + + 256 + + + + + ${logDirectory}/${errorLogName}.log + + + ${logDirectory}/${errorLogName}.log.%d{yyyy-MM-dd}.zip + + 30 + + + ${errorLoggerPattern} + + + + + 256 + + + + + ${debugLogDirectory}/${debugLogName}.log + + + ${logDirectory}/${debugLogName}.log.%d{yyyy-MM-dd}.zip + + 30 + + + ${defaultLoggerPattern} + + + + + 256 + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/deliveries/properties_rackspace/ECOMPPORTALAPP/openid-connect.properties b/deliveries/properties_rackspace/ECOMPPORTALAPP/openid-connect.properties new file mode 100644 index 00000000..33c919b2 --- /dev/null +++ b/deliveries/properties_rackspace/ECOMPPORTALAPP/openid-connect.properties @@ -0,0 +1,3 @@ +authentication_server_url = http://portal.api.simpledemo.openecomp.org:8383/openid-connect-server-webapp/ +ecomp_openid_connect_client = http://portal.api.simpledemo.openecomp.org:8989/ECOMPPORTAL/openid_connect_login +ecomp_redirect_uri = http://portal.api.simpledemo.openecomp.org:8989/ECOMPPORTAL/welcome.htm diff --git a/deliveries/properties_rackspace/ECOMPPORTALAPP/portal.properties b/deliveries/properties_rackspace/ECOMPPORTALAPP/portal.properties new file mode 100644 index 00000000..f7fba31a --- /dev/null +++ b/deliveries/properties_rackspace/ECOMPPORTALAPP/portal.properties @@ -0,0 +1,23 @@ +portal.api.impl.class = org.openecomp.portalsdk.core.onboarding.client.OnBoardingApiServiceImpl +portal.api.prefix = /api +max.idle.time = 5 +user.attribute.name = user_attribute + +# for single sign on +ecomp_redirect_url = http://portal.api.simpledemo.openecomp.org:8989/ECOMPPORTAL/login.htm + +# URL of the ECOMP Portal REST API +ecomp_rest_url = http://portal.api.simpledemo.openecomp.org:8989/ECOMPPORTAL/auxapi + +ueb_listeners_enable = true + +ueb_app_key = 7GkVcrO6sIDb3ngW +ueb_app_secret = uCYgKjWKK5IxPGNNZzYSSWo9 +ueb_app_mailbox_name = ECOMP-PORTAL-INBOX + +ueb_url_list = ueb.api.simpledemo.openecomp.org +ecomp_portal_inbox_name = ECOMP-PORTAL-INBOX + +# Consumer group name for UEB topic. +# Use the special tag to generate a unique one for each sdk-app server. +ueb_app_consumer_group_name = {UUID} diff --git a/deliveries/properties_rackspace/ECOMPPORTALAPP/system.properties b/deliveries/properties_rackspace/ECOMPPORTALAPP/system.properties new file mode 100644 index 00000000..10842953 --- /dev/null +++ b/deliveries/properties_rackspace/ECOMPPORTALAPP/system.properties @@ -0,0 +1,97 @@ +#mysql +db.driver = com.mysql.jdbc.Driver +db.connectionURL = jdbc:mysql://portal-db:3306/portal +db.userName =root +db.password =Aa123456 +db.hib.dialect = org.hibernate.dialect.MySQLDialect +db.min_pool_size = 5 +db.max_pool_size = 10 +hb.dialect = org.hibernate.dialect.MySQLDialect +hb.show_sql = false +hb.db_reconnect = true +hb.idle_connection_test_period = 3600 + +app_display_name = Portal +files_path = /tmp +context_root = ECOMPPORTAL +# menu settings +menu_query_name = menuData +menu_properties_file_location = /WEB-INF/fusion/menu/ +application_menu_set_name = APP +application_menu_attribute_name = applicationMenuData +application_menu_properties_name = menu.properties +business_direct_menu_set_name = BD +business_direct_menu_properties_name = bd.menu.properties +business_direct_menu_attribute_name = businessDirectMenuData + +application_user_id = 30000 +post_default_role_id = 1 + +#Enable Fusion Mobile capabilities for the application +mobile_enable = false + +cache_config_file_path = /WEB-INF/conf/cache.ccf +cache_switch = 1 +cache_load_on_startup = false + +user_name = fullName +decryption_key = AGLDdG4D04BKm2IxIWEr8o== + + +#Cron Schedules +cron_site_name = one +log_cron = 0 * * * * ? * +sessiontimeout_feed_cron = 0 0/5 * * * ? * + +#Front end URL +frontend_url = http://portal.api.simpledemo.openecomp.org:8989/ECOMPPORTAL/applicationsHome + +#cookie domain +cookie_domain = openecomp.org + +# An Unqiue 128-bit value defined to indentify a specific version of +# ECOMP Portal deployed on a specific virtual machine. +# This value must be generated and updated at the time of +# the deployment. +# Online Unique UUID generator - https://www.uuidgenerator.net/ +instance_uuid = 90bc9497-10e6-49fe-916b-dcdfaa972383 + +elastic_search_url = http:// +contact_us_link = http:// +user_guide_link = http:// + +# Contact Us page properties +ush_ticket_url = http:// +feedback_email_address = portal@lists.openecomp.org +portal_info_url = https:// + +#Online user bar refresh interval, in seconds +online_user_update_rate = 30 + +#Online user bar refresh total duration, in seconds +online_user_update_duration = 300 + +#authenticate user server +authenticate_user_server=http://portal.api.simpledemo.openecomp.org:8383/openid-connect-server-webapp/allUsers + +#window width threshold to collapse left/right menu when page onload +window_width_threshold_left_menu = 1400 +window_width_threshold_right_menu = 1350 + +# User notification refresh interval and duration, in seconds +notification_update_rate = 90 +notification_update_duration = 900 + +#Microservices Related Properties for Portal +microservices.widget.protocol = http +microservices.widget.hostname = portal-wms +microservices.widget.username = widget_user +microservices.widget.password = KpuqIB08YHg+btG+pjX+sA== +#This property won't be needed after consul is functional on VMs - +microservices.widget.local.port = 8082 +microservices.m-learn.local.port = 8083 +#HALO API enable flag +external_access_enable = false + +#delete auditlog from number of days ago +auditlog_del_day_from = 365 diff --git a/deliveries/properties_rackspace/ECOMPSDKAPP/fusion.properties b/deliveries/properties_rackspace/ECOMPSDKAPP/fusion.properties new file mode 100644 index 00000000..8ce8cc95 --- /dev/null +++ b/deliveries/properties_rackspace/ECOMPSDKAPP/fusion.properties @@ -0,0 +1,35 @@ +# login settings +login_method_backdoor = backdoor +login_method_attribute_name = login_method + +# These properties will be removed after SingleSignOnController is cleaned +authentication_mechanism = BOTH +login_method_csp = csp +login_method_web_junction = web_junction + +#login message +login.error.hrid.empty = Login failed, please contact system administrator. +login.error.hrid.not-found = User not found, please contact system administrator. +login.error.user.inactive = Account is disabled, please contact system administrator. + +# User Session settings +user_attribute_name = user +roles_attribute_name = roles +role_function_list = role_function_list +role_functions_attribute_name = role_functions + +# Import-user LDAP settings +post_initial_context_factory = com.sun.jndi.ldap.LdapCtxFactory +post_provider_url = ldap://ldap.mycompany.com:389 +post_security_principal = ou=people,o=mycompany,c=us +post_max_result_size = 499 + +# menu settings +menu_query_name = menuData +application_menu_set_name = APP +application_menu_attribute_name = applicationMenuData +business_direct_menu_set_name = BD +business_direct_menu_attribute_name = businessDirectMenuData + +# Role settings +sys_admin_role_id = 1 diff --git a/deliveries/properties_rackspace/ECOMPSDKAPP/portal.properties b/deliveries/properties_rackspace/ECOMPSDKAPP/portal.properties new file mode 100644 index 00000000..b569e4fc --- /dev/null +++ b/deliveries/properties_rackspace/ECOMPSDKAPP/portal.properties @@ -0,0 +1,44 @@ +# Properties read by ECOMP Framework library, ecompFW.jar + +########################################################################## +# The following properties should NOT be changed by partner applications. +########################################################################## + +portal.api.prefix = /api +max.idle.time = 5 +user.attribute.name = user_attribute + +#Use REST API instead of UEB to fetch the functional menu data +use_rest_for_functional_menu=true + +########################################################################## +# The following properties MUST be changed by partner applications. +########################################################################## + +# Name of java class that implements the OnBoardingApiService interface. +portal.api.impl.class = org.openecomp.portalapp.service.OnBoardingApiServiceImpl + +# CSP Global Log On for single sign on +ecomp_redirect_url = http://portal.api.simpledemo.openecomp.org:8989/ECOMPPORTAL/login.htm + +# URL of the ECOMP Portal REST API + +ecomp_rest_url = http://portal.api.simpledemo.openecomp.org:8989/ECOMPPORTAL/auxapi + +# Applications do not need to run a UEB listener in 1610. +ueb_listeners_enable = false + +# UEB Configuration +ueb_url_list = ueb.api.simpledemo.openecomp.org +# ECOMP Portal listens on this UEB topic +ecomp_portal_inbox_name = ECOMP-PORTAL-INBOX +# Replace these 3 default values with the ones for your specific App, +# as shown on the on-boarding page on the ECOMP Portal web application. +ueb_app_key = jQd4a9zVNi4ePyBp +ueb_app_secret = P0HpqEBhKJvxjRYdw2sCTUll +ueb_app_mailbox_name = ECOMP-PORTAL-OUTBOX-APP1 +# Consumer group name for UEB topic. +# Use the special tag '{UUID}' to generate a unique one for each sdk-app server. +ueb_app_consumer_group_name = {UUID} + +decryption_key = AGLDdG4D04BKm2IxIWEr8o== diff --git a/deliveries/properties_rackspace/ECOMPSDKAPP/system.properties b/deliveries/properties_rackspace/ECOMPSDKAPP/system.properties new file mode 100644 index 00000000..105502f1 --- /dev/null +++ b/deliveries/properties_rackspace/ECOMPSDKAPP/system.properties @@ -0,0 +1,65 @@ +# Properties read by ECOMP Core library, ecompSDK-core.jar + +########################################################################## +# The following properties should NOT be changed by partner applications. +########################################################################## + +application_user_id = 30000 +post_default_role_id = 16 +clustered = true + +#Enable Fusion Mobile capabilities for the application +mobile_enable = false + +# Cache config file is needed on the classpath +cache_config_file_path = /WEB-INF/classes/cache.ccf +cache_switch = 199 +cache_load_on_startup = false + +user_name = fullName +decryption_key = AGLDdG4D04BKm2IxIWEr8o== + +########################################################################## +# The following properties MAY require changes by partner applications. +########################################################################## + +#Mysql +db.driver = com.mysql.jdbc.Driver +db.connectionURL = jdbc:mysql://portal-db:3306/ecomp_sdk +db.userName = root +db.password = Aa123456 +db.min_pool_size = 5 +db.max_pool_size = 10 +hb.dialect = org.hibernate.dialect.MySQLDialect +# SQL statements are logged to stdout +hb.show_sql = true +hb.idle_connection_test_period = 3600 + +app_display_name = Demo App +files_path = /tmp + +#element map files +element_map_file_path = /tmp +element_map_icon_path = app/fusionapp/icons/ + +#Cron Schedules +log_cron = 0 0/1 * * * ?; +mylogins_feed_cron = 0 0/60 * * * ?; +#sessiontimeout_feed_cron = 0 * * * * ? * +my_login_feed_output_dir = /tmp/MyLogins + +# Link shown in Help menu +contact_us_link = https://todo_contact_us_link.com + +# An Unique 128-bit value defined to identify a specific version +# of an application deployed on a specific virtual machine. +# This value must be generated and updated by the application +# which is using the ECOMP SDK at the time of its deployment. +# Online Unique UUID generator - https://www.uuidgenerator.net/ +instance_uuid=8da691c9-987d-43ed-a358-00ac2f35685d + +# R Cloud feature - configure this property to enable notebook feature - for more details on RCloud please visit https://rcloud.social/index.html +guard_notebook_url= + +#authenticate user server +authenticate_user_server=http://portal.openecomp.org:8383/openid-connect-server-webapp/allUsers diff --git a/deliveries/properties_rackspace/ECOMPWIDGETMS/application.properties b/deliveries/properties_rackspace/ECOMPWIDGETMS/application.properties new file mode 100644 index 00000000..7c95923f --- /dev/null +++ b/deliveries/properties_rackspace/ECOMPWIDGETMS/application.properties @@ -0,0 +1,35 @@ +## General App Properties +server.contextPath=/widget +server.port=8082 +spring.http.multipart.max-file-size=128MB +spring.http.multipart.max-request-size=128MB +microservice.widget.location=/tmp + +## App DB Properties +spring.datasource.url=jdbc:mysql://portal-db:3306/portal +spring.datasource.username=root +spring.datasource.password=Aa123456 +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect +spring.database.driver.classname=org.mariadb.jdbc.Driver +spring.jpa.show-sql=false +spring.jpa.properties.hibernate.format_sql=false + +## Basic Authentication Properties +security.user.name=widget_user +security.user.password=ENC(IjywcRnI9+nuVEh9+OFFiRWAjBT1n718) + +initialization.default.widgets=true +initialization.widgetData.url=http://portal.api.simpledemo.openecomp.org:8989/ECOMPPORTAL/commonWidgets + +## Account Basic Authentication Properties +account.user.name=portal +account.user.password=6APqvG4AU2rfLgCvMdySwQ== + +## Certificate Properties +#server.ssl.key-store=classpath:widget-keystore.p12 +#server.ssl.key-store-password=ENC(DiIYnAMab4u7rEW2yKhF9zBL00uU55q8) +#server.ssl.keyStoreType=PKCS12 +#server.ssl.keyAlias=widget-microservice + +## Jasypt Properties +jasypt.encryptor.password=EncryptionKey diff --git a/deliveries/run.sh b/deliveries/run.sh deleted file mode 100755 index bd2a5dd1..00000000 --- a/deliveries/run.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -# Stop on errors; show output -set -e -x -# 1610 builder -# ./os_build_febe.sh -# 1707 builder -./build_portalapps_dockers.sh -./createMaria.sh -docker images diff --git a/deliveries/configure-and-run.sh b/deliveries/start-apps-cmd.sh similarity index 94% rename from deliveries/configure-and-run.sh rename to deliveries/start-apps-cmd.sh index 5c2b2f46..bbe2a7cb 100755 --- a/deliveries/configure-and-run.sh +++ b/deliveries/start-apps-cmd.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh LOGFILE=/opt/apache-tomcat-8.0.37/logs/catalina.out echo "`date`:<-------------------- Starting -------------------->" >> $LOGFILE diff --git a/deliveries/start-wms-cmd.sh b/deliveries/start-wms-cmd.sh new file mode 100755 index 00000000..dc8336e7 --- /dev/null +++ b/deliveries/start-wms-cmd.sh @@ -0,0 +1,2 @@ +#!/bin/sh +java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar diff --git a/deliveries/wait-for.sh b/deliveries/wait-for.sh new file mode 100755 index 00000000..be9a443f --- /dev/null +++ b/deliveries/wait-for.sh @@ -0,0 +1,82 @@ +#!/bin/sh +# https://github.com/Eficode/wait-for.git +# MIT License + +TIMEOUT=15 +QUIET=0 + +echoerr() { + if [ "$QUIET" -ne 1 ]; then printf "%s\n" "$*" 1>&2; fi +} + +usage() { + exitcode="$1" + cat << USAGE >&2 +Usage: + $cmdname host:port [-t timeout] [-- command args] + -q | --quiet Do not output any status messages + -t TIMEOUT | --timeout=timeout Timeout in seconds, zero for no timeout + -- COMMAND ARGS Execute command with args after the test finishes +USAGE + exit "$exitcode" +} + +wait_for() { + command="$*" + for i in `seq $TIMEOUT` ; do + nc -z "$HOST" "$PORT" > /dev/null 2>&1 + result=$? + if [ $result -eq 0 ] ; then + if [ "$QUIET" -ne 1 ]; then echo "Operation succeeded on try $i"; fi + if [ -n "$command" ] ; then + exec $command + fi + exit 0 + fi + sleep 1 + done + echo "Operation timed out" >&2 + exit 1 +} + +while [ $# -gt 0 ] +do + case "$1" in + *:* ) + HOST=$(printf "%s\n" "$1"| cut -d : -f 1) + PORT=$(printf "%s\n" "$1"| cut -d : -f 2) + shift 1 + ;; + -q | --quiet) + QUIET=1 + shift 1 + ;; + -t) + TIMEOUT="$2" + if [ "$TIMEOUT" = "" ]; then break; fi + shift 2 + ;; + --timeout=*) + TIMEOUT="${1#*=}" + shift 1 + ;; + --) + shift + break + ;; + --help) + usage 0 + ;; + *) + echoerr "Unknown argument: $1" + usage 1 + ;; + esac +done + +if [ "$HOST" = "" -o "$PORT" = "" ]; then + echoerr "Error: you need to provide a host and port to test." + usage 2 +fi + +wait_for "$@" diff --git a/deliveries/widget_ms_start.sh b/deliveries/widget_ms_start.sh deleted file mode 100755 index b5fbdc25..00000000 --- a/deliveries/widget_ms_start.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -# Establish environment variables -source $(dirname $0)/os_settings.sh - -BASEDIR=/PROJECT/OpenSource/UbuntuEP -WIDGETMSAPPPROPDIR=ECOMPWIDGETMS - -echo "Running docker image ${WMS_IMG_NAME} as container ${WMS_CONT_NAME}" -docker run -d --name ${WMS_CONT_NAME} -p 8082:8082 -v ${BASEDIR}/etc/${WIDGETMSAPPPROPDIR}/application.properties:/application.properties ${WMS_IMG_NAME} diff --git a/deliveries/widget_ms_stop.sh b/deliveries/widget_ms_stop.sh deleted file mode 100755 index dd5c9645..00000000 --- a/deliveries/widget_ms_stop.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -# Establish environment variables -source $(dirname $0)/os_settings.sh - -echo "Stopping docker container ${WMS_CONT_NAME}" -docker stop ${WMS_CONT_NAME} -echo "Removing docker image ${WMS_CONT_NAME}" -docker rm ${WMS_CONT_NAME} diff --git a/ecomp-portal-BE-common-test/pom.xml b/ecomp-portal-BE-common-test/pom.xml index 2e47388b..afdf35ac 100644 --- a/ecomp-portal-BE-common-test/pom.xml +++ b/ecomp-portal-BE-common-test/pom.xml @@ -2,9 +2,9 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.openecomp.portal + org.onap.portal ecomp-portal-BE-common-test - 1.1.0 + 1.3.0-SNAPSHOT jar ecompportal-be-common-test @@ -105,7 +105,7 @@ 1.8.5 - org.openecomp.portal + org.onap.portal ecompportal-be-common ${project.version} jar diff --git a/ecomp-portal-BE-common/pom.xml b/ecomp-portal-BE-common/pom.xml index f5f925b8..af828cf2 100644 --- a/ecomp-portal-BE-common/pom.xml +++ b/ecomp-portal-BE-common/pom.xml @@ -1,18 +1,18 @@ 4.0.0 - org.openecomp.portal + org.onap.portal ecompportal-be-common war - 1.1.0 + 1.3.0-SNAPSHOT 4.2.0.RELEASE 4.3.11.Final 1.0.0 2.7.4 - 1.1.0 + 1.3.0-SNAPSHOT UTF-8 true @@ -503,7 +503,7 @@ - org.openecomp.ecompsdkos + org.onap.portal.sdk epsdk-fw ${epsdk.version} @@ -526,7 +526,7 @@ - org.openecomp.ecompsdkos + org.onap.portal.sdk epsdk-core ${epsdk.version} @@ -537,12 +537,12 @@ - org.openecomp.ecompsdkos + org.onap.portal.sdk epsdk-app-common ${epsdk.version} - org.openecomp.ecompsdkos + org.onap.portal.sdk epsdk-workflow ${epsdk.version} @@ -550,7 +550,7 @@ - org.openecomp.ecompsdkos + org.onap.portal.sdk epsdk-analytics ${epsdk.version} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/config/PortalCentralAccessConfiguration.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/config/PortalCentralAccessConfiguration.java new file mode 100644 index 00000000..4ee4be20 --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/config/PortalCentralAccessConfiguration.java @@ -0,0 +1,29 @@ +package org.openecomp.portalapp.config; + +import org.openecomp.portalapp.portal.service.EPRoleFunctionService; +import org.openecomp.portalapp.portal.service.EPRoleFunctionServiceCentralizedImpl; +import org.openecomp.portalapp.portal.service.EPRoleFunctionServiceImpl; +import org.openecomp.portalsdk.core.service.CentralAccessCondition; +import org.openecomp.portalsdk.core.service.LocalAccessCondition; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class PortalCentralAccessConfiguration { + + + @Bean + @Conditional(LocalAccessCondition.class) + public EPRoleFunctionService ePRoleFunctionServiceImpl() { + return new EPRoleFunctionServiceImpl(); + } + + + @Bean + @Conditional(CentralAccessCondition.class) + public EPRoleFunctionService ePRoleFunctionServiceCentralizedImpl() { + return new EPRoleFunctionServiceCentralizedImpl(); + } + +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/AppsControllerExternalRequest.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/AppsControllerExternalRequest.java index 774eb3ee..00cf627e 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/AppsControllerExternalRequest.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/AppsControllerExternalRequest.java @@ -209,7 +209,7 @@ public class AppsControllerExternalRequest implements BasicAuthenticationControl "myLoginsAppOwner" : "abc123", "name": "dashboard", "url": "http://k8s/something", - "restUrl" : "http://aic.att.com", + "restUrl" : "http://targeturl.com", "restrictedApp" : true, "isOpen" : true, "isEnabled": false @@ -295,7 +295,7 @@ public class AppsControllerExternalRequest implements BasicAuthenticationControl "myLoginsAppOwner" : "abc123", "name": "dashboard", "url": "http://k8s/something", - "restUrl" : "http://aic.att.com", + "restUrl" : "http://targeturl.com", "restrictedApp" : true, "isOpen" : true, "isEnabled": false diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/ExternalAccessRolesController.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/ExternalAccessRolesController.java new file mode 100644 index 00000000..43e07af3 --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/ExternalAccessRolesController.java @@ -0,0 +1,330 @@ +package org.openecomp.portalapp.portal.controller; + + +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.openecomp.portalapp.portal.domain.CentralRoleFunction; +import org.openecomp.portalapp.portal.domain.EPApp; +import org.openecomp.portalapp.portal.ecomp.model.PortalRestResponse; +import org.openecomp.portalapp.portal.ecomp.model.PortalRestStatusEnum; +import org.openecomp.portalapp.portal.logging.aop.EPAuditLog; +import org.openecomp.portalapp.portal.service.ExternalAccessRolesService; +import org.openecomp.portalapp.portal.transport.CentralRole; +import org.openecomp.portalsdk.core.domain.Role; +import org.openecomp.portalsdk.core.domain.RoleFunction; +import org.openecomp.portalsdk.core.logging.logic.EELFLoggerDelegate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.HttpClientErrorException; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import io.swagger.annotations.ApiOperation; + +@RestController +@RequestMapping("/auxapi") +@org.springframework.context.annotation.Configuration +@EnableAspectJAutoProxy +@EPAuditLog +public class ExternalAccessRolesController implements BasicAuthenticationController { + + private static final String UEBKEY = "uebkey"; + + private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(ExternalAccessRolesController.class); + + @Autowired + private ExternalAccessRolesService externalAccessRolesService; + + @ApiOperation(value = "Gets user role for an application.", response = String.class, responseContainer="List") + @RequestMapping(value = { + "/user/{loginId}" }, method = RequestMethod.GET, produces = "application/json") + public String getUser(HttpServletRequest request, HttpServletResponse response, @PathVariable("loginId") String loginId) throws Exception { + + String answer = null; + try { + answer = externalAccessRolesService.getUser(loginId, request.getHeader(UEBKEY)); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, "getUser failed", e); + } + return answer; + } + + @ApiOperation(value = "Gets roles for an application.", response = CentralRole.class, responseContainer="Json") + @RequestMapping(value = { + "/roles" }, method = RequestMethod.GET, produces = "application/json") + public List getRolesForApp(HttpServletRequest request, HttpServletResponse response) throws Exception { + logger.debug(EELFLoggerDelegate.debugLogger, "Request received for getRolesForApp"); + List applicationList=new ArrayList<>(); + applicationList = externalAccessRolesService.getApp(request.getHeader(UEBKEY)); + EPApp app = applicationList.get(0); + externalAccessRolesService.SyncApplicationRolesWithEcompDB(app); + List answer = null; + try { + answer = externalAccessRolesService.getRolesForApp(request.getHeader(UEBKEY)); + } catch (HttpClientErrorException e) { + if("Application not found".equalsIgnoreCase(e.getMessage())){ + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + } + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + logger.error(EELFLoggerDelegate.errorLogger, "getRolesForApp failed", e); + } + logger.debug(EELFLoggerDelegate.debugLogger, "Request completed for getRolesForApp"); + return answer; + } + + @ApiOperation(value = "Gets all role functions for an application.", response = CentralRoleFunction.class, responseContainer="Json") + @RequestMapping(value = { + "/functions" }, method = RequestMethod.GET, produces = "application/json") + public List getRoleFunctionsList(HttpServletRequest request, HttpServletResponse response) throws Exception { + List answer = null; + logger.debug(EELFLoggerDelegate.debugLogger, "Request received for getRoleFunctionsList"); + try { + answer = externalAccessRolesService.getRoleFuncList(request.getHeader(UEBKEY)); + } catch (HttpClientErrorException e) { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + logger.error(EELFLoggerDelegate.errorLogger, "getRoleFunctionsList failed", e); + } + logger.debug(EELFLoggerDelegate.debugLogger, "Request completed for getRoleFunctionsList"); + return answer; + } + + @ApiOperation(value = "Gets role information for an application.", response = CentralRole.class, responseContainer="Json") + @RequestMapping(value = { + "/role/{role_id}" }, method = RequestMethod.GET, produces = "application/json") + public CentralRole getRoleInfo(HttpServletRequest request, HttpServletResponse response, @PathVariable("role_id") Long roleId) throws Exception { + CentralRole answer = null; + logger.debug(EELFLoggerDelegate.debugLogger, "Request received for getRoleInfo"); + + try { + answer = externalAccessRolesService.getRoleInfo(roleId, request.getHeader(UEBKEY)); + } catch (HttpClientErrorException e) { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + logger.error(EELFLoggerDelegate.errorLogger, "getRoleInfo failed", e); + } + logger.debug(EELFLoggerDelegate.debugLogger, "Request completed for getRoleInfo"); + return answer; + } + + @ApiOperation(value = "Gets role information for an application provided by function code.", response = CentralRoleFunction.class, responseContainer = "Json") + @RequestMapping(value = { "/function/{code}" }, method = RequestMethod.GET, produces = "application/json") + public CentralRoleFunction getRoleFunction(HttpServletRequest request, HttpServletResponse response, + @PathVariable("code") String code) throws Exception { + CentralRoleFunction centralRoleFunction = null; + try { + centralRoleFunction = externalAccessRolesService.getRoleFunction(code, request.getHeader(UEBKEY)); + } catch (HttpClientErrorException e) { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + logger.error(EELFLoggerDelegate.errorLogger, "getRoleInfo failed", e); + } + return centralRoleFunction; + } + + @ApiOperation(value = "Saves role function for an application.", response = PortalRestResponse.class, responseContainer = "Json") + @RequestMapping(value = { "/roleFunction" }, method = RequestMethod.POST, produces = "application/json") + public PortalRestResponse saveRoleFunction(HttpServletRequest request, HttpServletResponse response, + @RequestBody String roleFunc) throws Exception { + + ObjectMapper mapper = new ObjectMapper(); + List applicationList = externalAccessRolesService.getApp(request.getHeader(UEBKEY)); + EPApp requestedApp = applicationList.get(0); + Long appId = requestedApp.getId(); + try { + String data = roleFunc; + CentralRoleFunction availableRoleFunction = mapper.readValue(data, CentralRoleFunction.class); + availableRoleFunction.setAppId(appId); + externalAccessRolesService.saveCentralRoleFunction(availableRoleFunction, requestedApp); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, "saveRoleFunction failed", e); + return new PortalRestResponse(PortalRestStatusEnum.ERROR, e.getMessage(), "Failed"); + } + return new PortalRestResponse(PortalRestStatusEnum.OK, "Successfully Saved", "Success"); + } + + @ApiOperation(value = "Deletes role function for an application.", response = PortalRestResponse.class, responseContainer = "Json") + @RequestMapping(value = { "/roleFunction/{code}" }, method = RequestMethod.DELETE, produces = "application/json") + public PortalRestResponse deleteRoleFunction(HttpServletRequest request, HttpServletResponse response, @PathVariable("code") String code) throws Exception { + try { + externalAccessRolesService.deleteCentralRoleFunction(code, request.getHeader(UEBKEY)); + } catch (HttpClientErrorException e) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + logger.error(EELFLoggerDelegate.errorLogger, "deleteRoleFunction failed", e); + return new PortalRestResponse(PortalRestStatusEnum.ERROR, "Failed to deleteRoleFunction", "Failed"); + } + return new PortalRestResponse(PortalRestStatusEnum.OK, "Successfully Deleted", "Success"); + + } + + @ApiOperation(value = "Saves role for an application.", response = PortalRestResponse.class, responseContainer = "Json") + @RequestMapping(value = { "/role" }, method = RequestMethod.POST, produces = "application/json") + public PortalRestResponse saveRole(HttpServletRequest request, HttpServletResponse response, + @RequestBody Role role) throws Exception { + try { + externalAccessRolesService.saveRoleForApplication(role,request.getHeader(UEBKEY)); + } catch (Exception e) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + logger.error(EELFLoggerDelegate.errorLogger, "saveRole failed", e); + return new PortalRestResponse(PortalRestStatusEnum.ERROR, "Failed to saveRole", "Failed"); + } + return new PortalRestResponse(PortalRestStatusEnum.OK, "Successfully Saved", "Success"); + } + + @ApiOperation(value = "Deletes role for an application.", response = PortalRestResponse.class, responseContainer = "Json") + @RequestMapping(value = { "/deleteRole/{code}" }, method = RequestMethod.DELETE, produces = "application/json") + public PortalRestResponse deleteRole(HttpServletRequest request, HttpServletResponse response, + @PathVariable String code) throws Exception { + try { + externalAccessRolesService.deleteRoleForApplication(code, request.getHeader(UEBKEY)); + } catch (Exception e) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + logger.error(EELFLoggerDelegate.errorLogger, "deleteRole failed", e); + return new PortalRestResponse(PortalRestStatusEnum.ERROR, "Failed to deleteRole", "Failed"); + } + return new PortalRestResponse(PortalRestStatusEnum.OK, "Successfully Deleted", "Success"); + + } + + @ApiOperation(value = "Gets active roles for an application.", response = CentralRole.class, responseContainer = "Json") + @RequestMapping(value = { "/activeRoles" }, method = RequestMethod.GET, produces = "application/json") + public List getActiveRoles(HttpServletRequest request, HttpServletResponse response) throws Exception { + List cenRole = null; + try { + cenRole = externalAccessRolesService.getActiveRoles(request.getHeader(UEBKEY)); + } catch (HttpClientErrorException e) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + logger.error(EELFLoggerDelegate.errorLogger, "getActiveRoles failed", e); + } + return cenRole; + + } + + @ApiOperation(value = "deletes user roles for an application.", response = PortalRestResponse.class, responseContainer = "Json") + @RequestMapping(value = { "/deleteDependcyRoleRecord/{roleId}" }, method = RequestMethod.DELETE, produces = "application/json") + public PortalRestResponse deleteDependcyRoleRecord(HttpServletRequest request, HttpServletResponse response, @PathVariable("roleId") Long roleId) throws Exception { + try { + externalAccessRolesService.deleteDependcyRoleRecord(roleId,request.getHeader(UEBKEY), request.getHeader("LoginId")); + } catch (HttpClientErrorException e) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + logger.error(EELFLoggerDelegate.errorLogger, "deleteDependcyRoleRecord failed", e); + return new PortalRestResponse(PortalRestStatusEnum.ERROR, "Failed to deleteDependcyRoleRecord", "Failed"); + } + return new PortalRestResponse(PortalRestStatusEnum.OK, "Successfully Deleted", "Success"); + } + + @ApiOperation(value = "Bulk upload functions for an application.", response = PortalRestResponse.class, responseContainer = "Json") + @RequestMapping(value = { "/upload/portal/functions" }, method = RequestMethod.POST, produces = "application/json") + public PortalRestResponse bulkUploadFunctions(HttpServletRequest request, HttpServletResponse response) throws Exception { + Integer result = 0; + try { + result = externalAccessRolesService.bulkUploadFunctions(request.getHeader(UEBKEY)); + } catch (HttpClientErrorException e) { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + logger.error(EELFLoggerDelegate.errorLogger, "bulkUploadFunctions failed", e); + return new PortalRestResponse(PortalRestStatusEnum.ERROR, "Failed to bulkUploadFunctions", "Failed"); + } + return new PortalRestResponse(PortalRestStatusEnum.OK, "Successfully added: "+result, "Success"); + } + + @ApiOperation(value = "Bulk upload roles for an application.", response = PortalRestResponse.class, responseContainer = "Json") + @RequestMapping(value = { "/upload/portal/roles" }, method = RequestMethod.POST, produces = "application/json") + public PortalRestResponse bulkUploadRoles(HttpServletRequest request, HttpServletResponse response) throws Exception { + Integer result = 0; + try { + result = externalAccessRolesService.bulkUploadRoles(request.getHeader(UEBKEY)); + } catch (HttpClientErrorException e) { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + logger.error(EELFLoggerDelegate.errorLogger, "bulkUploadRoles failed", e); + return new PortalRestResponse(PortalRestStatusEnum.ERROR, "Failed to bulkUploadRoles", "Failed"); + } + return new PortalRestResponse(PortalRestStatusEnum.OK, "Successfully added: "+result, "Success"); + } + + @ApiOperation(value = "Bulk upload role functions for an application.", response = PortalRestResponse.class, responseContainer = "Json") + @RequestMapping(value = { "/upload/portal/roleFunctions" }, method = RequestMethod.POST, produces = "application/json") + public PortalRestResponse bulkUploadRoleFunctions(HttpServletRequest request, HttpServletResponse response) throws Exception { + Integer result = 0; + try { + result = externalAccessRolesService.bulkUploadRolesFunctions(request.getHeader(UEBKEY)); + } catch (HttpClientErrorException e) { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + logger.error(EELFLoggerDelegate.errorLogger, "bulkUploadRoleFunctions failed", e); + return new PortalRestResponse(PortalRestStatusEnum.ERROR, "Failed to bulkUploadRoleFunctions", "Failed"); + } + return new PortalRestResponse(PortalRestStatusEnum.OK, "Successfully added: "+result, "Success"); + } + + @ApiOperation(value = "Bulk upload user roles for an application.", response = PortalRestResponse.class, responseContainer = "Json") + @RequestMapping(value = { "/upload/portal/userRoles" }, method = RequestMethod.POST, produces = "application/json") + public PortalRestResponse bulkUploadUserRoles(HttpServletRequest request, HttpServletResponse response) throws Exception { + Integer result = 0; + try { + result = externalAccessRolesService.bulkUploadUserRoles(request.getHeader(UEBKEY)); + } catch (HttpClientErrorException e) { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + logger.error(EELFLoggerDelegate.errorLogger, "bulkUploadUserRoles failed", e); + return new PortalRestResponse(PortalRestStatusEnum.ERROR, "Failed to bulkUploadUserRoles", "Failed"); + } + return new PortalRestResponse(PortalRestStatusEnum.OK, "Successfully added: "+result, "Success"); + } + + @ApiOperation(value = "Bulk upload functions for an partner application.", response = PortalRestResponse.class, responseContainer = "Json") + @RequestMapping(value = { "/upload/partner/functions" }, method = RequestMethod.POST, produces = "application/json") + public PortalRestResponse bulkUploadPartnerFunctions(HttpServletRequest request, HttpServletResponse response, @RequestBody List upload) throws Exception { + try { + externalAccessRolesService.bulkUploadPartnerFunctions(request.getHeader(UEBKEY), upload); + } catch (HttpClientErrorException e) { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + logger.error(EELFLoggerDelegate.errorLogger, "bulkUploadFunctions failed", e); + return new PortalRestResponse(PortalRestStatusEnum.ERROR, "Failed to bulkUploadFunctions", "Failed"); + } + return new PortalRestResponse(PortalRestStatusEnum.OK, "Successfully added", "Success"); + } + + @ApiOperation(value = "Bulk upload roles for an partner application.", response = PortalRestResponse.class, responseContainer = "Json") + @RequestMapping(value = { "/upload/partner/roles" }, method = RequestMethod.POST, produces = "application/json") + public PortalRestResponse bulkUploadPartnerRoles(HttpServletRequest request, HttpServletResponse response, @RequestBody List upload) throws Exception { + try { + externalAccessRolesService.bulkUploadPartnerRoles(request.getHeader(UEBKEY), upload); + } catch (HttpClientErrorException e) { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + logger.error(EELFLoggerDelegate.errorLogger, "bulkUploadRoles failed", e); + return new PortalRestResponse(PortalRestStatusEnum.ERROR, "Failed to bulkUploadRoles", "Failed"); + } + return new PortalRestResponse(PortalRestStatusEnum.OK, "Successfully added", "Success"); + } + + @ApiOperation(value = "Bulk upload role functions for an partner application.", response = PortalRestResponse.class, responseContainer = "Json") + @RequestMapping(value = { "/upload/partner/roleFunctions" }, method = RequestMethod.POST, produces = "application/json") + public PortalRestResponse bulkUploadPartnerRoleFunctions(HttpServletRequest request, HttpServletResponse response, @RequestBody List upload) throws Exception { + try { + externalAccessRolesService.bulkUploadPartnerRoleFunctions(request.getHeader(UEBKEY), upload); + } catch (HttpClientErrorException e) { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + logger.error(EELFLoggerDelegate.errorLogger, "bulkUploadRoles failed", e); + return new PortalRestResponse(PortalRestStatusEnum.ERROR, "Failed to bulkUploadPartnerRoleFunctions", "Failed"); + } + return new PortalRestResponse(PortalRestStatusEnum.OK, "Successfully added", "Success"); + } + + @ApiOperation(value = "Gets all functions along with global functions", response = List.class, responseContainer = "Json") + @RequestMapping(value = { "/menuFunctions" }, method = RequestMethod.GET, produces = "application/json") + public List getMenuFunctions(HttpServletRequest request, HttpServletResponse response) throws Exception { + List functionsList = null; + try { + functionsList = externalAccessRolesService.getMenuFunctionsList(request.getHeader(UEBKEY)); + } catch (HttpClientErrorException e) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + logger.error(EELFLoggerDelegate.errorLogger, "getMenuFunctions failed", e); + } + return functionsList; + } + +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/RoleManageController.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/RoleManageController.java index 2d0fe279..eefd5004 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/RoleManageController.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/RoleManageController.java @@ -26,9 +26,13 @@ import org.openecomp.portalapp.controller.EPRestrictedBaseController; import org.openecomp.portalapp.controller.core.RoleController; import org.openecomp.portalapp.controller.core.RoleFunctionListController; import org.openecomp.portalapp.controller.core.RoleListController; +import org.openecomp.portalapp.portal.domain.EPApp; import org.openecomp.portalapp.portal.ecomp.model.PortalRestResponse; import org.openecomp.portalapp.portal.ecomp.model.PortalRestStatusEnum; import org.openecomp.portalapp.portal.logging.aop.EPAuditLog; +import org.openecomp.portalapp.portal.service.ExternalAccessRolesService; +import org.openecomp.portalapp.portal.service.ExternalAccessRolesServiceImpl; +import org.openecomp.portalsdk.core.logging.logic.EELFLoggerDelegate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.web.bind.annotation.RequestBody; @@ -47,6 +51,7 @@ import org.springframework.web.servlet.ModelAndView; @EnableAspectJAutoProxy @EPAuditLog public class RoleManageController extends EPRestrictedBaseController { + private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(RoleManageController.class); @Autowired private RoleController roleController; @@ -57,6 +62,9 @@ public class RoleManageController extends EPRestrictedBaseController { @Autowired private RoleFunctionListController roleFunctionListController; + + @Autowired + ExternalAccessRolesService externalAccessRolesService; /** * Calls an SDK-Core library method that gets the available roles and writes * them to the request object. Portal specifies a Hibernate mappings from @@ -120,7 +128,7 @@ public class RoleManageController extends EPRestrictedBaseController { } @RequestMapping(value = { "/portalApi/get_role" }, method = RequestMethod.GET) - public void getRole(HttpServletRequest request, HttpServletResponse response) { + public void getRole(HttpServletRequest request, HttpServletResponse response) throws Exception{ getRoleController().getRole(request, response); } @@ -163,4 +171,13 @@ public class RoleManageController extends EPRestrictedBaseController { this.roleFunctionListController = roleFunctionListController; } + @RequestMapping(value = { "/portalApi/syncRoles" }, method = RequestMethod.GET) + public void syncRoles(EPApp app) + { + try { + externalAccessRolesService.SyncApplicationRolesWithEcompDB(app); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.debugLogger, "failed syncRoles"); + } + } } diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/RolesApprovalSystemController.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/RolesApprovalSystemController.java index c150528e..3dba301a 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/RolesApprovalSystemController.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/RolesApprovalSystemController.java @@ -78,7 +78,7 @@ public class RolesApprovalSystemController implements BasicAuthenticationControl } catch (Exception e) { logger.error(EELFLoggerDelegate.errorLogger, "postUserProfile: failed for app {}, user {}", extSysUser.getApplicationName(), extSysUser.getLoginId(), e); - if(reqResult == null || (!reqResult.isResult() && !e.getMessage().contains("404"))){ + if(reqResult == null || (!reqResult.isResult() && !e.getMessage().contains("404") && !e.getMessage().contains("405"))){ response.setStatus(HttpServletResponse.SC_BAD_REQUEST); return new PortalRestResponse(PortalRestStatusEnum.ERROR, e.getMessage(), "save user profile failed"); @@ -86,10 +86,14 @@ public class RolesApprovalSystemController implements BasicAuthenticationControl response.setStatus(HttpServletResponse.SC_NOT_FOUND); return new PortalRestResponse(PortalRestStatusEnum.ERROR, e.getMessage(), "save user profile failed"); - } else{ + } else if (e.getMessage().contains("405")) { + response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED); + return new PortalRestResponse(PortalRestStatusEnum.ERROR, e.getMessage(), + "save user profile failed"); + } else { response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - return new PortalRestResponse(PortalRestStatusEnum.ERROR, - e.getMessage(), "save user profile failed"); + return new PortalRestResponse(PortalRestStatusEnum.ERROR, e.getMessage(), + "save user profile failed"); } } return new PortalRestResponse(PortalRestStatusEnum.OK, reqResult.getDetailMessage(), "Success"); @@ -117,7 +121,7 @@ public class RolesApprovalSystemController implements BasicAuthenticationControl } catch (Exception e) { logger.error(EELFLoggerDelegate.errorLogger, "putUserProfile: failed for app {}, user {}", extSysUser.getApplicationName(), extSysUser.getLoginId(), e); - if(reqResult == null || (!reqResult.isResult() && !e.getMessage().contains("404"))){ + if(reqResult == null || (!reqResult.isResult() && !e.getMessage().contains("404") && !e.getMessage().contains("405"))){ response.setStatus(HttpServletResponse.SC_BAD_REQUEST); return new PortalRestResponse(PortalRestStatusEnum.ERROR, e.getMessage(), "save user profile failed"); @@ -125,6 +129,9 @@ public class RolesApprovalSystemController implements BasicAuthenticationControl response.setStatus(HttpServletResponse.SC_NOT_FOUND); return new PortalRestResponse(PortalRestStatusEnum.ERROR, e.getMessage(), "save user profile failed"); + } else if (e.getMessage().contains("405")) { + response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED); + return new PortalRestResponse(PortalRestStatusEnum.ERROR, e.getMessage(), "save user profile failed"); } else{ response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return new PortalRestResponse(PortalRestStatusEnum.ERROR, diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/SharedContextRestController.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/SharedContextRestController.java index 984bbf75..08a0d49b 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/SharedContextRestController.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/SharedContextRestController.java @@ -151,7 +151,7 @@ public class SharedContextRestController extends EPRestrictedRESTfulBaseControll SharedContext lastNameContext = contextService.getSharedContext(context_id, EPCommonSystemProperties.USER_LAST_NAME); SharedContext emailContext = contextService.getSharedContext(context_id, EPCommonSystemProperties.USER_EMAIL); - SharedContext attuidContext = contextService.getSharedContext(context_id, + SharedContext orgUserIdContext = contextService.getSharedContext(context_id, EPCommonSystemProperties.USER_ORG_USERID); if (firstNameContext != null) listSharedContext.add(firstNameContext); @@ -159,8 +159,8 @@ public class SharedContextRestController extends EPRestrictedRESTfulBaseControll listSharedContext.add(lastNameContext); if (emailContext != null) listSharedContext.add(emailContext); - if (attuidContext != null) - listSharedContext.add(attuidContext); + if (orgUserIdContext != null) + listSharedContext.add(orgUserIdContext); String jsonResponse = convertResponseToJSON(listSharedContext); return jsonResponse; } diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/TicketEventController.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/TicketEventController.java index e0a9e587..102f7709 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/TicketEventController.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/controller/TicketEventController.java @@ -36,8 +36,10 @@ import org.openecomp.portalapp.portal.logging.aop.EPAuditLog; import org.openecomp.portalapp.portal.service.UserNotificationService; import org.openecomp.portalapp.portal.transport.EpNotificationItem; import org.openecomp.portalapp.portal.transport.EpRoleNotificationItem; +import org.openecomp.portalapp.portal.utils.EPCommonSystemProperties; import org.openecomp.portalapp.portal.utils.PortalConstants; import org.openecomp.portalsdk.core.logging.logic.EELFLoggerDelegate; +import org.openecomp.portalsdk.core.util.SystemProperties; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @@ -62,6 +64,7 @@ import io.swagger.annotations.ApiOperation; @EPAuditLog public class TicketEventController implements BasicAuthenticationController { + @Autowired private UserNotificationService userNotificationService; @@ -73,6 +76,8 @@ public class TicketEventController implements BasicAuthenticationController { private final ObjectMapper mapper = new ObjectMapper(); + + @ApiOperation(value = "Accepts messages from external ticketing systems and creates notifications for Portal users.", response = PortalRestResponse.class) @RequestMapping(value = { "/ticketevent" }, method = RequestMethod.POST) public PortalRestResponse handleRequest(HttpServletRequest request, HttpServletResponse response, @@ -108,6 +113,12 @@ public class TicketEventController implements BasicAuthenticationController { } String eventSource = header.get("eventSource").asText(); epItem.setMsgSource(eventSource); + String ticket = body.get("ticketNum").asText(); + String hyperlink = SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_SYSTEM_NOTIFICATION_URL)+eventSource+"num="+ticket; + if(body.get("notificationHyperlink")!=null){ + hyperlink=body.get("notificationHyperlink").asText(); + } + epItem.setNotificationHyperlink(hyperlink); epItem.setStartTime(new Date(eventDate)); Calendar calendar = Calendar.getInstance(); calendar.setTime(epItem.getStartTime()); @@ -171,14 +182,26 @@ public class TicketEventController implements BasicAuthenticationController { JsonNode header = event.get("header"); JsonNode body = event.get("body"); JsonNode SubscriberInfo = ticketEventNotif.get("SubscriberInfo"); + JsonNode userList = SubscriberInfo.get("UserList"); + if (application == null) - return "application is mandatory"; + return "Application is mandatory"; if (body == null) return "body is mandatory"; if (header.get("eventSource") == null) return "Message Source is mandatory"; - if (SubscriberInfo.get("UserList") == null) + if (userList == null) return "At least one user Id is mandatory"; + JsonNode eventDate=body.get("eventDate"); + + if(eventDate!=null&&eventDate.asText().length()==8) + return "EventDate is invalid"; + String UserIds[] = userList.toString().replace("[", "").replace("]", "").trim().replace("\"", "") + .split(","); + List users = userNotificationService.getUsersByOrgIds(Arrays.asList(UserIds)); + if(users==null||users.size()==0) + return "Invalid Attuid"; return null; } + } diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/CentralRoleFunction.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/CentralRoleFunction.java new file mode 100644 index 00000000..2d659e9c --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/CentralRoleFunction.java @@ -0,0 +1,100 @@ +package org.openecomp.portalapp.portal.domain; + +import org.openecomp.portalsdk.core.domain.support.DomainVo; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +@SuppressWarnings("rawtypes") +public class CentralRoleFunction extends DomainVo implements java.io.Serializable, Comparable{ + + /** + * + */ + private static final long serialVersionUID = -4018975640065252688L; + private String code; + private String name; + @JsonIgnore + private Long appId; + @JsonIgnore + private Long roleId; + private String editUrl; + + + public CentralRoleFunction() { + + } + + + public CentralRoleFunction(Long id, String code, String name, Long appId, String editUrl) { + super(); + this.id = id; + this.code = code; + this.name = name; + this.appId = appId; + this.editUrl = editUrl; + } + + public CentralRoleFunction(String code, String name) { + super(); + this.code = code; + this.name = name; + } + + /** + * @return the code + */ + public String getCode() { + return code; + } + /** + * @param code the code to set + */ + public void setCode(String code) { + this.code = code; + } + /** + * @return the name + */ + public String getName() { + return name; + } + /** + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + /** + * @return the appId + */ + public Long getAppId() { + return appId; + } + /** + * @param appId the appId to set + */ + public void setAppId(Long appId) { + this.appId = appId; + } + /** + * @return the editUrl + */ + public String getEditUrl() { + return editUrl; + } + /** + * @param editUrl the editUrl to set + */ + public void setEditUrl(String editUrl) { + this.editUrl = editUrl; + } + public int compareTo(Object obj){ + String c1 = getName(); + String c2 = ((CentralRoleFunction)obj).getName(); + + return (c1 == null || c2 == null) ? 1 : c1.compareTo(c2); + } + + + +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/EPApp.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/EPApp.java index b0cd13b2..edb3c905 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/EPApp.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/EPApp.java @@ -51,8 +51,9 @@ public class EPApp extends DomainVo { private String uebKey; private String uebSecret; private Integer appType; - private AppContactUs contactUs; + private Boolean centralAuth; + private String nameSpace; public EPApp() { // Attention!!! @@ -282,6 +283,28 @@ public class EPApp extends DomainVo { public void setContactUs(AppContactUs contactUs) { this.contactUs = contactUs; } + + public Boolean getCentralAuth() { + return centralAuth; + } + + public void setCentralAuth(Boolean centralAuth) { + if (centralAuth == null) { + centralAuth = new Boolean(false); + } + this.centralAuth = centralAuth; + } + + public String getNameSpace() { + return nameSpace; + } + + public void setNameSpace(String nameSpace) { + if (StringUtils.isEmpty(nameSpace)) { + nameSpace = null; + } + this.nameSpace = nameSpace; + } @Override public String toString() { diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/EPAppRoleFunction.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/EPAppRoleFunction.java new file mode 100644 index 00000000..7665fd36 --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/EPAppRoleFunction.java @@ -0,0 +1,50 @@ +package org.openecomp.portalapp.portal.domain; + +import org.openecomp.portalsdk.core.domain.support.DomainVo; + +public class EPAppRoleFunction extends DomainVo implements java.io.Serializable{ + + private static final long serialVersionUID = 7752385247460299630L; + + private Long roleId; + private Long appId; + private String code; + + /** + * @return the roleId + */ + public Long getRoleId() { + return roleId; + } + /** + * @param roleId the roleId to set + */ + public void setRoleId(Long roleId) { + this.roleId = roleId; + } + /** + * @return the appId + */ + public Long getAppId() { + return appId; + } + /** + * @param appId the appId to set + */ + public void setAppId(Long appId) { + this.appId = appId; + } + /** + * @return the code + */ + public String getCode() { + return code; + } + /** + * @param code the code to set + */ + public void setCode(String code) { + this.code = code; + } + +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/EpUserAppRoles.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/EPUserAppRoles.java similarity index 97% rename from ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/EpUserAppRoles.java rename to ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/EPUserAppRoles.java index 2649cfd0..574645e3 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/EpUserAppRoles.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/EPUserAppRoles.java @@ -30,7 +30,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; @Entity @JsonInclude(JsonInclude.Include.NON_NULL) -public class EpUserAppRoles extends DomainVo { +public class EPUserAppRoles extends DomainVo { private static final long serialVersionUID = -1484592641766545668L; diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/EcompApp.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/EcompApp.java index 6df37e82..24564aaa 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/EcompApp.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/EcompApp.java @@ -143,4 +143,26 @@ public class EcompApp { public void setRestrictedApp(Boolean restrictedApp) { this.restrictedApp = restrictedApp; } + + private Boolean centralAuth; + + public Boolean getCentralAuth() { + return centralAuth; + } + + public void setCentralAuth(Boolean centralAuth) { + this.centralAuth = centralAuth; + } + + private String nameSpace; + + public String getNameSpace() { + return nameSpace; + } + + public void setNameSpace(String nameSpace) { + this.nameSpace = nameSpace; + } + + } diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/ExternalRoleDetails.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/ExternalRoleDetails.java new file mode 100644 index 00000000..e30b5d36 --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/domain/ExternalRoleDetails.java @@ -0,0 +1,78 @@ +package org.openecomp.portalapp.portal.domain; + +import java.util.List; + +public class ExternalRoleDetails implements Comparable { + + + private String name; + private boolean active; + private Integer priority; + + private Long appId; // used by ECOMP only + private Long appRoleId; // used by ECOMP only + + private List perms; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isActive() { + return active; + } + + public void setActive(boolean active) { + this.active = active; + } + + public Integer getPriority() { + return priority; + } + + public void setPriority(Integer priority) { + this.priority = priority; + } + + public Long getAppId() { + return appId; + } + + public void setAppId(Long appId) { + this.appId = appId; + } + + public Long getAppRoleId() { + return appRoleId; + } + + public void setAppRoleId(Long appRoleId) { + this.appRoleId = appRoleId; + } + + + + public List getPerms() { + return perms; + } + + public void setPerms(List perms) { + this.perms = perms; + } + + @Override + public int compareTo(Object obj) { + EPRole other = (EPRole)obj; + + String c1 = getName(); + String c2 = other.getName(); + + return (c1 == null || c2 == null) ? 1 : c1.compareTo(c2); + } + + +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/logging/aop/EPEELFLoggerAdvice.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/logging/aop/EPEELFLoggerAdvice.java index 89f1b92f..1db63fe8 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/logging/aop/EPEELFLoggerAdvice.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/logging/aop/EPEELFLoggerAdvice.java @@ -170,6 +170,8 @@ public class EPEELFLoggerAdvice { EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(className); logger.debug(EELFLoggerDelegate.debugLogger, "EPEELFLoggerAdvice#after: finished {}", methodName); + // add the metrics log + logger.info(EELFLoggerDelegate.metricsLogger, methodName + " operation is completed."); // Log security message, if necessary if (securityEventType != null) { diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/logging/format/EPAppMessagesEnum.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/logging/format/EPAppMessagesEnum.java index 82c3ad37..62519530 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/logging/format/EPAppMessagesEnum.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/logging/format/EPAppMessagesEnum.java @@ -25,7 +25,6 @@ import org.openecomp.portalsdk.core.logging.format.ErrorTypeEnum; /** * - * @author rc580q * Add ECOMP Portal Specific Error Code Enums here, for generic * ones (ones you think are useful not only Portal but also SDK), add it * to the enum class AppMessagesEnum defined in SDK. diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/logging/format/EPErrorCodesEnum.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/logging/format/EPErrorCodesEnum.java index 498bfcfe..99a6c34a 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/logging/format/EPErrorCodesEnum.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/logging/format/EPErrorCodesEnum.java @@ -24,7 +24,6 @@ import com.att.eelf.i18n.EELFResourceManager; /** * - * @author rc580q * Add ECOMP Portal Specific Error Code Enums here, for generic * ones (ones you think are useful not only Portal but also SDK), add it * to the enum class AppMessagesEnum defined in SDK. diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/AdminRolesServiceImpl.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/AdminRolesServiceImpl.java index 20daa4fc..b5bccfe3 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/AdminRolesServiceImpl.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/AdminRolesServiceImpl.java @@ -22,6 +22,7 @@ package org.openecomp.portalapp.portal.service; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; import javax.annotation.PostConstruct; @@ -29,14 +30,8 @@ import org.apache.cxf.common.util.StringUtils; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.EnableAspectJAutoProxy; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import org.openecomp.portalsdk.core.logging.logic.EELFLoggerDelegate; -import org.openecomp.portalsdk.core.service.DataAccessService; -import org.openecomp.portalsdk.core.util.SystemProperties; +import org.json.JSONArray; +import org.json.JSONObject; import org.openecomp.portalapp.portal.domain.EPApp; import org.openecomp.portalapp.portal.domain.EPRole; import org.openecomp.portalapp.portal.domain.EPUser; @@ -48,8 +43,24 @@ import org.openecomp.portalapp.portal.logging.format.EPAppMessagesEnum; import org.openecomp.portalapp.portal.logging.logic.EPLogUtil; import org.openecomp.portalapp.portal.transport.AppNameIdIsAdmin; import org.openecomp.portalapp.portal.transport.AppsListWithAdminRole; +import org.openecomp.portalapp.portal.transport.ExternalAccessUser; import org.openecomp.portalapp.portal.utils.EPCommonSystemProperties; import org.openecomp.portalapp.portal.utils.EcompPortalUtils; +import org.openecomp.portalapp.portal.utils.PortalConstants; +import org.openecomp.portalsdk.core.logging.logic.EELFLoggerDelegate; +import org.openecomp.portalsdk.core.service.DataAccessService; +import org.openecomp.portalsdk.core.util.SystemProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.client.RestTemplate; + +import com.fasterxml.jackson.databind.ObjectMapper; @Service("adminRolesService") @Transactional @@ -72,7 +83,9 @@ public class AdminRolesServiceImpl implements AdminRolesService { SearchService searchService; @Autowired EPAppService appsService; - + + RestTemplate template = new RestTemplate(); + @PostConstruct private void init() { try { @@ -208,7 +221,9 @@ public class AdminRolesServiceImpl implements AdminRolesService { localSession.save(EPUserApp.class.getName(), newUserApp); } transaction.commit(); - result = true; + + // Add user admin role for list of centralized applications in external system + result = addAdminRoleInExternalSystem(user, localSession, newAppsWhereUserIsAdmin); } catch (Exception e) { EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeDaoSystemError, e); logger.error(EELFLoggerDelegate.errorLogger, "setAppsWithAdminRoleStateForUser: exception in point 2", e); @@ -233,6 +248,129 @@ public class AdminRolesServiceImpl implements AdminRolesService { return result; } + @SuppressWarnings("unchecked") + private boolean addAdminRoleInExternalSystem(EPUser user, Session localSession, List newAppsWhereUserIsAdmin) { + boolean result = false; + try { + // Reset All admin role for centralized applications + List appList = dataAccessService.executeNamedQuery("getCentralizedApps", null, null); + HttpHeaders headers = EcompPortalUtils.base64encodeKeyForAAFBasicAuth(); + for (EPApp app : appList) { + String name = ""; + if (EPCommonSystemProperties + .containsProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_USER_DOMAIN)) { + name = user.getOrgUserId() + SystemProperties + .getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_USER_DOMAIN); + } + String extRole = app.getNameSpace() + "." + PortalConstants.ADMIN_ROLE.replaceAll(" ", "_"); + HttpEntity entity = new HttpEntity<>(headers); + logger.debug(EELFLoggerDelegate.debugLogger, "Connecting to External Access system"); + try { + ResponseEntity getResponse = template + .exchange(SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + + "roles/" + extRole, HttpMethod.GET, entity, String.class); + + if (getResponse.getBody().equals("{}")) { + String addDesc = "{\"name\":\"" + extRole + "\"}"; + HttpEntity roleEntity = new HttpEntity<>(addDesc, headers); + template.exchange( + SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + + "role", + HttpMethod.POST, roleEntity, String.class); + } else { + try { + HttpEntity deleteUserRole = new HttpEntity<>(headers); + template.exchange( + SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + + "userRole/" + name + "/" + extRole, + HttpMethod.DELETE, deleteUserRole, String.class); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, + " Role not found for this user may be it gets deleted before", e); + } + } + } catch (Exception e) { + if (e.getMessage().equalsIgnoreCase("404 Not Found")) { + logger.debug(EELFLoggerDelegate.debugLogger, "Application Not found for app {}", + app.getNameSpace(), e.getMessage()); + } else{ + logger.error(EELFLoggerDelegate.errorLogger, "Application Not found for app {}", + app.getNameSpace(), e); + } + } + } + // Add admin role in external application + // application + for (AppNameIdIsAdmin appNameIdIsAdmin : newAppsWhereUserIsAdmin) { + EPApp app = (EPApp) localSession.get(EPApp.class, appNameIdIsAdmin.id); + try { + if (app.getCentralAuth()) { + String extRole = app.getNameSpace() + "." + PortalConstants.ADMIN_ROLE.replaceAll(" ", "_"); + HttpEntity entity = new HttpEntity<>(headers); + String name = ""; + if (EPCommonSystemProperties + .containsProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_USER_DOMAIN)) { + name = user.getOrgUserId() + SystemProperties + .getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_USER_DOMAIN); + } + logger.debug(EELFLoggerDelegate.debugLogger, "Connecting to External Access system"); + ResponseEntity getUserRolesResponse = template.exchange( + SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + + "userRoles/user/" + name, + HttpMethod.GET, entity, String.class); + logger.debug(EELFLoggerDelegate.debugLogger, "Connected to External Access system"); + if (!getUserRolesResponse.getBody().equals("{}")) { + JSONObject jsonObj = new JSONObject(getUserRolesResponse.getBody()); + JSONArray extRoles = jsonObj.getJSONArray("userRole"); + final Map extUserRoles = new HashMap<>(); + for (int i = 0; i < extRoles.length(); i++) { + String userRole = extRoles.getJSONObject(i).getString("role"); + if (userRole.startsWith(app.getNameSpace() + ".") + && !userRole.equals(app.getNameSpace() + ".admin") + && !userRole.equals(app.getNameSpace() + ".owner")) { + + extUserRoles.put(userRole, extRoles.getJSONObject(i)); + } + } + if (!extUserRoles.containsKey(extRole)) { + // Assign with new apps user admin + try { + ExternalAccessUser extUser = new ExternalAccessUser(name, extRole); + // Assign user role for an application in external access system + ObjectMapper addUserRoleMapper = new ObjectMapper(); + String userRole = addUserRoleMapper.writeValueAsString(extUser); + HttpEntity addUserRole = new HttpEntity<>(userRole, headers); + template.exchange( + SystemProperties.getProperty( + EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + "userRole", + HttpMethod.POST, addUserRole, String.class); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, "Failed to add user admin role", e); + } + + } + } + } + result = true; + } catch (Exception e) { + if (e.getMessage().equalsIgnoreCase("404 Not Found")) { + logger.debug(EELFLoggerDelegate.errorLogger, + "Application name space not found in External system for app {} due to bad rquest name space ", app.getNameSpace(), + e.getMessage()); + } else { + logger.error(EELFLoggerDelegate.errorLogger, "Failed to assign admin role for application {}", + app.getNameSpace(), e); + result = false; + } + } + } + } catch (Exception e) { + result = false; + logger.error(EELFLoggerDelegate.errorLogger, "Failed to assign admin roles operation", e); + } + return result; + } + @SuppressWarnings("unchecked") @Override public boolean isSuperAdmin(EPUser user) { @@ -318,7 +456,7 @@ public class AdminRolesServiceImpl implements AdminRolesService { @EPMetricsLog public List getRolesByApp(EPUser user, Long appId) { List list = new ArrayList<>(); - String sql = "SELECT * FROM FN_ROLE WHERE APP_ID = " + appId; + String sql = "SELECT * FROM FN_ROLE WHERE UPPER(ACTIVE_YN) = 'Y' AND APP_ID = " + appId; @SuppressWarnings("unchecked") List roles = dataAccessService.executeSQLQuery(sql, EPRole.class, null); for (EPRole role: roles) { diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPAppCommonServiceImpl.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPAppCommonServiceImpl.java index f38b921a..6a0da9ba 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPAppCommonServiceImpl.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPAppCommonServiceImpl.java @@ -44,6 +44,8 @@ import org.openecomp.portalapp.portal.domain.AppIdAndNameTransportModel; import org.openecomp.portalapp.portal.domain.AppsResponse; import org.openecomp.portalapp.portal.domain.EPApp; import org.openecomp.portalapp.portal.domain.EPUser; +import org.openecomp.portalapp.portal.domain.EPUserAppRolesRequest; +import org.openecomp.portalapp.portal.domain.EPUserAppRolesRequestDetail; import org.openecomp.portalapp.portal.domain.EPUserAppsManualSortPreference; import org.openecomp.portalapp.portal.domain.EPUserAppsSortPreference; import org.openecomp.portalapp.portal.domain.EPWidgetsManualSortPreference; @@ -180,6 +182,8 @@ public class EPAppCommonServiceImpl implements EPAppService { ecompApp.setUebKey(app.getUebKey()); ecompApp.setUebSecret(app.getUebSecret()); ecompApp.setEnabled(app.getEnabled()); + ecompApp.setCentralAuth(app.getCentralAuth()); + ecompApp.setNameSpace(app.getNameSpace()); ecompApp.setRestrictedApp(app.isRestrictedApp()); ecompAppList.add(ecompApp); } @@ -322,15 +326,10 @@ public class EPAppCommonServiceImpl implements EPAppService { @Override public UserRoles getUserProfile(String loginId) { - String format = "SELECT DISTINCT user.USER_ID, role.ROLE_ID, user.org_user_id, user.FIRST_NAME, user.LAST_NAME, role.ROLE_NAME FROM fn_user_role userrole " - + "INNER JOIN fn_user user ON user.USER_ID = userrole.USER_ID " - + "INNER JOIN fn_role role ON role.ROLE_ID = userrole.ROLE_ID " - + "WHERE user.org_user_id = \"%s\" and (userrole.app_id = 1 or role.role_id = " + ACCOUNT_ADMIN_ROLE_ID - + ") "; - String sql = String.format(format, loginId); - logQuery(sql); + final Map params = new HashMap<>(); + params.put("org_user_id", loginId); @SuppressWarnings("unchecked") - List userRoleList = dataAccessService.executeSQLQuery(sql, UserRole.class, null); + List userRoleList = dataAccessService.executeNamedQuery( "getUserRoles", params, null); ArrayList usersRolesList = aggregateUserProfileRowsResultsByRole(userRoleList); if (usersRolesList == null || usersRolesList.size() < 1) return null; @@ -382,9 +381,11 @@ public class EPAppCommonServiceImpl implements EPAppService { public List getAppRoles(Long appId) { String sql = ""; if (isRestrictedApp(appId)) { - sql = "SELECT ROLE_ID, ROLE_NAME from FN_ROLE where ROLE_ID = '" + RESTRICTED_APP_ROLE_ID + "'"; - } else { - sql = "SELECT ROLE_ID, ROLE_NAME from FN_ROLE where APP_ID = '" + appId + "'"; + sql = "SELECT ROLE_ID, ROLE_NAME from FN_ROLE where UPPER(ACTIVE_YN) = 'Y' AND ROLE_ID = '" + RESTRICTED_APP_ROLE_ID + "'"; + }else if(appId == 1){ + sql = "SELECT ROLE_ID, ROLE_NAME from FN_ROLE where UPPER(ACTIVE_YN) = 'Y' AND APP_ID IS NULL"; + }else{ + sql = "SELECT ROLE_ID, ROLE_NAME from FN_ROLE where UPPER(ACTIVE_YN) = 'Y' AND APP_ID = '" + appId + "'"; } logQuery(sql); @SuppressWarnings("unchecked") @@ -475,8 +476,8 @@ public class EPAppCommonServiceImpl implements EPAppService { * (non-Javadoc) * * @see - * org.openecomp.portalapp.portal.service.EPAppService#getAppCatalog(com.att - * .fusionapp.ecomp.portal.domain.EPUser) + * org.openecomp.portalapp.portal.service.EPAppService#getAppCatalog( + * org.openecomp.portalapp.portal.domain.EPUser) */ @Override public List getUserAppCatalog(EPUser user) { @@ -721,6 +722,7 @@ public class EPAppCommonServiceImpl implements EPAppService { return fieldsValidator; } + @SuppressWarnings("unchecked") @Override public FieldsValidator deleteOnboardingApp(EPUser user, Long appid) { FieldsValidator fieldsValidator = new FieldsValidator(); @@ -728,6 +730,16 @@ public class EPAppCommonServiceImpl implements EPAppService { fieldsValidator.httpStatusCode = new Long(HttpServletResponse.SC_FORBIDDEN); return fieldsValidator; } + final Map params = new HashMap<>(); + params.put("app_id", appid); + List EPUserAppRolesRequestList= new ArrayList<>(); + EPUserAppRolesRequestList = dataAccessService.executeNamedQuery( "getRequestIdsForApp", params, null); + for(int i=0;i getUserRemoteApps(String id) { throw new RuntimeException(" Cannot be called from parent class"); } + + @Override + public UserRoles getUserProfileForLeftMenu(String loginId) { + final Map params = new HashMap<>(); + params.put("org_user_id", loginId); + @SuppressWarnings("unchecked") + List userRoleList = dataAccessService.executeNamedQuery( "getUserRolesForLeftMenu", params, null); + ArrayList usersRolesList = aggregateUserProfileRowsResultsByRole(userRoleList); + if (usersRolesList == null || usersRolesList.size() < 1) + return null; + + return usersRolesList.get(0); + } + + + @Override + public UserRoles getUserProfileNormalizedForLeftMenu(EPUser user) { + // Check database. + UserRoles userAndRoles = getUserProfileForLeftMenu(user.getLoginId()); + // If no roles are defined, treat this user as a guest. + if (user.isGuest() || userAndRoles == null) { + logger.debug(EELFLoggerDelegate.debugLogger, "getUserProfileForLeftMenu: treating user {} as guest", + user.getLoginId()); + UserRole userRole = new UserRole(); + userRole.setUser_Id(user.getId()); + userRole.setOrgUserId(user.getLoginId()); + userRole.setFirstName(user.getFirstName()); + userRole.setLastName(user.getLastName()); + userRole.setRoleId(-1L); + userRole.setRoleName("Guest"); + userRole.setUser_Id(-1L); + userAndRoles = new UserRoles(userRole); + } + + return userAndRoles; + } + } diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPAppService.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPAppService.java index 1e12dd52..3ab12983 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPAppService.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPAppService.java @@ -97,7 +97,7 @@ public interface EPAppService { * the user has a defined role for that app. * * @param user - * EPUser object with the user's ATT UID + * EPUser object with the user's Org User ID * @return the user's list of applications, which may be empty. */ List getUserApps(EPUser user); @@ -109,7 +109,7 @@ public interface EPAppService { * applications which the user has chosen to show. * * @param user - * EPUser object with the user's ATT UID + * EPUser object with the user's Org User ID * @return the user's personalized list of applications, which may be empty. */ List getPersAdminApps(EPUser user); @@ -122,7 +122,7 @@ public interface EPAppService { * result. * * @param user - * EPUser object with the user's ATT UID + * EPUser object with the user's Org User ID * @return the user's personalized list of applications, which may be empty. */ List getPersUserApps(EPUser user); @@ -210,4 +210,8 @@ public interface EPAppService { void createOnboardingFromApp(EPApp app, OnboardingApp onboardingApp); + UserRoles getUserProfileNormalizedForLeftMenu(EPUser user); + + UserRoles getUserProfileForLeftMenu(String loginId); + } diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPLeftMenuServiceImpl.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPLeftMenuServiceImpl.java index 9158e990..f24ab87f 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPLeftMenuServiceImpl.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPLeftMenuServiceImpl.java @@ -73,7 +73,7 @@ public class EPLeftMenuServiceImpl implements EPLeftMenuService { // be revised as Account Administrator may become obsolete try { if (user != null) { - UserRoles uRoles = appService.getUserProfileNormalized(user); + UserRoles uRoles = appService.getUserProfileNormalizedForLeftMenu(user); if (uRoles.getRoles().contains("Account Administrator")) loadAccAdminNavMap(defaultNavMap); } diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPRoleFunctionService.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPRoleFunctionService.java new file mode 100644 index 00000000..66a9ccc2 --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPRoleFunctionService.java @@ -0,0 +1,31 @@ +package org.openecomp.portalapp.portal.service; + +import java.util.List; +import java.util.Set; + +import javax.servlet.http.HttpServletRequest; + +import org.openecomp.portalapp.portal.domain.EPUser; +import org.openecomp.portalsdk.core.domain.RoleFunction; + +public interface EPRoleFunctionService { + /** + * Builds a set of role functions and sets a session attribute with it. + * + * @param request + * HttpServletRequest + * @return Set of role functions that was built. + */ + public List getRoleFunctions(); + + + /** + * Builds a set of role functions of user + * + * @param request + * HttpServletRequest + * @return Set of role functions that was built. + */ + public Set getRoleFunctions(HttpServletRequest request, EPUser user); + +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPRoleFunctionServiceCentralizedImpl.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPRoleFunctionServiceCentralizedImpl.java new file mode 100644 index 00000000..d41100ff --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPRoleFunctionServiceCentralizedImpl.java @@ -0,0 +1,70 @@ +package org.openecomp.portalapp.portal.service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import org.hibernate.SessionFactory; +import org.openecomp.portalapp.portal.domain.CentralRoleFunction; +import org.openecomp.portalapp.portal.domain.EPUser; +import org.openecomp.portalsdk.core.domain.RoleFunction; +import org.openecomp.portalsdk.core.service.DataAccessService; +import org.openecomp.portalsdk.core.util.SystemProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + + +@Transactional +public class EPRoleFunctionServiceCentralizedImpl implements EPRoleFunctionService{ + + + @Autowired + private DataAccessService dataAccessService; + + @Autowired + private SessionFactory sessionFactory; + + @SuppressWarnings({ "unchecked"}) + @Override + public List getRoleFunctions() { + List getRoleFuncList = null; + List getRoleFuncListOfPortal = new ArrayList<>(); + final Map params = new HashMap<>(); + params.put("appId", (long) 1); + //Sync all functions from external system into Ecomp portal DB + getRoleFuncList = dataAccessService.executeNamedQuery("getAllRoleFunctions", params, null); + for(CentralRoleFunction roleFunction : getRoleFuncList) + { + RoleFunction roleFun = new RoleFunction(); + roleFun.setCode(roleFunction.getCode()); + roleFun.setName(roleFunction.getName()); + getRoleFuncListOfPortal.add(roleFun); + } + return getRoleFuncListOfPortal; + } + + @SuppressWarnings("unchecked") + @Override + public Set getRoleFunctions(HttpServletRequest request, EPUser user) { + HttpSession session = request.getSession(); + String userId = user.getId().toString(); + final Map params = new HashMap<>(); + params.put("userId", userId); + @SuppressWarnings("unchecked") + List getRoleFuncListOfPortal = dataAccessService.executeNamedQuery("getRoleFunctionsOfUser", params, null); + Set getRoleFuncListOfPortalSet = new HashSet<>(getRoleFuncListOfPortal); + session.setAttribute(SystemProperties.getProperty(SystemProperties.ROLE_FUNCTIONS_ATTRIBUTE_NAME), + getRoleFuncListOfPortalSet); + return getRoleFuncListOfPortalSet; + + } + + + +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPRoleFunctionServiceImpl.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPRoleFunctionServiceImpl.java new file mode 100644 index 00000000..f36aa544 --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/EPRoleFunctionServiceImpl.java @@ -0,0 +1,79 @@ +package org.openecomp.portalapp.portal.service; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import org.openecomp.portalapp.portal.domain.EPRole; +import org.openecomp.portalapp.portal.domain.EPUser; +import org.openecomp.portalapp.util.EPUserUtils; +import org.openecomp.portalsdk.core.domain.RoleFunction; +import org.openecomp.portalsdk.core.service.DataAccessService; +import org.openecomp.portalsdk.core.util.SystemProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +@Transactional +public class EPRoleFunctionServiceImpl implements EPRoleFunctionService { + @Autowired + private DataAccessService dataAccessService; + + + + public DataAccessService getDataAccessService() { + return dataAccessService; + } + + public void setDataAccessService(DataAccessService dataAccessService) { + this.dataAccessService = dataAccessService; + } + + @SuppressWarnings("unchecked") + @Override + public List getRoleFunctions() { + return getDataAccessService().getList(RoleFunction.class, null); + } + + @SuppressWarnings("unchecked") + @Override + public Set getRoleFunctions(HttpServletRequest request, EPUser user) { + HashSet roleFunctions = null; + + HttpSession session = request.getSession(); + roleFunctions = (HashSet) session + .getAttribute(SystemProperties.getProperty(SystemProperties.ROLE_FUNCTIONS_ATTRIBUTE_NAME)); + + if (roleFunctions == null) { + HashMap roles = EPUserUtils.getRoles(request); + roleFunctions = new HashSet(); + + Iterator i = roles.keySet().iterator(); + + while (i.hasNext()) { + Long roleKey = (Long) i.next(); + EPRole role = (EPRole) roles.get(roleKey); + + Iterator j = role.getRoleFunctions().iterator(); + + while (j.hasNext()) { + RoleFunction function = (RoleFunction) j.next(); + roleFunctions.add(function.getCode()); + } + } + + session.setAttribute(SystemProperties.getProperty(SystemProperties.ROLE_FUNCTIONS_ATTRIBUTE_NAME), + roleFunctions); + } + + return roleFunctions; + } + + + + +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/ExternalAccessRolesService.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/ExternalAccessRolesService.java new file mode 100644 index 00000000..e57d4fa5 --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/ExternalAccessRolesService.java @@ -0,0 +1,190 @@ +package org.openecomp.portalapp.portal.service; + +import java.util.List; + +import org.hibernate.Session; +import org.openecomp.portalapp.portal.domain.CentralRoleFunction; +import org.openecomp.portalapp.portal.domain.EPApp; +import org.openecomp.portalapp.portal.domain.EPRole; +import org.openecomp.portalapp.portal.transport.CentralRole; +import org.openecomp.portalsdk.core.domain.Role; +import org.openecomp.portalsdk.core.domain.RoleFunction; + +public interface ExternalAccessRolesService { + + /** + * It gets all application roles + * + * @param appId + * @param extRequestValue + * @return List + * @throws Exception + */ + public List getAppRoles(Long appId, Boolean extRequestValue) throws Exception; + + /** + * It returns application details + * + * @param uebkey + * @return List + * @throws Exception + */ + public List getApp(String uebkey) throws Exception; + + /** + * Adds role in the external access system if fails throws exception + * + * @param addRoles + * @param UE + * @return boolean + * @throws Exception + */ + public boolean addRole(Role addRoles, String uebkey) throws Exception; + + /** + * Updates role in the external access system otherwise throws exception + * + * @param updateRole + * @param uebkey + * @return boolean + * @throws Exception + */ + void updateRole(Role updateRole, EPApp app) throws Exception; + + /** + * It returns complete user information including application roles permissions + * + * @param loginId + * @param uebkey + * @return String + * @throws Exception + */ + String getUser(String loginId, String uebkey) throws Exception; + + /** + * It returns list of all role functions + * @param string + * @return List + * @throws Exception + */ + List getRoleFuncList(String string) throws Exception; + + /** + * It return list of role provided by the app uebkey and roleId + * + * @param roleId + * @param uebkey + * @return CentralRole + * @throws Exception + */ + CentralRole getRoleInfo(Long roleId, String uebkey) throws Exception; + + /** + * It returns the CentralRoleFunction object + * + * @param functionCode + * @param uebkey + * @return CentralRoleFunction + * @throws Exception + */ + public CentralRoleFunction getRoleFunction(String functionCode, String uebkey) throws Exception; + + /** + * It saves role function in the DB + * + * @param domainCentralRoleFunction + * @param requestedApp + * @throws Exception + */ + public void saveCentralRoleFunction(CentralRoleFunction domainCentralRoleFunction, EPApp requestedApp) throws Exception; + + /** + * It deletes role function in the DB + * + * @param code + * @param string + */ + public void deleteCentralRoleFunction(String code, String string); + + /** + * It gets all roles the applications + * + * @param uebkey + * @return List + * @throws Exception + */ + public List getRolesForApp(String uebkey) throws Exception; + + /** + * It saves role function in the DB + * + * @param saveRole + * @param uebkey + * @throws Exception + */ + void saveRoleForApplication(Role saveRole, String uebkey) throws Exception; + + /** + * It deletes role in the DB + * + * @param code + * @param uebkey + * @throws Exception + */ + void deleteRoleForApplication(String code, String uebkey) throws Exception; + + /** + * It gets all active roles for single application + * + * @param uebkey + * @return List + * @throws Exception + */ + List getActiveRoles(String uebkey) throws Exception; + + /** + * It deletes user related roles for an application in the table + * @param roleId + * @param uebkey + * @param LoginId + * @return + * @throws Exception + */ + public void deleteDependcyRoleRecord(Long roleId, String uebkey, String LoginId) throws Exception; + + /** + * It sync new functions codes and names from and updates role functions from external access system + * + * @param app + * @throws Exception + */ + public void syncRoleFunctionFromExternalAccessSystem(EPApp app) throws Exception; + + public Integer bulkUploadFunctions(String uebkey) throws Exception; + + public Integer bulkUploadRoles(String uebkey) throws Exception; + + public void bulkUploadPartnerFunctions(String header, List upload) throws Exception; + + public void bulkUploadPartnerRoles(String header, List upload) throws Exception; + + Integer bulkUploadRolesFunctions(String uebkey) throws Exception; + + /** + * SyncApplicationRolesWithEcompDB sync the roles and rolefunctions to the ecomp DB from AAF + * @param app + * @throws Exception + */ + + void SyncApplicationRolesWithEcompDB(EPApp app) throws Exception; + + public Integer bulkUploadUserRoles(String uebkey) throws Exception; + + void bulkUploadPartnerRoleFunctions(String uebkey, List roleList) throws Exception; + + public void deleteRoleDependeciesRecord(Session localSession, Long roleId) throws Exception; + + List getMenuFunctionsList(String uebkey) throws Exception; + + +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/ExternalAccessRolesServiceImpl.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/ExternalAccessRolesServiceImpl.java new file mode 100644 index 00000000..17d9ceb0 --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/ExternalAccessRolesServiceImpl.java @@ -0,0 +1,1678 @@ +package org.openecomp.portalapp.portal.service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.stream.Collectors; + +import org.hibernate.Query; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.Transaction; +import org.json.JSONArray; +import org.json.JSONObject; +import org.openecomp.portalapp.portal.domain.CentralRoleFunction; +import org.openecomp.portalapp.portal.domain.EPApp; +import org.openecomp.portalapp.portal.domain.EPAppRoleFunction; +import org.openecomp.portalapp.portal.domain.EPRole; +import org.openecomp.portalapp.portal.domain.EPUser; +import org.openecomp.portalapp.portal.domain.EPUserApp; +import org.openecomp.portalapp.portal.domain.ExternalRoleDetails; +import org.openecomp.portalapp.portal.logging.aop.EPMetricsLog; +import org.openecomp.portalapp.portal.transport.BulkUploadRoleFunction; +import org.openecomp.portalapp.portal.transport.BulkUploadUserRoles; +import org.openecomp.portalapp.portal.transport.CentralApp; +import org.openecomp.portalapp.portal.transport.CentralRole; +import org.openecomp.portalapp.portal.transport.CentralUser; +import org.openecomp.portalapp.portal.transport.CentralUserApp; +import org.openecomp.portalapp.portal.transport.ExternalAccessPerms; +import org.openecomp.portalapp.portal.transport.ExternalAccessPermsDetail; +import org.openecomp.portalapp.portal.transport.ExternalAccessRole; +import org.openecomp.portalapp.portal.transport.ExternalAccessRolePerms; +import org.openecomp.portalapp.portal.transport.ExternalAccessUser; +import org.openecomp.portalapp.portal.transport.ExternalRoleDescription; +import org.openecomp.portalapp.portal.utils.EPCommonSystemProperties; +import org.openecomp.portalapp.portal.utils.EcompPortalUtils; +import org.openecomp.portalapp.portal.utils.PortalConstants; +import org.openecomp.portalsdk.core.domain.Role; +import org.openecomp.portalsdk.core.domain.RoleFunction; +import org.openecomp.portalsdk.core.logging.logic.EELFLoggerDelegate; +import org.openecomp.portalsdk.core.service.DataAccessService; +import org.openecomp.portalsdk.core.util.SystemProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.client.RestTemplate; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.type.TypeFactory; + +@Service("externalAccessRolesService") +@EnableAspectJAutoProxy +@EPMetricsLog +public class ExternalAccessRolesServiceImpl implements ExternalAccessRolesService { + + private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(ExternalAccessRolesServiceImpl.class); + + @Autowired + private DataAccessService dataAccessService; + + @Autowired + private SessionFactory sessionFactory; + + + RestTemplate template = new RestTemplate(); + + @SuppressWarnings("unchecked") + public List getAppRoles(Long appId, Boolean extRequestValue) throws Exception { + List applicationRoles = null; + String filter = null; + try { + if (appId == 1) { + filter = " where app_id is null"; + } else { + filter = " where app_id = " + appId; + } + applicationRoles = dataAccessService.getList(EPRole.class, filter, null, null); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, "getAppRoles is failed", e); + throw new Exception(e.getMessage()); + } + return applicationRoles; + } + + @SuppressWarnings("unchecked") + @Override + public List getApp(String uebkey) throws Exception { + List app = null; + try { + app = (List) dataAccessService.getList(EPApp.class, " where ueb_key = '" + uebkey + "'", null, null); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, "getApp is failed", e); + throw new Exception(e.getMessage()); + } + return app; + } + + public String getSingleAppRole(String addRole, EPApp app) throws Exception { + String response = ""; + HttpHeaders headers = EcompPortalUtils.base64encodeKeyForAAFBasicAuth(); + HttpEntity entity = new HttpEntity<>(headers); + logger.debug(EELFLoggerDelegate.debugLogger, "Connecting to External Access system"); + response = template + .exchange( + SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + "roles/" + + app.getNameSpace() + "." + addRole.replaceAll(" ", "_"), + HttpMethod.GET, entity, String.class) + .getBody(); + logger.debug(EELFLoggerDelegate.debugLogger, "Connected to External Access system"); + + return response; + } + + @Override + public boolean addRole(Role addRole, String uebkey) throws Exception { + boolean response = false; + ResponseEntity addResponse = null; + HttpHeaders headers = EcompPortalUtils.base64encodeKeyForAAFBasicAuth(); + EPApp app = getApp(uebkey).get(0); + String newRole = createNewRoleInExternalSystem(addRole, app); + HttpEntity entity = new HttpEntity<>(newRole, headers); + logger.debug(EELFLoggerDelegate.debugLogger, "Connecting to External Access system"); + addResponse = template.exchange( + SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + "role", + HttpMethod.POST, entity, String.class); + if (addResponse.getStatusCode().value() == 201) { + response = true; + logger.debug(EELFLoggerDelegate.debugLogger, "Connected to External Access system"); + } + if (addResponse.getStatusCode().value() == 406) { + logger.debug(EELFLoggerDelegate.debugLogger, "Connected to External Access system but something went wrong!"); + throw new Exception("Failed to create role"); + } + return response; + } + + @Override + public void updateRole(Role addRole, EPApp app) throws Exception { + boolean addResponse = updateRoleInExternalSystem(addRole, app); + if (!addResponse) { + throw new Exception("Failed to update a role"); + } + } + + private ResponseEntity deleteRoleInExternalSystem(String delRole) throws Exception { + ResponseEntity delResponse = null; + HttpHeaders headers = EcompPortalUtils.base64encodeKeyForAAFBasicAuth(); + HttpEntity entity = new HttpEntity<>(delRole, headers); + logger.debug(EELFLoggerDelegate.debugLogger, "Connecting to External Access system"); + delResponse = template.exchange( + SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + "role?force=true", + HttpMethod.DELETE, entity, String.class); + logger.debug(EELFLoggerDelegate.debugLogger, "Connected to External Access system"); + return delResponse; + } + + @SuppressWarnings("unchecked") + private boolean updateRoleInExternalSystem(Role updateExtRole, EPApp app) throws Exception { + boolean response = false; + ObjectMapper mapper = new ObjectMapper(); + ResponseEntity deleteResponse = null; + HttpHeaders headers = EcompPortalUtils.base64encodeKeyForAAFBasicAuth(); + ExternalAccessRolePerms extRolePerms = null; + ExternalAccessPerms extPerms = null; + List epRoleList = null; + epRoleList = dataAccessService.getList(EPRole.class, + " where role_id = " + updateExtRole.getId(), null, null); + String appRole = getSingleAppRole(epRoleList.get(0).getName(), app); + if (!appRole.equals("{}")) { + JSONObject jsonObj = new JSONObject(appRole); + JSONArray extRole = jsonObj.getJSONArray("role"); + if (!extRole.getJSONObject(0).has("description")) { + String roleName = extRole.getJSONObject(0).getString("name"); + String delRoleKey = "{\"name\":\"" + roleName + "\"}"; + deleteResponse = deleteRoleInExternalSystem(delRoleKey); + if (deleteResponse.getStatusCode().value() != 200) { + throw new Exception("Failed to delete role in external access system!"); + } + addRole(updateExtRole, app.getUebKey()); + } else { + String desc = extRole.getJSONObject(0).getString("description"); + String name = extRole.getJSONObject(0).getString("name"); + List list = null; + if (extRole.getJSONObject(0).has("perms")) { + JSONArray perms = extRole.getJSONObject(0).getJSONArray("perms"); + ObjectMapper permsMapper = new ObjectMapper(); + list = permsMapper.readValue(perms.toString(), TypeFactory.defaultInstance() + .constructCollectionType(List.class, ExternalAccessPerms.class)); + } + ObjectMapper roleMapper = new ObjectMapper(); + ExternalRoleDescription sysRoleList = roleMapper.readValue(desc, ExternalRoleDescription.class); + // If role name or role functions are updated then delete record in External System and add new record to avoid conflicts + Boolean existingRoleActive; + boolean res; + // check role active status + existingRoleActive = new Boolean(sysRoleList.getActive()); + res = existingRoleActive.equals(updateExtRole.getActive()); + if (!sysRoleList.getName().equals(updateExtRole.getName())) { + String deleteRoleKey = "{\"name\":\"" + name + "\"}"; + deleteResponse = deleteRoleInExternalSystem(deleteRoleKey); + if (deleteResponse.getStatusCode().value() != 200) { + throw new Exception("Failed to delete role in external access system!"); + } + response = addRole(updateExtRole, app.getUebKey()); + ObjectMapper addPermsMapper = new ObjectMapper(); + response = addRoleFunctionsInExternalSystem(updateExtRole, addPermsMapper, app); + } + ExternalAccessRole updateRole = new ExternalAccessRole(); + if (!res || !sysRoleList.getPriority().equals(String.valueOf(updateExtRole.getPriority())) || + sysRoleList.getId().equals("null")) { + String updateDesc = ""; + List getRole = dataAccessService.getList(EPRole.class, + " where role_name = '" + updateExtRole.getName() + "'", null, null); + if (app.getId().equals(PortalConstants.PORTAL_APP_ID)) { + updateDesc = "{\"id\":\"" + getRole.get(0).getId() + "\",\"name\":\"" + updateExtRole.getName() + + "\",\"active\":\"" + updateExtRole.getActive() + "\",\"priority\":\"" + + updateExtRole.getPriority() + "\",\"appId\":\"null\",\"appRoleId\":\"null\"}"; + + } else { + updateDesc = "{\"id\":\"" + getRole.get(0).getId() + "\",\"name\":\"" + updateExtRole.getName() + + "\",\"active\":\"" + updateExtRole.getActive() + "\",\"priority\":\"" + + updateExtRole.getPriority() + "\",\"appId\":\"" + app.getId() + "\",\"appRoleId\":\"" + + getRole.get(0).getAppRoleId() + "\"}"; + + } + updateRole.setName(app.getNameSpace() + "." + updateExtRole.getName().replaceAll(" ", "_")); + updateRole.setDescription(updateDesc); + String updateRoleDesc = mapper.writeValueAsString(updateRole); + HttpEntity entity = new HttpEntity<>(updateRoleDesc, headers); + logger.debug(EELFLoggerDelegate.debugLogger, "Connecting to External Access system"); + template.exchange( + SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + "role", + HttpMethod.PUT, entity, String.class); + logger.debug(EELFLoggerDelegate.debugLogger, "Connected to External Access system"); + } + List roleFunctionListNew = convertSetToListOfRoleFunctions(updateExtRole); + Map updateRoleFunc = new HashMap<>(); + for (RoleFunction addPerm : roleFunctionListNew) { + updateRoleFunc.put(addPerm.getCode(), addPerm); + } + final Map extRolePermMap = new HashMap<>(); + // Update permissions in the ExternalAccess System + ObjectMapper permMapper = new ObjectMapper(); + if (list != null) { + for (ExternalAccessPerms perm : list) { + if (!updateRoleFunc.containsKey(perm.getInstance())) { + removePermForRole(perm, permMapper, name, headers); + } + extRolePermMap.put(perm.getInstance(), perm); + } + } + response = true; + if (!roleFunctionListNew.isEmpty() || roleFunctionListNew.size() > 0) { + for (RoleFunction roleFunc : roleFunctionListNew) { + if (!extRolePermMap.containsKey(roleFunc.getCode())) { + String checkType = roleFunc.getCode().contains("menu") ? "menu" : "url"; + extPerms = new ExternalAccessPerms(app.getNameSpace() + "." + checkType, roleFunc.getCode(), + "*"); + extRolePerms = new ExternalAccessRolePerms(extPerms, + app.getNameSpace() + "." + updateExtRole.getName().replaceAll(" ", "_")); + String updateRolePerms = mapper.writeValueAsString(extRolePerms); + HttpEntity entity = new HttpEntity<>(updateRolePerms, headers); + logger.debug(EELFLoggerDelegate.debugLogger, "Connecting to External Access system"); + ResponseEntity addResponse = template.exchange( + SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + + "role/perm", + HttpMethod.POST, entity, String.class); + if (addResponse.getStatusCode().value() != 201) { + response = false; + logger.debug(EELFLoggerDelegate.debugLogger, + "Connected to External Access system but something went wrong! due to {} and statuscode: {}", addResponse.getStatusCode().getReasonPhrase(), addResponse.getStatusCode().value()); + } else { + response = true; + logger.debug(EELFLoggerDelegate.debugLogger, "Connected to External Access system"); + } + } + } + } + } + } else { + // It seems like role exists in local DB but not in External Access system + addRole(updateExtRole, app.getUebKey()); + List roleFunctionListUpdate = convertSetToListOfRoleFunctions(updateExtRole); + response = true; + if (!roleFunctionListUpdate.isEmpty() || roleFunctionListUpdate.size() > 0) { + ObjectMapper addPermsMapper = new ObjectMapper(); + addRoleFunctionsInExternalSystem(updateExtRole, addPermsMapper, app); + } + } + return response; + } + + private boolean addRoleFunctionsInExternalSystem(Role updateExtRole, ObjectMapper addPermsMapper, EPApp app) throws Exception { + boolean response = false; + ExternalAccessRolePerms extAddRolePerms = null; + ExternalAccessPerms extAddPerms = null; + List roleFunctionListAdd = convertSetToListOfRoleFunctions(updateExtRole); + HttpHeaders headers = EcompPortalUtils.base64encodeKeyForAAFBasicAuth(); + for (RoleFunction roleFunc : roleFunctionListAdd) { + String checkType = roleFunc.getCode().contains("menu") ? "menu" : "url"; + extAddPerms = new ExternalAccessPerms(app.getNameSpace() + "." + checkType, roleFunc.getCode(), + "*"); + extAddRolePerms = new ExternalAccessRolePerms(extAddPerms, + app.getNameSpace() + "." + updateExtRole.getName().replaceAll(" ", "_")); + String updateRolePerms = addPermsMapper.writeValueAsString(extAddRolePerms); + HttpEntity entity = new HttpEntity<>(updateRolePerms, headers); + logger.debug(EELFLoggerDelegate.debugLogger, "Connecting to External Access system"); + ResponseEntity addResponse = template.exchange( + SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + + "role/perm", + HttpMethod.POST, entity, String.class); + if (addResponse.getStatusCode().value() != 201) { + response = false; + logger.debug(EELFLoggerDelegate.debugLogger, + "Connected to External Access system but something went wrong! due to {} and statuscode: {}", addResponse.getStatusCode().getReasonPhrase(), addResponse.getStatusCode().value()); + } else { + response = true; + logger.debug(EELFLoggerDelegate.debugLogger, "Connected to External Access system"); + } + } + return response; + } + + @SuppressWarnings("unchecked") + private List convertSetToListOfRoleFunctions(Role updateExtRole){ + Set roleFunctionSetList = updateExtRole.getRoleFunctions(); + List roleFunctionList = new ArrayList<>(); + ObjectMapper roleFuncMapper = new ObjectMapper(); + Iterator itetaror = roleFunctionSetList.iterator(); + while (itetaror.hasNext()) { + Object nextValue = itetaror.next(); + RoleFunction roleFunction = roleFuncMapper.convertValue(nextValue, RoleFunction.class); + roleFunctionList.add(roleFunction); + } + return roleFunctionList.stream().distinct().collect(Collectors.toList()); + } + + private void removePermForRole(ExternalAccessPerms perm, ObjectMapper permMapper,String name, HttpHeaders headers) throws Exception { + ExternalAccessRolePerms extAccessRolePerms = new ExternalAccessRolePerms(perm, name); + String permDetails = permMapper.writeValueAsString(extAccessRolePerms); + HttpEntity deleteEntity = new HttpEntity<>(permDetails, headers); + logger.debug(EELFLoggerDelegate.debugLogger, "Connecting to External Access system"); + ResponseEntity deletePermResponse = template.exchange(SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + + "role/"+name+"/perm", HttpMethod.DELETE, deleteEntity, String.class); + if (deletePermResponse.getStatusCode().value() != 200) { + throw new Exception("Failed to delete role function"); + } + logger.debug(EELFLoggerDelegate.debugLogger, "Connected to External Access system"); + } + + private boolean addNewRoleInExternalSystem(List newRole, EPApp app) throws Exception { + boolean response = false; + HttpHeaders headers = EcompPortalUtils.base64encodeKeyForAAFBasicAuth(); + ObjectMapper mapper = new ObjectMapper(); + String addNewRole = ""; + ExternalAccessRole extRole = new ExternalAccessRole(); + String addDesc = null; + addDesc = "{\"id\":\"" + newRole.get(0).getId() + "\",\"name\":\"" + newRole.get(0).getName() + "\",\"active\":\"" + + newRole.get(0).getActive() + "\",\"priority\":\"" +newRole.get(0).getPriority() + "\",\"appId\":\"" + + newRole.get(0).getAppId() + "\",\"appRoleId\":\"" + newRole.get(0).getAppRoleId() + "\"}"; + + extRole.setName(app.getNameSpace() + "." + newRole.get(0).getName().replaceAll(" ", "_")); + extRole.setDescription(addDesc); + addNewRole = mapper.writeValueAsString(extRole); + HttpEntity deleteEntity = new HttpEntity<>(addNewRole, headers); + logger.debug(EELFLoggerDelegate.debugLogger, "Connecting to External Access system"); + ResponseEntity addNewRoleInExternalSystem = template.exchange(SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + + "role", HttpMethod.POST, deleteEntity, String.class); + if (addNewRoleInExternalSystem.getStatusCode().value() != 201) { + throw new Exception("Failed to add Role in External System"); + } else{ + logger.debug(EELFLoggerDelegate.debugLogger, "Connected to External Access system"); + response = true; + } + return response; + } + + @SuppressWarnings("unchecked") + private String createNewRoleInExternalSystem(Role addRole, EPApp app) throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + String addNewRole = ""; + ExternalAccessRole extRole = new ExternalAccessRole(); + List role = null; + String addDesc = null; + if(app.getId().equals(PortalConstants.PORTAL_APP_ID)){ + role = dataAccessService.getList(EPRole.class, + " where role_id = " + addRole.getId(), null, null); + addDesc = "{\"id\":\"" + role.get(0).getId() + "\",\"name\":\"" + addRole.getName() + "\",\"active\":\"" + + role.get(0).getActive() + "\",\"priority\":\"" + role.get(0).getPriority() + + "\",\"appId\":\"null\",\"appRoleId\":\"null\"}"; + } else{ + role = dataAccessService.getList(EPRole.class, + " where app_role_id = " + addRole.getId(), null, null); + addDesc = "{\"id\":\"" + role.get(0).getId() + "\",\"name\":\"" + addRole.getName() + "\",\"active\":\"" + + role.get(0).getActive() + "\",\"priority\":\"" + addRole.getPriority() + "\",\"appId\":\"" + + app.getId() + "\",\"appRoleId\":\"" + role.get(0).getAppRoleId() + "\"}"; + } + extRole.setName(app.getNameSpace() + "." + addRole.getName().replaceAll(" ", "_")); + extRole.setDescription(addDesc); + addNewRole = mapper.writeValueAsString(extRole); + return addNewRole; + } + + @SuppressWarnings("unchecked") + @Transactional + private boolean addRoleInEcompDB(Role addRoleInDB, EPApp app) throws Exception { + boolean result = false; + List applicationRoles = null; + EPRole epRole = null; + Set roleFunctionList = addRoleInDB.getRoleFunctions(); + List roleFunctionListNew = new ArrayList<>(); + ObjectMapper mapper = new ObjectMapper(); + Iterator itetaror = roleFunctionList.iterator(); + while (itetaror.hasNext()) { + Object nextValue = itetaror.next(); + RoleFunction roleFunction = mapper.convertValue(nextValue, RoleFunction.class); + roleFunctionListNew.add(roleFunction); + } + List listWithoutDuplicates = roleFunctionListNew.stream().distinct().collect(Collectors.toList()); + try { + if (addRoleInDB.getId() == null) { // check if it is new role + checkIfRoleExitsInExternalSystem(addRoleInDB, app); + EPRole epRoleNew = new EPRole(); + epRoleNew.setActive(addRoleInDB.getActive()); + epRoleNew.setName(addRoleInDB.getName()); + epRoleNew.setPriority(addRoleInDB.getPriority()); + if (app.getId().equals(PortalConstants.PORTAL_APP_ID)) { + epRoleNew.setAppId(null); + } else { + epRoleNew.setAppId(app.getId()); + } + dataAccessService.saveDomainObject(epRoleNew, null); + List getRoleCreated = null; + if (!app.getId().equals(PortalConstants.PORTAL_APP_ID)) { + List roleCreated = dataAccessService.getList(EPRole.class, + " where role_name = '" + addRoleInDB.getName() +"'", null, null); + EPRole epUpdateRole = roleCreated.get(0); + epUpdateRole.setAppRoleId(epUpdateRole.getId()); + dataAccessService.saveDomainObject(epUpdateRole, null); + getRoleCreated = dataAccessService.getList(EPRole.class, + " where role_name = '" + addRoleInDB.getName() +"'", null, null); + } else{ + getRoleCreated = dataAccessService.getList(EPRole.class, + " where role_name = '" + addRoleInDB.getName() +"'", null, null); + } + // Add role in External Access system + boolean response = addNewRoleInExternalSystem(getRoleCreated, app); + + if (!response) { + throw new Exception("Failed to add role!"); + } + } else { // if role already exists then update it + if (app.getId().equals(PortalConstants.PORTAL_APP_ID)) { + applicationRoles = dataAccessService.getList(EPRole.class, + " where app_id is null " + " and role_id = " + addRoleInDB.getId(), null, null); + } else { + applicationRoles = dataAccessService.getList(EPRole.class, + " where app_id = " + app.getId() + " and app_role_id = " + addRoleInDB.getId(), null, null); + } + if(applicationRoles.isEmpty() && !app.getId().equals(PortalConstants.PORTAL_APP_ID)){ + applicationRoles = dataAccessService.getList(EPRole.class, + " where app_id = " + app.getId() + " and role_id = " + addRoleInDB.getId(), null, null); + } + updateRoleInExternalSystem(addRoleInDB, app); + deleteRoleFunction(app, applicationRoles); + if (applicationRoles.size() > 0 || !applicationRoles.isEmpty()) { + epRole = applicationRoles.get(0); + epRole.setName(addRoleInDB.getName()); + epRole.setPriority(addRoleInDB.getPriority()); + epRole.setActive(addRoleInDB.getActive()); + if (app.getId().equals(PortalConstants.PORTAL_APP_ID)) { + epRole.setAppId(null); + epRole.setAppRoleId(null); + } else if(!app.getId().equals(PortalConstants.PORTAL_APP_ID) && applicationRoles.get(0).getAppRoleId() == null){ + epRole.setAppRoleId(epRole.getId()); + } + dataAccessService.saveDomainObject(epRole, null); + } + + saveRoleFunction(listWithoutDuplicates, app, applicationRoles); + } + result = true; + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, "addRoleInEcompDB is failed", e); + throw new Exception(e.getMessage()); + } + return result; + } + + private void checkIfRoleExitsInExternalSystem(Role checkRole, EPApp app) throws Exception { + HttpHeaders headers = EcompPortalUtils.base64encodeKeyForAAFBasicAuth(); + String roleName = app.getNameSpace()+"."+checkRole.getName().replaceAll(" ", "_"); + HttpEntity checkRoleEntity = new HttpEntity<>(headers); + logger.debug(EELFLoggerDelegate.debugLogger, "Connecting to External Access system"); + ResponseEntity checkRoleInExternalSystem = template.exchange(SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + + "roles/"+roleName, HttpMethod.GET, checkRoleEntity, String.class); + if(!checkRoleInExternalSystem.getBody().equals("{}")){ + logger.debug("Role already exists in external system ", checkRoleInExternalSystem.getBody()); + throw new Exception("Role already exists in external system"); + } + } + + private void saveRoleFunction(List roleFunctionListNew, EPApp app, List applicationRoles) throws Exception { + for (RoleFunction roleFunc : roleFunctionListNew) { + EPAppRoleFunction appRoleFunc = new EPAppRoleFunction(); + appRoleFunc.setAppId(app.getId()); + appRoleFunc.setRoleId(applicationRoles.get(0).getId()); + appRoleFunc.setCode(roleFunc.getCode()); + dataAccessService.saveDomainObject(appRoleFunc, null); + } + } + + @SuppressWarnings("unchecked") + private void deleteRoleFunction(EPApp app, List role) { + List appRoleFunctionList = dataAccessService.getList(EPAppRoleFunction.class, + " where app_id = " + app.getId() + " and role_id = " + role.get(0).getId(), null, null); + if (!appRoleFunctionList.isEmpty() || appRoleFunctionList.size() > 0) { + for (EPAppRoleFunction approleFunction : appRoleFunctionList) { + dataAccessService.deleteDomainObject(approleFunction, null); + } + } + } + + @SuppressWarnings("unchecked") + public String getUser(String loginId, String uebkey) throws Exception { + final Map params = new HashMap<>(); + List userList = null; + CentralUser cenUser = null; + EPApp app = null; + String result = null; + try { + params.put("orgUserIdValue", loginId); + List appList = (List) getApp(uebkey); + if (appList.size() > 0) { + app = appList.get(0); + userList = (List) dataAccessService.getList(EPUser.class, + " where org_user_id = '" + loginId + "'", null, null); + if (userList.size() > 0) { + EPUser user = userList.get(0); + ObjectMapper mapper = new ObjectMapper(); + Set userAppSet = user.getEPUserApps(); + cenUser = createEPUser(user, userAppSet, app); + result = mapper.writeValueAsString(cenUser); + } else if (userList.size() == 0) { + throw new Exception("User not found"); + } + } else { + throw new Exception("Application not found"); + } + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, "getUser is failed", e); + throw new Exception(e.getMessage()); + } + return result; + } + + @Override + public List getRolesForApp(String uebkey) throws Exception { + logger.debug(EELFLoggerDelegate.debugLogger, "Entering into getRolesForApp"); + List roleList = new ArrayList<>(); + final Map params = new HashMap<>(); + try { + List app = getApp(uebkey); + List appRolesList = getAppRoles(app.get(0).getId(), null); + createCentralRoleObject(app, appRolesList, roleList, params); + } catch (Exception e) { + throw new Exception("getRolesForApp Failed", e); + } + logger.debug(EELFLoggerDelegate.debugLogger, "Finished getRolesForApp"); + return roleList; + } + + @SuppressWarnings("unchecked") + @Override + public List getRoleFuncList(String uebkey) throws Exception { + EPApp app = getApp(uebkey).get(0); + List getRoleFuncList = null; + final Map params = new HashMap<>(); + params.put("appId", app.getId()); + //Sync all functions from external system into Ecomp portal DB + logger.debug(EELFLoggerDelegate.debugLogger, "Entering into syncRoleFunctionFromExternalAccessSystem"); + syncRoleFunctionFromExternalAccessSystem(app); + logger.debug(EELFLoggerDelegate.debugLogger, "Finished syncRoleFunctionFromExternalAccessSystem"); + getRoleFuncList = dataAccessService.executeNamedQuery("getAllRoleFunctions", params, null); + return getRoleFuncList; + } + + @SuppressWarnings("unchecked") + public CentralUser createEPUser(EPUser userInfo, Set userAppSet, EPApp app) throws Exception { + + final Map params = new HashMap<>(); + CentralUser userAppList = new CentralUser(); + CentralUser user1 = null; + try { + userAppList.userApps = new TreeSet(); + for (EPUserApp userApp : userAppSet) { + if (userApp.getRole().getActive()) { + EPApp epApp = userApp.getApp(); + String globalRole = userApp.getRole().getName().toLowerCase(); + if (((epApp.getId().equals(app.getId())) + && (!userApp.getRole().getId().equals(PortalConstants.ACCOUNT_ADMIN_ROLE_ID))) + || ((epApp.getId().equals(PortalConstants.PORTAL_APP_ID)) + && (globalRole.startsWith("global_")))) { + CentralUserApp cua = new CentralUserApp(); + cua.setUserId(null); + CentralApp cenApp = new CentralApp(1L, epApp.getCreated(), epApp.getModified(), + epApp.getCreatedId(), epApp.getModifiedId(), epApp.getRowNum(), epApp.getName(), + epApp.getImageUrl(), epApp.getDescription(), epApp.getNotes(), epApp.getUrl(), + epApp.getAlternateUrl(), epApp.getAppRestEndpoint(), epApp.getMlAppName(), + epApp.getMlAppAdminId(), String.valueOf(epApp.getMotsId()), epApp.getAppPassword(), + String.valueOf(epApp.getOpen()), String.valueOf(epApp.getEnabled()), + epApp.getThumbnail(), epApp.getUsername(), epApp.getUebKey(), epApp.getUebSecret(), + epApp.getUebTopicName()); + cua.setApp(cenApp); + params.put("roleId", userApp.getRole().getId()); + params.put("appId", userApp.getApp().getId()); + List appRoleFunctionList = dataAccessService + .executeNamedQuery("getAppRoleFunctionList", params, null); + SortedSet roleFunctionSet = new TreeSet(); + for (CentralRoleFunction roleFunc : appRoleFunctionList) { + CentralRoleFunction cenRoleFunc = new CentralRoleFunction(roleFunc.getId(), + roleFunc.getCode(), roleFunc.getName(), null, null); + roleFunctionSet.add(cenRoleFunc); + } + CentralRole cenRole = new CentralRole(userApp.getRole().getAppRoleId(), + userApp.getRole().getCreated(), userApp.getRole().getModified(), + userApp.getRole().getCreatedId(), userApp.getRole().getModifiedId(), + userApp.getRole().getRowNum(), userApp.getRole().getName(), + userApp.getRole().getActive(), userApp.getRole().getPriority(), roleFunctionSet, null, + null); + cua.setRole(cenRole); + + userAppList.userApps.add(cua); + } + } + } + + user1 = new CentralUser(null, userInfo.getCreated(), userInfo.getModified(), userInfo.getCreatedId(), + userInfo.getModifiedId(), userInfo.getRowNum(), userInfo.getOrgId(), userInfo.getManagerId(), + userInfo.getFirstName(), userInfo.getMiddleInitial(), userInfo.getLastName(), userInfo.getPhone(), + userInfo.getFax(), userInfo.getCellular(), userInfo.getEmail(), userInfo.getAddressId(), + userInfo.getAlertMethodCd(), userInfo.getHrid(), userInfo.getOrgUserId(), userInfo.getOrgCode(), + userInfo.getAddress1(), userInfo.getAddress2(), userInfo.getCity(), userInfo.getState(), + userInfo.getZipCode(), userInfo.getCountry(), userInfo.getOrgManagerUserId(), + userInfo.getLocationClli(), userInfo.getBusinessCountryCode(), userInfo.getBusinessCountryName(), + userInfo.getBusinessUnit(), userInfo.getBusinessUnitName(), userInfo.getDepartment(), + userInfo.getDepartmentName(), userInfo.getCompanyCode(), userInfo.getCompany(), + userInfo.getZipCodeSuffix(), userInfo.getJobTitle(), userInfo.getCommandChain(), + userInfo.getSiloStatus(), userInfo.getCostCenter(), userInfo.getFinancialLocCode(), + userInfo.getLoginId(), userInfo.getLoginPwd(), userInfo.getLastLoginDate(), userInfo.getActive(), + userInfo.getInternal(), userInfo.getSelectedProfileId(), userInfo.getTimeZoneId(), + userInfo.isOnline(), userInfo.getChatId(), userAppList.userApps, null); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, "createEPUser failed", e); + throw new Exception(e.getMessage()); + } + + return user1; + } + + @SuppressWarnings("unchecked") + @Override + public CentralRole getRoleInfo(Long roleId, String uebkey) throws Exception { + final Map params = new HashMap<>(); + List roleList = new ArrayList<>(); + CentralRole cenRole = new CentralRole(); + List roleInfo = null; + List app = null; + try { + app = getApp(uebkey); + if (app.isEmpty() || app.size() == 0) { + throw new Exception("Application not found"); + } + String filter = null; + if (app.get(0).getId() == PortalConstants.PORTAL_APP_ID) { + filter = " where role_id = " + roleId + " and app_id is null "; + } else { + filter = " where app_role_id = " + roleId + " and app_id = " + app.get(0).getId(); + + } + roleInfo = dataAccessService.getList(EPRole.class, filter, null, null); + roleList = createCentralRoleObject(app, roleInfo, roleList, params); + if (roleList.isEmpty()) { + return cenRole; + } + + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, "getRoleInfo failed", e); + throw new Exception(e.getMessage()); + + } + return roleList.get(0); + } + + @SuppressWarnings("unchecked") + private List createCentralRoleObject(List app, List roleInfo, + List roleList, Map params) { + for (EPRole role : roleInfo) { + params.put("roleId", role.getId()); + params.put("appId", app.get(0).getId()); + List cenRoleFuncList = dataAccessService.executeNamedQuery("getAppRoleFunctionList", + params, null); + SortedSet roleFunctionSet = new TreeSet(); + for (CentralRoleFunction roleFunc : cenRoleFuncList) { + CentralRoleFunction cenRoleFunc = new CentralRoleFunction(role.getId(), roleFunc.getCode(), + roleFunc.getName(), null, null); + roleFunctionSet.add(cenRoleFunc); + } + SortedSet childRoles = new TreeSet(); + CentralRole cenRole = null; + if (role.getAppRoleId() == null) { + cenRole = new CentralRole(role.getId(), role.getCreated(), role.getModified(), role.getCreatedId(), + role.getModifiedId(), role.getRowNum(), role.getName(), role.getActive(), role.getPriority(), + roleFunctionSet, childRoles, null); + } else { + cenRole = new CentralRole(role.getAppRoleId(), role.getCreated(), role.getModified(), + role.getCreatedId(), role.getModifiedId(), role.getRowNum(), role.getName(), role.getActive(), + role.getPriority(), roleFunctionSet, childRoles, null); + } + roleList.add(cenRole); + } + return roleList; + } + + @SuppressWarnings("unchecked") + @Override + public CentralRoleFunction getRoleFunction(String functionCode, String uebkey) throws Exception { + CentralRoleFunction roleFunc = null; + EPApp app = getApp(uebkey).get(0); + List getRoleFuncList = null; + final Map params = new HashMap<>(); + try { + params.put("functionCode", functionCode); + params.put("appId", String.valueOf(app.getId())); + getRoleFuncList = dataAccessService.executeNamedQuery("getRoleFunction", params, null); + if (getRoleFuncList.isEmpty() | getRoleFuncList.size() == 0) { + return roleFunc; + } + + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, "getRoleFunction failed", e); + throw new Exception("getRoleFunction failed"); + } + return getRoleFuncList.get(0); + } + + @Override + public void saveCentralRoleFunction(CentralRoleFunction domainCentralRoleFunction, EPApp app) throws Exception { + try { + addRoleFunctionInExternalSystem(domainCentralRoleFunction, app); + dataAccessService.saveDomainObject(domainCentralRoleFunction, null); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, "saveCentralRoleFunction failed", e); + throw new Exception(e.getMessage()); + } + } + + @SuppressWarnings("unchecked") + private void addRoleFunctionInExternalSystem(CentralRoleFunction domainCentralRoleFunction, EPApp app) + throws Exception { + ObjectMapper mapper = new ObjectMapper(); + final Map params = new HashMap<>(); + params.put("functionCd", domainCentralRoleFunction.getCode()); + params.put("appId", String.valueOf(app.getId())); + ExternalAccessPerms extPerms = new ExternalAccessPerms(); + HttpHeaders headers = EcompPortalUtils.base64encodeKeyForAAFBasicAuth(); + List appRoleFunc = dataAccessService.executeNamedQuery("getAppFunctionDetails", params, + null); + String roleFuncName = null; + if (!appRoleFunc.isEmpty()) { + roleFuncName = appRoleFunc.get(0).getCode(); + } else { + roleFuncName = domainCentralRoleFunction.getCode(); + } + String checkType = domainCentralRoleFunction.getCode().contains("menu") ? "menu" : "url"; + HttpEntity getSinglePermEntity = new HttpEntity<>(headers); + logger.debug(EELFLoggerDelegate.debugLogger, "Connecting to External Access system"); + ResponseEntity getResponse = template.exchange( + SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + "perms/" + + app.getNameSpace() + "." + checkType + "/" + roleFuncName + "/*", + HttpMethod.GET, getSinglePermEntity, String.class); + if (getResponse.getStatusCode().value() != 200) { + throw new Exception(getResponse.getBody()); + } + logger.debug(EELFLoggerDelegate.debugLogger, "Connected to External Access system"); + String res = getResponse.getBody(); + if (res.equals("{}")) { + try{ + extPerms.setAction("*"); + extPerms.setInstance(domainCentralRoleFunction.getCode()); + extPerms.setType(app.getNameSpace() + "." + checkType); + extPerms.setDescription(domainCentralRoleFunction.getName()); + String updateRole = mapper.writeValueAsString(extPerms); + HttpEntity entity = new HttpEntity<>(updateRole, headers); + logger.debug(EELFLoggerDelegate.debugLogger, "Connecting to External Access system"); + template.exchange( + SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + "perm", + HttpMethod.POST, entity, String.class); + logger.debug(EELFLoggerDelegate.debugLogger, "Connected to External Access system"); + }catch(Exception e){ + logger.error(EELFLoggerDelegate.errorLogger, "Failed to add fucntion in external central auth system", e); + } + } else { + try{ + extPerms.setAction("*"); + extPerms.setInstance(domainCentralRoleFunction.getCode()); + extPerms.setType(app.getNameSpace() + "." + checkType); + extPerms.setDescription(domainCentralRoleFunction.getName()); + String updateRole = mapper.writeValueAsString(extPerms); + HttpEntity entity = new HttpEntity<>(updateRole, headers); + logger.debug(EELFLoggerDelegate.debugLogger, "Connecting to External Access system"); + template.exchange( + SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + "perm", + HttpMethod.PUT, entity, String.class); + logger.debug(EELFLoggerDelegate.debugLogger, "Connected to External Access system"); + } catch(Exception e){ + logger.error(EELFLoggerDelegate.errorLogger, "Failed to add fucntion in external central auth system", e); + + } + } + } + + @Override + @Transactional + public void deleteCentralRoleFunction(String code, String uebkey) { + try { + EPApp app = getApp(uebkey).get(0); + final Map params = new HashMap<>(); + params.put("functionCd", code); + params.put("appId", String.valueOf(app.getId())); + CentralRoleFunction domainCentralRoleFunction = (CentralRoleFunction) dataAccessService.executeNamedQuery("getAppFunctionDetails", params, null).get(0); + deleteRoleFunctionInExternalSystem(domainCentralRoleFunction, app); + //Delete role function dependecy records + deleteAppRoleFunctions(code, app); + dataAccessService.deleteDomainObject(domainCentralRoleFunction, null); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, "deleteCentralRoleFunction failed", e); + } + } + + private void deleteAppRoleFunctions(String code, EPApp app) { + dataAccessService.deleteDomainObjects(EPAppRoleFunction.class, " app_id = "+app.getId()+" and function_cd = '"+ code +"'", null); + } + + private void deleteRoleFunctionInExternalSystem(CentralRoleFunction domainCentralRoleFunction, EPApp app) + throws Exception { + try{ + ObjectMapper mapper = new ObjectMapper(); + ExternalAccessPerms extPerms = new ExternalAccessPerms(); + String checkType = domainCentralRoleFunction.getCode().contains("menu") ? "menu" : "url"; + HttpHeaders headers = EcompPortalUtils.base64encodeKeyForAAFBasicAuth(); + extPerms.setAction("*"); + extPerms.setInstance(domainCentralRoleFunction.getCode()); + extPerms.setType(app.getNameSpace() + "." + checkType); + extPerms.setDescription(domainCentralRoleFunction.getName()); + String updateRole = mapper.writeValueAsString(extPerms); + HttpEntity entity = new HttpEntity<>(updateRole, headers); + template.exchange( + SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + "perm?force=true", + HttpMethod.DELETE, entity, String.class); + } catch(Exception e){ + if(e.getMessage().equalsIgnoreCase("404 Not Found")){ + logger.debug(EELFLoggerDelegate.debugLogger, " It seems like function is already deleted in external central auth system but exists in local DB", e.getMessage()); + } else{ + logger.error(EELFLoggerDelegate.errorLogger, "Failed to delete functions in External System", e); + } + } + } + + @Override + public void saveRoleForApplication(Role saveRole, String uebkey) throws Exception { + try { + EPApp app = getApp(uebkey).get(0); + addRoleInEcompDB(saveRole, app); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, "saveRoleForApplication failed", e); + throw new Exception(e.getMessage()); + } + } + + @SuppressWarnings("unchecked") + @Override + public void deleteRoleForApplication(String deleteRole, String uebkey) throws Exception { + Session localSession = null; + Transaction transaction = null; + boolean result = false; + try { + localSession = sessionFactory.openSession(); + transaction = localSession.beginTransaction(); + + List epRoleList = null; + ResponseEntity deleteResponse = null; + EPApp app = getApp(uebkey).get(0); + if(app.getId() == 1) + { + epRoleList = dataAccessService.getList(EPRole.class, + " where app_id is null " + "and role_name = '" + deleteRole +"'", null, null); + } + else{ + epRoleList = dataAccessService.getList(EPRole.class, + " where app_id = " + app.getId() + " and role_name = '" + deleteRole +"'", null, null); + } + // Delete app role functions before deleting role + deleteRoleFunction(app, epRoleList); + if(app.getId() == 1) + { + // Delete fn_user_ role + dataAccessService.deleteDomainObjects(EPUserApp.class, + " app_id = " + app.getId() + " and role_id = " + epRoleList.get(0).getId(), null); + + deleteRoleDependeciesRecord(localSession, epRoleList.get(0).getId()); + } + // Delete Role in External System + String deleteRoleKey = "{\"name\":\"" + app.getNameSpace() + "." + + epRoleList.get(0).getName().replaceAll(" ", "_") + "\"}"; + deleteResponse = deleteRoleInExternalSystem(deleteRoleKey); + if (deleteResponse.getStatusCode().value() != 200) { + throw new Exception("Failed to delete role in external access system!"); + } + logger.debug(EELFLoggerDelegate.debugLogger, "about to commit the transaction"); + transaction.commit(); + logger.debug(EELFLoggerDelegate.debugLogger, "committed the transaction"); + dataAccessService.deleteDomainObject(epRoleList.get(0), null); + result = true; + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, "deleteRoleForApplication failed", e); + throw new Exception(e.getMessage()); + }finally { + localSession.close(); + if (!result) { + throw new Exception( + "Exception occurred in deleteRoleForApplication while closing database session for role: '" + deleteRole + "'."); + } + } + } + + private void deleteUserRoleInExternalSystem(EPRole role, EPApp app, String LoginId) throws Exception { + HttpHeaders headers = EcompPortalUtils.base64encodeKeyForAAFBasicAuth(); + HttpEntity entity = new HttpEntity<>(headers); + logger.debug(EELFLoggerDelegate.debugLogger, "Connecting to External Access system"); + ResponseEntity getResponse = template + .exchange( + SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + "userRole/" + + LoginId + + SystemProperties + .getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_USER_DOMAIN) + + "/" + app.getNameSpace() + "." + role.getName().replaceAll(" ", "_"), + HttpMethod.GET, entity, String.class); + if (getResponse.getStatusCode().value() != 200) { + throw new Exception(getResponse.getBody()); + } + logger.debug(EELFLoggerDelegate.debugLogger, "Connected to External Access system"); + String res = getResponse.getBody(); + if (!res.equals("{}")) { + HttpEntity userRoleentity = new HttpEntity<>(headers); + logger.debug(EELFLoggerDelegate.debugLogger, "Connecting to External Access system"); + ResponseEntity deleteResponse = template + .exchange( + SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + + "userRole/" + LoginId + + SystemProperties + .getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_USER_DOMAIN) + + "/" + app.getNameSpace() + "." + role.getName().replaceAll(" ", "_"), + HttpMethod.DELETE, userRoleentity, String.class); + if (deleteResponse.getStatusCode().value() != 200) { + throw new Exception("Failed to delete user role"); + } + logger.debug(EELFLoggerDelegate.debugLogger, "Connected to External Access system"); + } + } + + @SuppressWarnings("unchecked") + @Override + public List getActiveRoles(String uebkey) throws Exception { + List roleList = new ArrayList<>(); + try { + List app = getApp(uebkey); + final Map params = new HashMap<>(); + // check if portal + Long appId = null; + if (!app.get(0).getId().equals(PortalConstants.PORTAL_APP_ID)) { + appId = app.get(0).getId(); + } + List epRole = dataAccessService.getList(EPRole.class, + " where app_id = " + appId + " and active_yn = 'Y'", null, null); + roleList = createCentralRoleObject(app, epRole, roleList, params); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, "getActiveRoles failed", e); + throw new Exception(e.getMessage()); + } + return roleList; + + } + + @SuppressWarnings("unchecked") + @Override + public void deleteDependcyRoleRecord(Long roleId, String uebkey, String LoginId) throws Exception { + boolean result = false; + Session localSession = null; + Transaction transaction = null; + EPApp app = null; + try { + localSession = sessionFactory.openSession(); + transaction = localSession.beginTransaction(); + List epRoleList = null; + app = getApp(uebkey).get(0); + epRoleList = dataAccessService.getList(EPRole.class, + " where app_id = " + app.getId() + " and app_role_id = " + roleId, null, null); + if(epRoleList.isEmpty()){ + epRoleList = dataAccessService.getList(EPRole.class, + " where app_id = " + app.getId() + " and role_id = " + roleId, null, null); + } + // Delete User Role in External System before deleting role + deleteUserRoleInExternalSystem(epRoleList.get(0), app, LoginId); + // Delete user app roles + dataAccessService.deleteDomainObjects(EPUserApp.class, + " app_id = " + app.getId() + " and role_id = " + epRoleList.get(0).getId(), null); + + deleteRoleDependeciesRecord(localSession, epRoleList.get(0).getId()); + logger.debug(EELFLoggerDelegate.debugLogger, "about to commit the transaction"); + transaction.commit(); + logger.debug(EELFLoggerDelegate.debugLogger, "committed the transaction"); + result = true; + } catch (Exception e) { + EcompPortalUtils.rollbackTransaction(transaction, + "deleteDependcyRoleRecord rollback, exception = " + e); + logger.error(EELFLoggerDelegate.errorLogger, EcompPortalUtils.getStackTrace(e)); + }finally { + localSession.close(); + if (!result) { + throw new Exception( + "Exception occurred in syncAppRoles while closing database session for role: '" + app.getId() + "'."); + } + } + } + + @SuppressWarnings("unchecked") + @Transactional + public void syncRoleFunctionFromExternalAccessSystem(EPApp app){ + try{ + ResponseEntity response = null; + HttpHeaders headers = EcompPortalUtils.base64encodeKeyForAAFBasicAuth(); + HttpEntity entity = new HttpEntity<>(headers); + logger.debug(EELFLoggerDelegate.debugLogger, "Connecting to External Access system"); + response = template.exchange(SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + + "perms/ns/" + app.getNameSpace(), HttpMethod.GET, entity, String.class); + + String res = response.getBody(); + logger.debug(EELFLoggerDelegate.debugLogger, "Connected to External Access system and the result is :", res); + JSONObject jsonObj = new JSONObject(res); + JSONArray extPerms = jsonObj.getJSONArray("perm"); + for (int i = 0; i < extPerms.length(); i++) { + if (extPerms.getJSONObject(i).getString("type").equals(app.getNameSpace() + ".access")) { + extPerms.remove(i); + i--; + } + } + ExternalAccessPermsDetail permDetails = null; + List permsDetailList = new ArrayList<>(); + for (int i = 0; i < extPerms.length(); i++) { + if (extPerms.getJSONObject(i).has("roles")) { + ObjectMapper rolesListMapper = new ObjectMapper(); + JSONArray resRoles = extPerms.getJSONObject(i).getJSONArray("roles"); + List list = rolesListMapper.readValue(resRoles.toString(), + TypeFactory.defaultInstance().constructCollectionType(List.class, String.class)); + permDetails = new ExternalAccessPermsDetail(extPerms.getJSONObject(i).getString("type"), + extPerms.getJSONObject(i).getString("instance"), extPerms.getJSONObject(i).getString("action"), + list, extPerms.getJSONObject(i).getString("description")); + permsDetailList.add(permDetails); + } else { + permDetails = new ExternalAccessPermsDetail(extPerms.getJSONObject(i).getString("type"), + extPerms.getJSONObject(i).getString("instance"), extPerms.getJSONObject(i).getString("action"), + extPerms.getJSONObject(i).getString("description")); + permsDetailList.add(permDetails); + } + } + + final Map params = new HashMap<>(); + final Map roleFuncMap = new HashMap<>(); + params.put("appId", app.getId()); + List appFunctions = dataAccessService.executeNamedQuery("getAllRoleFunctions", params, + null); + if (appFunctions.size() > 0) { + for (CentralRoleFunction roleFunc : appFunctions) { + roleFuncMap.put(roleFunc.getCode(), roleFunc); + } + } + // delete all application role functions + dataAccessService.deleteDomainObjects(EPAppRoleFunction.class, " app_id = " + app.getId(), null); + + // Add if new functions and app role functions were added in Externalsystem + for (ExternalAccessPermsDetail permsDetail : permsDetailList) { + if (!roleFuncMap.containsKey(permsDetail.getInstance())) { + CentralRoleFunction addFunction = new CentralRoleFunction(); + addFunction.setAppId(app.getId()); + addFunction.setCode(permsDetail.getInstance()); + addFunction.setName(permsDetail.getDescription()); + dataAccessService.saveDomainObject(addFunction, null); + } + List epRolesList = null; + List roles = permsDetail.getRoles(); + if (roles != null) { + for (String roleList : roles) { + if (app.getId().equals(PortalConstants.PORTAL_APP_ID)) { + epRolesList = dataAccessService.getList(EPRole.class, + " where app_id is null " + " and role_name = '" + + roleList.substring(app.getNameSpace().length() + 1).replaceAll("_", " ") +"'", + null, null); + } else { + epRolesList = dataAccessService.getList(EPRole.class, + " where app_id = " + app.getId() + " and role_name = '" + + roleList.substring(app.getNameSpace().length() + 1).replaceAll("_", " ") +"'", + null, null); + } + if(epRolesList.isEmpty()){ + if (app.getId().equals(PortalConstants.PORTAL_APP_ID)) { + epRolesList = dataAccessService.getList(EPRole.class, + " where app_id is null " + " and role_name = '" + + roleList.substring(app.getNameSpace().length() + 1) + + "'", + null, null); + } else { + epRolesList = dataAccessService.getList(EPRole.class, + " where app_id = " + app.getId() + " and role_name = '" + + roleList.substring(app.getNameSpace().length() + 1)+"'", + null, null); + } + } + // save all application role functions + if (epRolesList.size() > 0 || !epRolesList.isEmpty()) { + EPAppRoleFunction addAppRoleFunc = new EPAppRoleFunction(); + addAppRoleFunc.setAppId(app.getId()); + addAppRoleFunc.setCode(permsDetail.getInstance()); + addAppRoleFunc.setRoleId(epRolesList.get(0).getId()); + dataAccessService.saveDomainObject(addAppRoleFunc, null); + } + } + } + } + logger.debug(EELFLoggerDelegate.debugLogger, "Finished syncRoleFunctionFromExternalAccessSystem"); + } catch(Exception e){ + logger.error(EELFLoggerDelegate.errorLogger, "Failed syncRoleFunctionFromExternalAccessSystem", e); + + } + } + + @SuppressWarnings("unchecked") + public Integer bulkUploadFunctions(String uebkey) throws Exception { + EPApp app = getApp(uebkey).get(0); + List roleFuncList = null; + roleFuncList = dataAccessService.getList(RoleFunction.class, null); + CentralRoleFunction cenRoleFunc = null; + Integer functionsAdded = 0; + try { + for (RoleFunction roleFunc : roleFuncList) { + cenRoleFunc = new CentralRoleFunction(roleFunc.getCode(), roleFunc.getName()); + addRoleFunctionInExternalSystem(cenRoleFunc, app); + functionsAdded++; + } + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, "bulkUploadFunctions failed", e.getMessage(), e); + } + return functionsAdded; + } + + public Integer bulkUploadRoles(String uebkey) throws Exception { + List app = getApp(uebkey); + List roles = getAppRoles(app.get(0).getId(), null); + List cenRoleList = new ArrayList<>(); + final Map params = new HashMap<>(); + Integer rolesListAdded = 0; + try { + cenRoleList = createCentralRoleObject(app, roles, cenRoleList, params); + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false); + String roleList = mapper.writeValueAsString(cenRoleList); + List roleObjectList = mapper.readValue(roleList, + TypeFactory.defaultInstance().constructCollectionType(List.class, Role.class)); + for (Role role : roleObjectList) { + addRoleInExternalSystem(role, app.get(0)); + rolesListAdded++; + } + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, "bulkUploadRoles failed", e); + throw new Exception(e.getMessage()); + } + return rolesListAdded; + } + + private void addRoleInExternalSystem(Role role, EPApp app) throws Exception { + String addRoleNew = createNewRoleInExternalSystem(role, app); + HttpHeaders headers = EcompPortalUtils.base64encodeKeyForAAFBasicAuth(); + try{ + HttpEntity entity = new HttpEntity<>(addRoleNew, headers); + template.exchange( + SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + "role", + HttpMethod.POST, entity, String.class); + } catch(Exception e){ + if (e.getMessage().equalsIgnoreCase("409 Conflict")) { + logger.error(EELFLoggerDelegate.errorLogger, "Role already exits but does not break functionality"); + } else { + logger.error(EELFLoggerDelegate.errorLogger, "Failed to addRoleInExternalSystem", e.getMessage()); + } + } + } + + @SuppressWarnings("unchecked") + public Integer bulkUploadRolesFunctions(String uebkey) throws Exception { + EPApp app = getApp(uebkey).get(0); + List roles = getAppRoles(app.getId(), null); + final Map params = new HashMap<>(); + Integer roleFunctions = 0; + try { + for (EPRole role : roles) { + params.put("roleId", role.getId()); + List appRoleFunc = dataAccessService.executeNamedQuery("uploadAllRoleFunctions", params, null); + if(!appRoleFunc.isEmpty()){ + for(BulkUploadRoleFunction addRoleFunc : appRoleFunc){ + addRoleFunctionsInExternalSystem(addRoleFunc, role, app); + roleFunctions++; + } + } + } + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, "bulkUploadRolesFunctions failed", e); + } + return roleFunctions; + } + + private void addRoleFunctionsInExternalSystem(BulkUploadRoleFunction addRoleFunc, EPRole role, EPApp app){ + String checkType = addRoleFunc.getFunctionCd().contains("menu") ? "menu" : "url"; + ExternalAccessRolePerms extRolePerms = null; + ExternalAccessPerms extPerms = null; + ObjectMapper mapper = new ObjectMapper(); + try{ + HttpHeaders headers = EcompPortalUtils.base64encodeKeyForAAFBasicAuth(); + + extPerms = new ExternalAccessPerms(app.getNameSpace() + "." + checkType, addRoleFunc.getFunctionCd(), "*", addRoleFunc.getFunctionName()); + extRolePerms = new ExternalAccessRolePerms(extPerms, + app.getNameSpace() + "." + role.getName().replaceAll(" ", "_")); + String updateRolePerms = mapper.writeValueAsString(extRolePerms); + HttpEntity entity = new HttpEntity<>(updateRolePerms, headers); + template + .exchange(SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + + "role/perm", HttpMethod.POST, entity, String.class); + } catch(Exception e){ + if (e.getMessage().equalsIgnoreCase("409 Conflict")) { + logger.error(EELFLoggerDelegate.errorLogger, "RoleFunction already exits but does not break functionality",e); + } else { + logger.error(EELFLoggerDelegate.errorLogger, "Failed to addRoleFunctionsInExternalSystem", e.getMessage()); + } + } + } + + @Override + public void bulkUploadPartnerFunctions(String uebkey, List roleFunctionsList) throws Exception { + EPApp app = getApp(uebkey).get(0); + CentralRoleFunction cenRoleFunc = null; + for (RoleFunction roleFunction : roleFunctionsList) { + cenRoleFunc = new CentralRoleFunction(roleFunction.getCode(), roleFunction.getName()); + addRoleFunctionInExternalSystem(cenRoleFunc, app); + } + } + + @Override + public void bulkUploadPartnerRoles(String uebkey, List roleList) throws Exception { + EPApp app = getApp(uebkey).get(0); + for (Role role : roleList) { + addRoleInExternalSystem(role, app); + } + } + + @SuppressWarnings("unchecked") + @Override + public void bulkUploadPartnerRoleFunctions(String uebkey, List roleList) throws Exception { + EPApp app = getApp(uebkey).get(0); + HttpHeaders headers = EcompPortalUtils.base64encodeKeyForAAFBasicAuth(); + for (Role role : roleList) { + try { + Set roleFunctionList = role.getRoleFunctions(); + List roleFunctionListNew = new ArrayList<>(); + ObjectMapper roleFunctionsMapper = new ObjectMapper(); + Iterator itetaror = roleFunctionList.iterator(); + while (itetaror.hasNext()) { + Object nextValue = itetaror.next(); + RoleFunction roleFunction = roleFunctionsMapper.convertValue(nextValue, RoleFunction.class); + roleFunctionListNew.add(roleFunction); + } + List listWithoutDuplicates = roleFunctionListNew.stream().distinct() + .collect(Collectors.toList()); + for (RoleFunction roleFunction : listWithoutDuplicates) { + String checkType = roleFunction.getCode().contains("menu") ? "menu" : "url"; + ExternalAccessRolePerms extRolePerms = null; + ExternalAccessPerms extPerms = null; + ObjectMapper mapper = new ObjectMapper(); + extPerms = new ExternalAccessPerms(app.getNameSpace() + "." + checkType, roleFunction.getCode(), + "*"); + extRolePerms = new ExternalAccessRolePerms(extPerms, + app.getNameSpace() + "." + role.getName().replaceAll(" ", "_")); + String updateRolePerms = mapper.writeValueAsString(extRolePerms); + HttpEntity entity = new HttpEntity<>(updateRolePerms, headers); + template.exchange(SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + + "role/perm", HttpMethod.PUT, entity, String.class); + } + } catch (Exception e) { + if (e.getMessage().equalsIgnoreCase("409 Conflict")) { + logger.error(EELFLoggerDelegate.errorLogger, + "RoleFunction already exits but does not break functionality"); + } else { + logger.error(EELFLoggerDelegate.errorLogger, "Failed to addRoleFunctionsInExternalSystem", + e.getMessage()); + } + } + + } + } + + @SuppressWarnings("unchecked") + @Transactional + public void SyncApplicationRolesWithEcompDB(EPApp app){ + try{ + ResponseEntity response = null; + List finalRoleList = new ArrayList<>(); + ExternalRoleDescription ApplicationRole = new ExternalRoleDescription(); + ExternalAccessPerms externalAccessPerms = null; + List functionCodelist = new ArrayList<>(); + List externalRoleDetailsList = new ArrayList<>(); + ObjectMapper mapper = new ObjectMapper(); + HttpHeaders headers = EcompPortalUtils.base64encodeKeyForAAFBasicAuth(); + HttpEntity entity = new HttpEntity<>(headers); + logger.debug(EELFLoggerDelegate.debugLogger, "Connecting to External Access system"); + response = template.exchange(SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + + "roles/ns/" + app.getNameSpace(), HttpMethod.GET, entity, String.class); + String res = response.getBody(); + logger.debug(EELFLoggerDelegate.debugLogger, "Connected to External Access system and the result is :", res); + JSONObject jsonObj = new JSONObject(res); + JSONArray extRole = jsonObj.getJSONArray("role"); + for (int i = 0; i < extRole.length(); i++) { + if (extRole.getJSONObject(i).getString("name").equals(app.getNameSpace() + ".admin") + || extRole.getJSONObject(i).getString("name").equals(app.getNameSpace() + ".owner") + ) { + extRole.remove(i); + i--; + } + if(!app.getId().equals(PortalConstants.PORTAL_APP_ID) && extRole.getJSONObject(i).get("name").equals(app.getNameSpace()+"."+PortalConstants.ADMIN_ROLE.replaceAll(" ", "_"))){ + extRole.remove(i); + i--; + } + } + List applicationRoleFunctionList = new ArrayList<>(); + for (int i = 0; i < extRole.length(); i++) { + ExternalRoleDetails externalRoleDetail = new ExternalRoleDetails(); + EPAppRoleFunction ePAppRoleFunction = new EPAppRoleFunction(); + JSONObject Role = (JSONObject) extRole.get(i); + if(!extRole.getJSONObject(i).has("description")) + { + ApplicationRole.setActive("true"); + ApplicationRole.setAppId("null"); + ApplicationRole.setPriority("null"); + ApplicationRole.setAppRoleId("null"); + String roleName =extRole.getJSONObject(i).getString("name"); + ApplicationRole.setName(roleName.substring(app.getNameSpace().length()+1)); + } + else { + String desc = extRole.getJSONObject(i).getString("description"); + ApplicationRole = mapper.readValue(desc, ExternalRoleDescription.class); + } + + + SortedSet externalAccessPermsOfRole = new TreeSet<>(); + if (extRole.getJSONObject(i).has("perms")) { + JSONArray extPerm = (JSONArray) Role.get("perms"); + for (int j = 0; j < extPerm.length(); j++) { + JSONObject perms = extPerm.getJSONObject(j); + externalAccessPerms = new ExternalAccessPerms(perms.getString("type"), perms.getString("instance"), + perms.getString("action")); + ePAppRoleFunction.setCode(externalAccessPerms.getInstance()); + functionCodelist.add(ePAppRoleFunction.getCode()); + externalAccessPermsOfRole.add(externalAccessPerms); + } + } + + if (ApplicationRole.getActive().equals("null")) { + externalRoleDetail.setActive(false); + } else { + externalRoleDetail.setActive(Boolean.parseBoolean(ApplicationRole.getActive().toString())); + } + externalRoleDetail.setName(ApplicationRole.getName()); + + if (ApplicationRole.getAppId().equals("null") && app.getId() == 1) { + externalRoleDetail.setAppId(null); + } else if(ApplicationRole.getAppId().equals("null")){ + externalRoleDetail.setAppId(app.getId()); + }else { + externalRoleDetail.setAppId(Long.parseLong(ApplicationRole.getAppId().toString())); + } + + if (ApplicationRole.getPriority().equals("null")) { + externalRoleDetail.setPriority(null); + } else { + externalRoleDetail.setPriority(Integer.parseInt(ApplicationRole.getPriority().toString())); + } + + if (ApplicationRole.getAppRoleId().equals("null") && app.getId() == 1) { + externalRoleDetail.setAppRoleId(null); + } + + if (!externalAccessPermsOfRole.isEmpty() || externalAccessPermsOfRole.size() > 0) { + for (ExternalAccessPerms externalpermission : externalAccessPermsOfRole) { + EPAppRoleFunction apRoleFunction = new EPAppRoleFunction(); + apRoleFunction.setAppId(app.getId()); + apRoleFunction.setRoleId(Long.parseLong(ApplicationRole.getId())); + apRoleFunction.setCode(externalpermission.getInstance()); + applicationRoleFunctionList.add(apRoleFunction); + } + } + externalRoleDetailsList.add(externalRoleDetail); + } + + for (ExternalRoleDetails externalRole : externalRoleDetailsList) { + EPRole ecompRole = new EPRole(); + ecompRole = convertExternalRoleDetailstoEpRole(externalRole); + finalRoleList.add(ecompRole); + } + + List applicationRolesList = new ArrayList<>(); + applicationRolesList = getAppRoles(app.getId(), null); + List applicationRoleIdList = new ArrayList<>(); + for (EPRole applicationRole : applicationRolesList) { + applicationRoleIdList.add(applicationRole.getName()); + } + + List roleListToBeAddInEcompDB = new ArrayList<>(); + for (EPRole aafRole : finalRoleList) { + if (!applicationRoleIdList.contains(aafRole.getName())) { + roleListToBeAddInEcompDB.add(aafRole); + } + } + + // Check if roles exits in external Access system and make it inactive + final Map checkRolesInactive = new HashMap<>(); + for(EPRole extrole : finalRoleList){ + checkRolesInactive.put(extrole.getName(), extrole); + } + for (EPRole role : applicationRolesList) { + final Map extRoleParams = new HashMap<>(); + List roleList = new ArrayList<>(); + extRoleParams.put("appRoleName", role.getName()); + if (!checkRolesInactive.containsKey(role.getName())) { + if (app.getId() == 1) { + roleList = dataAccessService.executeNamedQuery("getPortalAppRoles", extRoleParams, null); + } else { + extRoleParams.put("appId", app.getId().toString()); + roleList = dataAccessService.executeNamedQuery("getRoletoUpdateAAF", extRoleParams, null); + } + EPRole updateRoleInactive = roleList.get(0); + updateRoleInactive.setActive(false); + dataAccessService.saveDomainObject(updateRoleInactive, null); + } + } + + for (EPRole roleItem : finalRoleList) { + final Map roleParams = new HashMap<>(); + List currentList = new ArrayList<>(); + roleParams.put("appRoleName", roleItem.getName()); + if (app.getId() == 1) { + currentList = dataAccessService.executeNamedQuery("getPortalAppRoles", roleParams, null); + } else { + roleParams.put("appId", app.getId().toString()); + currentList = dataAccessService.executeNamedQuery("getRoletoUpdateAAF", roleParams, null); + } + + if (!currentList.isEmpty()) { + Boolean aafRoleActive; + Boolean localRoleActive; + boolean result; + aafRoleActive = Boolean.valueOf(roleItem.getActive()); + localRoleActive = Boolean.valueOf(currentList.get(0).getActive()); + result = aafRoleActive.equals(localRoleActive); + EPRole updateRole = currentList.get(0); + + if (!result) { + updateRole.setActive(roleItem.getActive()); + dataAccessService.saveDomainObject(updateRole, null); + } + if (roleItem.getPriority() != null + && !currentList.get(0).getPriority().equals(roleItem.getPriority())) { + updateRole.setPriority(roleItem.getPriority()); + dataAccessService.saveDomainObject(updateRole, null); + } + } + } + + EPRole roleToBeAddedInEcompDB = new EPRole(); + for (int i = 0; i < roleListToBeAddInEcompDB.size(); i++) { + roleToBeAddedInEcompDB = roleListToBeAddInEcompDB.get(i); + if(app.getId() == 1) + { + roleToBeAddedInEcompDB.setAppRoleId(null); + } + dataAccessService.saveDomainObject(roleToBeAddedInEcompDB, null); + List getRoleCreatedInSync = null; + if (!app.getId().equals(PortalConstants.PORTAL_APP_ID)) { + getRoleCreatedInSync = dataAccessService.getList(EPRole.class, + " where role_name = '" + roleToBeAddedInEcompDB.getName() +"'", null, null); + EPRole epUpdateRole = getRoleCreatedInSync.get(0); + epUpdateRole.setAppRoleId(epUpdateRole.getId()); + dataAccessService.saveDomainObject(epUpdateRole, null); + } + List roleList = new ArrayList<>(); + final Map params = new HashMap<>(); + + params.put("appRoleName", roleToBeAddedInEcompDB.getName()); + if (app.getId() == 1) { + roleList = dataAccessService.executeNamedQuery("getPortalAppRoles", params, null); + } else { + params.put("appId", app.getId().toString()); + roleList = dataAccessService.executeNamedQuery("getRoletoUpdateAAF", params, null); + } + EPRole role = roleList.get(0); + Role aaFrole = new Role(); + aaFrole.setId(role.getId()); + aaFrole.setActive(role.getActive()); + aaFrole.setPriority(role.getPriority()); + aaFrole.setName(role.getName()); + updateRoleInExternalSystem(aaFrole, app); + } + dataAccessService.deleteDomainObjects(EPAppRoleFunction.class, " app_id = " + app.getId(), null); + for (EPAppRoleFunction rolefun : applicationRoleFunctionList) { + dataAccessService.saveDomainObject(rolefun, null); + } + + logger.debug(EELFLoggerDelegate.debugLogger, "Finished SyncApplicationRolesWithEcompDB"); + }catch(Exception e){ + logger.error(EELFLoggerDelegate.errorLogger, "Failed to SyncApplicationRolesWithEcompDB", e); + } + } + + public EPRole convertExternalRoleDetailstoEpRole(ExternalRoleDetails externalRoleDetails) { + EPRole role = new EPRole(); + role.setActive(externalRoleDetails.isActive()); + role.setAppId(externalRoleDetails.getAppId()); + role.setAppRoleId(externalRoleDetails.getAppRoleId()); + role.setName(externalRoleDetails.getName()); + role.setPriority(externalRoleDetails.getPriority()); + return role; + } + + @SuppressWarnings("unchecked") + @Override + public Integer bulkUploadUserRoles(String uebkey) throws Exception { + EPApp app = getApp(uebkey).get(0); + final Map params = new HashMap<>(); + params.put("uebKey", app.getUebKey()); + List userRolesList = null; + Integer userRolesAdded = 0; + if (app.getCentralAuth()) { + userRolesList = dataAccessService.executeNamedQuery("getBulkUserRoles", params, null); + for (BulkUploadUserRoles userRolesUpload : userRolesList) { + addUserRoleInExternalSystem(userRolesUpload); + userRolesAdded++; + } + } + return userRolesAdded; + } + + private void addUserRoleInExternalSystem(BulkUploadUserRoles userRolesUpload){ + try{ + String name = ""; + ObjectMapper mapper = new ObjectMapper(); + if (EPCommonSystemProperties.containsProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_USER_DOMAIN)) { + name = userRolesUpload.getOrgUserId() + + SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_USER_DOMAIN); + } + ExternalAccessUser extUser = new ExternalAccessUser(name, + userRolesUpload.getAppNameSpace() + "." + userRolesUpload.getRoleName().replaceAll(" ", "_")); + String userRole = mapper.writeValueAsString(extUser); + HttpHeaders headers = EcompPortalUtils.base64encodeKeyForAAFBasicAuth(); + HttpEntity entity = new HttpEntity<>(userRole, headers); + template.exchange( + SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + "userRole", + HttpMethod.POST, entity, String.class); + } catch (Exception e) { + if (e.getMessage().equalsIgnoreCase("409 Conflict")) { + logger.error(EELFLoggerDelegate.errorLogger, "UserRole already exits but does not break functionality"); + } else { + logger.error(EELFLoggerDelegate.errorLogger, "Failed to addUserRoleInExternalSystem", e.getMessage()); + } + } + } + + @Override + public void deleteRoleDependeciesRecord(Session localSession, Long roleId) throws Exception { + try { + // Delete from fn_role_function + String sql = "DELETE FROM fn_role_function WHERE role_id=" + roleId; + logger.debug(EELFLoggerDelegate.debugLogger, "Executing query: " + sql); + Query query = localSession.createSQLQuery(sql); + query.executeUpdate(); + + // Delete from ep_app_role_function + sql = "DELETE FROM ep_app_role_function WHERE role_id=" + roleId; + logger.debug(EELFLoggerDelegate.debugLogger, "Executing query: " + sql); + query = localSession.createSQLQuery(sql); + query.executeUpdate(); + + // Delete from ep_role_notification + sql = "DELETE FROM ep_role_notification WHERE role_id=" + roleId; + logger.debug(EELFLoggerDelegate.debugLogger, "Executing query: " + sql); + query = localSession.createSQLQuery(sql); + query.executeUpdate(); + + // Delete from fn_role_composite + sql = "DELETE FROM fn_role_composite WHERE parent_role_id=" + roleId + " OR child_role_id=" + + roleId; + logger.debug(EELFLoggerDelegate.debugLogger, "Executing query: " + sql); + query = localSession.createSQLQuery(sql); + query.executeUpdate(); + + // Delete from fn_user_pseudo_role + sql = "DELETE FROM fn_user_pseudo_role WHERE pseudo_role_id=" + roleId; + logger.debug(EELFLoggerDelegate.debugLogger, "Executing query: " + sql); + query = localSession.createSQLQuery(sql); + query.executeUpdate(); + + //Delete form EP_WIDGET_CATALOG_ROLE + sql = "DELETE FROM EP_WIDGET_CATALOG_ROLE WHERE role_id=" + roleId; + logger.debug(EELFLoggerDelegate.debugLogger, "Executing query: " + sql); + query = localSession.createSQLQuery(sql); + query.executeUpdate(); + + //Delete form EP_WIDGET_CATALOG_ROLE + sql = "DELETE FROM ep_user_roles_request_det WHERE requested_role_id=" + roleId; + logger.debug(EELFLoggerDelegate.debugLogger, "Executing query: " + sql); + query = localSession.createSQLQuery(sql); + query.executeUpdate(); + + //Delete form fn_menu_functional_roles + sql = "DELETE FROM fn_menu_functional_roles WHERE role_id=" + roleId; + logger.debug(EELFLoggerDelegate.debugLogger, "Executing query: " + sql); + query = localSession.createSQLQuery(sql); + query.executeUpdate(); + + } catch (Exception e) { + logger.debug(EELFLoggerDelegate.debugLogger, "deleteRoleDependeciesRecord failed " , e); + throw new Exception("delete Failed"+ e.getMessage()); + } + + } + + + @SuppressWarnings("unchecked") + @Override + public List getMenuFunctionsList(String uebkey) throws Exception { + List appMenuFunctionsList = null; + try{ + EPApp app = getApp(uebkey).get(0); + final Map appParams = new HashMap<>(); + appParams.put("appId", app.getId()); + appMenuFunctionsList = dataAccessService.executeNamedQuery("getMenuFunctions", appParams, null); + } catch(Exception e){ + logger.error(EELFLoggerDelegate.errorLogger, "Failed getMenuFunctionsList", e); + return appMenuFunctionsList; + } + return appMenuFunctionsList; + } +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/PortalAdminServiceImpl.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/PortalAdminServiceImpl.java index 0963f048..5979fe82 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/PortalAdminServiceImpl.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/PortalAdminServiceImpl.java @@ -29,25 +29,34 @@ import javax.servlet.http.HttpServletResponse; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; +import org.openecomp.portalapp.portal.domain.EPApp; import org.openecomp.portalapp.portal.domain.EPUser; import org.openecomp.portalapp.portal.logging.aop.EPMetricsLog; +import org.openecomp.portalapp.portal.transport.ExternalAccessUser; import org.openecomp.portalapp.portal.transport.FieldsValidator; import org.openecomp.portalapp.portal.transport.PortalAdmin; import org.openecomp.portalapp.portal.transport.PortalAdminUserRole; import org.openecomp.portalapp.portal.utils.EPCommonSystemProperties; import org.openecomp.portalapp.portal.utils.EcompPortalUtils; +import org.openecomp.portalapp.portal.utils.PortalConstants; import org.openecomp.portalsdk.core.logging.logic.EELFLoggerDelegate; import org.openecomp.portalsdk.core.service.DataAccessService; import org.openecomp.portalsdk.core.util.SystemProperties; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import com.fasterxml.jackson.databind.ObjectMapper; @Service("portalAdminService") @org.springframework.context.annotation.Configuration @EnableAspectJAutoProxy @EPMetricsLog -public class PortalAdminServiceImpl implements PortalAdminService { +public class PortalAdminServiceImpl implements PortalAdminService { private String SYS_ADMIN_ROLE_ID = "1"; private String ECOMP_APP_ID = "1"; @@ -60,7 +69,11 @@ public class PortalAdminServiceImpl implements PortalAdminService { private DataAccessService dataAccessService; @Autowired SearchService searchService; - + @Autowired + private EPAppService epAppService; + + RestTemplate template = new RestTemplate(); + @PostConstruct private void init() { SYS_ADMIN_ROLE_ID = SystemProperties.getProperty(SystemProperties.SYS_ADMIN_ROLE_ID); @@ -130,7 +143,8 @@ public class PortalAdminServiceImpl implements PortalAdminService { } transaction.commit(); - result = true; + // Add role in the external central auth system + result = addPortalAdminInExternalCentralAuth(user.getOrgUserId(), PortalConstants.PORTAL_ADMIN_ROLE); } catch (Exception e) { EcompPortalUtils.rollbackTransaction(transaction, "createPortalAdmin rollback, exception = " + e); logger.error(EELFLoggerDelegate.errorLogger, EcompPortalUtils.getStackTrace(e)); @@ -147,6 +161,42 @@ public class PortalAdminServiceImpl implements PortalAdminService { } return fieldsValidator; } + + private boolean addPortalAdminInExternalCentralAuth(String loginId, String portalAdminRole){ + boolean result = false; + try{ + String name = ""; + if (EPCommonSystemProperties.containsProperty( + EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_USER_DOMAIN)) { + name = loginId + SystemProperties + .getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_USER_DOMAIN); + } + EPApp app = epAppService.getApp(PortalConstants.PORTAL_APP_ID); + String extRole = app.getNameSpace()+"."+portalAdminRole.replaceAll(" ", "_"); + ObjectMapper addUserRoleMapper = new ObjectMapper(); + ExternalAccessUser extUser = new ExternalAccessUser(name, extRole); + String userRole = addUserRoleMapper.writeValueAsString(extUser); + HttpHeaders headers = EcompPortalUtils.base64encodeKeyForAAFBasicAuth(); + + HttpEntity addUserRole = new HttpEntity<>(userRole, headers); + template.exchange( + SystemProperties.getProperty( + EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + + "userRole", + HttpMethod.POST, addUserRole, String.class); + result = true; + } catch (Exception e) { + // This happens only if role already exists in external central access system but not in local DB thats where we logging here + if (e.getMessage().equalsIgnoreCase("409 Conflict")) { + result = true; + logger.debug(EELFLoggerDelegate.debugLogger, "Portal Admin role already exists", e.getMessage()); + } else{ + logger.error(EELFLoggerDelegate.errorLogger, "Failed to add Portal Admin role ", e); + result = false; + } + } + return result; + } public FieldsValidator deletePortalAdmin(Long userId) { FieldsValidator fieldsValidator = new FieldsValidator(); @@ -161,7 +211,7 @@ public class PortalAdminServiceImpl implements PortalAdminService { dataAccessService.deleteDomainObjects(PortalAdminUserRole.class, "user_id='" + userId + "' AND role_id='" + SYS_ADMIN_ROLE_ID + "'", null); transaction.commit(); - result = true; + result = deletePortalAdminInExternalCentralAuth(userId, PortalConstants.PORTAL_ADMIN_ROLE); } catch (Exception e) { EcompPortalUtils.rollbackTransaction(transaction, "deletePortalAdmin rollback, exception = " + e); logger.error(EELFLoggerDelegate.errorLogger, EcompPortalUtils.getStackTrace(e)); @@ -177,6 +227,40 @@ public class PortalAdminServiceImpl implements PortalAdminService { return fieldsValidator; } + + @SuppressWarnings("unchecked") + private boolean deletePortalAdminInExternalCentralAuth(Long userId, String portalAdminRole){ + boolean result = false; + try{ + String name = ""; + List localUserList = dataAccessService.getList(EPUser.class, " where user_id = " + userId, + null, null); + if (EPCommonSystemProperties.containsProperty( + EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_USER_DOMAIN)) { + name = localUserList.get(0).getOrgUserId() + SystemProperties + .getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_USER_DOMAIN); + } + EPApp app = epAppService.getApp(PortalConstants.PORTAL_APP_ID); + String extRole = app.getNameSpace()+"."+portalAdminRole.replaceAll(" ", "_"); + HttpHeaders headers = EcompPortalUtils.base64encodeKeyForAAFBasicAuth(); + HttpEntity addUserRole = new HttpEntity<>(headers); + template.exchange( + SystemProperties.getProperty( + EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + + "userRole/"+name+"/"+extRole, + HttpMethod.DELETE, addUserRole, String.class); + result = true; + } catch (Exception e) { + if (e.getMessage().equalsIgnoreCase("404 Not Found")) { + logger.debug(EELFLoggerDelegate.debugLogger, "Portal Admin role already deleted or may not be found", e.getMessage()); + } else{ + logger.error(EELFLoggerDelegate.errorLogger, "Failed to add Portal Admin role ", e); + result = false; + } + } + return result; + } + private void logQuery(String sql) { logger.debug(EELFLoggerDelegate.debugLogger, "Executing query: " + sql); } diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/SharedContextServiceImpl.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/SharedContextServiceImpl.java index 1b1b6069..b222d189 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/SharedContextServiceImpl.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/SharedContextServiceImpl.java @@ -108,7 +108,7 @@ public class SharedContextServiceImpl implements SharedContextService { * (non-Javadoc) * * @see org.openecomp.portalsdk.core.service.SharedContextService# - * saveSharedContext(com. att.fusion.core.domain.SharedContext) + * saveSharedContext(org.openecomp.portalapp.portal.domain.SharedContext) */ @Override public void saveSharedContext(SharedContext context) { @@ -119,7 +119,7 @@ public class SharedContextServiceImpl implements SharedContextService { * (non-Javadoc) * * @see org.openecomp.portalsdk.core.service.SharedContextService# - * deleteSharedContext(com. att.fusion.core.domain.SharedContext) + * deleteSharedContext(org.openecomp.portalapp.portal.domain.SharedContext) */ @Override public void deleteSharedContext(SharedContext context) { diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/UserRolesCommonServiceImpl.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/UserRolesCommonServiceImpl.java index 58809210..1315c5e9 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/UserRolesCommonServiceImpl.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/UserRolesCommonServiceImpl.java @@ -31,16 +31,18 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; +import java.util.stream.Collectors; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; import org.apache.cxf.transport.http.HTTPException; -import org.hibernate.Query; import org.hibernate.SQLQuery; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; +import org.json.JSONArray; +import org.json.JSONObject; import org.openecomp.portalapp.externalsystemapproval.model.ExternalSystemRoleApproval; import org.openecomp.portalapp.externalsystemapproval.model.ExternalSystemUser; import org.openecomp.portalapp.portal.domain.EPApp; @@ -48,15 +50,20 @@ import org.openecomp.portalapp.portal.domain.EPRole; import org.openecomp.portalapp.portal.domain.EPUser; import org.openecomp.portalapp.portal.domain.EPUserApp; import org.openecomp.portalapp.portal.domain.EPUserAppCatalogRoles; +import org.openecomp.portalapp.portal.domain.EPUserAppRoles; import org.openecomp.portalapp.portal.domain.EPUserAppRolesRequest; import org.openecomp.portalapp.portal.domain.EPUserAppRolesRequestDetail; -import org.openecomp.portalapp.portal.domain.EpUserAppRoles; import org.openecomp.portalapp.portal.domain.ExternalSystemAccess; import org.openecomp.portalapp.portal.logging.aop.EPMetricsLog; import org.openecomp.portalapp.portal.logging.format.EPAppMessagesEnum; import org.openecomp.portalapp.portal.logging.logic.EPLogUtil; import org.openecomp.portalapp.portal.transport.AppWithRolesForUser; +import org.openecomp.portalapp.portal.transport.EPUserAppCurrentRoles; +import org.openecomp.portalapp.portal.transport.EcompUserAppRoles; +import org.openecomp.portalapp.portal.transport.ExternalAccessUser; +import org.openecomp.portalapp.portal.transport.ExternalAccessUserRoleDetail; import org.openecomp.portalapp.portal.transport.ExternalRequestFieldsValidator; +import org.openecomp.portalapp.portal.transport.ExternalRoleDescription; import org.openecomp.portalapp.portal.transport.FieldsValidator; import org.openecomp.portalapp.portal.transport.FunctionalMenuItem; import org.openecomp.portalapp.portal.transport.FunctionalMenuRole; @@ -74,6 +81,11 @@ import org.openecomp.portalsdk.core.service.DataAccessService; import org.openecomp.portalsdk.core.service.RoleService; import org.openecomp.portalsdk.core.util.SystemProperties; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; @@ -87,7 +99,7 @@ public class UserRolesCommonServiceImpl { private static final Object syncRests = new Object(); @Autowired - private DataAccessService dataAccessService; + private DataAccessService dataAccessService; @Autowired private SessionFactory sessionFactory; @Autowired @@ -99,7 +111,12 @@ public class UserRolesCommonServiceImpl { @Autowired private EPRoleService epRoleService; @Autowired - private RoleService roleService; + private RoleService roleService; + + @Autowired + private ExternalAccessRolesService externalAccessRolesService; + + RestTemplate template = new RestTemplate(); /** * @@ -255,12 +272,10 @@ public class UserRolesCommonServiceImpl { EPApp app = (EPApp) localSession.get(EPApp.class, appId); HashMap rolesMap = new HashMap(); - if (appId == PortalConstants.PORTAL_APP_ID) { // local app - String appIdValue = null; + if (appId.equals(PortalConstants.PORTAL_APP_ID)) { // local app + String appIdValue = ""; if(!extRequestValue){ - appIdValue = "and id != " + PortalConstants.PORTAL_APP_ID; - }else{ - appIdValue = ""; + appIdValue = "and id != " + PortalConstants.SYS_ADMIN_ROLE_ID; } @SuppressWarnings("unchecked") List roles = localSession @@ -274,19 +289,27 @@ public class UserRolesCommonServiceImpl { List roles = localSession .createQuery("from " + EPRole.class.getName() + " where appId=" + appId).list(); for (EPRole role : roles) { - rolesMap.put(role.getAppRoleId(), role); + if (!extRequestValue && app.getCentralAuth()) { + rolesMap.put(role.getId(), role); + } else { + rolesMap.put(role.getAppRoleId(), role); + } } } + EPRole role = null; for (EcompRole userRole : newRolesToAdd) { EPUserApp userApp = new EPUserApp(); if (("PUT".equals(reqType) || "POST".equals(reqType)) && userRole.getName().equals(PortalConstants.ADMIN_ROLE)) { role = (EPRole) localSession.get(EPRole.class, new Long(PortalConstants.ACCOUNT_ADMIN_ROLE_ID)); userApp.setRole(role); - } else if (userRole.getId().equals(PortalConstants.ACCOUNT_ADMIN_ROLE_ID) && !extRequestValue){ + } else if ((userRole.getId().equals(PortalConstants.ACCOUNT_ADMIN_ROLE_ID)) && !extRequestValue){ continue; - } else { - userApp.setRole(rolesMap.get(userRole.getId())); + }else if((userRole.getId().equals(PortalConstants.SYS_ADMIN_ROLE_ID)) && app.getId().equals(PortalConstants.PORTAL_APP_ID) && !extRequestValue){ + continue; + } + else { + userApp.setRole(rolesMap.get(userRole.getId())); } userApp.setUserId(client.getId()); @@ -305,10 +328,10 @@ public class UserRolesCommonServiceImpl { * code expects the app_id to be null as there is no * concept of App_id in SDK */ + localSession.flush(); SQLQuery sqlQuery = localSession .createSQLQuery("update fn_role set app_id = null where app_id = 1 "); sqlQuery.executeUpdate(); - } } @@ -523,32 +546,7 @@ public class UserRolesCommonServiceImpl { } } } - - // Delete from fn_role_function - String sql = "DELETE FROM fn_role_function WHERE role_id=" + roleId; - logger.debug(EELFLoggerDelegate.debugLogger, "Executing query: " + sql); - Query query = localSession.createSQLQuery(sql); - query.executeUpdate(); - - // Delete from ep_role_notification - sql = "DELETE FROM ep_role_notification WHERE role_id=" + roleId; - logger.debug(EELFLoggerDelegate.debugLogger, "Executing query: " + sql); - query = localSession.createSQLQuery(sql); - query.executeUpdate(); - - // Delete from fn_role_composite - sql = "DELETE FROM fn_role_composite WHERE parent_role_id=" + roleId + " OR child_role_id=" - + roleId; - logger.debug(EELFLoggerDelegate.debugLogger, "Executing query: " + sql); - query = localSession.createSQLQuery(sql); - query.executeUpdate(); - - // Delete from fn_user_pseudo_role - sql = "DELETE FROM fn_user_pseudo_role WHERE pseudo_role_id=" + roleId; - logger.debug(EELFLoggerDelegate.debugLogger, "Executing query: " + sql); - query = localSession.createSQLQuery(sql); - query.executeUpdate(); - + externalAccessRolesService.deleteRoleDependeciesRecord(localSession, roleId); logger.debug(EELFLoggerDelegate.debugLogger, "about to delete the role: " + role.toString()); localSession.delete(role); logger.debug(EELFLoggerDelegate.debugLogger, "deleted the role"); @@ -571,6 +569,10 @@ public class UserRolesCommonServiceImpl { } } + + + + /** * Called when updating the list of roles for the user * @@ -691,8 +693,8 @@ public class UserRolesCommonServiceImpl { } if (rolesInAppForUser != null) { - EcompRole[] userAppRoles = new EcompRole[rolesInAppForUser.roles.size()]; - for (int i = 0; i < rolesInAppForUser.roles.size(); i++) { + EcompRole[] userAppRoles = new EcompRole[rolesInAppForUser.roles.stream().distinct().collect(Collectors.toList()).size()]; + for (int i = 0; i < rolesInAppForUser.roles.stream().distinct().collect(Collectors.toList()).size(); i++) { RoleInAppForUser roleInAppForUser = rolesInAppForUser.roles.get(i); EcompRole role = new EcompRole(); role.setId(roleInAppForUser.roleId); @@ -759,6 +761,67 @@ public class UserRolesCommonServiceImpl { return rolesList; } + /** + * It adds new user for remote application + * + * @param roleInAppForUserList + * @param remoteAppUser + * @param userId + * @param app + * @param mapper + * @param searchService + * @param applicationsRestClientService + * @throws Exception + */ + private void addRemoteUser(List roleInAppForUserList, String userId, EPApp app, ObjectMapper mapper, SearchService searchService, ApplicationsRestClientService applicationsRestClientService) throws Exception{ + EPUser addRemoteUser = null; + if (remoteUserShouldBeCreated(roleInAppForUserList)) { + + createNewUserOnRemoteApp(userId, app, applicationsRestClientService, searchService, mapper, isAppUpgradeVersion(app)); + // If we succeed, we know that the new user was + // persisted on remote app. + addRemoteUser = getUserFromApp(userId, app, applicationsRestClientService); + if (addRemoteUser == null) { + logger.error(EELFLoggerDelegate.errorLogger, + "Failed to persist new user: " + userId + " in remote app. appId = " + app.getId()); + // return null; + } + } + } + + /** + * It checks whether the remote user exists or not + * if exits returns user object else null + * + * @param userId + * @param app + * @param applicationsRestClientService + * @return + * @throws HTTPException + */ + private EPUser checkIfRemoteUserExits(String userId, EPApp app, ApplicationsRestClientService applicationsRestClientService) throws HTTPException{ + EPUser checkRemoteUser = null; + try { + checkRemoteUser = getUserFromApp(userId, app, applicationsRestClientService); + } catch (HTTPException e) { + // Some apps are returning 400 if user is not found. + if (e.getResponseCode() == 400) { + logger.debug(EELFLoggerDelegate.debugLogger, + "setAppWithUserRoleStateForUser: getuserFromApp threw exception with response code 400; continuing", + e); + } else if(e.getResponseCode() == 404) { + logger.debug(EELFLoggerDelegate.debugLogger, + "setAppWithUserRoleStateForUser: getuserFromApp threw exception with response code 404; continuing", + e); + } else { + // Other response code, let it come thru. + throw e; + } + } + return checkRemoteUser; + } + + /* * (non-Javadoc) * @@ -783,58 +846,59 @@ public class UserRolesCommonServiceImpl { EPApp app = appsService.getApp(appId); applyChangesToUserAppRolesForMyLoginsRequest(user, appId); - // if local app - if (appId == PortalConstants.PORTAL_APP_ID) { - // EPUser localUser = getUserFromApp(userId, app, applicationsRestClientService); + // if centralized app + if (app.getCentralAuth()) { + // We should add If user does not exist in remote application + if (!app.getId().equals(PortalConstants.PORTAL_APP_ID)) { + EPUser remoteAppUser = null; + remoteAppUser = checkIfRemoteUserExits(userId, app, applicationsRestClientService); + + if (remoteAppUser == null) { + addRemoteUser(roleInAppForUserList, userId, app, mapper, searchService, + applicationsRestClientService); + } + } + Set userRolesInLocalApp = postUsersRolesToLocalApp(roleInAppForUserList, mapper, applicationsRestClientService, appId, userId); RolesInAppForUser rolesInAppForUser = constructRolesInAppForUserUpdate(userId, appId, userRolesInLocalApp); - result = applyChangesInUserRolesForAppToEcompDB(rolesInAppForUser, epRequestValue, null); - - } else {// remote app + List roleAppUserList = rolesInAppForUser.roles; + // Apply changes in external Access system + updateUserRolesInExternalSystem(app, rolesInAppForUser.orgUserId, roleAppUserList); + result = applyChangesInUserRolesForAppToEcompDB(rolesInAppForUser, epRequestValue, "Portal"); + } + // In case if portal is not centralized then follow existing approach + else if(!app.getCentralAuth() && app.getId().equals(PortalConstants.PORTAL_APP_ID)){ + Set userRolesInLocalApp = postUsersRolesToLocalApp(roleInAppForUserList, mapper, + applicationsRestClientService, appId, userId); + RolesInAppForUser rolesInAppForUser = constructRolesInAppForUserUpdate(userId, appId, + userRolesInLocalApp); + result = applyChangesInUserRolesForAppToEcompDB(rolesInAppForUser, epRequestValue, "Portal"); + } else{// remote app EPUser remoteAppUser = null; - try { - remoteAppUser = getUserFromApp(userId, app, applicationsRestClientService); - } catch (HTTPException e) { - // Some apps are returning 400 if user is not found. - if (e.getResponseCode() == 400) { - logger.debug(EELFLoggerDelegate.debugLogger, - "setAppWithUserRoleStateForUser: getuserFromApp threw exception with response code 400; continuing", - e); - } else { - // Other response code, let it come thru. - throw e; - } - } - if (remoteAppUser == null) { - if (remoteUserShouldBeCreated(roleInAppForUserList)) { - - createNewUserOnRemoteApp(userId, app, applicationsRestClientService, searchService, mapper, isAppUpgradeVersion(app)); - // If we succeed, we know that the new user was - // persisted on remote app. - remoteAppUser = getUserFromApp(userId, app, applicationsRestClientService); - if (remoteAppUser == null) { - logger.error(EELFLoggerDelegate.errorLogger, - "Failed to persist new user: " + userId + " in remote app. appId = " + appId); - // return null; - } + if(!app.getCentralAuth() && !app.getId().equals(PortalConstants.PORTAL_APP_ID)){ + + remoteAppUser = checkIfRemoteUserExits(userId, app, applicationsRestClientService); + + if (remoteAppUser == null) { + addRemoteUser(roleInAppForUserList, userId, app, mapper, searchService, applicationsRestClientService); } - } - if (remoteAppUser != null) { - Set userRolesInRemoteApp = postUsersRolesToRemoteApp(roleInAppForUserList, mapper, - applicationsRestClientService, appId, userId); - RolesInAppForUser rolesInAppForUser = constructRolesInAppForUserUpdate(userId, appId, - userRolesInRemoteApp); - result = applyChangesInUserRolesForAppToEcompDB(rolesInAppForUser, epRequestValue, null); + if (remoteAppUser != null) { + Set userRolesInRemoteApp = postUsersRolesToRemoteApp(roleInAppForUserList, mapper, + applicationsRestClientService, appId, userId); + RolesInAppForUser rolesInAppForUser = constructRolesInAppForUserUpdate(userId, appId, + userRolesInRemoteApp); + result = applyChangesInUserRolesForAppToEcompDB(rolesInAppForUser, epRequestValue, null); - // If no roles remain, request app to set user inactive. - if (userRolesInRemoteApp.size() == 0) { - logger.debug(EELFLoggerDelegate.debugLogger, - "setAppWithUserRoleStateForUser: no roles in app {}, set user {} to inactive", app, - userId); - remoteAppUser.setActive(false); - postUserToRemoteApp(userId, user, app, applicationsRestClientService); + // If no roles remain, request app to set user inactive. + if (userRolesInRemoteApp.size() == 0) { + logger.debug(EELFLoggerDelegate.debugLogger, + "setAppWithUserRoleStateForUser: no roles in app {}, set user {} to inactive", app, + userId); + remoteAppUser.setActive(false); + postUserToRemoteApp(userId, user, app, applicationsRestClientService); + } } } } @@ -849,7 +913,147 @@ public class UserRolesCommonServiceImpl { } return result; } - + + @SuppressWarnings("unchecked") + private void updateUserRolesInExternalSystem(EPApp app, String orgUserId, List roleInAppUser) + { + try{ + //check if user exists + final Map userParams = new HashMap<>(); + userParams.put("orgUserIdValue", orgUserId); + List userInfo = checkIfUserExists(userParams); + if (userInfo.size() == 0 || userInfo.isEmpty()) { + createLocalUserIfNecessary(orgUserId); + } + final Map loginIdParams = new HashMap<>(); + loginIdParams.put("orgUserIdValue", orgUserId); + EPUser user = (EPUser) dataAccessService.executeNamedQuery("epUserAppId", loginIdParams, null).get(0); + String name = ""; + if (EPCommonSystemProperties.containsProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_USER_DOMAIN)) { + name = orgUserId + + SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_USER_DOMAIN); + } + ObjectMapper mapper = new ObjectMapper(); + HttpHeaders headers = EcompPortalUtils.base64encodeKeyForAAFBasicAuth() ; + HttpEntity getUserRolesEntity = new HttpEntity<>(headers); + logger.debug(EELFLoggerDelegate.debugLogger, "Connecting to external system to get current user roles"); + ResponseEntity getResponse = template + .exchange(SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + + "roles/user/" + name, HttpMethod.GET, getUserRolesEntity, String.class); + if(getResponse.getStatusCode().value() == 200){ + logger.debug(EELFLoggerDelegate.debugLogger, "Connected to external system and received user roles: ", getResponse.getBody()); + + } + List userRoleDetailList = new ArrayList<>(); + String res = getResponse.getBody(); + JSONObject jsonObj = null; + JSONArray extRoles = null; + if (!res.equals("{}")) { + jsonObj = new JSONObject(res); + extRoles = jsonObj.getJSONArray("role"); + } + ExternalAccessUserRoleDetail userRoleDetail = null; + if (extRoles != null) { + for (int i = 0; i < extRoles.length(); i++) { + if (extRoles.getJSONObject(i).getString("name").startsWith(app.getNameSpace() + ".") && !extRoles.getJSONObject(i).getString("name").equals(app.getNameSpace()+".admin") + && !extRoles.getJSONObject(i).getString("name").equals(app.getNameSpace()+".owner")) { + ObjectMapper descMapper = new ObjectMapper(); + if(extRoles.getJSONObject(i).has("description")){ + ExternalRoleDescription desc = descMapper.readValue( + extRoles.getJSONObject(i).getString("description"), ExternalRoleDescription.class); + userRoleDetail = new ExternalAccessUserRoleDetail(extRoles.getJSONObject(i).getString("name"), + desc); + userRoleDetailList.add(userRoleDetail); + }else{ + userRoleDetail = new ExternalAccessUserRoleDetail(extRoles.getJSONObject(i).getString("name"), + null); + userRoleDetailList.add(userRoleDetail); + } + + } + } + } + for (ExternalAccessUserRoleDetail userRole : userRoleDetailList) { + HttpEntity entity = new HttpEntity<>(headers); + template.exchange(SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + + "userRole/" + name + "/" + userRole.getName(), HttpMethod.DELETE, entity, String.class); + } + final Map roleInAppUserMap = new HashMap<>(); + for(RoleInAppForUser roleInAppUserNew: roleInAppUser){ + roleInAppUserMap.put(roleInAppUserNew.getRoleName(), roleInAppUserNew); + } + final Map params = new HashMap<>(); + params.put("appId", app.getId()); + params.put("userId", user.getId()); + List userAppList = dataAccessService.executeNamedQuery("getUserAppExistingRoles", params, null); + // Check if incoming request has sys admin or account admin, if exists add in external system + if (!roleInAppUser.isEmpty()) { + for (EcompUserAppRoles userApp : userAppList) { + if ((userApp.getRoleId().equals(PortalConstants.SYS_ADMIN_ROLE_ID) + || userApp.getRoleId().equals(PortalConstants.ACCOUNT_ADMIN_ROLE_ID)) && !roleInAppUserMap.containsKey(userApp.getRoleName())) { + RoleInAppForUser addSpecialRole = new RoleInAppForUser(); + addSpecialRole.setIsApplied(true); + addSpecialRole.setRoleId(userApp.getRoleId()); + addSpecialRole.setRoleName(userApp.getRoleName()); + roleInAppUser.add(addSpecialRole); + } + } + } + List roleInAppUserNonDupls = roleInAppUser.stream().distinct().collect(Collectors.toList()); + for (RoleInAppForUser addRole : roleInAppUserNonDupls) { + ExternalAccessUser extUser = null; + if ((addRole.getRoleId().equals(PortalConstants.ACCOUNT_ADMIN_ROLE_ID)) + && !app.getId().equals(PortalConstants.PORTAL_APP_ID)) { + try{ + String extRole = app.getNameSpace()+"."+PortalConstants.ADMIN_ROLE.replaceAll(" ","_"); + HttpEntity entity = new HttpEntity<>(headers); + logger.debug(EELFLoggerDelegate.debugLogger, "Connecting to External Access system"); + ResponseEntity getRoleResponse = template.exchange( + SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + "roles/"+extRole, + HttpMethod.GET, entity, String.class); + String extAdminRole = app.getNameSpace()+"."+PortalConstants.ADMIN_ROLE.replaceAll(" ", "_"); + if(getRoleResponse.getBody().equals("{}")){ + String addDesc = "{\"name\":\"" +extAdminRole+ "\"}"; + HttpEntity roleEntity = new HttpEntity<>(addDesc,headers); + template.exchange( + SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + "role", + HttpMethod.POST, roleEntity, String.class); + } + extUser = new ExternalAccessUser(name, + app.getNameSpace() + "." + PortalConstants.ADMIN_ROLE.replaceAll(" ", "_")); + } catch(Exception e){ + logger.error(EELFLoggerDelegate.errorLogger, "Failed to add admin role for application {} ",app.getId(),e); + continue; + } + } else { + extUser = new ExternalAccessUser(name, + app.getNameSpace() + "." + addRole.getRoleName().replaceAll(" ", "_")); + } + // Assign user role for an application in external access system + String userRole = mapper.writeValueAsString(extUser); + HttpEntity entity = new HttpEntity<>(userRole, headers); + if (addRole.getIsApplied()) { + logger.debug(EELFLoggerDelegate.debugLogger, "Connecting to external system and adding user role", + addRole.getRoleName()); + ResponseEntity addResponse = template.exchange( + SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_ACCESS_URL) + "userRole", + HttpMethod.POST, entity, String.class); + logger.debug(EELFLoggerDelegate.debugLogger, "Connected to external system and added user role", + getResponse.getBody(), addRole.getRoleName()); + if (addResponse.getStatusCode().value() != 201) { + logger.debug(EELFLoggerDelegate.debugLogger, + "Connected to external system unable to save user role", getResponse.getBody(), + addRole.getRoleName()); + throw new Exception("Failed to add user role for application"); + } + } + } + }catch(Exception e){ + logger.error(EELFLoggerDelegate.errorLogger, "Failed to add user role for application {}", app.getId(),e); + } + + } + /** * * @param userId @@ -1066,60 +1270,86 @@ public class UserRolesCommonServiceImpl { .executeNamedQuery("userAppRolesRequestList", params, null); epRequestIdSize = epRequestId.size(); } - if(!app.getId().equals(PortalConstants.PORTAL_APP_ID)){ + if(!app.getId().equals(PortalConstants.PORTAL_APP_ID) && !app.getCentralAuth()){ EcompRole[] appRoles = applicationsRestClientService.get(EcompRole[].class, app.getId(), "/roles"); syncAppRoles(sessionFactory, app.getId(), appRoles); } List roleInAppForUserList = roleInAppForUserList(newAppRolesForUser.getRoles(), app.getId(), app.getMlAppName()); - // if local app - if (app.getId() == PortalConstants.PORTAL_APP_ID) { - // EPUser localUser = getUserFromApp(orgUserId, app, applicationsRestClientService); + List userRoleList = null; + if(userId != null){ + final Map appParams = new HashMap<>(); + appParams.put("userId", userId.getId()); + appParams.put("appId", app.getId()); + userRoleList = dataAccessService.executeNamedQuery("getUserAppExistingRoles", appParams, null); + } + boolean checkIfAdminRoleExists = false; + if (reqType.equals("DELETE")) { + checkIfAdminRoleExists = userRoleList.stream() + .anyMatch(userRole -> userRole.getRoleId().equals(PortalConstants.ACCOUNT_ADMIN_ROLE_ID)); + } else { + checkIfAdminRoleExists = roleInAppForUserList.stream() + .anyMatch(roleList -> roleList.getRoleId().equals(PortalConstants.ACCOUNT_ADMIN_ROLE_ID)); + } + // if Centralized app + if (app.getCentralAuth()) { + // We should add If user does not exist in remote application + try { + if (!(!app.getId().equals(PortalConstants.PORTAL_APP_ID) && checkIfAdminRoleExists + && (roleInAppForUserList.size() == 1 || reqType.equals("DELETE")))) { + EPUser remoteAppUser = null; + remoteAppUser = checkIfRemoteUserExits(userId.getOrgUserId(), app, + applicationsRestClientService); + if (remoteAppUser == null) { + addRemoteUser(roleInAppForUserList, userId.getOrgUserId(), app, mapper, searchService, + applicationsRestClientService); + reqMessage = "Saved Successfully"; + } + } + } catch (Exception e) { + reqMessage = e.getMessage(); + logger.error(EELFLoggerDelegate.errorLogger, "Failed to added remote user", e); + throw new Exception(reqMessage); + } Set userRolesInLocalApp = postUsersRolesToLocalApp(roleInAppForUserList, mapper, applicationsRestClientService, app.getId(), orgUserId); RolesInAppForUser rolesInAppForUser = constructRolesInAppForUserUpdate(orgUserId, app.getId(), userRolesInLocalApp); - logger.info(EELFLoggerDelegate.debugLogger, "{} user app roles: for app {}, user {}", - logMessage, newAppRolesForUser.getApplicationName(), newAppRolesForUser.getLoginId()); + List roleAppUserList = rolesInAppForUser.roles; + // Apply changes in external Access system + updateUserRolesInExternalSystem(app, rolesInAppForUser.orgUserId, roleAppUserList); + logger.info(EELFLoggerDelegate.debugLogger, "{} user app roles: for app {}, user {}", logMessage, + newAppRolesForUser.getApplicationName(), newAppRolesForUser.getLoginId()); + result = applyChangesInUserRolesForAppToEcompDB(rolesInAppForUser, externalSystemRequest, reqType); + } + // If local application is not centralized + else if(!app.getCentralAuth() && app.getId().equals(PortalConstants.PORTAL_APP_ID)){ + Set userRolesInLocalApp = postUsersRolesToLocalApp(roleInAppForUserList, mapper, + applicationsRestClientService, app.getId(), orgUserId); + RolesInAppForUser rolesInAppForUser = constructRolesInAppForUserUpdate(orgUserId, app.getId(), + userRolesInLocalApp); result = applyChangesInUserRolesForAppToEcompDB(rolesInAppForUser, externalSystemRequest, reqType); } else {// remote app + + if(!((roleInAppForUserList.size() == 1 || reqType.equals("DELETE")) && checkIfAdminRoleExists)){ EPUser remoteAppUser = null; - try { - remoteAppUser = getUserFromApp(orgUserId, app, applicationsRestClientService); - } catch (HTTPException e) { - // Some apps are returning 400 if user is not found. - if (e.getResponseCode() == 400) { - logger.debug(EELFLoggerDelegate.debugLogger, - "setAppWithUserRoleStateForUser: getuserFromApp threw exception with response code 400; continuing", - e); - } else { - // Other response code, let it come thru. - throw e; - } - } + remoteAppUser = checkIfRemoteUserExits(userId.getOrgUserId(), app, applicationsRestClientService); if (remoteAppUser == null) { - createNewUserOnRemoteApp(orgUserId, app, applicationsRestClientService, searchService, mapper, - isAppUpgradeVersion(app)); - // If we succeed, we know that the new user was - // persisted on remote app. - remoteAppUser = getUserFromApp(orgUserId, app, applicationsRestClientService); - if (remoteAppUser == null) { - logger.error(EELFLoggerDelegate.errorLogger, "Failed to persist new user: " + orgUserId - + " in remote app. appId = " + app.getId()); - // return null; - } + addRemoteUser(roleInAppForUserList, userId.getOrgUserId(), app, mapper, searchService, applicationsRestClientService); reqMessage = "Saved Successfully"; } - if (remoteAppUser != null) { + if (remoteAppUser != null) { Set userRolesInRemoteApp = postUsersRolesToRemoteApp(roleInAppForUserList, - mapper, applicationsRestClientService, app.getId(), orgUserId); - + mapper, applicationsRestClientService, app.getId(), orgUserId); + RolesInAppForUser rolesInAppForUser = constructRolesInAppForUserUpdate(orgUserId, app.getId(), userRolesInRemoteApp); - logger.info(EELFLoggerDelegate.debugLogger, "{} user app roles: for app {}, user {}", - logMessage, newAppRolesForUser.getApplicationName(), newAppRolesForUser.getLoginId()); - result = applyChangesInUserRolesForAppToEcompDB(rolesInAppForUser, externalSystemRequest, reqType); + logger.info(EELFLoggerDelegate.debugLogger, "{} user app roles: for app {}, user {}", + logMessage, newAppRolesForUser.getApplicationName(), + newAppRolesForUser.getLoginId()); + result = applyChangesInUserRolesForAppToEcompDB(rolesInAppForUser, externalSystemRequest, + reqType); // If no roles remain, request app to set user inactive. /*if (userRolesInRemoteApp.size() == 0) { logger.debug(EELFLoggerDelegate.debugLogger, @@ -1129,7 +1359,19 @@ public class UserRolesCommonServiceImpl { remoteAppUser.setActive(false); postUserToRemoteApp(orgUserId, user, app, applicationsRestClientService); }*/ + } + } else { + if(!(reqType.equals("DELETE") && userId == null)){ + reqMessage = "Saved Successfully"; + } + Set userRolesInRemoteApp = constructUsersEcompRoles(roleInAppForUserList); + RolesInAppForUser rolesInAppForUser = constructRolesInAppForUserUpdate(orgUserId, app.getId(), + userRolesInRemoteApp); + logger.info(EELFLoggerDelegate.debugLogger, "{} user app roles: for app {}, user {}", + logMessage, newAppRolesForUser.getApplicationName(), newAppRolesForUser.getLoginId()); + result = applyChangesInUserRolesForAppToEcompDB(rolesInAppForUser, externalSystemRequest, + reqType); } if(!result){ reqMessage = "Failed to save the user app role(s)"; @@ -1138,7 +1380,6 @@ public class UserRolesCommonServiceImpl { updateStatus = "C"; applyChangesToAppRolesRequest(app.getId(), userId.getId(), updateStatus, epRequestId.get(0)); } - } } catch (Exception e) { String message = String.format("Failed to create user or update user roles for User %s, AppId %s", @@ -1268,23 +1509,16 @@ public class UserRolesCommonServiceImpl { * @see org.openecomp.portalapp.portal.service.UserRolesService# * getAppRolesForUser(java.lang.Long, java.lang.String) */ + @SuppressWarnings("unchecked") public List getAppRolesForUser(Long appId, String userId, Boolean extRequestValue) { List rolesInAppForUser = null; - List userInfo = null; + EPApp app = appsService.getApp(appId); try { - // for ecomp portal app, no need to make a remote call if (appId == PortalConstants.PORTAL_APP_ID) { - final Map userParams = new HashMap<>(); - userParams.put("orgUserIdValue", userId); - userInfo = checkIfUserExists(userParams); - if(userInfo.size() == 0 || userInfo.isEmpty()) - { - createLocalUserIfNecessary(userId); - } - List roleList = roleService.getAvailableRoles(); + List roleList = roleService.getAvailableRoles(userId); List activeRoleList = new ArrayList(); for(Role role: roleList) { if(role.getActive()) { @@ -1296,28 +1530,66 @@ public class UserRolesCommonServiceImpl { } } - - EPApp app = appsService.getApp(appId); - EPUser localUser = getUserFromApp(userId, app, applicationsRestClientService); - Set roleSet = localUser.getAppEPRoles(app); - rolesInAppForUser = constructRolesInAppForUserGet(activeRoleList, roleSet.toArray(new EPRole[0]), extRequestValue); + EPUser localUser = getUserFromApp(userId, app, applicationsRestClientService); + // If localUser does not exists return roles + Set roleSet = null; + EPRole[] roleSetList = null; + if(localUser != null){ + roleSet = localUser.getAppEPRoles(app); + roleSetList = roleSet.toArray(new EPRole[0]); + } + rolesInAppForUser = constructRolesInAppForUserGet(activeRoleList, roleSetList, extRequestValue); return rolesInAppForUser; } - - EcompRole[] appRoles = applicationsRestClientService.get(EcompRole[].class, appId, "/roles"); - + + EcompRole[] appRoles = null; + List roles = new ArrayList<>(); + if(app.getCentralAuth()){ + List applicationRoles = dataAccessService.getList(EPRole.class, " where app_id = "+app.getId()+ " and active_yn = 'Y'", null, null);; + for(EPRole role : applicationRoles){ + EcompRole ecompRole = new EcompRole(); + ecompRole.setId(role.getId()); + ecompRole.setName(role.getName()); + roles.add(ecompRole); + } + appRoles = roles.toArray(new EcompRole[roles.size()]); + } else{ + appRoles = applicationsRestClientService.get(EcompRole[].class, appId, "/roles"); + } // Test this error case, for generating an internal Ecomp Portal // error // EcompRole[] appRoles = null; // If there is an exception in the rest client api, then null will // be returned. if (appRoles != null) { + if(!app.getCentralAuth()) { syncAppRoles(sessionFactory, appId, appRoles); + } EcompRole[] userAppRoles = null; try { try { - userAppRoles = applicationsRestClientService.get(EcompRole[].class, appId, - String.format("/user/%s/roles", userId)); + if(app.getCentralAuth()){ + final Map params = new HashMap<>(); + final Map userParams = new HashMap<>(); + params.put("orgUserIdValue", userId); + List user = dataAccessService.executeNamedQuery("epUserAppId", params, null); + userParams.put("appId", app.getId()); + userParams.put("userId", user.get(0).getId()); + List userAppsRolesList = dataAccessService.executeNamedQuery("getUserAppCurrentRoles", userParams, null); + List setUserRoles = new ArrayList<>(); + for(EPUserAppCurrentRoles role : userAppsRolesList){ + EcompRole ecompRole = new EcompRole(); + ecompRole.setId(role.getRoleId()); + ecompRole.setName(role.getRoleName()); + setUserRoles.add(ecompRole); + } + userAppRoles = setUserRoles.toArray(new EcompRole[setUserRoles.size()]); + rolesInAppForUser = constructRolesInAppForUserGet(appRoles, userAppRoles); + return rolesInAppForUser; + }else{ + userAppRoles = applicationsRestClientService.get(EcompRole[].class, appId, + String.format("/user/%s/roles", userId)); + } } catch (HTTPException e) { // Some apps are returning 400 if user is not found. if (e.getResponseCode() == 400) { @@ -1390,7 +1662,7 @@ public class UserRolesCommonServiceImpl { public FieldsValidator putUserAppRolesRequest(AppWithRolesForUser userAppRolesData, EPUser user) { FieldsValidator fieldsValidator = new FieldsValidator(); final Map params = new HashMap<>(); - EpUserAppRoles appRole= new EpUserAppRoles(); + EPUserAppRoles appRole= new EPUserAppRoles(); try { logger.error(EELFLoggerDelegate.errorLogger,"Should not be reached here, still the endpoint is yet to be defined"); boolean result = postUserRolesToMylogins(userAppRolesData, applicationsRestClientService, userAppRolesData.appId, user.getId()); @@ -1409,7 +1681,7 @@ public class UserRolesCommonServiceImpl { Boolean isAppliedVal = userAppRoles.isApplied; params.put("appRoleId", userAppRoles.roleId); if (isAppliedVal) { - appRole = (EpUserAppRoles) dataAccessService.executeNamedQuery("appRoles", params, null).get(0); + appRole = (EPUserAppRoles) dataAccessService.executeNamedQuery("appRoles", params, null).get(0); EPUserAppRolesRequestDetail epAppRoleDetail = new EPUserAppRolesRequestDetail(); epAppRoleDetail.setReqRoleId(appRole.getRoleId()); epAppRoleDetail.setReqType("P"); diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/WidgetParameterServiceImpl.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/WidgetParameterServiceImpl.java index d7685627..1fead505 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/WidgetParameterServiceImpl.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/service/WidgetParameterServiceImpl.java @@ -49,8 +49,8 @@ public class WidgetParameterServiceImpl implements WidgetParameterService{ List restrictionsList = new ArrayList(); Criterion widgetIdCrit = Restrictions.eq("widgetId", widgetId); restrictionsList.add(widgetIdCrit); - Criterion attIdCrit = Restrictions.eq("userId", userId); - restrictionsList.add(attIdCrit); + Criterion userIdCrit = Restrictions.eq("userId", userId); + restrictionsList.add(userIdCrit); Criterion paramIdCrit = Restrictions.eq("paramId", paramId); restrictionsList.add(paramIdCrit); diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/BulkUploadRoleFunction.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/BulkUploadRoleFunction.java new file mode 100644 index 00000000..d25cec5d --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/BulkUploadRoleFunction.java @@ -0,0 +1,68 @@ +package org.openecomp.portalapp.portal.transport; + +import java.io.Serializable; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; + +import com.fasterxml.jackson.annotation.JsonInclude; + +@Entity +@JsonInclude(JsonInclude.Include.NON_NULL) +public class BulkUploadRoleFunction implements Serializable{ + + + private static final long serialVersionUID = -1880947347092068841L; + + @Id + @Column(name="function_name") + private String functionName; + @Id + @Column(name="function_cd") + private String functionCd; + + public String getFunctionName() { + return functionName; + } + public void setFunctionName(String functionName) { + this.functionName = functionName; + } + public String getFunctionCd() { + return functionCd; + } + public void setFunctionCd(String functionCd) { + this.functionCd = functionCd; + } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((functionCd == null) ? 0 : functionCd.hashCode()); + result = prime * result + ((functionName == null) ? 0 : functionName.hashCode()); + return result; + } + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + BulkUploadRoleFunction other = (BulkUploadRoleFunction) obj; + if (functionCd == null) { + if (other.functionCd != null) + return false; + } else if (!functionCd.equals(other.functionCd)) + return false; + if (functionName == null) { + if (other.functionName != null) + return false; + } else if (!functionName.equals(other.functionName)) + return false; + return true; + } + + +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/BulkUploadUserRoles.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/BulkUploadUserRoles.java new file mode 100644 index 00000000..8187ce4e --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/BulkUploadUserRoles.java @@ -0,0 +1,83 @@ +package org.openecomp.portalapp.portal.transport; + +import java.io.Serializable; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; + +import com.fasterxml.jackson.annotation.JsonInclude; + +@Entity +@JsonInclude(JsonInclude.Include.NON_NULL) +public class BulkUploadUserRoles implements Serializable{ + + private static final long serialVersionUID = -7478654947593502185L; + + @Id + @Column(name="role_name") + private String roleName; + @Id + @Column(name="org_user_id") + private String orgUserId; + @Id + @Column(name="auth_namespace") + private String appNameSpace; + + public String getRoleName() { + return roleName; + } + public void setRoleName(String roleName) { + this.roleName = roleName; + } + public String getOrgUserId() { + return orgUserId; + } + public void setOrgUserId(String orgUserId) { + this.orgUserId = orgUserId; + } + public String getAppNameSpace() { + return appNameSpace; + } + public void setAppNameSpace(String appNameSpace) { + this.appNameSpace = appNameSpace; + } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((appNameSpace == null) ? 0 : appNameSpace.hashCode()); + result = prime * result + ((orgUserId == null) ? 0 : orgUserId.hashCode()); + result = prime * result + ((roleName == null) ? 0 : roleName.hashCode()); + return result; + } + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + BulkUploadUserRoles other = (BulkUploadUserRoles) obj; + if (appNameSpace == null) { + if (other.appNameSpace != null) + return false; + } else if (!appNameSpace.equals(other.appNameSpace)) + return false; + if (orgUserId == null) { + if (other.orgUserId != null) + return false; + } else if (!orgUserId.equals(other.orgUserId)) + return false; + if (roleName == null) { + if (other.roleName != null) + return false; + } else if (!roleName.equals(other.roleName)) + return false; + return true; + } + + + +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/CentralApp.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/CentralApp.java new file mode 100644 index 00000000..97907422 --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/CentralApp.java @@ -0,0 +1,210 @@ +package org.openecomp.portalapp.portal.transport; + +import java.util.Date; + +public class CentralApp { + public Long id; + public Date created; + public Date modified; + public Long createdId; + public Long modifiedId; + public Long rowNum; + public String name; // app_name + public String imageUrl; // app_image_url + public String description; // app_description + public String notes; // app_notes + public String url; // app_url + public String alternateUrl; // app_alternate_url + public String restEndpoint; // app_rest_endpoint + public String mlAppName; // ml_app_name + public String mlAppAdminId; // ml_app_admin_id; + public String motsId; // mots_id + public String appPassword; // app_password + public String open; + public String enabled; + public byte[] thumbnail; + public String username; // app_username + public String uebKey; // ueb_key + public String uebSecret; // ueb_secret + public String uebTopicName; // ueb_topic_name + + + public CentralApp(Long id, Date created, Date modified, Long createdId, Long modifiedId, Long rowNum, String name, + String imageUrl, String description, String notes, String url, String alternateUrl, String restEndpoint, + String mlAppName, String mlAppAdminId, String motsId, String appPassword, String open, String enabled, + byte[] thumbnail, String username, String uebKey, String uebSecret, String uebTopicName) { + super(); + this.id = id; + this.created = created; + this.modified = modified; + this.createdId = createdId; + this.modifiedId = modifiedId; + this.rowNum = rowNum; + this.name = name; + this.imageUrl = imageUrl; + this.description = description; + this.notes = notes; + this.url = url; + this.alternateUrl = alternateUrl; + this.restEndpoint = restEndpoint; + this.mlAppName = mlAppName; + this.mlAppAdminId = mlAppAdminId; + this.motsId = motsId; + this.appPassword = appPassword; + this.open = open; + this.enabled = enabled; + this.thumbnail = thumbnail; + this.username = username; + this.uebKey = uebKey; + this.uebSecret = uebSecret; + this.uebTopicName = uebTopicName; + } + + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + + public Date getCreated() { + return created; + } + public void setCreated(Date created) { + this.created = created; + } + public Date getModified() { + return modified; + } + public void setModified(Date modified) { + this.modified = modified; + } + public Long getCreatedId() { + return createdId; + } + public void setCreatedId(Long createdId) { + this.createdId = createdId; + } + public Long getModifiedId() { + return modifiedId; + } + public void setModifiedId(Long modifiedId) { + this.modifiedId = modifiedId; + } + public Long getRowNum() { + return rowNum; + } + public void setRowNum(Long rowNum) { + this.rowNum = rowNum; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public String getImageUrl() { + return imageUrl; + } + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + public String getNotes() { + return notes; + } + public void setNotes(String notes) { + this.notes = notes; + } + public String getUrl() { + return url; + } + public void setUrl(String url) { + this.url = url; + } + public String getAlternateUrl() { + return alternateUrl; + } + public void setAlternateUrl(String alternateUrl) { + this.alternateUrl = alternateUrl; + } + public String getRestEndpoint() { + return restEndpoint; + } + public void setRestEndpoint(String restEndpoint) { + this.restEndpoint = restEndpoint; + } + public String getMlAppName() { + return mlAppName; + } + public void setMlAppName(String mlAppName) { + this.mlAppName = mlAppName; + } + public String getMlAppAdminId() { + return mlAppAdminId; + } + public void setMlAppAdminId(String mlAppAdminId) { + this.mlAppAdminId = mlAppAdminId; + } + public String getMotsId() { + return motsId; + } + public void setMotsId(String motsId) { + this.motsId = motsId; + } + public String getAppPassword() { + return appPassword; + } + public void setAppPassword(String appPassword) { + this.appPassword = appPassword; + } + public String getOpen() { + return open; + } + public void setOpen(String open) { + this.open = open; + } + public String getEnabled() { + return enabled; + } + public void setEnabled(String enabled) { + this.enabled = enabled; + } + public byte[] getThumbnail() { + return thumbnail; + } + public void setThumbnail(byte[] thumbnail) { + this.thumbnail = thumbnail; + } + public String getUsername() { + return username; + } + public void setUsername(String username) { + this.username = username; + } + public String getUebKey() { + return uebKey; + } + public void setUebKey(String uebKey) { + this.uebKey = uebKey; + } + public String getUebSecret() { + return uebSecret; + } + public void setUebSecret(String uebSecret) { + this.uebSecret = uebSecret; + } + public String getUebTopicName() { + return uebTopicName; + } + public void setUebTopicName(String uebTopicName) { + this.uebTopicName = uebTopicName; + } + + +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/CentralRole.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/CentralRole.java new file mode 100644 index 00000000..a3c3c9d5 --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/CentralRole.java @@ -0,0 +1,159 @@ +package org.openecomp.portalapp.portal.transport; + +import java.util.Date; +import java.util.SortedSet; + +import org.openecomp.portalapp.portal.domain.CentralRoleFunction; +import org.openecomp.portalapp.portal.domain.EPRole; + +public class CentralRole implements Comparable{ + public Long id; + public Date created; + public Date modified; + public Long createdId; + public Long modifiedId; + public Long rowNum; + + public String name; + public boolean active; + public Integer priority; + + public SortedSet roleFunctions = null; + + public SortedSet childRoles = null; + + public SortedSet parentRoles = null; + + public CentralRole(Long id, Date created, Date modified, Long createdId, Long modifiedId, Long rowNum, + String name, boolean active, Integer priority, SortedSet roleFunctions, + SortedSet childRoles, SortedSet parentRoles) { + super(); + this.id = id; + this.created = created; + this.modified = modified; + this.createdId = createdId; + this.modifiedId = modifiedId; + this.rowNum = rowNum; + this.name = name; + this.active = active; + this.priority = priority; + this.roleFunctions = roleFunctions; + this.childRoles = childRoles; + this.parentRoles = parentRoles; + } + + public CentralRole(){ + + } + + public CentralRole(Long id, String name){ + this.id = id; + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Date getCreated() { + return created; + } + + public void setCreated(Date created) { + this.created = created; + } + + public Date getModified() { + return modified; + } + + public void setModified(Date modified) { + this.modified = modified; + } + + public Long getCreatedId() { + return createdId; + } + + public void setCreatedId(Long createdId) { + this.createdId = createdId; + } + + public Long getModifiedId() { + return modifiedId; + } + + public void setModifiedId(Long modifiedId) { + this.modifiedId = modifiedId; + } + + public Long getRowNum() { + return rowNum; + } + + public void setRowNum(Long rowNum) { + this.rowNum = rowNum; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isActive() { + return active; + } + + public void setActive(boolean active) { + this.active = active; + } + + public Integer getPriority() { + return priority; + } + + public void setPriority(Integer priority) { + this.priority = priority; + } + + public SortedSet getRoleFunctions() { + return roleFunctions; + } + + public void setRoleFunctions(SortedSet roleFunctions) { + this.roleFunctions = roleFunctions; + } + + public SortedSet getChildRoles() { + return childRoles; + } + + public void setChildRoles(SortedSet childRoles) { + this.childRoles = childRoles; + } + + public SortedSet getParentRoles() { + return parentRoles; + } + + public void setParentRoles(SortedSet parentRoles) { + this.parentRoles = parentRoles; + } + + public int compareTo(Object obj){ + EPRole other = (EPRole)obj; + + String c1 = getName(); + String c2 = other.getName(); + + return (c1 == null || c2 == null) ? 1 : c1.compareTo(c2); + } + +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/CentralUser.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/CentralUser.java new file mode 100644 index 00000000..f8174825 --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/CentralUser.java @@ -0,0 +1,139 @@ +package org.openecomp.portalapp.portal.transport; + +import java.util.Date; +import java.util.Set; + +public class CentralUser { + + + public Long id; + public Date created; + public Date modified; + public Long createdId; + public Long modifiedId; + public Long rowNum; + + public Long orgId; + public Long managerId; + public String firstName; + public String middleInitial; + public String lastName; + public String phone; + public String fax; + public String cellular; + public String email; + public Long addressId; + public String alertMethodCd; + public String hrid; + public String orgUserId; + public String orgCode; + public String address1; + public String address2; + public String city; + public String state; + public String zipCode; + public String country; + public String orgManagerUserId; + public String locationClli; + public String businessCountryCode; + public String businessCountryName; + public String businessUnit; + public String businessUnitName; + public String department; + public String departmentName; + public String companyCode; + public String company; + public String zipCodeSuffix; + public String jobTitle; + public String commandChain; + public String siloStatus; + public String costCenter; + public String financialLocCode; + + public String loginId; + public String loginPwd; + public Date lastLoginDate; + public boolean active; + public boolean internal; + public Long selectedProfileId; + public Long timeZoneId; + public boolean online; + public String chatId; + + public Set userApps = null; + public Set pseudoRoles = null; + + public CentralUser(){ + + } + + public CentralUser(Long id, Date created, Date modified, Long createdId, Long modifiedId, Long rowNum, Long orgId, + Long managerId, String firstName, String middleInitial, String lastName, String phone, String fax, + String cellular, String email, Long addressId, String alertMethodCd, String hrid, String orgUserId, + String orgCode, String address1, String address2, String city, String state, String zipCode, String country, + String orgManagerUserId, String locationClli, String businessCountryCode, String businessCountryName, + String businessUnit, String businessUnitName, String department, String departmentName, String companyCode, + String company, String zipCodeSuffix, String jobTitle, String commandChain, String siloStatus, + String costCenter, String financialLocCode, String loginId, String loginPwd, Date lastLoginDate, + boolean active, boolean internal, Long selectedProfileId, Long timeZoneId, boolean online, String chatId, + Set userApps, Set pseudoRoles) { + super(); + this.id = id; + this.created = created; + this.modified = modified; + this.createdId = createdId; + this.modifiedId = modifiedId; + this.rowNum = rowNum; + this.orgId = orgId; + this.managerId = managerId; + this.firstName = firstName; + this.middleInitial = middleInitial; + this.lastName = lastName; + this.phone = phone; + this.fax = fax; + this.cellular = cellular; + this.email = email; + this.addressId = addressId; + this.alertMethodCd = alertMethodCd; + this.hrid = hrid; + this.orgUserId = orgUserId; + this.orgCode = orgCode; + this.address1 = address1; + this.address2 = address2; + this.city = city; + this.state = state; + this.zipCode = zipCode; + this.country = country; + this.orgManagerUserId = orgManagerUserId; + this.locationClli = locationClli; + this.businessCountryCode = businessCountryCode; + this.businessCountryName = businessCountryName; + this.businessUnit = businessUnit; + this.businessUnitName = businessUnitName; + this.department = department; + this.departmentName = departmentName; + this.companyCode = companyCode; + this.company = company; + this.zipCodeSuffix = zipCodeSuffix; + this.jobTitle = jobTitle; + this.commandChain = commandChain; + this.siloStatus = siloStatus; + this.costCenter = costCenter; + this.financialLocCode = financialLocCode; + this.loginId = loginId; + this.loginPwd = loginPwd; + this.lastLoginDate = lastLoginDate; + this.active = active; + this.internal = internal; + this.selectedProfileId = selectedProfileId; + this.timeZoneId = timeZoneId; + this.online = online; + this.chatId = chatId; + this.userApps = userApps; + this.pseudoRoles = pseudoRoles; + } + + + + +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/CentralUserApp.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/CentralUserApp.java new file mode 100644 index 00000000..9317b9fe --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/CentralUserApp.java @@ -0,0 +1,70 @@ +package org.openecomp.portalapp.portal.transport; + +@SuppressWarnings("rawtypes") +public class CentralUserApp implements Comparable{ + + private Long userId; + private CentralApp app; + private CentralRole role; + private Short priority; + + + + public Long getUserId() { + return userId; + } + + + + public void setUserId(Long userId) { + this.userId = userId; + } + + + + public CentralApp getApp() { + return app; + } + + + + public void setApp(CentralApp app) { + this.app = app; + } + + + + public CentralRole getRole() { + return role; + } + + + + public void setRole(CentralRole role) { + this.role = role; + } + + + + public Short getPriority() { + return priority; + } + + + + public void setPriority(Short priority) { + this.priority = priority; + } + + + + public int compareTo(Object other){ + CentralUserApp castOther = (CentralUserApp) other; + + Long c1 = (this.getUserId()==null ? 0 : this.getUserId()) + (this.priority==null ? 0 : this.priority); + Long c2 = (castOther.getUserId()==null ? 0 : castOther.getUserId()) + (castOther.getApp()==null||castOther.getApp().getId()==null ? 0 : castOther.getApp().getId()) + (castOther.priority==null ? 0 : castOther.priority); + + return c1.compareTo(c2); + } + +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/EPUserAppCurrentRoles.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/EPUserAppCurrentRoles.java new file mode 100644 index 00000000..085df3b8 --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/EPUserAppCurrentRoles.java @@ -0,0 +1,98 @@ +package org.openecomp.portalapp.portal.transport; + +import java.io.Serializable; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; + +import com.fasterxml.jackson.annotation.JsonInclude; + +@Entity +@JsonInclude(JsonInclude.Include.NON_NULL) +public class EPUserAppCurrentRoles implements Serializable{ + + private static final long serialVersionUID = -8145807875293949759L; + + @Id + @Column(name="role_name") + private String roleName; + @Id + @Column(name="user_id") + private Long userId; + @Id + @Column(name="priority") + private String priority ; + @Id + @Column(name="role_id") + private Long roleId; + public String getRoleName() { + return roleName; + } + public void setRoleName(String roleName) { + this.roleName = roleName; + } + public Long getUserId() { + return userId; + } + public void setUserId(Long userId) { + this.userId = userId; + } + public String getPriority() { + return priority; + } + public void setPriority(String priority) { + this.priority = priority; + } + public Long getRoleId() { + return roleId; + } + public void setRoleId(Long roleId) { + this.roleId = roleId; + } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((priority == null) ? 0 : priority.hashCode()); + result = prime * result + ((roleId == null) ? 0 : roleId.hashCode()); + result = prime * result + ((roleName == null) ? 0 : roleName.hashCode()); + result = prime * result + ((userId == null) ? 0 : userId.hashCode()); + return result; + } + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + EPUserAppCurrentRoles other = (EPUserAppCurrentRoles) obj; + if (priority == null) { + if (other.priority != null) + return false; + } else if (!priority.equals(other.priority)) + return false; + if (roleId == null) { + if (other.roleId != null) + return false; + } else if (!roleId.equals(other.roleId)) + return false; + if (roleName == null) { + if (other.roleName != null) + return false; + } else if (!roleName.equals(other.roleName)) + return false; + if (userId == null) { + if (other.userId != null) + return false; + } else if (!userId.equals(other.userId)) + return false; + return true; + } + + + +} + \ No newline at end of file diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/EcompUserAppRoles.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/EcompUserAppRoles.java new file mode 100644 index 00000000..3ac21040 --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/EcompUserAppRoles.java @@ -0,0 +1,66 @@ +package org.openecomp.portalapp.portal.transport; + +import java.io.Serializable; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; + +import com.fasterxml.jackson.annotation.JsonInclude; + +@Entity +@JsonInclude(JsonInclude.Include.NON_NULL) +public class EcompUserAppRoles implements Serializable { + + private static final long serialVersionUID = -3394219387296578741L; + + @Id + @Column(name="app_id") + private String appId; + @Id + @Column(name="user_id") + private Long userId; + @Id + @Column(name="priority") + private String priority ; + @Id + @Column(name="role_id") + private Long roleId; + @Id + @Column(name="role_name") + private String roleName; + public String getAppId() { + return appId; + } + public void setAppId(String appId) { + this.appId = appId; + } + public Long getUserId() { + return userId; + } + public void setUserId(Long userId) { + this.userId = userId; + } + public String getPriority() { + return priority; + } + public void setPriority(String priority) { + this.priority = priority; + } + public Long getRoleId() { + return roleId; + } + public void setRoleId(Long roleId) { + this.roleId = roleId; + } + public String getRoleName() { + return roleName; + } + public void setRoleName(String roleName) { + this.roleName = roleName; + } + + + + +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/EpNotificationItem.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/EpNotificationItem.java index 00df522a..6f7c96b3 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/EpNotificationItem.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/EpNotificationItem.java @@ -88,6 +88,9 @@ public class EpNotificationItem extends DomainVo { @Column(name = "created_date") public Date createdDate; + + @Column(name = "notification_hyperlink") + public String notificationHyperlink; @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL}, orphanRemoval = true) @@ -212,6 +215,14 @@ public class EpNotificationItem extends DomainVo { public void setMsgSource(String msgSource) { this.msgSource = msgSource; } + + public String getNotificationHyperlink() { + return notificationHyperlink; + } + + public void setNotificationHyperlink(String notificationHyperlink) { + this.notificationHyperlink = notificationHyperlink; + } @Override public int hashCode() { diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/EpNotificationItemVO.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/EpNotificationItemVO.java index 3cb0f3a6..d1ebe13c 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/EpNotificationItemVO.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/EpNotificationItemVO.java @@ -65,7 +65,10 @@ public class EpNotificationItemVO extends DomainVo { private Date createdDate; private String loginId; + + private String notificationHyperlink; + /** * Answers whether the notification is expired. * @@ -188,4 +191,13 @@ public class EpNotificationItemVO extends DomainVo { public void setMsgSource(String msgSource) { this.msgSource = msgSource; } + + public String getNotificationHyperlink() { + return notificationHyperlink; + } + + public void setNotificationHyperlink(String notificationHyperlink) { + this.notificationHyperlink = notificationHyperlink; + } + } diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/EventWidget.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/EventWidget.java index 4922b03e..fe4a3cde 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/EventWidget.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/EventWidget.java @@ -31,7 +31,6 @@ import com.fasterxml.jackson.annotation.JsonInclude; *//** * This is to handle portal admins - * @author aw3218 *//* @Entity @Table(name="fn_event_widget_data") diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessPerms.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessPerms.java new file mode 100644 index 00000000..60f9f63a --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessPerms.java @@ -0,0 +1,96 @@ +package org.openecomp.portalapp.portal.transport; + +import java.io.Serializable; + +public class ExternalAccessPerms implements Serializable, Comparable{ + + /** + * + */ + private static final long serialVersionUID = -200964838466882602L; + public String type; + public String instance; + public String action; + public String description; + + + public ExternalAccessPerms() { + super(); + } + + + + public ExternalAccessPerms(String type, String instance, String action, String description) { + super(); + this.type = type; + this.instance = instance; + this.action = action; + this.description = description; + } + + public ExternalAccessPerms(String type, String instance, String action) { + super(); + this.type = type; + this.instance = instance; + this.action = action; + } + + + /** + * @return the type + */ + public String getType() { + return type; + } + /** + * @param type the type to set + */ + public void setType(String type) { + this.type = type; + } + /** + * @return the instance + */ + public String getInstance() { + return instance; + } + /** + * @param instance the instance to set + */ + public void setInstance(String instance) { + this.instance = instance; + } + /** + * @return the action + */ + public String getAction() { + return action; + } + /** + * @param action the action to set + */ + public void setAction(String action) { + this.action = action; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + + @Override + public int compareTo(Object obj){ + ExternalAccessPerms other = (ExternalAccessPerms)obj; + + String c1 = getInstance(); + String c2 = other.getInstance(); + + return (c1 == null || c2 == null) ? 1 : c1.compareTo(c2); + } + + +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessPermsDetail.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessPermsDetail.java new file mode 100644 index 00000000..39c29dd8 --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessPermsDetail.java @@ -0,0 +1,90 @@ +package org.openecomp.portalapp.portal.transport; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonRootName; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonRootName(value="perm") +public class ExternalAccessPermsDetail { + + private String type; + private String instance; + private String action; + private List roles; + private String description; + + + + public ExternalAccessPermsDetail() { + super(); + } + + /** + * @param type + * @param instance + * @param action + * @param roles + * @param description + */ + public ExternalAccessPermsDetail(String type, String instance, String action, List roles, + String description) { + super(); + this.type = type; + this.instance = instance; + this.action = action; + this.roles = roles; + this.description = description; + } + + /** + * @param type + * @param instance + * @param action + * @param description + */ + public ExternalAccessPermsDetail(String type, String instance, String action, + String description) { + super(); + this.type = type; + this.instance = instance; + this.action = action; + this.description = description; + } + + public String getType() { + return type; + } + public void setType(String type) { + this.type = type; + } + public String getInstance() { + return instance; + } + public void setInstance(String instance) { + this.instance = instance; + } + public String getAction() { + return action; + } + public void setAction(String action) { + this.action = action; + } + public List getRoles() { + return roles; + } + + public void setRoles(List roles) { + this.roles = roles; + } + + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + + +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessRole.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessRole.java new file mode 100644 index 00000000..949c191e --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessRole.java @@ -0,0 +1,39 @@ +package org.openecomp.portalapp.portal.transport; + +import java.io.Serializable; + +public class ExternalAccessRole implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 3439986826362436339L; + public String name; + public String description; + + public ExternalAccessRole() { + + } + + public ExternalAccessRole(String name, String description) { + super(); + this.name = name; + this.description = description; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessRolePerms.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessRolePerms.java new file mode 100644 index 00000000..460b02ac --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessRolePerms.java @@ -0,0 +1,29 @@ +package org.openecomp.portalapp.portal.transport; + +public class ExternalAccessRolePerms { + + private ExternalAccessPerms perm; + private String role; + + + public ExternalAccessRolePerms(ExternalAccessPerms perm, String role) { + super(); + this.perm = perm; + this.role = role; + } + + public ExternalAccessPerms getPerm() { + return perm; + } + public void setPerm(ExternalAccessPerms perm) { + this.perm = perm; + } + public String getRole() { + return role; + } + public void setRole(String role) { + this.role = role; + } + + +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessUser.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessUser.java new file mode 100644 index 00000000..30674bf3 --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessUser.java @@ -0,0 +1,28 @@ +package org.openecomp.portalapp.portal.transport; + +public class ExternalAccessUser { + + private String user; + private String role; + + public ExternalAccessUser(String user, String role) { + super(); + this.user = user; + this.role = role; + } + + public String getUser() { + return user; + } + public void setUser(String user) { + this.user = user; + } + public String getRole() { + return role; + } + public void setRole(String role) { + this.role = role; + } + + +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessUserRoleDetail.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessUserRoleDetail.java new file mode 100644 index 00000000..e5d89e22 --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalAccessUserRoleDetail.java @@ -0,0 +1,36 @@ +package org.openecomp.portalapp.portal.transport; + +public class ExternalAccessUserRoleDetail { + + private String name; + private ExternalRoleDescription description; + + + /** + * + */ + public ExternalAccessUserRoleDetail() { + super(); + } + + public ExternalAccessUserRoleDetail(String name, ExternalRoleDescription description) { + super(); + this.name = name; + this.description = description; + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public ExternalRoleDescription getDescription() { + return description; + } + public void setDescription(ExternalRoleDescription description) { + this.description = description; + } + + +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalRoleDescription.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalRoleDescription.java new file mode 100644 index 00000000..d6eba633 --- /dev/null +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/ExternalRoleDescription.java @@ -0,0 +1,50 @@ +package org.openecomp.portalapp.portal.transport; + +public class ExternalRoleDescription { + + private String id; + private String name; + private String active; + private String priority; + private String appId; + private String appRoleId; + + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public String getActive() { + return active; + } + public void setActive(String active) { + this.active = active; + } + public String getPriority() { + return priority; + } + public void setPriority(String priority) { + this.priority = priority; + } + public String getAppId() { + return appId; + } + public void setAppId(String appId) { + this.appId = appId; + } + public String getAppRoleId() { + return appRoleId; + } + public void setAppRoleId(String appRoleId) { + this.appRoleId = appRoleId; + } + + +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/OnboardingApp.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/OnboardingApp.java index a4198d1d..3187d093 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/OnboardingApp.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/transport/OnboardingApp.java @@ -66,6 +66,10 @@ public class OnboardingApp { public String uebSecret; public Boolean restrictedApp; + + public Boolean isCentralAuth; + + public String nameSpace; /** * Sets the name, myLoginsAppName, myLoginsAppOwner, username and diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/ueb/EPUebHelper.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/ueb/EPUebHelper.java index 34be46e3..a80517d2 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/ueb/EPUebHelper.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/ueb/EPUebHelper.java @@ -155,7 +155,7 @@ public class EPUebHelper { // // Test existence of topic at UEB url // - // (ie http://uebsb91kcdc.it.att.com:3904/topics/ECOMP-PORTAL-INBOX) + // (ie http://uebsb91kcdc.it.com:3904/topics/ECOMP-PORTAL-INBOX) // boolean available = true; LinkedList urlList = Helper.uebUrlList(); diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/utils/EPCommonSystemProperties.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/utils/EPCommonSystemProperties.java index dd33bf6e..4d472801 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/utils/EPCommonSystemProperties.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/utils/EPCommonSystemProperties.java @@ -61,7 +61,14 @@ public class EPCommonSystemProperties extends SystemProperties { public static final String AUTH_USER_SERVER = "auth_user_server"; public static final String EXTERNAL_ACCESS_ENABLE = "external_access_enable"; + + public static final String EXTERNAL_SYSTEM_NOTIFICATION_URL = "external_system_notification_url"; + public static final String EXTERNAL_CENTRAL_AUTH_USER_NAME = "ext_central_access_user_name"; + public static final String EXTERNAL_CENTRAL_AUTH_PASSWORD = "ext_central_access_password"; + public static final String EXTERNAL_CENTRAL_ACCESS_URL = "ext_central_access_url"; + public static final String EXTERNAL_CENTRAL_ACCESS_USER_DOMAIN = "ext_central_access_user_domain"; + public static final String WIDGET_MS_PROTOCOL = "microservices.widget.protocol"; public static final String WIDGET_MS_HOSTNAME = "microservices.widget.hostname"; -} \ No newline at end of file +} diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/utils/EcompPortalUtils.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/utils/EcompPortalUtils.java index d471d90b..0284452a 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/utils/EcompPortalUtils.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/utils/EcompPortalUtils.java @@ -29,6 +29,7 @@ import java.util.Date; import java.util.List; import javax.servlet.http.HttpServletResponse; +import javax.xml.bind.DatatypeConverter; import org.hibernate.Session; import org.hibernate.Transaction; @@ -36,8 +37,11 @@ import org.openecomp.portalapp.portal.domain.EPUser; import org.openecomp.portalapp.portal.logging.format.EPAppMessagesEnum; import org.openecomp.portalapp.portal.logging.logic.EPLogUtil; import org.openecomp.portalsdk.core.logging.logic.EELFLoggerDelegate; +import org.openecomp.portalsdk.core.onboarding.util.CipherUtil; import org.openecomp.portalsdk.core.util.SystemProperties; import org.slf4j.MDC; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -369,5 +373,45 @@ public class EcompPortalUtils { } } + /** + * It returns headers where username and password of external central auth + * is encoded to base64 + * + * @return header which contains external central auth username and password + * base64 encoded + * @throws Exception + * if unable to decrypt the password + */ + public static HttpHeaders base64encodeKeyForAAFBasicAuth() throws Exception { + + String userName = ""; + String decryptedPass = ""; + if (EPCommonSystemProperties + .containsProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_AUTH_USER_NAME) && EPCommonSystemProperties + .containsProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_AUTH_PASSWORD)) { + decryptedPass = SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_AUTH_PASSWORD); + userName = SystemProperties.getProperty(EPCommonSystemProperties.EXTERNAL_CENTRAL_AUTH_USER_NAME); + } + String decPass = decrypted(decryptedPass); + String usernamePass = userName + ":" + decPass; + String encToBase64 = String.valueOf((DatatypeConverter.printBase64Binary(usernamePass.getBytes()))); + HttpHeaders headers = new HttpHeaders(); + headers.add("Authorization", "Basic " + encToBase64); + headers.setContentType(MediaType.APPLICATION_JSON); + return headers; + } + + private static String decrypted(String encrypted) throws Exception { + String result = ""; + if (encrypted != null && encrypted.length() > 0) { + try { + result = CipherUtil.decrypt(encrypted, SystemProperties.getProperty(SystemProperties.Decryption_Key)); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, "decryptedPassword failed", e); + throw e; + } + } + return result; + } } diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/utils/PortalConstants.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/utils/PortalConstants.java index 485a80f5..57bb543f 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/utils/PortalConstants.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/portal/utils/PortalConstants.java @@ -24,6 +24,7 @@ public interface PortalConstants { public static final Long DEFAULT_NOTIFICATION_CREATOR = 1L; public static final String REST_AUX_API = "/auxapi"; public static final Long ACCOUNT_ADMIN_ROLE_ID = 999L; - public static final int SYS_ADMIN_ROLE_ID = 1; + public static final Long SYS_ADMIN_ROLE_ID = 1L; public static final String ADMIN_ROLE = "Account Administrator"; + public static final String PORTAL_ADMIN_ROLE = "System Administrator"; } diff --git a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/util/EPUserUtils.java b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/util/EPUserUtils.java index 7dcf0e95..533ed53d 100644 --- a/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/util/EPUserUtils.java +++ b/ecomp-portal-BE-common/src/main/java/org/openecomp/portalapp/util/EPUserUtils.java @@ -19,11 +19,13 @@ */ package org.openecomp.portalapp.util; +import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.UUID; @@ -31,15 +33,24 @@ import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.criterion.Projections; +import org.hibernate.criterion.Restrictions; +import org.hibernate.transform.Transformers; +import org.openecomp.portalapp.portal.domain.CentralRoleFunction; import org.openecomp.portalapp.portal.domain.EPRole; import org.openecomp.portalapp.portal.domain.EPUser; import org.openecomp.portalapp.portal.domain.EPUserApp; +import org.openecomp.portalapp.portal.service.EPRoleFunctionService; import org.openecomp.portalapp.portal.utils.EcompPortalUtils; import org.openecomp.portalsdk.core.domain.RoleFunction; import org.openecomp.portalsdk.core.exception.SessionExpiredException; import org.openecomp.portalsdk.core.lm.FusionLicenseManager; import org.openecomp.portalsdk.core.logging.logic.EELFLoggerDelegate; import org.openecomp.portalsdk.core.menu.MenuBuilder; +import org.openecomp.portalsdk.core.onboarding.util.PortalApiConstants; +import org.openecomp.portalsdk.core.onboarding.util.PortalApiProperties; import org.openecomp.portalsdk.core.service.DataAccessService; import org.openecomp.portalsdk.core.util.SystemProperties; import org.openecomp.portalsdk.core.web.support.AppUtils; @@ -54,6 +65,9 @@ public class EPUserUtils { public static final String ALL_ROLE_FUNCTIONS = "allRoleFunctions"; private static DataAccessService dataAccessService; + + @Autowired + private static SessionFactory sessionFactory; /** * Gets the EPUser object from the session. @@ -89,17 +103,17 @@ public class EPUserUtils { */ @SuppressWarnings("rawtypes") public static void setUserSession(HttpServletRequest request, EPUser user, Set applicationMenuData, - Set businessDirectMenuData, String loginMethod_ignored, List allRoleFunctions) { + Set businessDirectMenuData, String loginMethod_ignored, EPRoleFunctionService ePRoleFunctionService) { HttpSession session = request.getSession(true); // clear the current user session to avoid any conflicts EPUserUtils.clearUserSession(request); session.setAttribute(SystemProperties.getProperty(SystemProperties.USER_ATTRIBUTE_NAME), user); - getAllRoleFunctions(allRoleFunctions, session); - - getRoleFunctions(request); - + setAllRoleFunctions(ePRoleFunctionService.getRoleFunctions(), session); + + ePRoleFunctionService.getRoleFunctions(request,user); + // truncate the role (and therefore the role function) data to save // memory in the session user.setEPRoles(null); @@ -146,7 +160,7 @@ public class EPUserUtils { * @param session * HttpSession */ - private static void getAllRoleFunctions(List allRoleFunctions, HttpSession session) { + private static void setAllRoleFunctions(List allRoleFunctions, HttpSession session) { if (allRoleFunctions == null) return; Set roleFnSet = new HashSet(); @@ -176,45 +190,6 @@ public class EPUserUtils { session.removeAttribute(SystemProperties.getProperty(SystemProperties.ROLE_FUNCTIONS_ATTRIBUTE_NAME)); } - /** - * Builds a set of role functions and sets a session attribute with it. - * - * @param request - * HttpServletRequest - * @return Set of role functions that was built. - */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - private static Set getRoleFunctions(HttpServletRequest request) { - HashSet roleFunctions = null; - - HttpSession session = request.getSession(); - roleFunctions = (HashSet) session - .getAttribute(SystemProperties.getProperty(SystemProperties.ROLE_FUNCTIONS_ATTRIBUTE_NAME)); - - if (roleFunctions == null) { - HashMap roles = getRoles(request); - roleFunctions = new HashSet(); - - Iterator i = roles.keySet().iterator(); - - while (i.hasNext()) { - Long roleKey = (Long) i.next(); - EPRole role = (EPRole) roles.get(roleKey); - - Iterator j = role.getRoleFunctions().iterator(); - - while (j.hasNext()) { - RoleFunction function = (RoleFunction) j.next(); - roleFunctions.add(function.getCode()); - } - } - - session.setAttribute(SystemProperties.getProperty(SystemProperties.ROLE_FUNCTIONS_ATTRIBUTE_NAME), - roleFunctions); - } - - return roleFunctions; - } /** * Gets role information from the user session, in the cached user object. @@ -225,7 +200,7 @@ public class EPUserUtils { * @return Map of role ID to role object */ @SuppressWarnings("rawtypes") - private static HashMap getRoles(HttpServletRequest request) { + public static HashMap getRoles(HttpServletRequest request) { HashMap roles = null; HttpSession session = AppUtils.getSession(request); diff --git a/ecomp-portal-BE-common/src/main/webapp/WEB-INF/fusion/orm/EP.hbm.xml b/ecomp-portal-BE-common/src/main/webapp/WEB-INF/fusion/orm/EP.hbm.xml index eea9467a..342a6e8c 100644 --- a/ecomp-portal-BE-common/src/main/webapp/WEB-INF/fusion/orm/EP.hbm.xml +++ b/ecomp-portal-BE-common/src/main/webapp/WEB-INF/fusion/orm/EP.hbm.xml @@ -321,7 +321,12 @@ - + + + + + + @@ -433,6 +438,29 @@ + + + + + seq_epp_app_role_func + + + + + + + + + + + + + + + + @@ -612,17 +640,17 @@ + + + + + @@ -1074,7 +1112,7 @@ where fn_role.app_id = fn_app.app_id and fn_app.enabled='Y' order by app_name a.APP_NOTES , a.APP_URL , a.APP_ALTERNATE_URL , a.APP_REST_ENDPOINT , a.ML_APP_NAME , a.ML_APP_ADMIN_ID , a.MOTS_ID , a.APP_PASSWORD , a.THUMBNAIL , a.APP_USERNAME , a.OPEN , a.ENABLED , - a.UEB_TOPIC_NAME , a.UEB_KEY , a.UEB_SECRET , a.APP_TYPE + a.UEB_TOPIC_NAME , a.UEB_KEY , a.UEB_SECRET , a.APP_TYPE , a.AUTH_CENTRAL from FN_APP a -- Portal assigns role 999 to app administrator left outer join FN_USER_ROLE r ON a.APP_ID = r.APP_ID and r.USER_ID = :userId and r.ROLE_ID != 999 @@ -1102,7 +1140,8 @@ where fn_role.app_id = fn_app.app_id and fn_app.enabled='Y' order by app_name a.APP_NOTES , a.APP_URL , a.APP_ALTERNATE_URL , a.APP_REST_ENDPOINT , a.ML_APP_NAME , a.ML_APP_ADMIN_ID , a.MOTS_ID , a.APP_PASSWORD , a.THUMBNAIL , a.APP_USERNAME , a.OPEN , a.ENABLED , - a.UEB_TOPIC_NAME , a.UEB_KEY , a.UEB_SECRET , a.APP_TYPE + a.UEB_TOPIC_NAME , a.UEB_KEY , a.UEB_SECRET , a.APP_TYPE , a.AUTH_CENTRAL , + a.AUTH_NAMESPACE from FN_APP a -- Portal assigns role 999 to app administrator left outer join FN_USER_ROLE r ON a.APP_ID = r.APP_ID and r.USER_ID = :userId and r.ROLE_ID != 999 @@ -1131,7 +1170,8 @@ where fn_role.app_id = fn_app.app_id and fn_app.enabled='Y' order by app_name a.APP_NOTES , a.APP_URL , a.APP_ALTERNATE_URL , a.APP_REST_ENDPOINT , a.ML_APP_NAME , a.ML_APP_ADMIN_ID , a.MOTS_ID , a.APP_PASSWORD , a.THUMBNAIL , a.APP_USERNAME , a.OPEN , a.ENABLED , - a.UEB_TOPIC_NAME , a.UEB_KEY , a.UEB_SECRET , a.APP_TYPE + a.UEB_TOPIC_NAME , a.UEB_KEY , a.UEB_SECRET , a.APP_TYPE , a.AUTH_CENTRAL , + a.AUTH_NAMESPACE from FN_APP a -- Portal assigns role 999 to app administrator left outer join FN_USER_ROLE r ON a.APP_ID = r.APP_ID and r.USER_ID = :userId and r.ROLE_ID != 999 @@ -1161,7 +1201,8 @@ where fn_role.app_id = fn_app.app_id and fn_app.enabled='Y' order by app_name a.APP_NOTES , a.APP_URL , a.APP_ALTERNATE_URL , a.APP_REST_ENDPOINT , a.ML_APP_NAME , a.ML_APP_ADMIN_ID , a.MOTS_ID , a.APP_PASSWORD , a.THUMBNAIL , a.APP_USERNAME , a.OPEN , a.ENABLED , - a.UEB_TOPIC_NAME , a.UEB_KEY , a.UEB_SECRET , a.APP_TYPE + a.UEB_TOPIC_NAME , a.UEB_KEY , a.UEB_SECRET , a.APP_TYPE , a.AUTH_CENTRAL , + a.AUTH_NAMESPACE from FN_APP a -- Portal assigns role 999 to app administrator left outer join FN_USER_ROLE r ON a.APP_ID = r.APP_ID and r.USER_ID = :userId and r.ROLE_ID != 999 @@ -1193,7 +1234,8 @@ where fn_role.app_id = fn_app.app_id and fn_app.enabled='Y' order by app_name a.APP_NOTES , a.APP_URL , a.APP_ALTERNATE_URL , a.APP_REST_ENDPOINT , a.ML_APP_NAME , a.ML_APP_ADMIN_ID , a.MOTS_ID , a.APP_PASSWORD , a.THUMBNAIL , a.APP_USERNAME , a.OPEN , a.ENABLED , - a.UEB_TOPIC_NAME , a.UEB_KEY , a.UEB_SECRET , a.APP_TYPE + a.UEB_TOPIC_NAME , a.UEB_KEY , a.UEB_SECRET , a.APP_TYPE , a.AUTH_CENTRAL , + a.AUTH_NAMESPACE from FN_APP a -- Portal assigns role 999 to app administrator left outer join FN_USER_ROLE r ON a.APP_ID = r.APP_ID and r.USER_ID = :userId and r.ROLE_ID != 999 @@ -1228,7 +1270,8 @@ where fn_role.app_id = fn_app.app_id and fn_app.enabled='Y' order by app_name a.APP_NOTES , a.APP_URL , a.APP_ALTERNATE_URL , a.APP_REST_ENDPOINT , a.ML_APP_NAME , a.ML_APP_ADMIN_ID , a.MOTS_ID , a.APP_PASSWORD , a.THUMBNAIL , a.APP_USERNAME , a.OPEN , a.ENABLED , - a.UEB_TOPIC_NAME , a.UEB_KEY , a.UEB_SECRET , a.APP_TYPE + a.UEB_TOPIC_NAME , a.UEB_KEY , a.UEB_SECRET , a.APP_TYPE , a.AUTH_CENTRAL , + a.AUTH_NAMESPACE from FN_APP a -- Portal assigns role 999 to app administrator left outer join FN_USER_ROLE r ON a.APP_ID = r.APP_ID and r.USER_ID = :userId and r.ROLE_ID != 999 @@ -1266,7 +1309,8 @@ where fn_role.app_id = fn_app.app_id and fn_app.enabled='Y' order by app_name a.APP_NOTES , a.APP_URL , a.APP_ALTERNATE_URL , a.APP_REST_ENDPOINT , a.ML_APP_NAME , a.ML_APP_ADMIN_ID , a.MOTS_ID , a.APP_PASSWORD , a.THUMBNAIL , a.APP_USERNAME , a.OPEN , a.ENABLED , - a.UEB_TOPIC_NAME , a.UEB_KEY , a.UEB_SECRET , a.APP_TYPE + a.UEB_TOPIC_NAME , a.UEB_KEY , a.UEB_SECRET , a.APP_TYPE , a.AUTH_CENTRAL , + a.AUTH_NAMESPACE from FN_APP a -- Portal assigns role 999 to app administrator left outer join FN_USER_ROLE r ON a.APP_ID = r.APP_ID and r.USER_ID = :userId and r.ROLE_ID != 999 @@ -1307,7 +1351,8 @@ where fn_role.app_id = fn_app.app_id and fn_app.enabled='Y' order by app_name a.APP_NOTES , a.APP_URL , a.APP_ALTERNATE_URL , a.APP_REST_ENDPOINT , a.ML_APP_NAME , a.ML_APP_ADMIN_ID , a.MOTS_ID , a.APP_PASSWORD , a.THUMBNAIL , a.APP_USERNAME , a.OPEN , a.ENABLED , - a.UEB_TOPIC_NAME , a.UEB_KEY , a.UEB_SECRET , a.APP_TYPE + a.UEB_TOPIC_NAME , a.UEB_KEY , a.UEB_SECRET , a.APP_TYPE , a.AUTH_CENTRAL , + a.AUTH_NAMESPACE from FN_APP a -- Portal assigns role 999 to app administrator left outer join FN_USER_ROLE r ON a.APP_ID = r.APP_ID and r.USER_ID = :userId and r.ROLE_ID != 999 @@ -1344,7 +1389,8 @@ where fn_role.app_id = fn_app.app_id and fn_app.enabled='Y' order by app_name a.APP_NOTES , a.APP_URL , a.APP_ALTERNATE_URL , a.APP_REST_ENDPOINT , a.ML_APP_NAME , a.ML_APP_ADMIN_ID , a.MOTS_ID , a.APP_PASSWORD , a.THUMBNAIL , a.APP_USERNAME , a.OPEN , a.ENABLED , - a.UEB_TOPIC_NAME , a.UEB_KEY , a.UEB_SECRET , a.APP_TYPE + a.UEB_TOPIC_NAME , a.UEB_KEY , a.UEB_SECRET , a.APP_TYPE , a.AUTH_CENTRAL , + a.AUTH_NAMESPACE from FN_APP a -- Portal assigns role 999 to app administrator left outer join FN_USER_ROLE r ON a.APP_ID = r.APP_ID and r.USER_ID = :userId and r.ROLE_ID != 999 @@ -1381,7 +1427,8 @@ where fn_role.app_id = fn_app.app_id and fn_app.enabled='Y' order by app_name a.APP_NOTES , a.APP_URL , a.APP_ALTERNATE_URL , a.APP_REST_ENDPOINT , a.ML_APP_NAME , a.ML_APP_ADMIN_ID , a.MOTS_ID , a.APP_PASSWORD , a.THUMBNAIL , a.APP_USERNAME , a.OPEN , a.ENABLED , - a.UEB_TOPIC_NAME , a.UEB_KEY , a.UEB_SECRET , a.APP_TYPE + a.UEB_TOPIC_NAME , a.UEB_KEY , a.UEB_SECRET , a.APP_TYPE , a.AUTH_CENTRAL , + a.AUTH_NAMESPACE from FN_APP a -- Portal assigns role 999 to app administrator left outer join FN_USER_ROLE r ON a.APP_ID = r.APP_ID and r.USER_ID = :userId and r.ROLE_ID != 999 @@ -1460,6 +1507,16 @@ where fn_role.app_id = fn_app.app_id and fn_app.enabled='Y' order by app_name ]]> + + + + + + + class="org.openecomp.portalapp.portal.domain.EPUserAppRoles" /> @@ -1681,7 +1738,7 @@ where fn_role.app_id = fn_app.app_id and fn_app.enabled='Y' order by app_name select fr.role_name, fa.app_name from fn_role fr, fn_user_role fur, fn_app fa, fn_user fu - Where fu.user_id = fur.user_id and fur.role_id = fr.role_id and fa.app_id = fur.app_id and fu.org_user_id = :userId + Where fu.user_id = fur.user_id and fur.role_id = fr.role_id and fa.app_id = fur.app_id and fu.org_user_id = :userId and fr.active_yn='Y' and (fa.enabled = 'Y' or fa.app_id=1) ; ]]> @@ -1711,5 +1768,173 @@ where fn_role.app_id = fn_app.app_id and fn_app.enabled='Y' order by app_name delete from ep_user_notification where notification_id in (select notification_id from ep_notification where curdate() >= DATE_ADD(end_time,INTERVAL 3 MONTH)) ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ecomp-portal-BE-common/src/main/webapp/WEB-INF/jsp/login.jsp b/ecomp-portal-BE-common/src/main/webapp/WEB-INF/jsp/login.jsp deleted file mode 100644 index d90704c3..00000000 --- a/ecomp-portal-BE-common/src/main/webapp/WEB-INF/jsp/login.jsp +++ /dev/null @@ -1,120 +0,0 @@ -<%-- - ================================================================================ - 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. - ================================================================================ - --%> -<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles"%> -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ page import="java.net.URLEncoder" %> -<%@ page import="org.openecomp.portalsdk.core.util.SystemProperties" %> - - - - - - - - - - - - - - - - - - - - <% - String returnUrl = request.getParameter("returnUrl"); - String redirectUrl = request.getParameter("redirectUrl"); - returnUrl = ((returnUrl == null) ? (request.isSecure() ?"https://":"http://") + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/process_csp" + "?redirectUrl=" + redirectUrl: URLEncoder.encode(returnUrl)); - %> - - -
- -
- AT&T -
-
-
-
-
- -
- - Click here to login - -
-
-
-
-
-







- -
- - - - diff --git a/ecomp-portal-BE-common/src/main/webapp/WEB-INF/jsp/login_external.jsp b/ecomp-portal-BE-common/src/main/webapp/WEB-INF/jsp/login_external.jsp deleted file mode 100644 index 94c2f55e..00000000 --- a/ecomp-portal-BE-common/src/main/webapp/WEB-INF/jsp/login_external.jsp +++ /dev/null @@ -1,162 +0,0 @@ -<%-- - ================================================================================ - 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. - ================================================================================ - --%> -<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles"%> -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> -<%@ page import="org.openecomp.portalsdk.core.util.SystemProperties" %> - -" /> - - - - - - Login - - - - - - - - - - - - - - - - - -
- -
- AT&T -
-
- -
-
- Portal -

ECOMP Portal

- - -
-
- - -
-
-                - -
-
-
-






- -
- - - - diff --git a/ecomp-portal-BE-common/src/main/webapp/static/ebz/angular_js/app.js b/ecomp-portal-BE-common/src/main/webapp/static/ebz/angular_js/app.js deleted file mode 100644 index be422026..00000000 --- a/ecomp-portal-BE-common/src/main/webapp/static/ebz/angular_js/app.js +++ /dev/null @@ -1,3 +0,0 @@ -angular.module('att.abs.helper', []); - -var app=angular.module("abs", []); \ No newline at end of file diff --git a/ecomp-portal-BE-common/src/main/webapp/static/fusion/images/onap-portal-logo.png b/ecomp-portal-BE-common/src/main/webapp/static/fusion/images/onap-portal-logo.png index f48d3d47636b9fa02f3360b93c7a7897c3e06123..3fa9b92ef22f67e559f7db185c3d681fe7bb31f9 100644 GIT binary patch literal 58332 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 literal 71199 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 RmDZA8+H+yGP&W zhd$o9Q}3RAIzQe%q_bb2fUur{J!j7h|Nh6Ht2m31GgWbw23v&3TWciOrm< zNFVz03++31>d>)sr;a{>0ik_+59krp6R6iSxL2=`KB2)qfrdeWVSfIBU48w!2L*)m z?pf2R)dW5^u*__a7_{=)Lrt8ujH|xJ84aA#1}CzsoO@w&j;AP@#DUeRr0W<;H{c+$ z&t2$XA5c#OSWKZEe9=h^e3CjBDT!4v_GJoU(%fT`J)%=RL=1dUY9iDTVHOeTKncQb z1u_$VNJsXf@y*S}LxP|qPl zI){d~?bx|r|3M(}UKlv6NB58sgP+gOD*}CX)oiYyyfT|uG%t&lwVEtupn5eEbU#@P zThINv=J4KmyK*KJsmJZko>p2gWv6!TcKzpjcc@MuKh9aMV&s|`1c|{BWlICSfqe#J z#kmV-qhewQ4H*Wg0&I2Z>gVeh+`G@ye*Pi8zM= zms||{4z+XZQ(zAwoj|B}7pgpjQi{Cj3|DIHDyR`1tD_}OOXB5ZVLDm3g)G=YgefFC zgDh5%m}J3%R5I<0PSZYHz3-Q+EMXt(R-k=+HmkAH2GXn16dyJ!zzwu9&^}9-E@$G- z?A)KrcaJu}5PrDeV|BLh5X6myghXh)aN@{2IPuz*&OHlSe+w5bbdEG^MDI|2!B>-l zYk;z=={bQ4z+(oYFCZXj<;vAfGIHb3gD*6!k8eN^-;mzjLVI-Z59}V+GpI+OPMy04 z`38q|5BW^E@W$nv7TSYuv&YsNDlo}qmBmnIHdH#y+mf4?CC9&u-MMx8HtqD{tjtNe`r^~knRD!{Db=jg!Jnk*aPtA7Z_GA@Zp$NzN^v3@!&Ji zXgHJQrhz+dlL3W`f%NQpovCOj(t7U67iBU5Mg7unCV#Re@ z1LK4`m#7?S)e7YTW;j!%(w(ar@}Q{60x1RGq9n2)i9{xOEK-yBOfq+a`=U&5(WaIY z;$L5u{%yIVrw`sr^h#P-_GYfJzz48<_Sxs)eI6Rx1Jobv=j*Tc-VwMD8))Y?Al~Jn zgOC3$eJ0_NzI6Gu*WQ3@1+91R;AfF34N!ao2Mz?$H*DCjt5>f!g@2=|6(4f{?o!kD z;f}#`0#D2H&yN^5a4`cz+OH+A%P+NLi-Nt5*XILd!UbhaAzO? zQ6oRuvwJUggrUm<-4tf_gs=>q)FiyjaYu|5%9B5Qwx=LsSMIc3`bl5sOeo18TUz+Z z!EIv>6@6TsGpV$2=7H@q_T=M2^;UlE7w=9 z+ZfurUzdQOUIU+byi?b}p8bP+KkXOVuS2&`DBXkm1%wRn@#|49@G;K@^>sR@nX>19 zw;HIs#=>1TbL(~;Yx7~mV=<{73#1_Kc$3zSyjUrTlan|GCKP2cStObj%03AVMu|`uxNDMKR>^OgoHnNi5dlbHG!fnPoM z+%R}f;9-Nh&6yM4fNs7f2cK`};IM$c-F-s+{K5i4`?TxQZODr+Z`hK2t*jEC2aCx!Mlfy+H zA1EBPck4%A=Z@REb;`biIr|DkdkYsAZ`*6U@e^mfOjV@Ka$D+57WBe+wExiI_ePF< zvTL`X-hJD4>;hc&59{A8sBahlUOoYR{euVi2KKEl`0R(d6MWP?Q)RKhBYE1wy&AWv zTlji1bG=Kf%v~tu&8zm`hj9+_(}a zEFu%7=;w72Ntp`;OzdlFVK+ znoV5enY!>RDDZQj9<1TXUa?{oKRCxZLhXOf)OGY%+SOQjdF8wBz8418Pf!Tx7r1C} zIDmcwK!A?v-o1Oj{`%|a-)P(sCVw^O2HY{YT%h&f@xY4)Z;oGn`Sq^_zQBO6r^5#J z^6k|-sGm<~Kc8*^v*tw}{pHs(v&q21Q*2BM8LG?ey>WDKJRQjZ=IS?9<;s)CfcMkwM zhx8oi2Nm|~Pz>faD?Yq78+FLq}zKUfu;fKUqZD1|gCo{BE(;;6V^v;6N`{UBe;$72o zl~Z=;rj~9Se`wptgL&^C%!e}S@U~G0i$;|ce6p|b)6(r@4}CeZr0|2ic_R;O8+~Z| z=mP~G?cX|n|JI4Sb#r#e1$do&m|EV z?om?Uj+>B)FKTrvnVm}mT->6Qnn!JJGk@a~;Tt>5+1PRRW++e1+5F_(x)%6VmzisQ zW~}Z!Yh{NyE82xGdwkxqw)2-gHh)Fih&8b1HuJZ%oSzC*1?ss)(UBgmA{mJiyT>TV z>{LOl%6n-R3E$8HrJ)O0U1@EMpJ1$-cUu(u0{062g@K@frT8#iv; zrAwFi4*Ldo+dnMup??O~jd@wW149BrdW7}@ zlQ679mu>)p5at8zN(XoJL^Sm7Gr%8y;}^IvHtxnBSM0fu>_gif`I78fj}|~f@zpEI z$Bx8o&!4p|YucW?2_^Yp%#Qx1=)d0-z7OleMI#S^d0X`9{-O!{X!*2c`zNK_KQ7(= z(E<8TBM%jhI#~Gef&B3Y^QZ3HI&-H!YP&w+@ZRF9W@l##YrrDLE#DJ-_E2S~WTJcobCs1I z9l-HPYF?+=tD6hc$ed)dNGFJpdPd1yX{<8Zq)KLlrnpCJcwD%?{hTlS<}T?kT=VZu zy7-+xuh?@!`^)8=6KCsKa(}*<|KqisV>h%vURC^bHRZ?OmmD}TJ@4!PO12L8Z1a;- z7kW=z^jJhf>o_?uj)Y67Wet{Zw3rTbi;~mv9yA~Z5WKnN?8W1CJI~S_RqVx8X}&M` zuoDN(77W*bM;4m;JMa7(xQ29N0U5#2>}!ti3tqQw9RiCVzt{jp^U$3eDEeS2D%w$d zxCXRmxKOYGZF}m}=?Mvm=J3 zpn_uirW_r5Ix@O^N&2mm*hQE&2IS|;q<4(uDdpRx~>AkV%}4i-#0 zynW`OqFKdx;X88{@B315{^Yl&sxr(aXTdxc%q#^4!^dofic9Bz`)pBM|Ned3ckJL7 z6g*(?GjxOrqdCI8N1y(1g1B89_-@U}V^@DhX6Js-aj&mdw4JlgGddmQ9*L*UR*xtJ z>xt9Y2WiAeJw?gwgzG!bS~MhX)yk6Z58Jq(7&I|XyQy#~{!?}!m24jee(Jc6PD-B=F`d~^a& zi;ZuAX0sJ`i`1w|F~NnxR|2&80|yTM{`((*15`I?AmhaZ&B&nB2dD?X!69YSr%%VY zAG6c)XDr{Ezz4Sv>jUQkRhm3`>X|cV!JezAsH#`FeEBLo5AariOATw-2|ODznF5#y z$AxnQISj{zO99se^&M|e^HqY|xO3+&&M}$l9YN!b1HO>ZUeM-2^`H*IJS9j6P)WD} zM0l)S`)7tezacf{3TL>%nXegd8mcQP?4UVTuywiFQcXRbS6NP^yvt`+9oiMSCvW=h z{7-l1joni)?!b;Q2Y3FrwBSDn3qL%v6SN*sj}oo4aC}MOq&oS`?4W?!>o#+R)nKzb zR7}-nS8)EF{iVetM}OG4dzU8}{@`?g?0p6d0^|YBsgmtK@ZR9#a~iXmxotSei)I9+ z$M}Qe_Ed4bMH^erUFRB|K|_mURBo{fSCN85DTxrkrzbILcTwhJQCnJ%6HV3@NGQoNvJE!5LU^#mdVo zH*ekor-?5`I1tzhuF)F*+htdCp63H+Ox%=(RbQ$}i%qyB4#_MuX8`#4XXGoRaDiQ zO_l75)m!ml3ps!O;y?fSFR*j*Uu*6x?+w-z7;(wT$$T^Z-!gR#1{1%N`1pl9M{4m8 zz;|H%<(IoH)HJdF^wSAw_V6K452_664_zW~wLuZ%$k~Ad2Vyb~9PE70XvYRvyETCi zZz~2}ckSBkr_+-*qhfm2v*lG4`$+o)+LcK1gs!oL?Ax^bdRp&(-YNb8WWU z0>v8{d_DlVuwK~71@Z@2074H05p1I%df{)cYO-?6t4)}z@&=tMf-~4`l~pEGLk0_X zw#o{!3(&La!r7ron*-J^|Hr?$L*Kj4UY}RZ{R# z={DdUlu!55GJbzPUp}R!&{3%LL(6vzF!Y~fbRq&9lPSIknb+*3 z4l`Cq+3&k*z?$rQxo_G4H^^}7zpd*$B$!U{vYz{Vw1+@`0<~C6oUspTTACX zT%zZn9|7-!ci#Coog09SMTK=_q!0x1kRd}s-9Q2GVSgX&2=ldo?!$~G&pr1XTqwLs z{Do?8GQs;gH{e6KiIXNxX=tW~J2KAMLme+(q#i9;|KlHTVRs(f5$plDC-_E=9F4o; zUo(wt>SFQ|G;aX}06_r36YV>D_igdJ-b#he5H z8k3P`N~ogq)mmsWCjei{iEB?zU)(~NKq3=Kj0}oPbSjBTA|eURJr%7Zb0w{2Ci~6W zAU#?38qk5-f6+Er^swPW(Nx)zqw#>%K?&q2?Uh?;4Y=*U1Sz0O-W^{>_4rYvhQ zZIgGLoDSYtkmMC9ZW%6bK2PfwiQp4^EJ$iIW1;kiKLC7mcOXJ7H_cq7t)AdpwroXJ zl>z&q;guc}69;;smM{*!+uqO5Z^n!n4bDOGu)xPh@WFcH#?2i&c7EZ77ty6#OT-3f zI*CN)yq~YW`WimO){c%2WDuMJyb>_$+R&jx;SB+&wq(f?{;c^teGNfCaMf9++_>xq2I-EvyUAK$V_}vk=k67 z;jWW<=#<`CT}!3zaf#%`;=+IJ%YXmC_EGz{kJ?)>_UppQ`?gOn{c=h%8n#sB0qH(E zxOLQ_ts@W9HEc8X6D+|2O+EtFY4xo+iKN>U~_fT@HYV8s)J|R%~;YrY9oc+{4|hzg6Jdy9E{GO;1gKbO5sb7e8QKz&Ry%W zD1$88!h^5nT&;Tq8!)#(EQm{JH}{LpCBNLX58eQhmz(MjzRjDr@cvC4xdn|1J%cql zH!wZtGtWE|6chx^x_b5M|6Gy+SWcci^{;=ugT8F0)N1tV`uKGJ&wu`V`SMlgBbJv} zPMta(q%k^D;bLN#H}z{W=LUdp$dDm$iQuIE_P4*CI(6!fn8${V=%@*NILro3a#(-z z$=E-cw}$@{$OTUb$Tv*SQ&?C84;4!q+XrcTPv-{6j%DofB<+| z`9fO{>)os0(}2In+C4e^#h2ngTXg;A4V&Xa+tsFxNdp`>X67zb(R5OZ8x^l*Yul%6 zYNbk}0Lqe*EIG;6lI&~`U3Lqls!j6xFkSkqd$;}fyW&s2D;|4jH<+&D_Z9)sCV}EB zq2L=^y7l9OTakSq9m@UqVD2XewgULZm$3dm>gU}xW`FVM10eVIzqVH^w1nmv z2`zKg^l)1>WUJOINArYK?30)N7!Yz7*zXrnHLg}aVDK7EO2 z#Ae#ZHz$dKFNJ|Gjl{}Hq}*+8W(SdU$Y=7O*p)Nkh_GstwZdq(b9rZRoz|>_(Zu}B zHpgsgCYD;tOe248gNL(^mm_p)dZkXotX*Zu+6dNNPD}_pSh+MOJ z*ALh1<~&%+RVJ>wzTiXW20YpP>s>Ba*5cKL_6!ZZ4_n~b2RrWExpV(pV|76XaWsdy z0mZ<1i1{9yo9yw93JQ2Lk~y$snCuCLlne zP@p>I(^WNYI18Kw)B)qn;qwNA@4h)5zWw$H`g5TgK--$aS)elK&Rw`8{Z}nR*=n0} z!?}wTt|Ohf!l#>mx9(wqp}l+c@9N{%!N+IJ#PKDEOD*<{MXXE9QpJoZ8@d$@%p(ax z?@J3e|KK-aiAk+Dt!tO9a@7Lzlq5%et7NN*UMWzdH&diOq0J25rhC3*``br~Km4wE z^uaI39^6TL@%C+nGOi>K@He5fVB&%N2?w&qm+C()(T^#~`M5Oi4;Y2p;mhC>K2%nd*F#VYdnN0bWnsagAQ4XQxH)G5hl^JQ6j0gP~tXY-TRW=m+T2m z(F{Nvm9shPxH_$!6D68<9jShn-~8;;Ymv6Q4Wjn(BJN`4zQpq;E*wTd^vP>fu=c5Tj_Ibfr~mq0~y z@813Cr=JF^4PLY$Vc=N@7GOs{qI1lcPn|=woQFo#61VjLz~|hL<{WGYb*reTdhNA0 zFc1&U0?&oV2M)GJ8x}x6Y}l~t*RMOzzJ$Ai%k}ra{~hQCwm)WjWv_#K*ZK8-plKIiF* zw`|$+)KgD|g@lF#1P&hX^i%EH_v+nWtkcj6#( z_%a*SdV{l7paj2ijk{h($9tF!znuSV)U;_q1D^Hi+M`ojzX1V*-+yD|<=@M%->7uN zV{?2CQX}o`qyCKw2ENDUt^qwohi3>gK;^l{C`nW%5hV#?lih`4Z=u+I&iaw+Jy-2k zGtP-?Pwi*HJ=ag_uxtWU`I*=Y$%@HYX#!=A_5fBh&`%L>Yd&L*D_{;7$I|nWIFNqn zBv#@csrHCayF`my%w4l|=l9nUd^U^Ckx`;v;9I(MsZ+g&81a(BuJ2zH z_~5Gk`s?Z1Uw(B3pY!C61qB5-{Rgbuwrv{`5k)g+Sh>oZWvp`&)KC=-f}=qcmI~T) zWc}4*0VyG`F8gHfuF$0Qosu^^E=hDrPav{X&w^|UKD`EH7hnju<3WqkO{0WAfkXnO z(p4(nQn5KK&=vJ^+cELqSL!-)NmA7IJZEEnD?H|&-3BPmPbm@+kv(^bj zlBNb9Dn4Eo@hvT+CFYGmJ2$}~S+#xuLJ z-YCug@aXQ3zTf#_Y5sq|){id9{`By+j}L7db!f+j-|qVNH@jXhEgG~-@0TTRD^F^n zNbypOy)-fpo!V8ebZkBeIn;2$z%`12<(ov&twZB5`SXW(lyXEg<1 ztc(Yr3yoz-1@H+X(wYJLA`&JReACq6V}mcuMi#XQX7wz^u2!?xKLGHpTer@+BZZ%7 z(_k=+9z7b`GrU}JS{WRPg+sV7aT6MbKnFNbc=&wIDa#W!?^@d41McHHY8K0lKv$iw|_?){%!PFfwV#H^kFTPe?2F2d64Qy-z4T0kfWi*igDns6P z9G7(SkALPUf>PIcB`j^JPi>VaBbsEQNhO6^QkYFtQU*Sqhf3q6)HGM9TgjEJ50%7QmexwTrHy!9P*(bg;+%Jn>=^m|t`80ueXu|8{r&m>-oO2W zqx=8+a*;>58J9BeOU51B7?5>x&>Xj~f715|@@1B~fOAn3ILnA@O`Yd{OBnMh2#?Ym8hFpY9f)3gGhu_RZh?z`$p)8mrma z%~5^Tdd`Li0KSzgSEA6nd)m3fhY#b_?-;ZUzX3b}5rA~)C&8S37|a15>h;-t)GNvv z43v53;N$0vN9atOHUl#T1Nd-K5gd66;6tE5qlJxtfFStS($dnq_vS1rj~+b=cJ9+` zVcmSSjR2WGedZl~0{?U1`{R!*n4uOk8q{Lyo;r1=?tCY;+&t%5OMd+E$FIKn%EAUB zRA9s#KNP@7JBncQcN^75dpK^&{*u6iwH=ezJ}FOZn=d2kWTHxSDbx@s>U5%#kiuN* zWT2gEp!n1vwY-%|Z>1azUZUMfizb`sm_W3;4X|Z5p3<=mCJwV6&j&1MtmO?gsEZm_EKcroQIo z41B&~#flzmL9>_5*+vJ1!XEe-4s3F8tk+(9d^a|8Pg;iCQc<4?{bh5zSF z-6Kbi!sS9mTuUF{bI%Psd-l9D_-d~Yx$nCRr~USDhceYuD-~!YL?@$;i(DN|N|;{t!k63MEGd5L!2TEZ6o+QzwoOa- zPD^Q}QMAd|y94ahVzO05a@8b9g)S7AEHHJou6nhrR_dnZ!Kb!^FDr)>?I0=*Ek)Y} z1%*VaATq^MTXWl{Zt_iB`$o2Q<>_C)W)4uCYPQmBWN{)UHo1_&T6Tl|SBKQQ+3f|OpjZ6nq7r^&v?tupYKE96+OsHm!{ zdhfmWfOiNcHqUGyzV9ESJWg;f`S5^xV?78hbay}|9lAw;r}^P7nkhpTpSU6 z&x}|+_+EJ7MI7wGSEGU8bDm9{4+1ip;oVB9XSJF!V2$O7r>T;6-Q;Ez?CZBaJs?Ha zQLc0orxIzZTeiYgEpt^XC}Jq=)Kq!tv?MzV!3Qdgeuyqz5NJ6{#wmcKp5$mLA_0h6 z1yRX~Qr1kZYOB^hCD(MwPey2h^jcuA7>- zA$W7b_#I#8RoXC1ijiitHv;%<*RSBnSnJJlHVZ|Krf%82z{fi`1hL5v(z(In`Rra@ zIGvgDFI&xC{{XhYBw}VpbnMmyzQ6tL6)=jO zfB2^q-#u?Gy}uR%w8S#A=_VWRCCn-suwYf_>QuiJO?zo}bEV!zr6L+&mfBsRYNpaQ z*JXL=vZ-rTqj%9}yXtdUScwz(0C`*GwCKeoTTb=bRt=@0UIn_(B`b?4G+wIgw(5d* z()`Dgblxi^ZVM7g%=%_)B`p$Ft)*G5RJoq&Z0Z})YAH7XnmJ5h=0MSc;&aifXn&s` z_NjEyQn?4hYa`dR+nnaJWYaT?H!j(6;18zj zSV%Aq|6)L~VDOx&7O(D1ZSiAs*La9B=!`$HQkM3eB`JtWLFa~7WI8Cmaa#{Q0PtaO zA9{7c)NM0&y-Maba=NGbEa`#@4eY_G>C=@tMjUTrQ zmk2Hhrs_mSz#$N_{8VHO5Pda)4`7YC5)esfq&I9Vb4{Z-%FF2s^4)je<2!ksUll-G zco;CG8EP_eu0R}J;*GCP+kzFc6Rlx&rdTnWjM zk}NQgsskSvs&vVjGV2+u?o zs%O-yE_0U7QSUm#GDO`PhAMZ(HL(?yUq6rHNqc$yTY}mH38Dmq2 z0((RJMMuXvb@Q3;&QuBls;R+;u;Yh?Vd%-<|NeKLdd?n6J{A{G3eM>L_dme++qx{E z1TS2;fR_mOh7uBwf*Dizy!LQY-g@h8P(zJt>Z07n0VMF@xN#FObjDWC#b7XDG?KH4 z%17QvBr;6Nhgio>QUorn(KC)UnKo?(zlZy}_!|N~I@$>ukJ&)ek8^Ysn)vkD_A?^9 zBbSl|8_9ABNzjwbJXckLmpZSRItPloQcq+WqSS)c6X_Ms(>!BPLoo4S7*#xvRH&t9E##6_B-BvRF%aMuxw? ze@zqU0F`*N7vx@gx)>{Otzki`;szSRa3y_xeGy4;S$H2YUNM}n4%8p4;aCcVs$q(( zmPDjjfB09}|ClkK{+WDy7=rHnXIWXr!Gnk4{=%W*SOEb+IG`K79Q^wOb5p~5*|HV9 z%BzbHr~cq$1LiG;N@$MP*$4;qmVFvj^O4g`IqP}@%?qjNaZ&i+m z3Z$Q&1?Yha)6=d!m5TXuHC{^U(gpT;Q01kh9dKakYEy|iL!gm(XtiFNEKgaEdqxh~ zs3EIVlzQ<}I;=HTMUw+Z%jgWS@hSE}rpqNRn>AkIt<6>W9?Bedb+#K=)-+~CMIF0# zxyQh#NAM{ztPhGO7{W>kk*2#TB&{{t$2GcEVujZx30a&@Q`E&|2o}j(M5c9^zHXLm z|3!v59FSYdfxU0N;Ybwv2z(7Tb?=C37Kuaw0RcD~30g0-ZPYUSSW(y~zWJf4fB503 zbLTGHZFutRdjR0WL1u6uFi0yaE8l(hT`)y!0w2zih-U%K`_iS$b%~PU@d}4Hefsp^ z!Gp1{llKv0j5Klzk-^W^dEai(dVvqs7Wz-%^Xb!PVjp6C6(3$z5bQjy;018`^3}w| zLC2AY=j1=n{#?dU>m4O>>FPOOXZqa@8@128b`6#zm(EBNt$Yu`CEaH)Nk0 z1eXLPSTl{*TbPhJ5lubz_Hj#Xu z=DtqhovicD(0j|XT4-~;^jQM6il`J6d^wKcaXK~Y=A&BA4nB>-L#^~ss+!9+t);qF z$tsUk>10tNZTzBi5SU(zwXH>x4%0Wx5SRRJ7k2;@LnT*LM%l;aa(e{6hJw$zCkw5) zYuBy~8#WA`p4jmCek;ttj`I^?e_!|RewgVG)DW+XoX5;QFvW+9R;z_W+%crg8G_iy z2atjj{NjtHywa%!5ZJ+oM?o*gym|9LZNVNu+2N%|QOsL{{D23zK1D@48rQjjs706S z>#zTP#fnwSm#4Vbp@vDxc9gi^9lPZnj7I0c=# zbzze0(qzw#nVxC#W^%2kTFXX>sWC_ed)eI7_QE>aXmQtQJT)3GwYHf6`9KE0Oz)MU zb=@eZX6%9#Mz>6wz6lD>x=n}BXHY7|Nn97oT|oN9q)_}VOmSI~>bX(om8xth%koz1 zTvcjn^Xi$`B8zS4sJdjnT?C)fRiW_K>RajZTS{|X*DJ`P6e3C_QAu74WCF0PMPipY zh3CBVC#S3j@cm&=7zO`TnYnTUXD}e;9NAMIfv*AJ}J53$@`$wKz*=?Rz% zRqymCjqlUAX|g@RN)_t_i7K)>lPpdpu_<&6e@upJtk^X=gSJUwG7%-y&*RcaR2rQe zCsyhno9P;p<^rEbCz6;=_3`NyG%b~$_UO@oK8=(O;gD1E zs?=@@om;w|tXGr8nKUc%d@+d-y8&c@uz;$VOqcMab~Dz`k<(Zc8@hC9aNbRtlLnY# z#2}YP;A^<4iyN464;=+_=g#AIi*(}y-;jFPnKg9i@J^k&j2ZLkg$oy)9jx5#2~L_0 ze9rqXDk=ga_vxpBKDWi(I#Z8#LBz!^fS+QhUG4klWh@d9@Cv6kapGh+eMA6`?ZZLA zNI+QQO9HMEZ139jRbzn7h#4+43J1Hh)$*Kiw5>l>X9h1OGJhsGTlv-?jD`y7Mmsjn>S`7S+IdD z-Qtpv>8;SU(B-;mwL~FfZepMwYCWZ=O6jH4cqw(Q)cGVyMZQR*nlVl)h}XJ_w1Nnr zQYN#nr6gA75}DF&&W72ty}zRq%3`Lu+-)q43tVUef)6vrJCfhg%VlEFq1S4brnv2# zb?(s&d@(XQd83FOA|}-pG;&mmn<&+5{*$nEpP-v#R zrqdx|c9t2cJ*~nwx`?DM416Spfp0;o1AIybzEw+aOH0+r;JYIQ6aMRuKmPRc%dhhD z3IgCjD8UBKuZsBK({qAS*tBWWjT<+dhXeCnZ%u9Lf)GQ`%;d?FF>7@H{{1ly!x?-S z;DXZz!4=ES&b@f?(wQ@7p`1N?{Y_dM-e1w9s)U$WYwo)3u_hi~0EY zVaS;02KzMk>?!7MpVaBT+P2={vsxX=>8v!A9Mn$s>1zKOtJ;RAx<|2Q42?Nj43Ys0 z^}5CaN)pI|1oHV7vM$pjL)Su+-&~vTsm^v+>IF)Tt4iyx(Ryfg-l`n3TIsq}Nfv=1 z5)&a6bVLXnnJyv;6oFHLrg+CE0x(FU=_FzFpmgqtBod#>=&q}8U;IZ)>42t z6@GouF0josk+a2YpP}5w)jI>TW2PZ9>w>Ig@2U#wjIJek>zYPHz1s)NegeM zW5f*H4(zq;%@#~q1~(60cW=M_b^|8ftG9E*iVdpTOxvWDf=_qG&~4_L7W32T(5q9a1qw|w#e=~HQwWfJQI-{PHDm5qYQIy1FPz)jd07IXp zfki1;t8AH)^Q5BaDdqN7sd|^SVzM-me3nFF(kSwbU`I+jL6g=p_0b_!a%Rgo#$ZWKtwWs9l8` zP?QM1KWYFU%N1|tZOfX#M|%tz_*`frQaRuT$7`lqC%IVUgRb8t2t_|V7#Tb0i(itd+M`@a8rg39qQxb)1yZZ%vv^c=1lC_Xj<^uSWBc0+`xvZ z+HMD*NX~1z9iEUm+ZMx^+aMp+by{s%R%pKA)?JBHkn}m z7hjNoLh0jtqd7dd)70ahELVC}t0H{N74u2r!h<7nqq= zY_|O16EhM$qZER>zy~IOP2jUW5XFZG+q5YGeh#8<@Ze`_Z!KC2D_@rxiXRsEFsB1Qdphc35P+ef zq0c`1EPxQ?-k?E)u3o*`u!;BT4L%e0>lm^M#E@{ zLz;;yg=OHM^Q{;+$^4n7n6+z!4cX59upnw=#| z;W|(45v3tQg=cJLoB123L^OaqZeQRC(CbXRUcS+rt7Mnzv}};uvI{ zVe;vxpN3O_=Lrnny?ggwxpIYT&^$^F0Uu83%-Kxv+}9317m?guBy*3Fx zQ9ywW_=Lz!(@HwB{YxCcJNixa!c`{XSObD z`}{;!$0Wf#_&`J&t7$%cE1PpezOUuXO>nblw~p<+0&$fni}`FTL~fR0;~ z+%-}LYfqsP3N$3wa2c7BMrLHX&XNkIiOIxtmx&qPvs7(_S@2C7*T$5Z!#%>f4(*t` zyQJSL4(d^th)BjC*CPtBqH>$3be*jr6Ei%g$eK-4xKEXm3F%}~n&)h3iztm(gdET; z5K0~F6VnpUz(*m)z!xKK7JeV_vEUWE2lgJ|%Pw^WADwFrCxk*P!_A*J~|C1qcv+#&tg&g0l1xrTzz>;T^_QyPUvhVmbcNvCF22 zl+w>HVEXi#=;CN<@ac3}7)XrZL)}*kBY5w`19t2J^#%>1zR{gKck=A`3o1Sworaf) z&2knD?-iji`smT4n9q@aa`-t(nihQ3*n4le1wPF=WBX~#z2~PfQ&&M~zZGIjM#JBt zwNL~i9f?qra3z^3B~vrW6fv11h2kW`?lCGF@B#RX z%%D5uJ-jqe0UN$1OtX7$oh)3iZ9(WYkJUF5>fGn6sLBK6P06I3og{IAV@*)e!VU@? z6ik!~CS?kyWVp=`dxlHBfj-enPY{f7+$iSm5Qz!2{8$|kWq8k7JyBM0t~T%)%;@dB z1wM)`c(N{9x%i^*+Rs@_qpxE!UE>vO9`Pg+lk6Iu=@l)fVc4^`bQC7N^mzubwGtzu zEhej>jP~+bOr~qsD8X!XEl{5d>cTJ>sCR|Z&}IWGm(CXl;4@pQ%xu=?^p)QYJ`$1qc*OcOyN{Lek=3@_{0~h8KExLKOmV$`{{crxS6`g40*;H3y09G( z5Cpnl@Ze_=d_cg}tJm_(s;sPr4UI;JG0(O171jhk=O`K8j)qFU_Szem2oI@;{#=|$ z7l%^7KOv6cYYp(m)>QCJF>@DO1UO|(b6->7bbq$^`T5P9IrF|9e6=Sjfa4AwIvlSR zY~z$bja6QF;l-Czryk}1_W?gKorT!x~u&JBCP%1Z=s-Z5~mu&v? zH+j#`V382iP@>KRC?bVGq#;5riPDhyN-{@AsW&Z?fQ>m>LMF>;nWO{~xlB|+0T|Iw z!1A4$PUd8~%$K=FDg;6rOy?@HYe0K9T(rb4_kef8bl{Oan3*0_2F5kDZ6nln+ja(^ z7QrWFM^s^9$GrtU(0%UHGCgNWn$3|kpD*{0ltJ+Tc1NVTE>gS3X0vliZxgX$mUh>@ z6(4se_$+o`gn<=m>aHmM<*Avg-KmQ?!!1rqRqBEy5}N=h^oV9L*z=N~h}hCslyIbq z!ihy6!`_V6sv9iNGaJZ(gU{-=uI3EY_MsytI}llHOSPfQ#$@1ijyu9}{o*#ZjoUwo_9-$RGK;aj)SXwJ#m3f~0w)#7!n1$@r+K^AY@wjF)VC{i#K z1G$U??69jIBQxL=ICLWh`XcpU1L_Rx;lp1*2GuZBu73!N1|B+eXmN3|a}L4!f)D-I zIF4}2lxZa;r9c1tOJkKwmo8tudcC~7vi4a+9~}59Ef~o`Z6&kS1d31fTXp9dt6Iz# zQ->hyA%e!^E|PhO)b7zB^i*V?lFX8l>0(MBT4ZF3+z!6UN?;!kBl;)kK@fe@GssLa znIjdFVACrR8VWkT_sn&~-1+I)_@)jU-T0BEd|x*+CAUBOh3lQo;Z zd|X;~O>umdn!#r>)6`WdN3XP-vb=dbXxKD53K(qO&yq>(CK8zlqK`&yN71pmooB5~ zIeh*q>sY9&HZli=*?R3JS6&5e&So{*taMFN$J+;pnCZ67bjKP^Z#p{HZ03xtYSa)n z+2{|gph9mN=y;Otm$**j;vS1!?;W2GI`?kyHJh*WjLmE{Yvq>GUn@8~tdX9+Jp)~n z$MIoE3jgQ%^A}%#{qHFBu)hzplj0ay{!eu8!Wx<-3tOwgousCw^J!h`3qB+rKVc(| zgdabCBG4A8=X}=42!5I**e8CD)ozpmF9001%IEllQ@aDKw`Yav57dLTkB^T?Bw{MK zvH{?O7Yy%nfb)VY%!ds%O1bCD&pF@Xg9cv}i;mzdM%p{h(If?$GgV!uuWA*M;VM!I zq7{N@ncb5cp>U1Rkl8Xyy%`|%GMKRmMM@^gZh`MsQIRQ1Y67DzJXK6h)Y(!HZq%_D zrE-j>p!mBLz#Juk52?x%QAY|LXEsmn8m?f{Qf#+yoxwMSFLwAM_}nIDLUElScAF^n zm@M&}E^j_Z*?gX|`2r2_luXMI%u}>lq<(Dfy78&mjv;IJ2A{<-Ru|J0Fnk%{w%z17 z^=ZT76F+YWrg~%=4Xgp1cM*VZGk_1+P2!Yvpve5h)-zX6l<)qTbqiiFn95LKBIO*u zS%x~UF2(*EoD$E((x0(SI!d>k&YiR%=ethh7rRYc*7`Gr8yg8@2VWcopBDq4SDXaE zCpmVh0tac+@g(-Xp(X_%KI{BzpPxWdr^`acfg{-Y481sq8Ct%4E&zZIe4l5ZQmKY| zf-Gu4A0Iyej_-K{D~zB1jZd8AdFL5Dz2P{l^F>BhvwzfKHkFd=P7Em2Sv+6P4vI(2 zQoVKE6EQr<&4^gHdBE=;>1rXyJ zmBHdjSawxWX0xcIFj2ymqrabI*xA0Bkxya+Vz zFj_b`I23FyJR+Zk7zgmfcV2kmMbL@Z&8Jdn&_J#wET$Gy7n?T^!8vonvB%JPumN^d zLB()nF;oEX2Njb@WH>hnoL8e1*c+@-Z9#4S_~Xig1&cuX)fDmqb}oRAO;|k8*VlLX z^5qTl>SD(tCV+v%O_(r=zfesf`cP{(qS@P!>?};{W4d)SAVB%^jV_axwVs!bqxxMV zWrFYwmszQxlE{<{rriKTGQm{2>lC?QvJBwjGC@MulW4Kyk77=a-~&7%q!_0Vf?~Hh zN+$i(z&_7t4edaLCK@645^21mw17pyTsbvw;h>XgkP7YBn<@d`VWI4sB&Wx+D@w#- zCRE@y>Ou7;%j{nRSvp1RI#1#oSwIL`N1 zy@Kc%Ocg>ERXT3Cx5U5LN$j}cLhm4iq&rEcUJxMDLA`g0=9bt_ToZREPF!Mx8@2&c zRj=Re|DE~nM#~9^aj>0#a`ViyTJ7yl{pOwboB3u&jPcokPj3T0iw*c>0en`5M1Ss) zqtmPWQ>&$vIR@!#-^Jg#M>8EZQi{ul-UHnY7ueb>d60`q^>F%QTE0;boJh|E{t5s6f@`?Bc z*M7j~s;-=rSNn#Jg~pkriLXZa(Sc9&_R6+N_n&|M<&8Jq3}u$IS~Nv6b0y^qPiPB2 z(Ky$viKoxO_{NW)cyVjti_Gc@)`@ob*=JwSCZHm-G`}HEL?k#SOq@IS2092>Xzu^M z6I*WzTg8`Oe)XDbuDcNM@ncMwMGLMVeb-%g-H8(?e%O9|WHO0=f$3m;@?9UNWj}44CC3IQV>bkVmZD}h__%eD3k_hw!^;_HMvaS)d4hRc&2?S)r zh+u*Vt*&dE_|$EUv=pdU!~C*ZCF8UCr93F^U6wJ==5xs}Yvd^0#MN+)eGDjTypkHF zMLQ7SAk}`agvu+|@6LSc&9kzs9K}07@R=Qf4^-;|S^h=o3;ya#D7N0JS|3%lr@9gd z=%Z?NOWH4`JSAm3EoC2+vRVeFRt{gcIV5?*yoQ5C?|-uYXvaTIjHVssWbNd+{zShg z;`uRtJ;Ol|H=oNgkn|NPA1SMcCfPbM+ZKKZFR*HVuI!6m1NRP<9f848?6H)dk9+LON%|mjhjGcQ8qL* zk%8C`nA}ieac5_DVc{mi1+h&N0iW0y9sh!j(sOXJ{viHuy8a{xsan2#<%JG8;yY#G z3HpOb^bC_GO)4)h|6xnkD9d#29b%+RU0%9JERQy(zq~kj$-rmd>!(*X_nP!1@u z%}BhovPoLF+jm9jz!g<)4?i(%<<1q){NueI*>2KdQEn4u?NfD4Le=Ho$hKE88qpgb zk>$nhuMbMvYPy3Rx1IsF&Tv~n*H;YR4;o9FXDnBs4^x(qMCl?p* zU$CqF{w;NPY$%zPvn@Ph^T;(>qtfCffR8ld zR``Q}^c%wOeEa3b%BMR^Fup+lc3=U6VI6RIw8 zuDyHrU+7p%TH8}@%q7$i~|FY}xU3jL)B}%XjG$fHF= z?$5m`tGVuD?Ga9$^bFK2rtS`A$=!37tWLW1J$$oI=#(4~spGQPmxx(R28$Ietm>m9 zfyqz!sY=*z-2Yp3(s5@mAG?5BjJoz10<-DHY!8GQ8uT zTs9zKcfh)x-_s9@-#Ij4H~jE*>^fxq&Va<7{>eLiRXcsudwkR-2o{06r&h8pB)B#B zz>Ion%^u%Opm39kP!p-k|_B9_*w1K>p5BB{e<}4R(9@b;Wj!{d# z=9+7u!O<>wKpa9nAQAk=?`%C z-g|FINXX2YGig0Pt`QLt;G%$jGH(Q0iJF4$uN<{hLfFrBp!kpNr0*kJeIv~#My$>g>}Ft&!sKyY@Qe7tHI_M)`KJtSkOG+;X3bMmAK!y z#bwS0X?BkH|84bqaL?eybpw|*gF;FRLD^b3asjpuN-LfO{JAaJ>$R}edw#R`f<^$V zs}1=01jvdy+c4t&yZqz#4_I?RdbCPf2+r6B4E0&l;`!^$xvAB;&wl!L55sq4vy-Gk z*DGr~naa=5-)OSvQ6k4qpQN?1wi#8i53|`~>V$r5LdW`!&N3}y%aEj#3^uR5h@fadi`0LuOk>#ywliSNnah>RLB-y}POo-c4QS zf+w_h16e-WH;V(bP82o6x-{Xz$^BY|j0rL(&D%b3esREk`H$>;_Tb^(uk9mcTEcxJ z+nmPSeTGmE($d-6V>4!^1rkc&voStqHry#&5!8~_=ZCM^=#f~#)`VnNvvYy7`5AJV zwWM9r{tm7wO`QFa2Nc$`#UwW4?eBL@HmIvSi7oI$M z@|-zy!1$;x#JDH0FEB6&g+>PxBaO;U4F5-gk4`h8`#0Wrqpq&**zpsz#gWA}vSqXw zd#xtc61w#IUT$~xHJ>r8`A6rSne|uB+bI2ZoA2^{1J@pu7FJ1*mAI^~aZjj|R+dYv z%B7W+T+^)MleyfEZ)vOR@-`dfEv%OoHGt*$E^Y}})XIq7J*CnOMbeC1DK^U^F4u2r zf&Yv`DLPY%%ayL$=ym(zWu zzPQzWQM=3HeG=4LsNrh>f@RXe?L!xDA33k!CQZYhKOg;;uednF=SFqhAeax^nXKAw zU|G-EQwF{Eqkn$9aqHIO9o=0zqu3M5EY4k{-Px^rt*(YTBRfNb8J2UO)?!~z%{{$i z+i#U`zY46(u4ViF0}!*?@xGg;X;en@AlZ0WJeXRQn-PRjDfJ#tdr%OR_){TEhyJX-9xtY$!bgU4zh zQL(hVgaO|w4t&h!jvMjOf(kITrHueS=&im>TL&y^@tarY_uC5T>U?Qtt~4#jV_F^{ zFJS71fl;}B;W>U$h3*k~(v)16sRiCQZXbA0>7a+J2hOkcUtaIN0&!JHD@vu6rPAs$ zX>GZ*wt_{9=gaEYbO#$`+$SwL0O0dk|FraYsmuIr1LqfpEZvaQ{MtXd*>E19%3zUu z4MrNrXDk18Jtl^FCbL$HOI=;Vl$fcpGv<7L^gFZMH>Y8>D(r`?CX2CKZ-AC;InFzV z1vP&dy|i$ADhOshGY?K`^H8<9tJ_>s+N4zO)7ltLX~c#%wyhsHakFiU|1Yn65#e4b zZ6EWReNsC7UN(7R^H8+yp6&nK#*jC+kpW+B3)@3M)8MJD9JG4#b$Mm4YvpgPbf~6* ztsQ1FHs`GT|G9tgCXod1``;bo zBhpu2Uk}C}5*mK>+#C0lS9NK1Y;QiJUfbJg+gja1wqkr`sVsLGO((T_sD}-o%fBvr zeduFPcs;nmci|4#1v{mMyP07yLEcJkzGnkI=4l2Nx~<=mRuDb^2Ws4J-@$a-X*tks z-6Au6BC`Q`gQD^VMdS<&%NaCf^Ps3L17eCiqw=K4ENND*&+S_R9xNWRsK$R;mB-2| z4zFd>>QZS@zBQ#Zp&|I|Fn~a^9<mC2%{}~xCeu;9{+KMk zct*Z0r|OEwH;jz09+c2DU_DzU;+fpWtoaD_7#_87Pt?q|%b`mO8?F1Eo*!Ja|N5cAweGR*7WT!zTg=GRO{-tClvlNqJ3DVsSuzi|5Ks!xp4%ed`d?e5_Z?>so8> zJqzGt!yP{#@LB9mJUM#w=tB=ZG-=XgI>1b6cjAxi!Ty>P*4z5 zB{88vt%*SJ$9AZoq@*P9O>khgfx)a%J`KR&=KDM=+rpP1$3#ZOObQDA^>2Uk+zZc>1R4xF6Cd|68hVKUnoYE1z}R6nL-Tz@mh)aYJazr< zfCq9$t*96t-!45`&9uv9`=sUV((+agd<``E=CQcJdtsCB{6^o0YoXh^-n2!Ul@EP( zz|4&UrWW{4$@UG+@C(ZX>J5#`A0D%DaKxrzkz0qvZ1ImOa1T$HqEg*vXM5a~?|b)F z--mYjF0S%k$*r29@UE(5+hHwhu-WU`mT)wU@VExrWJ4tzHZe%D9kG;J%XZJ#lzv~I zR_c*f#eI#NrV8GbdnvurMNj%X3xIr2W3xdn?2t;9|WwAhZA z@<0FiDa~n!3i)3IKIOc7b8~ZWa46Eo0bdUQMA|Eh^&A7ZR@UsmG3c>5Le zH_qGf-2M-GPIGe&twq+EfmQru9sr-IhuJOmcJrY+`RS+raMR6q1cgM686P}hQYd_6 zR23g+jXpj(5oV2j<&|R+`9vlCJzlvFw0C#{ye9!k8s#y`1?pz+9PoS_!;oD)ZhcEDe6y z_0qbX-if=%YAOalp8m^?b#HXDq@L>0G0(mpj+119!GRo-sKAQ#bgAX9h&(4xW;WEA(9d zs9eA3T;G^n-{^e*$U^3$3jCw;`NM4Q*ldrfnXWUkq#4=L)J&J#c8y#4+^}WOO7}N= zFFfeJu+3{po5#|6pJkO^i?;bcntOF-Rly4%95yktWa#Q4qCSPoLt$!gg&}7TT`GzAb>BZ{2S@ z{D)5R-uA`WYipnOT%F~IZbSHX>}#@si1*1E-6*+iKT;*O0G;U8M$mz;L`kMHGh1o zn@{YR?VFE+_OcZ_Y$Jxg!;g4zZQs5VErbsF7Hxx?hhP?HY=wn|vf{LFF*AF)+^JJ% zZn)v5>#x5tI5-q3LBpoy9GB{m+V$&``j2`2{qG;pjst||WF11Jj|`+~YK7Ks0DM9B z1SlidKY<~Oa5VIJ@ZiCakPtAvnKNgSs(YdQA{QvSZ@xK77SW{YKK0ZyWPnYRA+!^s zIPX!c-+1Ja$K-wstN*KjZ+c8*TzCjD5BKbN_Q@evU3bHSkIw((^RKifX2@%>ShYrj z(QGg=>Zdbyf5-Q6u>b;z{XKtF&V1&}F%N7W^LY7)$EyM!tsXSLe!%1PUh`@PKhh{& zyHT2wCWWVZ#O3-=+c0FtrlC^{{X;T^)-MU4rLnGhB?AtaiB@0J^`?>cpgo2@tk zAGc=~Cp^+FQZiXMLx224mfL#dwJ*MX?bgcS@tM-%WRHaWAsZ^)(s#RNmAmCsyXDj| z>`Seb63e9cQntOTx>-`Ue%~wJ2TvrQR@di~tE7}_xAc0pE;ys!E4|Jut#)8?<(So5 zC(h5lyRfO{liqLmBvqGD9Mb{dv)e6l!*!kg@F_HBFg{wnfF=muMieCJrj0wJ}dV z`84uHM1Ibkt3@|PSw<=06I==S{+k&efG;*I7??M6YTWFZbK=nBMa70j#?HCn=AGqL zN6&N`>>D7N?A;vmI-NPBJ zr#>OYZVFlSOu+owL5s@e04OnfdB{Z7(~;(a^0o^w6|y=b2u%vw%*1 z`|pPzT(EN3xX_T;tHy-Ic@LWqI{jJ>d@&Qi_(H-bj<*A!#d6MKHF4IDZFdv}BHB$} zx;PgG^1gl6QvUX#<#o?qoxW|3+b~^5!W>l4X#?dNTIvg@TKVPV~ zG?sFaLtTH6{>!dFoS>j!#7LV1^J598T$0D~Ul>+ilhDHMFD zy0ph1^2iTq3#0wMDC4w92K~x{1&exnb;|u>|GR)MCKh-%Gd6Zw40PV;xEQt@TI}>$ zQB!A(4+;&AihXFo;ul_fotnfMJvRa2B#`Zf$xp=YGIVvwmNVR(?E{0n>DiC3U0HnP zUHLxOWr#(*47;{K7JYh6`8((gE_^xObnL?GcyF zu`eH<6Tm{>s7(Xow)jMC@Q%p$3eWM3$o7xR4`3Wn<9b`l_@zbagCD-z!<0BZhap{e z7hiqRWwse;bAU3)XHOamib}$!UgtY(!nlZOK)nf(Gk|)-CWeg(iJTA?6&Ml$;Ny(% zMh1LVi{iK+%eh`zxct;di$!okvz4(Y0>Mx8@*j^HH~!)Mlml-ssea*}ZS6PaR9&Sh zosm)!msT=uV`KDY_~!3(joZ{Xqp)uFhPqjWH4gr|CmL?s)&85RXCG^OHQ|L1Hh*}! zrGrgF9p-5O6+NSqJ9=z`7i>BjjL&SL^W?4e{ryb5)QAvOR#xA7>+R4n@3`X^x8Hu} zFMe^?op=6{JnrG~{I=WfsH>|JZITf1@{W9=?IAH|&U8HV&^*L=*ImED6{!-5`JVpf zn{VB?akCOkJ36{rTH0>9=@#S#=zuHoOB>-KzjNo_aN~_P;~_r8uLxnqidAA47Mh0< zMDM2=>9cZ&n?r{V-E+@9_uhN&4L96yq5NKV-St#Q$j)1Dz0=*@OP~+NhwR|_Ew|i; z*N|U&2Oj^TG_JjNE}m#K8JBl6zW*%X1Hp}qh?*8Rea5tzF;THmQ=)0xpODb-nAqt+ zz`)?Jh?uGBtlY!j9HRjsJt&~<9BUIF_3JUo+Ab@bGe2%&wBn6#<@?o*L#D6xja=&* z96xkMK>#$<=sY0ZfXE!^xkILH^a{%Wcl0Iz zpMOk|XIM6{a^$QHL#Jj8h)D1YUF9=n(VeN~ZHK$Q;Wo(zo+v}Njv3{dv{t@Dai_l1 z%qiPTzkl`D|M&37v0>vvc@GyE5_^&8GKPuury>Escyov)zU_gYNibY2rb-_4$j{zvzU z-Pli`J`3r`O;3*&9*w7~s|Q#57x$f=-Lwf3+3^w({75KZG@6edJq}$J>48TwF3AJ4 zPMkPpABEJ5{YUAnUc3N;gY29=+lgQCFWENZS9}P_IDY&D*@Xbs#WFPkd_RGzi&6#D zo;`b({_W`Kz`ahVyGVXfcgWO{Bi|5&i8N9%q6TrL%%TsVec_?|BeVFI4#c2U%>R|Z zH#K5POjPu==omJ7J$>qot7gxcIekV<7GpC0NXQ ztCfwUL5Vb5JI(CKM7i6-8rw;eyr=b}tMADf9=&2nbh=+;&Y-vr0kH+{p&HNd3^27p zGd6nD$X$OQ%Vsm6&Y|SW^wM24f5#FAB9zOA1s>0bcflZXIr;e z>}oMh28$s(rJhi2ivSGL8L-$v&~rmB#gcB)yM#3h+p%sMH#Nz_v(A#f?%< zXBElz-B6SZceN}+#!R~=JbHR~1k>5k)Pb#yG6fzRaf&EdJXD6E>5C)@IU z`gjLmFv@hW1}o~`ZY?x5!WM(Y+G{d&n{~a+pvI(Q=Vh=~^Zh-_n60hmSK*n?N?Y3M z4JM>oXJnOQ-&N3H1XDXfhCT4y1jj_9|pbLsOA zo+^6++W%QrY#K&X_rDhS!lI@{#?FbEepSpgwiqZnGHO~(^qlE&bEd~mjS3H&92gZI zGHd4asZ-hhuHjLU)33i~cSGe_V-K^4GjtOiuq9tK0m>VX!N62JBj2j?;9pF4Ep77& zUf~(MdeF3tfm5@6;&Oba6?()Lz=PJ&3KR7>V?Bt2#gF?e114Bb6 zB12(QLPDnmPMSP%5*`ExhXhUv8VBqPnk;}Xbj-xb0KQ`#It4UX`i{Zv$M~!Y#>Y=i zW6GqFA21*$L)daj-dh;h@fOBjS>Ge;wX(si)S3U~)#|933UAwA%<8}~Eg*e%bL(D{ zsS|Yq;M22R8Tx=v`4v}*9a}gx09x`X4)d1#Rz6sSHLp_4E~Anw@Rz1#fAB__q9rR& zx)DvCc%@j`O1RMfcn~vpVoK+yS+z#d5#D`I#z*-Tl$Pog*`W-IDi&Kki_%se!1Q0M z>O#r2d;7Mo(J>C*?&9zc<4xgV4?Z&QmDgUS;?nhMt!5h>81*JA2L(Ean^_E-7z~xx zy&X1t*}$Mjheap)Pf7QWEp(0C=sj(xN6Zr*F`EKrZSji9at%rHpPJs^<_rp(PCk9=2(`_ftcAL)O zKo*C=Fs0^2N8FM&3g4scHCb$ObNcjY@jcU3t?Wo#4uY0mqt<$ECoJX%#5lTQ>Y&fG z&93!m9T*Brl9jVvYu{e^?Cf0&6^zNk)*rIj3?z?DXc*06n6ig&L~1{8$TnuDoJ=IH z;b0Ok$el2cchLK2Q%tcf5Rnw|l>iR=0dE%NjDgq!fK2Cbr9c=JQLGgcQcau)QIKH` zB}wFht|FbHUMMI^7=aoEC{TuyM2Vp&L^TPUK9M7env$)AMRDjYJrU(VF^W8rCX0I! zg_1tg=k%s{F48IXAH`4S)xPnZ(l3T4MArHb&Qb~;G;0Suap0bGFFtV)35r^zU)fpa)`0*1Cv{`hRvYkrwc3A+7hmXih z5^KlBtsD}S`0#wn>_h>Kc+YV%E0dF&hSl zYet494x6;(o`-h7{+=01G*e-D>((1jqqPD`I(l?ElkJEy+_dd~^5)xr5gg78Q*aHB ziVX^lxN>~pxS<4RhX4S807*naRKUq$kuj6b!M;8}adIeLqk8}!8{<3MW&R$fRZ5dx zk~~r0Cr_SqXgNx$Qc44=x&N{!@jgYQe8EAil@cb*N^nEz5#p|F0R8nfJ>R87W(VD# zQA(b2!4JTK5`(M>SW%`8GVRa~5hluqUQ?cYh!UXaIyyQW+M7~?>z@qe_QDjeC_@MB z4{s`SdhFOShZ3L<5%Q^1rvwx#Lvz4ZS+RYVm}fwKm5ocJ6CVnc5pCF^nkrb-~Y_==*Vf>pw$NDqBQ(_EssMENLt z0(xJx7o`CJ6~)CzRDMq2BkZGHxpDuCU)>rmsbas(XRGu_0**zq4?A#J)xC7!g`bK6Bj=a5NaAe&Z?j75< zjmg9l+qRRLOpJ+bJL%ZAZF4fg#I`X(#~q)3{_n^4bBqZg09_Uf7)_jKr7RJ5Ulgi+HSrp-8k~qNRY{ zLfCMqGBjkQ-QW1grRrsCNFCEUb2-;YZCKj52ydber%N%Dmz%nzhOm4s7t>RcuPiRY zJH2iY;@-z4X9_b3mD6HmsKuIP6D|Q3LzCNkQ==KdKV%C$h0`jek@DTfWk3}-L)APc zR%+09KQrldhSbM>0tLLxw~hN7;AN(Cg}#0H;XPKlj;-+ae65!n0_9% zpnL+%hpF*c6dZi6U7k_$S?AU*B~hiB&s;6Kk2cqS*-I$A=GfNvn@)Mo@)xXvJ8A!A z311zB3dou#@~}{0dJG5XJ>jFmhB0C>Sl|_%Dg?a?uW2Ca3TGw8izGf-U>1Y=qVP!; z)nyZ!8uxT$Ig3>Lq>I>a$l*6})-Y!hZN+vfBIs|l&Xe{jkEBEk8BpPKVU?ubN?M{Y zd$cm)RCPFXAFkx`7l4k(R#?x1AkyS{V zRQ?Pj%j2r-#)DFaB-b-AqjR&Fr5Z(I@Oj0(e)mFuVScVrXDbvx&1X|vnLxurul&mB zSTs{abH-gtv~5xj#-@;rsrSv4MTqbNAr%cirqBbKF-k9ff@qC4xevx^(m*z_f< zC}pucc13zK#=i{V!rx!}bGwfFH1h{`;7Mx35PrF6An#Xz^?qere@{<1v-#J4ZLmC;Ej!vN6Ev?&v?2JN#KmUFb7zkrFJViw*3Kz#%E?`CMJfoYPD^-vW&Xjd%+zZ(3wiWOR{{a zypocVf`SBs=Uxn*@2lU zE(z{dM8ZZD8pVi!c0<7I$GAYb0$&#w&iTiO6_Y3O6)-pSul;)H6cxCyW+y8r=k@vi6ok|5ajh&X+W~gHCi6Zm{O{-XziwS8 zB_}hk%?RG1^cCHf3`og??aD5vvw1~cFPbOPOtiJzEN95(AStK?+%H6984MP=gQcv_ z&dw@e7r#xw>@7^Drl!it$@RY-v4PnIAHT^1NRmR0<%w6(KEDgveF3Mflq+P2Y zMx2z)*8heT#dwH@u9oB(dCI^(j*}FW)bp>do8k@Z$WDIya65T1H8UgfNdnboHAh8* zt`+!I4M$5$3y1L+1=&8rcOuWiR~-{ST&MRVwg9y-wL zMTnjrpX)5gTJ9SDBe9aj0G@&BobAOKPvd3o+*!{@qxHwj7~;Y*T8yrM^TfFi+1kUV z$tqq!EO8d$IpJE`*Ic~k*kxBmivi2oJEvhC6YtL}6Cr+IkS+z$cVq(iLnVC*0Y`Yv_D}ZrC(dqb?kdIJ&0^=6VQ^S$WEr$uw38qoO!5j@e^$GQmg_%1wwq z88R;zjF3kZOc?`jun|2F(eb3RJTI6*^lzY~s7g=G1qv8p5O+*JmLY}?W>XrsScbBt zsT3x*w6_-v^?>$c?oMXlv)(?Q`r%i>0~s!|17IID^gv|O5$uuR8L+726ZBhTAF-~s zwicjYS_UoGyBAIjL{!rh6hjzixs4wwo}+38Yg_nl|3^;WkAKps(G9`?XmZh*A@PY{ zL5x_v*)G=%_KTAHG7!Mmfxt$>un}maSQlC-QA3cHK}zG3ygR-UguhXV2&{6QWt@l( z4ElWe0--bgKAuk!Ww_?N?vA;+xrL@lL3HY29s2tEfOW8p30jASEDV^v^9Gk#OCkCBXbZsz3N?6dMPB7fY|YvQq4!unY5S zz10?zje_7i)64h=G|QB4O;RO#|{ZGlv2|BUIaN(DKtd6nb`ov zcjhWAb#a&=xN(Xa06iBE*Z0zBCV>8?=q-e<_+-eG(BtaQeH~FCxTiA9%KT&kSu938 zfI2T7qJ-0@>It^wft?+~%o_GZUPoyPOoNy$c}nzaAt}+W0Gf8>4vn|~IB?k1p(Z4* zAxHt{PArMei`F;$qYUMmQpFx$cLB7s9BxTi0Y_$1Ul^Qf}4Jl zA@FYEamXR)IBfGQ48%uJZt#^Miu?5QPczIdr!0`t5LSnaKiY_N4iQ$%No=77%Ghlq zI*oke(^Dk?_asozB=D-im@!W1=U)LDu7aKjb79WVUJ^&q9T?yGg2%7B5dn(1p@Yh+4|qbEiI&*wNE=NNDXFf z*#GF~>Q$$As?~4X4EJ46p=@~LHn(UuRhw3$D86BQi>cEw(AIWZh-+8Lz~KL72wX*^ zOb%v?G*3VLt(XB*10x9q>EtrZ+8*F{5&B%D(ZwP1iWH}+SivZB3gI=&JJ;+71~b!q z0Z1jGVEGM@^ZP=gR(wC-FMutON*oFnPA1zo0piamR+6dY2}V`Ol?Rp~Zi`Vt6+-U7 ztcaed4AEG{sN3uX_UxJzjTVI!%LNuu+ znjk_A_8!GHxb%)&N&}G?469gtp91XyN^eo1N%Dq0qF~#WtSwXwOsMb>l!OmiM9LO$ zq;>Vtl$6C1hj5P^6pKz_LJ$$N8^K`B#75i;J@@`i>M=WloT6bS$yXN94>f^wLjm@}0kk0#M)hRhpgTiXo zQZDHI$xn0Bl?W9EIB4Q=z`7H0Q;1YJ$H2NGNgNIbPZ<&&S`{V?^?==jQUE6!`X%rf zo&$~T)z9n}j*t4em?(5yeVD=@(hoo+vWO(QO`q?J zg^&LPmcE5Ni7kpM%qde?4ha)FKn2dGrT8)8;O$3oY`lEK9i%em(%hxaD>yp9mZb-f zR+j!Hv8v;e5xp9qa)RZRJczh2ri8q8zuJt-fx=FNrMXD&e=|2TqajtQ&WX^{cPk_; zwqvyUwkbhcEDi^cNh0<~sQ_Ia6LBm(Ihi_;%oA0fAyygS{DQ}d-SrHX?x@gYcaTNL zU=XsR;^5AxwG~8z?SV?*P<};fD^SNz|NPkd3H>`RmrMBT zx6m@%PbKsQVxeDDDTcE`ySv;gJ0;xU8EOL=bID2gcT6Jqhm9eA#4NORtaDr-Opj

moW=~!$Uidvv)%8Y82su1u>*Beu?5}5I$Qm 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

V}m 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 diff --git a/ecomp-portal-BE-os/README.md b/ecomp-portal-BE-os/README.md index aa406022..e116bc6d 100644 --- a/ecomp-portal-BE-os/README.md +++ b/ecomp-portal-BE-os/README.md @@ -14,10 +14,11 @@ https://www.eclipse.org/m2e-wtp/ ## Release Notes -Version 1.1.0, July 2017 +Version 1.1.0 (Amsterdam), November 2017 - [Portal-6] Updates to License and Trademark in the PORTAL Source Code - [Portal-7] Improvements added as part of the rebasing process - [Portal-17] Remove jfree related items +- [PORTAL-21] FE changes to OS for AAF centralization and name space field; DB script updates for EcompPortalDDLMySql_1710_Common.sql under ecomp-portal-DB-common, EcompPortalDMLMySql_1710_OS.sql under ecomp-portal-DB-os; - [Portal-30] Failed to communicate with the widget microservice: Fixed - [Portal-35] Replaced the portal logo with onap logo on the login screen. - [Portal-40] Fix to add user roles @@ -26,6 +27,12 @@ Version 1.1.0, July 2017 - [Portal-48] Fix to save a new app on Application onboarding - [Portal-49] image icon is missing on Widget corner - [Portal-63] remove att_abs_tpls*.js and greensock url +- [Portal-69] unable to pick role in Functional Menu Update +- [Portal-73] unable to onboard new Application fix +- [Portal-50] Enabled the junit coverage in ONAP +- [Portal-76] Edit functional menu modal doesn't show +- [Portal-61] Fixed the routing problem, loaded data and changed the notification hyperlink +- [Portal-77] Changes to remove preview image and update the new image automatically on App onbarding page Version 1.0.0, February 2017 - Initial release diff --git a/ecomp-portal-BE-os/pom.xml b/ecomp-portal-BE-os/pom.xml index d00d47a0..a8c19a54 100644 --- a/ecomp-portal-BE-os/pom.xml +++ b/ecomp-portal-BE-os/pom.xml @@ -1,7 +1,7 @@ 4.0.0 - org.openecomp.portal + org.onap.portal ecompportal-be-os war 1.1 @@ -10,18 +10,17 @@ 4.2.0.RELEASE 4.3.11.Final 1.0.0 - 1.1.0 - 1.1.0 + 1.3.0-SNAPSHOT + 1.3.0-SNAPSHOT UTF-8 - false - + true + 0 **.js https://nexus.onap.org content/repositories/snapshots/ content/repositories/releases/ - /content/sites/site/org/onap/portal/${project.version} @@ -42,28 +41,26 @@ true + ecomp-site - dav:${nexusproxy}${sitePath} + dav:${nexusproxy}/content/sites/site/org/onap/portal/${project.version} - ecomp-releases - OpenECOMP - Release Repository + onap-releases ${nexusproxy}/${releaseNexusPath} - ecomp-snapshots - OpenECOMP - Snapshot Repository + onap-snapshots ${nexusproxy}/${snapshotNexusPath} - ecomp-public - ecomp onap public Repository + onap-public https://nexus.onap.org/content/groups/public @@ -99,6 +96,121 @@ 1.8 + + org.jacoco + jacoco-maven-plugin + 0.7.5.201505241946 + + + + + pre-unit-test + + prepare-agent + + + + ${basedir}/target/coverage-reports/jacoco-ut.exec + + surefireArgLine + ${skipTests} + + + + + + post-unit-test + test + + report + + + + ${project.build.directory}/coverage-reports/jacoco-ut.exec + + ${project.reporting.outputDirectory}/jacoco-ut + ${skipTests} + + + + + + default-instrument + + instrument + + + ${skipTests} + + + + default-restore-instrumented-classes + + restore-instrumented-classes + + + ${skipTests} + + + + + + + org.apache.maven.plugins + maven-resources-plugin + 3.0.2 + + + copy-src + generate-resources + + copy-resources + + + ${basedir}/target/classes + false + ${skipTests} + + + ${basedir}/../ecomp-portal-BE-common/target/classes + + + + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.19.1 + + ${skipTests} + + **/*Test.java + **/*TestCase.java + **/*TestSuite.java + + + + **/*TestFromSuite.java + + + ${basedir}/src/main/webapp + ../ecomp-portal-BE-common/src/main/webapp + ../ecomp-portal-BE-common + + + classpath: + + + maven-war-plugin @@ -118,13 +230,13 @@ - org.openecomp.portal + org.onap.portal ecompportal-be-common - org.openecomp.ecompsdkos + org.onap.portal.sdk epsdk-app-overlay - + @@ -249,17 +361,29 @@ + org.springframework @@ -412,7 +536,6 @@ * - @@ -540,14 +663,14 @@ - org.openecomp.ecompsdkos + org.onap.portal.sdk epsdk-app-overlay ${epsdk.version} war - org.openecomp.ecompsdkos + org.onap.portal.sdk epsdk-app-common ${epsdk.version} jar @@ -555,14 +678,14 @@ - org.openecomp.portal + org.onap.portal ecompportal-be-common ${portal.version} war - org.openecomp.portal + org.onap.portal ecompportal-be-common ${portal.version} jar @@ -570,7 +693,7 @@ - org.openecomp.ecompsdkos + org.onap.portal.sdk epsdk-fw ${epsdk.version} @@ -594,13 +717,13 @@ - org.openecomp.ecompsdkos + org.onap.portal.sdk epsdk-core ${epsdk.version} - org.openecomp.ecompsdkos + org.onap.portal.sdk epsdk-workflow ${epsdk.version} @@ -608,7 +731,7 @@ - org.openecomp.ecompsdkos + org.onap.portal.sdk epsdk-analytics ${epsdk.version} @@ -628,13 +751,26 @@ 4.11 test - + org.onap.portal + ecomp-portal-BE-common-test + ${portal.version} + test + + + org.mockito + mockito-core + 1.8.5 + test + + commons-beanutils commons-beanutils 1.9.2 - + + + org.mitre diff --git a/ecomp-portal-BE-os/src/main/java/org/openecomp/portalapp/authentication/OpenIdConnectLoginStrategy.java b/ecomp-portal-BE-os/src/main/java/org/openecomp/portalapp/authentication/OpenIdConnectLoginStrategy.java index 8365ebc2..48f447b4 100644 --- a/ecomp-portal-BE-os/src/main/java/org/openecomp/portalapp/authentication/OpenIdConnectLoginStrategy.java +++ b/ecomp-portal-BE-os/src/main/java/org/openecomp/portalapp/authentication/OpenIdConnectLoginStrategy.java @@ -64,7 +64,7 @@ public class OpenIdConnectLoginStrategy extends org.openecomp.portalsdk.core.aut user.setLastName(userInfo.getFamilyName()); //store the currently logged in user's information in the session - EPUserUtils.setUserSession(request, user, new HashSet(), new HashSet(), SystemProperties.getProperty(SystemProperties.AUTHENTICATION_MECHANISM), null); + EPUserUtils.setUserSession(request, user, new HashSet(), new HashSet(), SystemProperties.getProperty(SystemProperties.AUTHENTICATION_MECHANISM),null); logger.info(EELFLoggerDelegate.errorLogger, request.getContextPath()); SessionCookieUtil.preSetUp(request, response); diff --git a/ecomp-portal-BE-os/src/main/java/org/openecomp/portalapp/authentication/SimpleLoginStrategy.java b/ecomp-portal-BE-os/src/main/java/org/openecomp/portalapp/authentication/SimpleLoginStrategy.java index c1fee7f3..0c3c4996 100644 --- a/ecomp-portal-BE-os/src/main/java/org/openecomp/portalapp/authentication/SimpleLoginStrategy.java +++ b/ecomp-portal-BE-os/src/main/java/org/openecomp/portalapp/authentication/SimpleLoginStrategy.java @@ -24,6 +24,7 @@ import javax.servlet.http.HttpServletResponse; import org.openecomp.portalapp.command.EPLoginBean; import org.openecomp.portalapp.portal.service.EPLoginService; +import org.openecomp.portalapp.portal.service.EPRoleFunctionService; import org.openecomp.portalapp.portal.service.EPRoleService; import org.openecomp.portalapp.portal.utils.EPSystemProperties; import org.openecomp.portalapp.portal.utils.EcompPortalUtils; @@ -45,6 +46,9 @@ public class SimpleLoginStrategy extends org.openecomp.portalsdk.core.auth.Login @Autowired private EPRoleService roleService; + @Autowired + private EPRoleFunctionService ePRoleFunctionService; + private static final String GLOBAL_LOCATION_KEY = "Location"; EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(SimpleLoginStrategy.class); @@ -66,7 +70,7 @@ public class SimpleLoginStrategy extends org.openecomp.portalsdk.core.auth.Login } else { // store the currently logged in user's information in the session - EPUserUtils.setUserSession(request, commandBean.getUser(), commandBean.getMenu(), commandBean.getBusinessDirectMenu(), "", roleService.getRoleFunctions()); + EPUserUtils.setUserSession(request, commandBean.getUser(), commandBean.getMenu(), commandBean.getBusinessDirectMenu(), "", ePRoleFunctionService); logger.info(EELFLoggerDelegate.debugLogger, commandBean.getUser().getOrgUserId() + " exists in the the system."); } diff --git a/ecomp-portal-BE-os/src/main/java/org/openecomp/portalapp/conf/ExternalAppConfig.java b/ecomp-portal-BE-os/src/main/java/org/openecomp/portalapp/conf/ExternalAppConfig.java index a16cf56b..92d63742 100644 --- a/ecomp-portal-BE-os/src/main/java/org/openecomp/portalapp/conf/ExternalAppConfig.java +++ b/ecomp-portal-BE-os/src/main/java/org/openecomp/portalapp/conf/ExternalAppConfig.java @@ -200,7 +200,7 @@ public class ExternalAppConfig extends AppConfig implements Configurable { registry.addInterceptor(sessionTimeoutInterceptor()).excludePathPatterns("/oid-login", "/portalApi/healthCheck", "/portalApi/healthCheck/", "/portalApi/healthCheckSuspend", "/portalApi/healthCheckSuspend/", "/portalApi/healthCheckResume", "/portalApi/healthCheckResume/", "/login_external", - "/login_external.htm*", "login", "/login.htm*", "/auxapi/*", "/context/*", "/api*", + "/login_external.htm*", "login", "/login.htm*","/auxapi/*","/context/*", "/api*", "/single_signon.htm", "/single_signon", "/dashboard", "/OpenSourceLogin.htm"); registry.addInterceptor(portalResourceInterceptor()); diff --git a/ecomp-portal-BE-os/src/main/java/org/openecomp/portalapp/controller/LoginController.java b/ecomp-portal-BE-os/src/main/java/org/openecomp/portalapp/controller/LoginController.java index 6f3d2278..33cc4dd7 100644 --- a/ecomp-portal-BE-os/src/main/java/org/openecomp/portalapp/controller/LoginController.java +++ b/ecomp-portal-BE-os/src/main/java/org/openecomp/portalapp/controller/LoginController.java @@ -36,6 +36,7 @@ import org.json.JSONObject; import org.openecomp.portalapp.command.EPLoginBean; import org.openecomp.portalapp.portal.domain.SharedContext; import org.openecomp.portalapp.portal.service.EPLoginService; +import org.openecomp.portalapp.portal.service.EPRoleFunctionService; import org.openecomp.portalapp.portal.service.EPRoleService; import org.openecomp.portalapp.portal.service.SharedContextService; import org.openecomp.portalapp.portal.utils.EPSystemProperties; @@ -84,6 +85,9 @@ public class LoginController extends EPUnRestrictedBaseController implements Log @Autowired private EPRoleService roleService; + @Autowired + private EPRoleFunctionService ePRoleFunctionService; + String viewName = "login"; private String welcomeView; @@ -142,8 +146,7 @@ public class LoginController extends EPUnRestrictedBaseController implements Log } else { // store the currently logged in user's information in the session - EPUserUtils.setUserSession(request, commandBean.getUser(), commandBean.getMenu(), commandBean.getBusinessDirectMenu(), SystemProperties.getProperty(SystemProperties.AUTHENTICATION_MECHANISM), - roleService.getRoleFunctions()); + EPUserUtils.setUserSession(request, commandBean.getUser(), commandBean.getMenu(), commandBean.getBusinessDirectMenu(), SystemProperties.getProperty(SystemProperties.AUTHENTICATION_MECHANISM),ePRoleFunctionService); try{ logger.info(EELFLoggerDelegate.debugLogger, "******************* store user info into share context begins"); @@ -249,7 +252,7 @@ public class LoginController extends EPUnRestrictedBaseController implements Log sbAdditionalInfo.append(String.format("Login-Id: %s, Login-Method: %s, Request-URL: %s", orgUserId, "", fullURL)); logger.info(EELFLoggerDelegate.debugLogger, "*********************** now set up user session for " + orgUserId); - EPUserUtils.setUserSession(request, commandBean.getUser(), commandBean.getMenu(), commandBean.getBusinessDirectMenu(), SystemProperties.getProperty(SystemProperties.AUTHENTICATION_MECHANISM), roleService.getRoleFunctions()); + EPUserUtils.setUserSession(request, commandBean.getUser(), commandBean.getMenu(), commandBean.getBusinessDirectMenu(), SystemProperties.getProperty(SystemProperties.AUTHENTICATION_MECHANISM),ePRoleFunctionService); logger.info(EELFLoggerDelegate.debugLogger, "*********************** now set up user session for " + orgUserId + " finished"); //Store user's information into share context diff --git a/ecomp-portal-BE-os/src/main/java/org/openecomp/portalapp/portal/transport/OnboardingApp.java b/ecomp-portal-BE-os/src/main/java/org/openecomp/portalapp/portal/transport/OnboardingApp.java index f953634a..eee12234 100644 --- a/ecomp-portal-BE-os/src/main/java/org/openecomp/portalapp/portal/transport/OnboardingApp.java +++ b/ecomp-portal-BE-os/src/main/java/org/openecomp/portalapp/portal/transport/OnboardingApp.java @@ -56,6 +56,10 @@ public class OnboardingApp { public String uebSecret; public Boolean restrictedApp; + + public Boolean isCentralAuth; + + public String nameSpace; public void normalize() { this.name = (this.name == null) ? "" : this.name.trim(); diff --git a/ecomp-portal-BE-os/src/main/resources/portal.properties b/ecomp-portal-BE-os/src/main/resources/portal.properties index a1982632..e23d04e4 100644 --- a/ecomp-portal-BE-os/src/main/resources/portal.properties +++ b/ecomp-portal-BE-os/src/main/resources/portal.properties @@ -42,3 +42,8 @@ ecomp_portal_inbox_name = ECOMP-PORTAL-INBOX-DEV-LOCAL # Consumer group name for UEB topic. # Use the special tag to generate a unique one for each sdk-app server. ueb_app_consumer_group_name = {UUID} + +role_access_centralized = remote + +ext_req_connection_timeout = 15000 +ext_req_read_timeout = 20000 diff --git a/ecomp-portal-BE-os/src/main/webapp/WEB-INF/conf/raptor.properties b/ecomp-portal-BE-os/src/main/webapp/WEB-INF/conf/raptor.properties index 0c32ef65..68d60140 100644 --- a/ecomp-portal-BE-os/src/main/webapp/WEB-INF/conf/raptor.properties +++ b/ecomp-portal-BE-os/src/main/webapp/WEB-INF/conf/raptor.properties @@ -107,7 +107,7 @@ flat_file_upper_limit=200000 request_get_params=c_master,isEmbedded print_footer_in_download=yes ## footer mentioned here appears in downloaded excel -footer_first_line=AT&T Proprietary +footer_first_line=Raptor footer_second_line=Use Pursuant to Company Instructions ## to run report in popup window report_in_popup_window=yes diff --git a/ecomp-portal-BE-os/src/main/webapp/WEB-INF/conf/system.properties b/ecomp-portal-BE-os/src/main/webapp/WEB-INF/conf/system.properties index 0fc2c69d..8f74a9f2 100644 --- a/ecomp-portal-BE-os/src/main/webapp/WEB-INF/conf/system.properties +++ b/ecomp-portal-BE-os/src/main/webapp/WEB-INF/conf/system.properties @@ -35,7 +35,7 @@ hb.idle_connection_test_period = 3600 # Ecomp portal title app_display_name = Portal -files_path = /demeter/WebApps/dev/ECOMP_APP/files +files_path = /tmp context_root = ECOMPPORTAL # menu settings menu_query_name = menuData @@ -116,3 +116,6 @@ authenticate_user_server=http://todo_enter_auth_server_hostname:8383/openid-conn #window width threshold to collapse left/right menu when page onload window_width_threshold_left_menu = 1400 window_width_threshold_right_menu = 1350 + +#External system notification URL +external_system_notification_url= http://todo_external_system_notification_url? diff --git a/ecomp-portal-BE-os/src/main/webapp/WEB-INF/jsp/login.jsp b/ecomp-portal-BE-os/src/main/webapp/WEB-INF/jsp/login.jsp index 1b269d80..a8265c71 100644 --- a/ecomp-portal-BE-os/src/main/webapp/WEB-INF/jsp/login.jsp +++ b/ecomp-portal-BE-os/src/main/webapp/WEB-INF/jsp/login.jsp @@ -37,11 +37,9 @@ - - + +

+ +
+ + +
+ +
+
-
- +
+
+ - -
+ \ No newline at end of file diff --git a/ecomp-portal-FE-common/client/app/views/dashboard/dashboard-widget-parameters.controller.js b/ecomp-portal-FE-common/client/app/views/dashboard/dashboard-widget-parameters.controller.js index fb9a254f..10ccb9bf 100644 --- a/ecomp-portal-FE-common/client/app/views/dashboard/dashboard-widget-parameters.controller.js +++ b/ecomp-portal-FE-common/client/app/views/dashboard/dashboard-widget-parameters.controller.js @@ -21,7 +21,8 @@ (function () { class WidgetParameterController { - constructor($scope, widgetsCatalogService, userProfileService) { + constructor($scope, widgetsCatalogService, userProfileService, $state,items) { + $scope.ngDialogData=items; let widgetId = $scope.ngDialogData.widgetId; $scope.modflag = false; $scope.isLoadingTable = false; @@ -70,12 +71,13 @@ if(res.status == 'OK'){ $scope.modflag = false; $scope.widgetParam[index].showEdit = false; + $state.reload(); } }); }; } } - WidgetParameterController.$inject = ['$scope', 'widgetsCatalogService', 'userProfileService']; + WidgetParameterController.$inject = ['$scope', 'widgetsCatalogService', 'userProfileService', '$state','items']; angular.module('ecompApp').controller('WidgetParameterController', WidgetParameterController); -})(); +})(); \ No newline at end of file diff --git a/ecomp-portal-FE-common/client/app/views/dashboard/dashboard-widget.controller.less b/ecomp-portal-FE-common/client/app/views/dashboard/dashboard-widget.controller.less index 8f326c42..5c0ce37d 100644 --- a/ecomp-portal-FE-common/client/app/views/dashboard/dashboard-widget.controller.less +++ b/ecomp-portal-FE-common/client/app/views/dashboard/dashboard-widget.controller.less @@ -79,4 +79,59 @@ padding-bottom: 20px; height: 32px; border-color: slategrey !important; width:100%; - } \ No newline at end of file + } + .heading1-txt { + margin-top: 10px; + margin-bottom: 10px; + } + .manage-widgets-txt { + margin-top: 25px; + } + .widget-table-control { + margin:30px; + } + .widget-table { + height:300px; + } + .widget-field { + margin-top: 15px; + margin-left: -80px; + } + .widget-add { + font-size:18px; + } + .widget-type-txt-area { + margin-top: 0px; + margin-bottom: 0px; + height: 150px; + } + .widget-button-height { + height:50px; + } + .widget-button { + float:right; + margin-top:20px; + } + .widget-close-button { + float:right; + } + + .btn-calendar-icon { + position: relative; + width: 10px; + right:25px; + top:0px; +} +.dialog-control{ +bottom:30px; +} +input[type="text"]:focus { + z-index: 0; +} + + .get-access-table{ + height:500px; + overflow:auto; + } + + \ No newline at end of file diff --git a/ecomp-portal-FE-common/client/app/views/dashboard/dashboard.controller.js b/ecomp-portal-FE-common/client/app/views/dashboard/dashboard.controller.js index 8481b5ed..4c5ee2cf 100644 --- a/ecomp-portal-FE-common/client/app/views/dashboard/dashboard.controller.js +++ b/ecomp-portal-FE-common/client/app/views/dashboard/dashboard.controller.js @@ -54,9 +54,10 @@ function _classCallCheck(instance, Constructor) { $scope.editWidgetModalPopup = function(availableData, resourceType) { $scope.editData = JSON.stringify(availableData); $scope.availableDataTemp = $scope.availableData; - ngDialog.open({ + var modalInstance = $modal.open({ templateUrl: 'app/views/dashboard/dashboard-widget-manage.html', controller: 'CommonWidgetController', + windowClass: 'modal-docked', resolve: { message: function message() { var message = { @@ -66,30 +67,41 @@ function _classCallCheck(instance, Constructor) { return message; } } - }).closePromise.then(needUpdate => { - if (resourceType == 'NEWS') { - $scope.updateNews(); - } else if (resourceType == 'EVENTS') { - $scope.updateEvents(); - } else if (resourceType == 'IMPORTANTRESOURCES') { - $scope.updateImportRes(); - } - }); + }) + + modalInstance.result.finally(function (needUpdate){ + if (resourceType == 'NEWS') { + $scope.updateNews(); + } else if (resourceType == 'EVENTS') { + $scope.updateEvents(); + } else if (resourceType == 'IMPORTANTRESOURCES') { + $scope.updateImportRes(); + } + }); }; $scope.editWidgetParameters = function(widgetId) { let data = { widgetId: widgetId } - ngDialog.open({ + var modalInstance = $modal.open({ templateUrl: 'app/views/dashboard/dashboard-widget-parameter-manage.html', controller: 'WidgetParameterController', - data: data - }).closePromise.then(needUpdate => { + windowClass: 'modal-docked', - }); + resolve: { + items: function () { + return data; + } + } + }) + + modalInstance.result.then(function (needUpdate) { + }); }; + + $scope.sort_options = [{ index: 0, value: 'N', @@ -488,7 +500,8 @@ function _classCallCheck(instance, Constructor) { } - }; + + }; this.auditLog = function(app) { console.log(app); diff --git a/ecomp-portal-FE-common/client/app/views/dashboard/dashboard.less b/ecomp-portal-FE-common/client/app/views/dashboard/dashboard.less index 8d8f39fe..02cd960d 100644 --- a/ecomp-portal-FE-common/client/app/views/dashboard/dashboard.less +++ b/ecomp-portal-FE-common/client/app/views/dashboard/dashboard.less @@ -33,7 +33,7 @@ flex-flow: row wrap; width: @table-width; //margin-left: 230px; - margin-bottom: 63px; + margin-bottom: 0px; margin:auto; .app-gridster-header { background-color: @u; @@ -478,10 +478,7 @@ On click the images will be displayed at normal size to complete the effect -webkit-transition: background-color 0.3s ease-out; -moz-transition: background-color 0.3s ease-out; transition: background-color 0.3s ease-out; - span{ - color: #888; } - } .widgetHeaderBtnPosition { width: 30px; @@ -910,4 +907,40 @@ ul { } .icon-content-gridguide{ cursor:move; -} \ No newline at end of file +} + .error-info-txt { + display: none; + font-size: 12px; + margin-left: 5px; + } + .account-info-msg { + color: red; + } + .icon-info { + margin-left: 50%; + font-size: 90px; + color: black; + } + .gridster-box-pointer { + cursor: pointer; + } + .gridster-txt{ + font-size: 12px; + } + .gridster-icon { + font-size: 80px; + color: #067ab4; + } + .widget-gridster { + cursor:move; + } + .widgetHeaderBtns-span { + color: #888; + } + .widgetHeaderBtns-img { + margin-bottom: 3px; + margin-left: 3px; + } + .widget-menu-options { + display: block; + } \ No newline at end of file diff --git a/ecomp-portal-FE-common/client/app/views/dashboard/dashboard.tpl.html b/ecomp-portal-FE-common/client/app/views/dashboard/dashboard.tpl.html index d71b8f79..a981fd66 100644 --- a/ecomp-portal-FE-common/client/app/views/dashboard/dashboard.tpl.html +++ b/ecomp-portal-FE-common/client/app/views/dashboard/dashboard.tpl.html @@ -19,12 +19,11 @@ -->
-