From a6df54991972b0b85e66f5127eeeecd6358b0b6f Mon Sep 17 00:00:00 2001 From: Isaac Parenteau Date: Fri, 4 Sep 2026 15:22:35 -0500 Subject: [PATCH] Upgraded all libraries, switched to npm, upgraded angular and jdk21 --- .gitignore | 21 +- Jenkinsfile | 85 + README.md | 94 +- bitbucket-pipelines.yml | 23 - docs/src/Deployment.tex | 10 +- docs/src/Development.tex | 24 +- docs/src/ToolsLibraries.tex | 25 +- docs/src/api/ConfigurationAPI.tex | 5 +- docs/src/api/sample/request/addGitRepoReq.tex | 2 +- .../api/sample/request/addScriptLocalReq.tex | 2 +- .../api/sample/request/addScriptRemoteReq.tex | 2 +- .../api/sample/request/addScriptScpReq.tex | 2 +- docs/src/api/sample/request/addUserReq.tex | 2 +- docs/src/api/sample/request/deleteUserReq.tex | 2 +- .../api/sample/response/addGitRepoResp.tex | 2 +- .../sample/response/addScriptLocalResp.tex | 2 +- .../sample/response/addScriptRemoteResp.tex | 2 +- .../api/sample/response/addScriptScpResp.tex | 2 +- docs/src/api/sample/response/addUserResp.tex | 4 +- .../api/sample/response/getAllReposResp.tex | 2 +- .../api/sample/response/getAllScriptsResp.tex | 2 +- .../api/sample/response/getAllUsersResp.tex | 8 +- docs/src/api/sample/response/getConfResp.tex | 4 +- docs/src/api/sample/response/loginResp.tex | 4 +- docs/src/appendix/ApacheAppendex.tex | 2 +- docs/src/appendix/NginxAppendex.tex | 2 +- docs/src/appendix/PropertiesAppendex.tex | 2 +- docs/src/appendix/Revisions.tex | 2 +- docs/src/appendix/SeedFileAppendex.tex | 2 +- docs/src/appendix/SettingsAppendex.tex | 2 +- docs/src/figures/portal.properties | 8 +- docs/src/figures/settings.xml | 13 +- docs/src/guides/LogLevel.tex | 4 +- docs/src/guides/Login.tex | 2 +- docs/src/macros.tex | 10 +- docs/src/portal.tex | 2 +- pipeline-settings.xml | 24 - pom.xml | 264 +- portal_client/.csslintrc | 37 - portal_client/.jshintrc | 62 - portal_client/.npmrc | 3 + portal_client/Gruntfile.js | 453 - portal_client/README.md | 35 +- portal_client/angular.json | 92 + portal_client/app/app.css | 523 -- portal_client/app/app.js | 130 - .../app/common/constants/constants.js | 43 - .../directives/compare-to/compare-to.js | 22 - .../has-permission/has-permission.js | 32 - .../portal-tab-set/portal-tab-set.html | 14 - .../portal-tab-set/portal-tab-set.js | 129 - .../portal-websocket/portal-websocket.html | 3 - .../portal-websocket/portal-websocket.js | 357 - .../factories/portal-pubsub/portal-pubsub.js | 9 - .../common/partials/add-creds/add-creds.html | 91 - .../common/partials/add-creds/add-creds.js | 60 - .../partials/add-directory/add-directory.html | 32 - .../partials/add-directory/add-directory.js | 67 - .../add-email-tmpl/add-email-tmpl.html | 39 - .../partials/add-email-tmpl/add-email-tmpl.js | 67 - .../app/common/partials/add-env/add-env.html | 50 - .../app/common/partials/add-env/add-env.js | 86 - .../app/common/partials/add-git/add-git.html | 74 - .../app/common/partials/add-git/add-git.js | 67 - .../add-permission/add-permission.html | 67 - .../partials/add-permission/add-permission.js | 92 - .../add-script/add-script-bottom.html | 63 - .../add-script/add-script-left-local.html | 9 - .../add-script/add-script-left-remote.html | 27 - .../add-script/add-script-left-scp.html | 78 - .../partials/add-script/add-script-left.html | 55 - .../add-script/add-script-right-chain.html | 60 - .../add-script/add-script-right-email.html | 89 - .../add-script/add-script-right-env-vars.html | 47 - .../add-script-right-parameters.html | 41 - .../partials/add-script/add-script-right.html | 21 - .../common/partials/add-script/add-script.css | 19 - .../partials/add-script/add-script.html | 31 - .../common/partials/add-script/add-script.js | 218 - .../common/partials/add-user/add-user.html | 102 - .../app/common/partials/add-user/add-user.js | 85 - .../partials/configuration/configuration.html | 146 - .../partials/configuration/configuration.js | 73 - .../common/partials/file-info/file-info.html | 87 - .../common/partials/file-info/file-info.js | 111 - .../partials/file-validate/file-validate.html | 22 - .../partials/file-validate/file-validate.js | 41 - .../partials/logger-info/logger-info.html | 46 - .../partials/logger-info/logger-info.js | 94 - .../script-status/view-script-status.html | 68 - .../script-status/view-script-status.js | 84 - .../common/partials/seed-info/seed-info.html | 26 - .../common/partials/seed-info/seed-info.js | 56 - .../partials/session-end/session-end.html | 20 - .../partials/session-end/session-end.js | 16 - .../common/partials/smtp-info/smtp-info.html | 93 - .../common/partials/smtp-info/smtp-info.js | 140 - .../templates/confirm-window.tmpl.html | 25 - .../partials/templates/purge-logs.tmpl.html | 39 - .../upload-patch-file/upload-patch-file.html | 31 - .../upload-patch-file/upload-patch-file.js | 73 - .../common/services/authorize/authorize.js | 125 - portal_client/app/common/services/map/map.js | 200 - .../common/services/model/cache/box/box.js | 133 - .../app/common/services/model/cache/cache.js | 192 - .../services/model/cache/listener/listener.js | 145 - .../model/cache/objects/account/account.js | 91 - .../application-log/application-log.js | 40 - .../model/cache/objects/config/config.js | 44 - .../cache/objects/credentials/credentials.js | 39 - .../objects/drop-down-item/drop-down-item.js | 30 - .../cache/objects/email-tmpl/email-tmpl.js | 40 - .../model/cache/objects/git-info/git-info.js | 42 - .../cache/objects/hash-type/hash-type.js | 28 - .../cache/objects/logger-info/logger-info.js | 30 - .../permission-object/permission-object.js | 85 - .../objects/resource-file/resource-file.js | 33 - .../model/cache/objects/script/script.js | 207 - .../cache/objects/upload-file/upload-file.js | 75 - .../services/model/cache/store/store.js | 137 - .../stores/account-stores/account-stores.js | 60 - .../application-log-stores.js | 33 - .../stores/config-stores/config-stores.js | 35 - .../credential-stores/credential-stores.js | 34 - .../cache/stores/git-stores/git-stores.js | 25 - .../stores/logger-stores/logger-stores.js | 26 - .../permission-stores/permission-stores.js | 65 - .../resource-file-stores.js | 33 - .../stores/script-stores/script-stores.js | 130 - .../services/model/cache/stores/stores.js | 27 - .../stores/system-stores/system-stores.js | 92 - .../rest/account-provider/account-provider.js | 76 - .../application-log-provider.js | 26 - .../rest/config-provider/config-provider.js | 33 - .../credential-provider.js | 38 - .../model/rest/file-provider/file-provider.js | 22 - .../model/rest/git-provider/git-provider.js | 39 - .../rest/logger-provider/logger-provider.js | 27 - .../permission-provider.js | 42 - .../services/model/rest/request/request.js | 177 - .../app/common/services/model/rest/rest.js | 38 - .../rest/script-provider/script-provider.js | 64 - .../rest/system-provider/system-provider.js | 90 - .../services/permissions/permissions.js | 40 - .../services/triggers/trigger-manager.js | 160 - .../app/common/services/triggers/triggers.js | 168 - .../app/common/services/utils/portalUtils.js | 276 - .../app/custom/portal-material-override.css | 208 - portal_client/app/login/login.css | 46 - portal_client/app/login/login.html | 24 - portal_client/app/login/login.js | 80 - .../cell-templates/cred-actions.html | 12 - .../app/main/cred-bank/cred-bank.html | 21 - portal_client/app/main/cred-bank/cred-bank.js | 115 - portal_client/app/main/dashboard.css | 21 - portal_client/app/main/dashboard.html | 60 - portal_client/app/main/dashboard.js | 215 - .../cell-templates/email-actions.html | 12 - .../app/main/email-bank/email-bank.html | 21 - .../app/main/email-bank/email-bank.js | 111 - portal_client/app/main/env-bank/env-bank.html | 29 - portal_client/app/main/env-bank/env-bank.js | 117 - .../git-bank/cell-templates/git-actions.html | 17 - portal_client/app/main/git-bank/git-bank.html | 21 - portal_client/app/main/git-bank/git-bank.js | 151 - portal_client/app/main/log-bank/log-bank.html | 22 - portal_client/app/main/log-bank/log-bank.js | 126 - .../cell-templates/permission-actions.html | 12 - .../main/permission-bank/permission-bank.html | 21 - .../main/permission-bank/permission-bank.js | 132 - .../cell-templates/script-actions.html | 17 - .../cell-templates/script-sched-actions.html | 10 - .../cell-templates/script-sched-status.html | 7 - .../app/main/script-bank/script-bank.html | 21 - .../app/main/script-bank/script-bank.js | 234 - .../cell-templates/user-actions.html | 12 - .../app/main/user-bank/user-bank.html | 21 - portal_client/app/main/user-bank/user-bank.js | 126 - portal_client/assets.js | 57 - portal_client/index.html | 125 - portal_client/package-lock.json | 8125 +++++++++++++++++ portal_client/package.json | 112 +- portal_client/pom.xml | 163 +- portal_client/{app => public}/favicon.ico | Bin .../google-md-icons/MaterialIcons-Regular.css | 18 +- .../google-md-icons/MaterialIcons-Regular.eot | Bin .../MaterialIcons-Regular.woff | Bin .../MaterialIcons-Regular.woff2 | Bin .../{app => public}/images/NGLogo.png | Bin .../{app => public}/images/background.png | Bin .../{app => public}/images/portal.png | Bin portal_client/src/app/app.config.ts | 13 + portal_client/src/app/app.html | 1 + portal_client/src/app/app.routes.spec.ts | 36 + portal_client/src/app/app.routes.ts | 14 + portal_client/src/app/app.scss | 0 portal_client/src/app/app.spec.ts | 24 + portal_client/src/app/app.ts | 11 + portal_client/src/app/core/auth.guard.ts | 11 + .../src/app/core/auth.interceptor.ts | 20 + portal_client/src/app/core/models.ts | 14 + .../src/app/core/permission.guard.ts | 13 + .../src/app/core/portal-api.service.spec.ts | 29 + .../src/app/core/portal-api.service.ts | 29 + .../src/app/core/realtime.service.ts | 39 + .../src/app/core/session.service.spec.ts | 16 + portal_client/src/app/core/session.service.ts | 11 + .../src/app/dashboard/admin-dialog.ts | 108 + portal_client/src/app/dashboard/dashboard.ts | 45 + .../src/app/features/entity-dialog.ts | 134 + .../src/app/features/environment-dialog.ts | 54 + .../src/app/features/feature-page.ts | 103 + .../src/app/features/permission-dialog.ts | 77 + .../src/app/features/purge-logs-dialog.ts | 24 + .../src/app/features/script-dialog.ts | 66 + .../src/app/features/script-status-dialog.ts | 38 + portal_client/src/app/login/login.ts | 38 + portal_client/src/index.html | 13 + portal_client/src/main.ts | 6 + portal_client/src/polyfills.ts | 3 + portal_client/src/styles.scss | 5 + portal_client/tsconfig.app.json | 14 + portal_client/tsconfig.json | 35 + portal_client/tsconfig.spec.json | 17 + portal_client/webpack.config.js | 43 - portal_client/yarn_file_copy.js | 110 - portal_common/pom.xml | 13 +- .../portal/common/PortalDataSource.java | 68 +- .../portal/common/enums/Configuration.java | 10 +- .../portal/common/http/HttpClientHelper.java | 4 +- .../portal/common/services/AESService.java | 13 +- .../common/services/ConfigurationService.java | 120 +- .../portal/common/utils/Constants.java | 24 +- .../portal/common/PortalDataSourceTest.java | 50 + portal_database/pom.xml | 58 +- .../config/PortalBeanConfiguration.java | 31 +- .../database/entities/ApplicationLog.java | 26 +- .../database/entities/ApplicationUser.java | 34 +- .../database/entities/CredentialType.java | 24 +- .../portal/database/entities/Credentials.java | 34 +- .../database/entities/EmailTemplate.java | 36 +- .../entities/EnvironmentVariable.java | 32 +- .../portal/database/entities/GitRepo.java | 32 +- .../portal/database/entities/HashType.java | 28 +- .../portal/database/entities/KeyValue.java | 32 +- .../portal/database/entities/Keyword.java | 30 +- .../portal/database/entities/Password.java | 30 +- .../portal/database/entities/Permission.java | 36 +- .../database/entities/PermissionCategory.java | 30 +- .../database/entities/PermissionGroup.java | 32 +- .../entities/PermissionGroupPermission.java | 32 +- .../database/entities/ResourceFile.java | 30 +- .../database/entities/ScheduleFrequency.java | 24 +- .../portal/database/entities/Script.java | 34 +- .../portal/database/entities/ScriptChain.java | 24 +- .../portal/database/entities/ScriptEmail.java | 34 +- .../entities/ScriptEmailRecipient.java | 30 +- .../entities/ScriptEnvironmentVariable.java | 32 +- .../database/entities/ScriptParameter.java | 24 +- .../database/entities/ScriptRemote.java | 24 +- .../database/entities/ScriptSchedule.java | 38 +- .../entities/ScriptScheduleResults.java | 36 +- .../portal/database/entities/ScriptScp.java | 32 +- .../portal/database/entities/ScriptType.java | 24 +- .../portal/database/entities/SshKey.java | 32 +- .../database/entities/UserAttribute.java | 26 +- .../entities/UserPasswordTracking.java | 32 +- .../database/entities/package-info.java | 2 +- .../database/migration/PortalMigration.java | 28 +- .../database/repos/CredentialsRepository.java | 30 +- .../repos/EmailTemplateRepository.java | 2 +- .../database/repos/KeyValueRepository.java | 2 +- .../repos/ScriptRemoteRepository.java | 2 +- .../database/repos/ScriptRepository.java | 2 +- .../database/repos/ScriptScpRepository.java | 2 +- .../main/resources/META-INF/persistence.xml | 43 - .../Data/V01_000_002__admin_user_create.sql | 6 +- .../Tables/V01_000_000__portal_tables.sql | 26 +- .../portal/json/ApplicationLogRequest.java | 3 +- .../portal/json/ConfigurationRequest.java | 37 +- .../portal/migration/util/MigrationItem.java | 6 +- .../migration/util/MigrationManager.java | 25 +- portal_webapp/pom.xml | 319 +- .../locusworks/portal/PortalApplication.java | 36 + .../config/PortalQuartzSchedulerConfig.java | 2 +- .../portal/config/WebSecurityConfig.java | 55 +- .../portal/config/WebSocketConfig.java | 62 +- .../portal/controllers/AccountController.java | 8 +- .../controllers/ApplicationLogController.java | 4 +- .../portal/controllers/BaseController.java | 2 +- .../controllers/ConfigurationController.java | 4 +- .../controllers/CredentialsController.java | 4 +- .../controllers/ExceptionController.java | 4 +- .../portal/controllers/FileController.java | 12 +- .../portal/controllers/GitController.java | 4 +- .../portal/controllers/LogController.java | 6 +- .../controllers/PermissionsController.java | 4 +- .../portal/controllers/ScriptController.java | 4 +- .../portal/controllers/SystemController.java | 4 +- .../portal/extendedlogger/ExtendedLogger.java | 4 +- .../extendedlogger/ExtendedLoggerFactory.java | 6 +- .../AbstractObjectMessageHandler.java | 13 +- .../handlers/BrokerAvailabilityHandler.java | 4 +- .../portal/handlers/LoggerInitializer.java | 35 +- .../PortalAuthenticationFailureHandler.java | 4 +- .../PortalAuthenticationSuccessHandler.java | 4 +- .../handlers/PortalLogoutSuccessHandler.java | 12 +- .../portal/handlers/SeedUpdatedHandler.java | 4 +- .../handlers/SystemTriggerMessageHandler.java | 6 +- .../handlers/SystemWebSocketHandler.java | 6 +- .../services/ApplicationLogService.java | 10 +- .../portal/services/CommService.java | 6 +- .../portal/services/CredentialService.java | 2 +- .../portal/services/GitService.java | 6 +- .../portal/services/PortalContextService.java | 20 +- .../portal/services/ResourceFileService.java | 4 +- .../portal/services/SchedulerService.java | 6 +- .../portal/services/ScriptService.java | 15 +- .../portal/services/SecureRandomService.java | 2 +- .../portal/services/SendMailService.java | 18 +- .../portal/services/SystemService.java | 4 +- .../portal/services/UserSecurityService.java | 20 +- .../portal/services/WebCommService.java | 4 +- .../util/FileDownloadServletResponse.java | 15 +- .../portal/util/GitConfigSession.java | 4 +- .../locusworks/portal/util/JSchHelper.java | 8 +- .../src/main/resources/application.properties | 7 + portal_webapp/src/main/resources/log4j2.xml | 4 +- .../src/main/resources/portal.properties | 8 +- .../src/main/webapp/META-INF/context.xml | 13 - .../src/main/webapp/WEB-INF/portal-config.xml | 58 - .../main/webapp/WEB-INF/portal-servlet.xml | 25 - portal_webapp/src/main/webapp/WEB-INF/web.xml | 59 - scripts/deploy-server.sh | 30 +- test.properties | 2 +- 335 files changed, 10923 insertions(+), 12700 deletions(-) create mode 100644 Jenkinsfile delete mode 100644 bitbucket-pipelines.yml delete mode 100644 pipeline-settings.xml delete mode 100644 portal_client/.csslintrc delete mode 100644 portal_client/.jshintrc create mode 100644 portal_client/.npmrc delete mode 100644 portal_client/Gruntfile.js create mode 100644 portal_client/angular.json delete mode 100644 portal_client/app/app.css delete mode 100644 portal_client/app/app.js delete mode 100644 portal_client/app/common/constants/constants.js delete mode 100644 portal_client/app/common/directives/compare-to/compare-to.js delete mode 100644 portal_client/app/common/directives/has-permission/has-permission.js delete mode 100644 portal_client/app/common/directives/portal-tab-set/portal-tab-set.html delete mode 100644 portal_client/app/common/directives/portal-tab-set/portal-tab-set.js delete mode 100644 portal_client/app/common/directives/portal-websocket/portal-websocket.html delete mode 100644 portal_client/app/common/directives/portal-websocket/portal-websocket.js delete mode 100644 portal_client/app/common/factories/portal-pubsub/portal-pubsub.js delete mode 100644 portal_client/app/common/partials/add-creds/add-creds.html delete mode 100644 portal_client/app/common/partials/add-creds/add-creds.js delete mode 100644 portal_client/app/common/partials/add-directory/add-directory.html delete mode 100644 portal_client/app/common/partials/add-directory/add-directory.js delete mode 100644 portal_client/app/common/partials/add-email-tmpl/add-email-tmpl.html delete mode 100644 portal_client/app/common/partials/add-email-tmpl/add-email-tmpl.js delete mode 100644 portal_client/app/common/partials/add-env/add-env.html delete mode 100644 portal_client/app/common/partials/add-env/add-env.js delete mode 100644 portal_client/app/common/partials/add-git/add-git.html delete mode 100644 portal_client/app/common/partials/add-git/add-git.js delete mode 100644 portal_client/app/common/partials/add-permission/add-permission.html delete mode 100644 portal_client/app/common/partials/add-permission/add-permission.js delete mode 100644 portal_client/app/common/partials/add-script/add-script-bottom.html delete mode 100644 portal_client/app/common/partials/add-script/add-script-left-local.html delete mode 100644 portal_client/app/common/partials/add-script/add-script-left-remote.html delete mode 100644 portal_client/app/common/partials/add-script/add-script-left-scp.html delete mode 100644 portal_client/app/common/partials/add-script/add-script-left.html delete mode 100644 portal_client/app/common/partials/add-script/add-script-right-chain.html delete mode 100644 portal_client/app/common/partials/add-script/add-script-right-email.html delete mode 100644 portal_client/app/common/partials/add-script/add-script-right-env-vars.html delete mode 100644 portal_client/app/common/partials/add-script/add-script-right-parameters.html delete mode 100644 portal_client/app/common/partials/add-script/add-script-right.html delete mode 100644 portal_client/app/common/partials/add-script/add-script.css delete mode 100644 portal_client/app/common/partials/add-script/add-script.html delete mode 100644 portal_client/app/common/partials/add-script/add-script.js delete mode 100644 portal_client/app/common/partials/add-user/add-user.html delete mode 100644 portal_client/app/common/partials/add-user/add-user.js delete mode 100644 portal_client/app/common/partials/configuration/configuration.html delete mode 100644 portal_client/app/common/partials/configuration/configuration.js delete mode 100644 portal_client/app/common/partials/file-info/file-info.html delete mode 100644 portal_client/app/common/partials/file-info/file-info.js delete mode 100644 portal_client/app/common/partials/file-validate/file-validate.html delete mode 100644 portal_client/app/common/partials/file-validate/file-validate.js delete mode 100644 portal_client/app/common/partials/logger-info/logger-info.html delete mode 100644 portal_client/app/common/partials/logger-info/logger-info.js delete mode 100644 portal_client/app/common/partials/script-status/view-script-status.html delete mode 100644 portal_client/app/common/partials/script-status/view-script-status.js delete mode 100644 portal_client/app/common/partials/seed-info/seed-info.html delete mode 100644 portal_client/app/common/partials/seed-info/seed-info.js delete mode 100644 portal_client/app/common/partials/session-end/session-end.html delete mode 100644 portal_client/app/common/partials/session-end/session-end.js delete mode 100644 portal_client/app/common/partials/smtp-info/smtp-info.html delete mode 100644 portal_client/app/common/partials/smtp-info/smtp-info.js delete mode 100644 portal_client/app/common/partials/templates/confirm-window.tmpl.html delete mode 100644 portal_client/app/common/partials/templates/purge-logs.tmpl.html delete mode 100644 portal_client/app/common/partials/upload-patch-file/upload-patch-file.html delete mode 100644 portal_client/app/common/partials/upload-patch-file/upload-patch-file.js delete mode 100644 portal_client/app/common/services/authorize/authorize.js delete mode 100644 portal_client/app/common/services/map/map.js delete mode 100644 portal_client/app/common/services/model/cache/box/box.js delete mode 100644 portal_client/app/common/services/model/cache/cache.js delete mode 100644 portal_client/app/common/services/model/cache/listener/listener.js delete mode 100644 portal_client/app/common/services/model/cache/objects/account/account.js delete mode 100644 portal_client/app/common/services/model/cache/objects/application-log/application-log.js delete mode 100644 portal_client/app/common/services/model/cache/objects/config/config.js delete mode 100644 portal_client/app/common/services/model/cache/objects/credentials/credentials.js delete mode 100644 portal_client/app/common/services/model/cache/objects/drop-down-item/drop-down-item.js delete mode 100644 portal_client/app/common/services/model/cache/objects/email-tmpl/email-tmpl.js delete mode 100644 portal_client/app/common/services/model/cache/objects/git-info/git-info.js delete mode 100644 portal_client/app/common/services/model/cache/objects/hash-type/hash-type.js delete mode 100644 portal_client/app/common/services/model/cache/objects/logger-info/logger-info.js delete mode 100644 portal_client/app/common/services/model/cache/objects/permission-object/permission-object.js delete mode 100644 portal_client/app/common/services/model/cache/objects/resource-file/resource-file.js delete mode 100644 portal_client/app/common/services/model/cache/objects/script/script.js delete mode 100644 portal_client/app/common/services/model/cache/objects/upload-file/upload-file.js delete mode 100644 portal_client/app/common/services/model/cache/store/store.js delete mode 100644 portal_client/app/common/services/model/cache/stores/account-stores/account-stores.js delete mode 100644 portal_client/app/common/services/model/cache/stores/application-log-stores/application-log-stores.js delete mode 100644 portal_client/app/common/services/model/cache/stores/config-stores/config-stores.js delete mode 100644 portal_client/app/common/services/model/cache/stores/credential-stores/credential-stores.js delete mode 100644 portal_client/app/common/services/model/cache/stores/git-stores/git-stores.js delete mode 100644 portal_client/app/common/services/model/cache/stores/logger-stores/logger-stores.js delete mode 100644 portal_client/app/common/services/model/cache/stores/permission-stores/permission-stores.js delete mode 100644 portal_client/app/common/services/model/cache/stores/resource-file-stores/resource-file-stores.js delete mode 100644 portal_client/app/common/services/model/cache/stores/script-stores/script-stores.js delete mode 100644 portal_client/app/common/services/model/cache/stores/stores.js delete mode 100644 portal_client/app/common/services/model/cache/stores/system-stores/system-stores.js delete mode 100644 portal_client/app/common/services/model/rest/account-provider/account-provider.js delete mode 100644 portal_client/app/common/services/model/rest/application-log-provider/application-log-provider.js delete mode 100644 portal_client/app/common/services/model/rest/config-provider/config-provider.js delete mode 100644 portal_client/app/common/services/model/rest/credential-provider/credential-provider.js delete mode 100644 portal_client/app/common/services/model/rest/file-provider/file-provider.js delete mode 100644 portal_client/app/common/services/model/rest/git-provider/git-provider.js delete mode 100644 portal_client/app/common/services/model/rest/logger-provider/logger-provider.js delete mode 100644 portal_client/app/common/services/model/rest/permission-provider/permission-provider.js delete mode 100644 portal_client/app/common/services/model/rest/request/request.js delete mode 100644 portal_client/app/common/services/model/rest/rest.js delete mode 100644 portal_client/app/common/services/model/rest/script-provider/script-provider.js delete mode 100644 portal_client/app/common/services/model/rest/system-provider/system-provider.js delete mode 100644 portal_client/app/common/services/permissions/permissions.js delete mode 100644 portal_client/app/common/services/triggers/trigger-manager.js delete mode 100644 portal_client/app/common/services/triggers/triggers.js delete mode 100644 portal_client/app/common/services/utils/portalUtils.js delete mode 100644 portal_client/app/custom/portal-material-override.css delete mode 100644 portal_client/app/login/login.css delete mode 100644 portal_client/app/login/login.html delete mode 100644 portal_client/app/login/login.js delete mode 100644 portal_client/app/main/cred-bank/cell-templates/cred-actions.html delete mode 100644 portal_client/app/main/cred-bank/cred-bank.html delete mode 100644 portal_client/app/main/cred-bank/cred-bank.js delete mode 100644 portal_client/app/main/dashboard.css delete mode 100644 portal_client/app/main/dashboard.html delete mode 100644 portal_client/app/main/dashboard.js delete mode 100644 portal_client/app/main/email-bank/cell-templates/email-actions.html delete mode 100644 portal_client/app/main/email-bank/email-bank.html delete mode 100644 portal_client/app/main/email-bank/email-bank.js delete mode 100644 portal_client/app/main/env-bank/env-bank.html delete mode 100644 portal_client/app/main/env-bank/env-bank.js delete mode 100644 portal_client/app/main/git-bank/cell-templates/git-actions.html delete mode 100644 portal_client/app/main/git-bank/git-bank.html delete mode 100644 portal_client/app/main/git-bank/git-bank.js delete mode 100644 portal_client/app/main/log-bank/log-bank.html delete mode 100644 portal_client/app/main/log-bank/log-bank.js delete mode 100644 portal_client/app/main/permission-bank/cell-templates/permission-actions.html delete mode 100644 portal_client/app/main/permission-bank/permission-bank.html delete mode 100644 portal_client/app/main/permission-bank/permission-bank.js delete mode 100644 portal_client/app/main/script-bank/cell-templates/script-actions.html delete mode 100644 portal_client/app/main/script-bank/cell-templates/script-sched-actions.html delete mode 100644 portal_client/app/main/script-bank/cell-templates/script-sched-status.html delete mode 100644 portal_client/app/main/script-bank/script-bank.html delete mode 100644 portal_client/app/main/script-bank/script-bank.js delete mode 100644 portal_client/app/main/user-bank/cell-templates/user-actions.html delete mode 100644 portal_client/app/main/user-bank/user-bank.html delete mode 100644 portal_client/app/main/user-bank/user-bank.js delete mode 100644 portal_client/assets.js delete mode 100644 portal_client/index.html create mode 100644 portal_client/package-lock.json rename portal_client/{app => public}/favicon.ico (100%) rename portal_client/{app => public}/fonts/google-md-icons/MaterialIcons-Regular.css (52%) rename portal_client/{app => public}/fonts/google-md-icons/MaterialIcons-Regular.eot (100%) rename portal_client/{app => public}/fonts/google-md-icons/MaterialIcons-Regular.woff (100%) rename portal_client/{app => public}/fonts/google-md-icons/MaterialIcons-Regular.woff2 (100%) rename portal_client/{app => public}/images/NGLogo.png (100%) rename portal_client/{app => public}/images/background.png (100%) rename portal_client/{app => public}/images/portal.png (100%) create mode 100644 portal_client/src/app/app.config.ts create mode 100644 portal_client/src/app/app.html create mode 100644 portal_client/src/app/app.routes.spec.ts create mode 100644 portal_client/src/app/app.routes.ts create mode 100644 portal_client/src/app/app.scss create mode 100644 portal_client/src/app/app.spec.ts create mode 100644 portal_client/src/app/app.ts create mode 100644 portal_client/src/app/core/auth.guard.ts create mode 100644 portal_client/src/app/core/auth.interceptor.ts create mode 100644 portal_client/src/app/core/models.ts create mode 100644 portal_client/src/app/core/permission.guard.ts create mode 100644 portal_client/src/app/core/portal-api.service.spec.ts create mode 100644 portal_client/src/app/core/portal-api.service.ts create mode 100644 portal_client/src/app/core/realtime.service.ts create mode 100644 portal_client/src/app/core/session.service.spec.ts create mode 100644 portal_client/src/app/core/session.service.ts create mode 100644 portal_client/src/app/dashboard/admin-dialog.ts create mode 100644 portal_client/src/app/dashboard/dashboard.ts create mode 100644 portal_client/src/app/features/entity-dialog.ts create mode 100644 portal_client/src/app/features/environment-dialog.ts create mode 100644 portal_client/src/app/features/feature-page.ts create mode 100644 portal_client/src/app/features/permission-dialog.ts create mode 100644 portal_client/src/app/features/purge-logs-dialog.ts create mode 100644 portal_client/src/app/features/script-dialog.ts create mode 100644 portal_client/src/app/features/script-status-dialog.ts create mode 100644 portal_client/src/app/login/login.ts create mode 100644 portal_client/src/index.html create mode 100644 portal_client/src/main.ts create mode 100644 portal_client/src/polyfills.ts create mode 100644 portal_client/src/styles.scss create mode 100644 portal_client/tsconfig.app.json create mode 100644 portal_client/tsconfig.json create mode 100644 portal_client/tsconfig.spec.json delete mode 100644 portal_client/webpack.config.js delete mode 100644 portal_client/yarn_file_copy.js create mode 100644 portal_common/src/test/java/net/locusworks/portal/common/PortalDataSourceTest.java delete mode 100644 portal_database/src/main/resources/META-INF/persistence.xml create mode 100644 portal_webapp/src/main/java/net/locusworks/portal/PortalApplication.java create mode 100644 portal_webapp/src/main/resources/application.properties delete mode 100644 portal_webapp/src/main/webapp/META-INF/context.xml delete mode 100644 portal_webapp/src/main/webapp/WEB-INF/portal-config.xml delete mode 100644 portal_webapp/src/main/webapp/WEB-INF/portal-servlet.xml delete mode 100644 portal_webapp/src/main/webapp/WEB-INF/web.xml diff --git a/.gitignore b/.gitignore index c392231..a4076f1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,19 +2,15 @@ .idea .project .settings -portal_client/dist/ -portal_client/nbproject/private/ -portal_client/node/ -portal_client/node_modules/ -portal_client/test_out/ -portal_client/temp/ -portal_client/app/compiled-less -portal_client/app/index.html -portal_client/app/yarn_components/** +portal_client/dist/ +portal_client/.angular/ +portal_client/nbproject/private/ +portal_client/node/ +portal_client/node_modules/ +portal_client/test_out/ +portal_client/temp/ portal_webapp/.externalToolBuilders/ -portal_client/yarn.l* -portal_client/yarn-* -npm-debug.log +npm-debug.log phantomjs tags *.DS_Store @@ -29,7 +25,6 @@ tags /filerepo_api/ **/*.aux **/*.bbl -**/yarn.lock **/*.blg **/*.log **/*.out diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..0f62d6e --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,85 @@ +pipeline { + agent any + + options { + buildDiscarder(logRotator(numToKeepStr: '5')) + disableConcurrentBuilds() + skipDefaultCheckout(true) + timestamps() + } + + stages { + stage('Checkout') { + steps { checkout scm } + } + + stage('Set version') { + steps { + script { + String branch = env.BRANCH_NAME + if (!branch) { error('BRANCH_NAME is unavailable; this pipeline must run as a multibranch job') } + env.DEPLOY_BUILD = 'false' + def releaseMatch = branch =~ /^release\/(\d+\.\d+(?:\.\d+)?)$/ + if (releaseMatch.matches()) { + env.BUILD_VERSION = "${releaseMatch[0][1]}.${env.BUILD_NUMBER}-RELEASE" + env.DEPLOY_BUILD = 'true' + } else if (branch == 'develop') { + env.BUILD_VERSION = "develop.${env.BUILD_NUMBER}-SNAPSHOT" + env.DEPLOY_BUILD = 'true' + } else { + String safeBranch = branch.replaceAll(/[^A-Za-z0-9._-]/, '-') + env.BUILD_VERSION = "0.0.${env.BUILD_NUMBER}-${safeBranch}-SNAPSHOT" + } + currentBuild.displayName = env.BUILD_VERSION + } + withMaven(maven: 'maven-3.9.16', globalMavenSettingsConfig: 'locusworks-settings') { + sh 'mvn -B org.codehaus.mojo:versions-maven-plugin:2.21.0:set -DprocessAllModules=true -DgenerateBackupPoms=false -DnewVersion="$BUILD_VERSION"' + sh 'mvn -B org.codehaus.mojo:versions-maven-plugin:2.21.0:set-property -Dproperty=current.version -DgenerateBackupPoms=false -DnewVersion="$BUILD_VERSION"' + } + } + } + + stage('Prepare OWASP cache') { + steps { + withCredentials([string(credentialsId: 'nvd-api-key', variable: 'NVD_API_KEY')]) { + lock(resource: 'owasp-nvd-cache') { + withMaven(maven: 'maven-3.9.16', globalMavenSettingsConfig: 'locusworks-settings') { + sh 'mkdir -p "$HOME/.cache/dependency-check"' + sh 'mvn -B org.owasp:dependency-check-maven:13.0.0:update-only -DdataDirectory="$HOME/.cache/dependency-check"' + } + } + } + } + } + + stage('Build and test') { + steps { + withMaven(maven: 'maven-3.9.16', globalMavenSettingsConfig: 'locusworks-settings') { + sh 'mvn -B clean verify -DdataDirectory="$HOME/.cache/dependency-check" -DautoUpdate=false -Dbuild.revision="$GIT_COMMIT"' + } + } + post { + always { junit allowEmptyResults: true, testResults: '**/target/surefire-reports/*.xml' } + success { + archiveArtifacts artifacts: '**/target/*.jar', fingerprint: true + archiveArtifacts artifacts: '**/target/site/jacoco/**', fingerprint: true, allowEmptyArchive: true + } + } + } + + stage('Deploy') { + when { expression { env.DEPLOY_BUILD == 'true' } } + steps { + withMaven(maven: 'maven-3.9.16', globalMavenSettingsConfig: 'locusworks-settings') { + sh 'mvn -B deploy -DskipTests -Ddependency-check.skip=true -Dbuild.number="$BUILD_NUMBER" -Dbuild.revision="$GIT_COMMIT"' + } + } + } + } + + post { + success { echo "Published build ${env.BUILD_VERSION} successfully" } + failure { echo "Build ${env.BUILD_VERSION ?: env.BUILD_NUMBER} failed" } + cleanup { deleteDir() } + } +} diff --git a/README.md b/README.md index c2a20dd..3ace643 100644 --- a/README.md +++ b/README.md @@ -2,23 +2,41 @@ --- 1. Clone the repository from BigMac: - Add your public key to BigMac account. - - Clone the repository: `git clone "ssh://git@bigmac.northgrum.com:8010/saipt/portal-webapp.git"` + - Clone the repository: `git clone "ssh://git@bigmac.locusworks.net:8010/saipt/portal-webapp.git"` 2. Create/Edit `settings.xml` in your `.m2` folder (see next section for example) -3. This project requires ngas-commons to be built prior to building this application - - Checkout `ngas-commons` (`"ssh://git@bigmac.northgrum.com:8010/saipt/ngas-commons.git"`) - - Change directories into `ngas-commons` and run `mvn clean install` -4. Change directories into the project and run `mvn clean install` (This might take awhile) -5. Once the server launches, you should be able to access the webapp by browsing to `http://localhost:8080/portal/` - -## Yarn ---- -Yarn is the the new package manager used with node.js in replacement of `npm` it uses the same package.json file. - -To download a new client side library use the command `yarn add --save`. This will add the files to the `node_modules` library. - -Next include the appropriate file into the `assets.js` file inside `portal_client` to make sure it will be injected into the `index.html` file during run time. - -The `assets.js` file specifies all the vendor libraries that have to be included into the client code during build. +3. Change directories into the project and run `mvn clean install` (this may take a while). +4. Start the executable Spring Boot application with `java -jar portal_webapp/target/portal_webapp-1.0.0-RELEASE.jar`. +5. Browse to `http://localhost:8080/portal/`. + +Application configuration is stored under `${user.home}/.portal` by default. Override this persistent location with the `PORTAL_HOME` environment variable or the `-Dportal.home=/path/to/portal` JVM property. The directory contains `portal.properties`, the AES seed, logger settings, logs, and temporary key files. + +Local runs use a persistent H2 database by default. Set `dbType=mysql` in `portal.properties` only when an external MySQL server is intended; H2 and MySQL have separate connection and credential properties. + +External MySQL deployments require MySQL Server 8.4 or newer with Connector/J 26.7.0. + +## npm +--- +npm is used to install the Angular client dependencies declared in `portal_client/package.json`. + +The Maven build provisions the supported Node.js LTS and npm versions declared in the root `pom.xml`; a global installation is not required for Maven builds. + +From `portal_client`, run `npm ci` for a reproducible install, `npm test` for unit tests, and `npm run build` for the production bundle. Angular CLI discovers application imports and static assets directly; no legacy asset-injection manifest is required. + +The `allowScripts` entries in `package.json` approve specific versions of the native Angular build helpers. Review and renew those entries when upgrading the corresponding packages. SockJS remains an explicitly allowed CommonJS dependency for the server's SockJS transport. STOMP uses its ESM entry through the TypeScript path mapping because version 7.3.0's browser export selects UMD. + +## Dependency checks + +`mvn clean install` runs OWASP Dependency-Check. NVD, RetireJS, and the npm lockfile audit remain enabled; the npm audit includes development dependencies. The Node Package Analyzer skips development dependencies to avoid treating uninstalled native binaries for other platforms as missing application packages. + +Sonatype OSS Index requires credentials and is opt-in. Configure a Maven `settings.xml` server with ID `oss-index`, your account username, and API token, then run `mvn clean install -Dportal.ossIndexEnabled=true` to include it. + +## H2 tests +--- +Tests use an isolated in-memory H2 database through the `portal.database.*` system-property overrides. Production continues to default to MySQL. + +Run the common-module datasource test with: + +`mvn -pl portal_common -am test` ## Settings.xml @@ -31,19 +49,19 @@ Sample: xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.1.0 http://maven.apache.org/xsd/settings-1.1.0.xsd"> - ngas-proxy + locusworks-proxy true http - eastproxy.northgrum.com + eastproxy.locusworks.net 80 (your MyID) (your login password) - ngas-proxy2 + locusworks-proxy2 true https - eastproxy.northgrum.com + eastproxy.locusworks.net 80 (your MyID) (your login password) @@ -55,29 +73,13 @@ Sample: root (mysql root password) - - - tomcat-localhost - (manager-script username) - (manager-script password) - - - - - local-deploy - - C:\development\apache-tomcat-8.5.24-portal - 8.5.24 - http://localhost:8080 - - - - -``` - -## Configuring Tomcat ---- -Tomcat cannot run on port 80 or 443 unless it is is running as root (big security concern with that). It is suggested to use proxy services like `NGINX` or `Apache` to proxy 80 or 443 traffic to redirect to tomcat + + +``` + +## Running Spring Boot +--- +The application is packaged as an executable JAR and does not require a separately installed application server. Spring Boot supplies the embedded web server. For production, NGINX or Apache can proxy ports 80 and 443 to the application on port 8080. #### NGINX 1. In the default /etc/nginx/conf.d add a file called portal.conf @@ -91,11 +93,11 @@ Tomcat cannot run on port 80 or 443 unless it is is running as root (big securit '' close; } - upstream tomcat { + upstream portal_app { # Use IP Hash for session persistence ip_hash; - # List of Tomcat application servers + # List of Portal application instances server 127.0.0.1:8080; } @@ -123,7 +125,7 @@ Tomcat cannot run on port 80 or 443 unless it is is running as root (big securit # WebSocket configuration location / { - proxy_pass http://tomcat; + proxy_pass http://portal_app; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml deleted file mode 100644 index 96184b9..0000000 --- a/bitbucket-pipelines.yml +++ /dev/null @@ -1,23 +0,0 @@ -pipelines: - default: - - step: - name: Portal build - image: maven:3.3.9 - size: 2x - caches: - - maven - - node - script: - - git clone git@bitbucket.org:locus2k/commons.git --branch 1.1.0-RELEASE - - mvn -B install -f commons/pom.xml - - mvn -s pipeline-settings.xml -B install # -B batch mode makes Maven less verbose - services: - - mysql - -definitions: - services: - mysql: - image: mysql:8.0.11 - environment: - MYSQL_DATABASE: 'portal' - MYSQL_ROOT_PASSWORD: 'let_me_in' diff --git a/docs/src/Deployment.tex b/docs/src/Deployment.tex index e36f300..c3ffe27 100644 --- a/docs/src/Deployment.tex +++ b/docs/src/Deployment.tex @@ -31,11 +31,11 @@ The following is a list of software that are required to be installed and on be \item Ant \AntVersion\ \cite{ant} \end{enumerate} -Two projects need to be checkout out from the git repository. The \portal project and the ngas-commons project. +Two projects need to be checkout out from the git repository. The \portal project and the locusworks-commons project. Section~\ref{dev-setup} describes how to checkout the \portal project -Section~\ref{ngas-commons} descrives how to checkout and build the \command{ngas-commons} library. This library is needed to build the main web application +Section~\ref{locusworks-commons} descrives how to checkout and build the \command{locusworks-commons} library. This library is needed to build the main web application To build the project issue the command \command{mvn clean install antrun:run@warcopy} (if tomcat is not running) or \command{mvn clean install tomcat7:redeploy} (if tomcat is currently running). This might take awhile as it will download the required libraries from the internet and deploy the war file to the tomcat server. @@ -46,15 +46,15 @@ Once the build has completed and deployed verify in the logs the application has \section{Encrypted MySQL Root Password} \label{mysql-root-password} -To encrypted the mysql root password first checkout and compile the \command{ngas-commons} library (See section~\ref{ngas-commons} to perform the task). +To encrypted the mysql root password first checkout and compile the \command{locusworks-commons} library (See section~\ref{locusworks-commons} to perform the task). Once the commons library has been downloaded and installed perform the following. \begin{legal} \item Navigate to the \command{.m2} directory located in the home directory - \item Navigate to \filename{repository/com/ngas/ngas-commons/\ngasCommonsVersion} + \item Navigate to \filename{repository/net/locusworks/locusworks-commons/\locusworksCommonsVersion} \item Execute the following command\newline - \command{java -cp ngas-commons-\ngasCommonsVersion.jar net.locusworks.commons.crypto.AES }\newline + \command{java -cp locusworks-commons-\locusworksCommonsVersion.jar net.locusworks.commons.crypto.AES }\newline Where ``root-password'' is the MySQL root password \end{legal} diff --git a/docs/src/Development.tex b/docs/src/Development.tex index 29b21ca..2d7fa85 100644 --- a/docs/src/Development.tex +++ b/docs/src/Development.tex @@ -20,32 +20,32 @@ This section describes how to setup the \portal environment to be able to build \begin{enumerate} \item Add developers public key to BigMac account \item Clone the repository \newline - \command{git clone ``ssh://git@bigmac.northgrum.com:8010/saipt/portal-webapp.git''} + \command{git clone ``ssh://git@bigmac.locusworks.net:8010/saipt/portal-webapp.git''} \end{enumerate} \item Create/Edit \command{settings.xml} in the \command{.m2} located in the home directory. See Subsection~\ref{settings.xml} - \item \portal requires \command{ngas-commons} library to be built prior to building the web application. See Subsection~\ref{ngas-commons} + \item \portal requires \command{locusworks-commons} library to be built prior to building the web application. See Subsection~\ref{locusworks-commons} \item Change directories into the project and run \command{mvn clean install antrun:run@warcopy}. This could take some time to download the required libraries. \item Start the tomcat server and navigate to \command{http://localhost:8080/portal/} to make sure the server comes up \end{enumerate} -\subsection{NGAS Commons} -\label{ngas-commons} -NGAS Commons is a common library of functions that other java applications can take advantage of. +\subsection{Locusworks Commons} +\label{locusworks-commons} +Locusworks Commons is a common library of functions that other java applications can take advantage of. To checkout the library:\newline -\command{git clone ``ssh://git@bigmac.northgrum.com:8010/saipt/ngas-commons.git''} +\command{git clone ``ssh://git@bigmac.locusworks.net:8010/saipt/locusworks-commons.git''} To build:\newline \command{mvn clean install} -Note: \command{ngas-commons} needs to be built prior to building the main application +Note: \command{locusworks-commons} needs to be built prior to building the main application -\section{Yarn} -\label{yarn} -Yarn is the new package manager used with \command{node.js} in replacement of \command{npm} it uses the same \command{pacakge.json} file that \command{npm} did. - -To download a new client side library use the command \command{yarn add --save}. This will add the file to the \command{node\_modules} library. +\section{npm} +\label{npm} +npm installs the client-side dependencies declared in \command{package.json}. + +From \command{portal\_client}, run \command{npm install} to install dependencies. To add a client-side library, run \command{npm install --save}. Next include the appropriate file into the \command{assets.js} file inside \command{portal\_client} to make sure it will be injected into the \command{index.html} file during compile time. diff --git a/docs/src/ToolsLibraries.tex b/docs/src/ToolsLibraries.tex index 1bc4d2f..5f654e5 100644 --- a/docs/src/ToolsLibraries.tex +++ b/docs/src/ToolsLibraries.tex @@ -20,7 +20,7 @@ The following list reflects the tools and libraries used by the \portal develope \item JSch \JSchVersion \item JGit \JGitVersion \item Node.js \NodeVersion - \item Yarn \YarnVersion + \item npm \NpmVersion \item Flyway \FlywayVersion \item Tomcat \TomcatVersion \end{itemize} @@ -65,7 +65,7 @@ invoke the ant process. \portal utilizes ant version \AntVersion but older versi \section{AngularJs} AngularJs\cite{angularjs} is extensively used inside the client html code along with various other 3rd party javascript libraries. The list of 3rd party libraries used in the client can be found in \filename{assets.js}. It is not necessary to download the AngularJs library as it will be downloaded automatically along with the other vendor libraries during the build -process. Yarn is utilized to do this task and place references to the files inside the \filename{index.html} during build. AngularJs is specifically called out because of how much it does +process. npm is utilized to do this task and place references to the files inside the \filename{index.html} during build. AngularJs is specifically called out because of how much it does inside the client and developers should be familiar with it. \portal utlizes version \AngularJsVersion of AngularJs as specified in the \filename{package.json} file. \section{Spring} @@ -163,22 +163,20 @@ This allows the developer to make changes and not have to rebuild the whole appl \portal utilizes version \NodeVersion\ of Node.js. It is possible to use older versions of Node.js but it not recommended for security concerns. -\section{Yarn} -\label{yarn2} +\section{npm} +\label{npm2} -Yarn\cite{yarn} is a package manager program that allows for easy download of 3rd party javascript/typescript libraries. It caches every package so it never needs to download it again. -Yarn is used as a replacement for node.js package manager (npm) and utilizes the same \filename{package.json} file as npm along with installing the packages in the same directory that -npm (\filename{portal\_client/node\_modules}). +npm is the package manager used to download third-party JavaScript libraries declared in \filename{package.json}. Packages are installed in +\filename{portal\_client/node\_modules}. -This allows for developers to switch easily from npm to yarn. During build time, maven will automatically download yarn locally to the project so it can use the local process to download -the 3rd party libraries as specified in the \filename{package.json} file. +During build time, Maven downloads Node.js and npm locally, then installs the exact dependency tree recorded in \filename{package-lock.json}. -Yarn needs to be installed on the developers home path to be utilizes by the developer to install new packages. To install new packages issue the command - \command{yarn add --save}. This will download the request package and save the package to the \filename{package.json} file for future reference. +To install dependencies, run \command{npm install}. To add a new package, run +\command{npm install --save} and commit both package files. -See~\ref{yarn} for more details. +See~\ref{npm} for more details. -\portal utilizes version \YarnVersion of yarn. No older version can be used at this time. +\portal utilizes version \NpmVersion of npm. \section{Flyway} Flyway\cite{flyway} is an open source database migration tool. It strongly favors simplicity and convention over configuration. It is based around 7 basic commands: Migrate, Clean, @@ -244,4 +242,3 @@ The developer just has to issues the command \command{mvn tomcat7:redeploy} to d \portal utilizes version \TomcatVersion of Tomcat. Older or newer versions of tomcat can be used but it is not recommend to go any lower than tomcat 7 - diff --git a/docs/src/api/ConfigurationAPI.tex b/docs/src/api/ConfigurationAPI.tex index 6e181b8..f6eb366 100644 --- a/docs/src/api/ConfigurationAPI.tex +++ b/docs/src/api/ConfigurationAPI.tex @@ -17,7 +17,7 @@ The following will get a specified configuration value if that value is present \ApiData{\input{api/sample/request/getConfValReq}}{\input{api/sample/response/getConfValResp}} \subsection{Get Configuration} -The following will get the current configuration values associated with the server as specified in the file \filename{\$TOMCAT\_HOME/conf/portal.properties} +The following will get the current configuration values associated with the server as specified in the file \filename{\$PORTAL\_HOME/portal.properties} \begin{apimethod} {Get Configuration} {config/getConfiguration.do} @@ -31,7 +31,7 @@ The following will get the current configuration values associated with the serv \ApiData{\input{api/sample/None}}{\input{api/sample/response/getConfResp}} \subsection{Save Configuration} -The following will save the server configuration values to \filename{\$TOMCAT\_HOME/conf/portal.properties}. All the parameters are option as they all do not need to be populated, just the ones that need to be changed +The following will save the server configuration values to \filename{\$PORTAL\_HOME/portal.properties}. All the parameters are option as they all do not need to be populated, just the ones that need to be changed \begin{apimethod} {Save Configuration} {config/saveConfiguration.do} @@ -52,4 +52,3 @@ The following will save the server configuration values to \filename{\$TOMCAT\_H \ApiData{\input{api/sample/response/getConfResp}}{\input{api/sample/SuccessResp}} - diff --git a/docs/src/api/sample/request/addGitRepoReq.tex b/docs/src/api/sample/request/addGitRepoReq.tex index b28ea74..8164037 100644 --- a/docs/src/api/sample/request/addGitRepoReq.tex +++ b/docs/src/api/sample/request/addGitRepoReq.tex @@ -2,7 +2,7 @@ \begin{lstlisting}[language=JSON] { "name": "Stig Apply", - "scm": "https://J65594@bigmac.northgrum.com/bitbucket/scm/saipt/stig-apply.git", + "scm": "https://J65594@bigmac.locusworks.net/bitbucket/scm/saipt/stig-apply.git", "branch": "develop", "directory": "C:\\stigapply", "credentials": { diff --git a/docs/src/api/sample/request/addScriptLocalReq.tex b/docs/src/api/sample/request/addScriptLocalReq.tex index 098f177..b51a4ac 100644 --- a/docs/src/api/sample/request/addScriptLocalReq.tex +++ b/docs/src/api/sample/request/addScriptLocalReq.tex @@ -30,7 +30,7 @@ "scriptEmails": [{ "emailName": "Script Status", "recipients": [{ - "email": "portalAdmin@ngc.com", + "email": "portalAdmin@locusworks.net", }] }], } diff --git a/docs/src/api/sample/request/addScriptRemoteReq.tex b/docs/src/api/sample/request/addScriptRemoteReq.tex index 2e78e96..f0aaa5a 100644 --- a/docs/src/api/sample/request/addScriptRemoteReq.tex +++ b/docs/src/api/sample/request/addScriptRemoteReq.tex @@ -34,7 +34,7 @@ "scriptEmails": [{ "emailName": "Script Status", "recipients": [{ - "email": "portalAdmin@ngc.com", + "email": "portalAdmin@locusworks.net", }] }], } diff --git a/docs/src/api/sample/request/addScriptScpReq.tex b/docs/src/api/sample/request/addScriptScpReq.tex index a7fd1cb..0269a75 100644 --- a/docs/src/api/sample/request/addScriptScpReq.tex +++ b/docs/src/api/sample/request/addScriptScpReq.tex @@ -31,7 +31,7 @@ "scriptEmails": [{ "emailName": "Script Status", "recipients": [{ - "email": "portalAdmin@ngc.com", + "email": "portalAdmin@locusworks.net", }] }], } diff --git a/docs/src/api/sample/request/addUserReq.tex b/docs/src/api/sample/request/addUserReq.tex index 8767cb5..29afbc8 100644 --- a/docs/src/api/sample/request/addUserReq.tex +++ b/docs/src/api/sample/request/addUserReq.tex @@ -4,7 +4,7 @@ "password": "bar", "lastName": "foo", "firstName": "bar", - "email": "bar@ngc.com", + "email": "bar@locusworks.net", "role": "USER", "expirationDate": "2028-03-31T19:54:40.550Z", "effectiveDate": "2018-04-03T19:54:39.929Z", diff --git a/docs/src/api/sample/request/deleteUserReq.tex b/docs/src/api/sample/request/deleteUserReq.tex index a40b23e..2cd88d6 100644 --- a/docs/src/api/sample/request/deleteUserReq.tex +++ b/docs/src/api/sample/request/deleteUserReq.tex @@ -1,7 +1,7 @@ \begin{minipage}[t]{0.45\textwidth} \begin{lstlisting}[language=JSON] { - "email": "bar@ngc.com", + "email": "bar@locusworks.net", } \end{lstlisting} \end{minipage} \ No newline at end of file diff --git a/docs/src/api/sample/response/addGitRepoResp.tex b/docs/src/api/sample/response/addGitRepoResp.tex index b081c0a..4046ffd 100644 --- a/docs/src/api/sample/response/addGitRepoResp.tex +++ b/docs/src/api/sample/response/addGitRepoResp.tex @@ -3,7 +3,7 @@ { "id": 5, "name": "Stig Apply", - "scm": "https://J65594@bigmac.northgrum.com/bitbucket/scm/saipt/stig-apply.git", + "scm": "https://J65594@bigmac.locusworks.net/bitbucket/scm/saipt/stig-apply.git", "branch": "develop", "directory": "C:\\stigapply", "credentials": { diff --git a/docs/src/api/sample/response/addScriptLocalResp.tex b/docs/src/api/sample/response/addScriptLocalResp.tex index ffef1c8..49f464f 100644 --- a/docs/src/api/sample/response/addScriptLocalResp.tex +++ b/docs/src/api/sample/response/addScriptLocalResp.tex @@ -60,7 +60,7 @@ "firstName": "Portal", "lastName": "Admin", "role": "ADMIN", - "email": "portalAdmin@ngc.com", + "email": "portalAdmin@locusworks.net", "expirationDate": 2.534022324e+14, "effectiveDate": 1519275600000, "enabled": true diff --git a/docs/src/api/sample/response/addScriptRemoteResp.tex b/docs/src/api/sample/response/addScriptRemoteResp.tex index 2b382e2..8114026 100644 --- a/docs/src/api/sample/response/addScriptRemoteResp.tex +++ b/docs/src/api/sample/response/addScriptRemoteResp.tex @@ -52,7 +52,7 @@ "firstName": "Portal", "lastName": "Admin", "role": "ADMIN", - "email": "portalAdmin@ngc.com", + "email": "portalAdmin@locusworks.net", "expirationDate": 2.534022324e+14, "effectiveDate": 1519275600000, "enabled": true diff --git a/docs/src/api/sample/response/addScriptScpResp.tex b/docs/src/api/sample/response/addScriptScpResp.tex index 0266dda..d15a91a 100644 --- a/docs/src/api/sample/response/addScriptScpResp.tex +++ b/docs/src/api/sample/response/addScriptScpResp.tex @@ -43,7 +43,7 @@ "scriptEmails": [{ "emailName": "Script Status", "recipients": [{ - "email": "portalAdmin@ngc.com", + "email": "portalAdmin@locusworks.net", }] }], } diff --git a/docs/src/api/sample/response/addUserResp.tex b/docs/src/api/sample/response/addUserResp.tex index 3736123..ffde903 100644 --- a/docs/src/api/sample/response/addUserResp.tex +++ b/docs/src/api/sample/response/addUserResp.tex @@ -6,9 +6,9 @@ "firstName": "bar", "lastName": "foo", "role": "USER", - "username": "bar@ngc.com", + "username": "bar@locusworks.net", "password": null, - "email": "bar@ngc.com", + "email": "bar@locusworks.net", "expirationDate": 1838145280550, "effectiveDate": 1522785279929, "enabled": true diff --git a/docs/src/api/sample/response/getAllReposResp.tex b/docs/src/api/sample/response/getAllReposResp.tex index 6522cb4..ec6d095 100644 --- a/docs/src/api/sample/response/getAllReposResp.tex +++ b/docs/src/api/sample/response/getAllReposResp.tex @@ -4,7 +4,7 @@ { "id": 5, "name": "Stig Apply", - "scm": "https://J65594@bigmac.northgrum.com/bitbucket/scm/saipt/stig-apply.git", + "scm": "https://J65594@bigmac.locusworks.net/bitbucket/scm/saipt/stig-apply.git", "branch": "develop", "directory": "C:\\stigapply", "credentials": { diff --git a/docs/src/api/sample/response/getAllScriptsResp.tex b/docs/src/api/sample/response/getAllScriptsResp.tex index bcdfeee..2442222 100644 --- a/docs/src/api/sample/response/getAllScriptsResp.tex +++ b/docs/src/api/sample/response/getAllScriptsResp.tex @@ -60,7 +60,7 @@ "firstName": "Portal", "lastName": "Admin", "role": "ADMIN", - "email": "portalAdmin@ngc.com", + "email": "portalAdmin@locusworks.net", "expirationDate": 2.534022324e+14, "effectiveDate": 1519275600000, "enabled": true diff --git a/docs/src/api/sample/response/getAllUsersResp.tex b/docs/src/api/sample/response/getAllUsersResp.tex index 9910c43..395ca27 100644 --- a/docs/src/api/sample/response/getAllUsersResp.tex +++ b/docs/src/api/sample/response/getAllUsersResp.tex @@ -7,9 +7,9 @@ "firstName": "Repo", "lastName": "Admin", "role": "ADMIN", - "username": "portalAdmin@ngc.com", + "username": "portalAdmin@locusworks.net", "password": null, - "email": "portalAdmin@ngc.com", + "email": "portalAdmin@locusworks.net", "expirationDate": 2.534022324e+14, "effectiveDate": 1517979600000, "enabled": true @@ -20,9 +20,9 @@ "firstName": "foo", "lastName": "bar", "role": "USER", - "username": "foo@ngc.com", + "username": "foo@locusworks.net", "password": null, - "email": "foo@ngc.com", + "email": "foo@locusworks.net", "expirationDate": 1838088000000, "effectiveDate": 1522728000000, "enabled": true diff --git a/docs/src/api/sample/response/getConfResp.tex b/docs/src/api/sample/response/getConfResp.tex index d3b1d34..b2a1104 100644 --- a/docs/src/api/sample/response/getConfResp.tex +++ b/docs/src/api/sample/response/getConfResp.tex @@ -10,7 +10,7 @@ "dbUsername": "portalAdmin", "filepath": "C:\\tempStorage", "dbPassword": "CWg48+h4q7iK4ICGaDhRd10EMQfFgthm3FjhkLd6gis=" - "aesSeedFile": "C:/development/apache-tomcat-8.5.24/conf/portal.tomcat" + "aesSeedFile": "C:/Users/user/.portal/portal.tomcat" } \end{lstlisting} -\end{minipage} \ No newline at end of file +\end{minipage} diff --git a/docs/src/api/sample/response/loginResp.tex b/docs/src/api/sample/response/loginResp.tex index b52f035..4aaaf6f 100644 --- a/docs/src/api/sample/response/loginResp.tex +++ b/docs/src/api/sample/response/loginResp.tex @@ -6,8 +6,8 @@ "firstName": "foo", "lastName": "bar", "role": "USER", - "username": "foo@ngc.com", - "email": "foo@ngc.com", + "username": "foo@locusworks.net", + "email": "foo@locusworks.net", "expirationDate": 2.534022324e+14, "effectiveDate": 1517979600000, "enabled": true, diff --git a/docs/src/appendix/ApacheAppendex.tex b/docs/src/appendix/ApacheAppendex.tex index 080ef21..d17d903 100644 --- a/docs/src/appendix/ApacheAppendex.tex +++ b/docs/src/appendix/ApacheAppendex.tex @@ -1,7 +1,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % FILE : ApacheAppendix.tex % SUBJECT : ApacheApendex. -% AUTHOR : (C) Copyright 2018 by Northrop Grumman +% AUTHOR : (C) Copyright 2018 by Locusworks % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/docs/src/appendix/NginxAppendex.tex b/docs/src/appendix/NginxAppendex.tex index 6fff2a7..2a87e3a 100644 --- a/docs/src/appendix/NginxAppendex.tex +++ b/docs/src/appendix/NginxAppendex.tex @@ -1,7 +1,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % FILE : Architecture.tex % SUBJECT : Document describing architecture issues in the entire Patch Repository system. -% AUTHOR : (C) Copyright 2018 by Northrop Grumman +% AUTHOR : (C) Copyright 2018 by Locusworks % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/docs/src/appendix/PropertiesAppendex.tex b/docs/src/appendix/PropertiesAppendex.tex index af078a7..4ff394d 100644 --- a/docs/src/appendix/PropertiesAppendex.tex +++ b/docs/src/appendix/PropertiesAppendex.tex @@ -1,7 +1,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % FILE : Architecture.tex % SUBJECT : Document describing architecture issues in the entire Patch Repository system. -% AUTHOR : (C) Copyright 2018 by Northrop Grumman +% AUTHOR : (C) Copyright 2018 by Locusworks % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/docs/src/appendix/Revisions.tex b/docs/src/appendix/Revisions.tex index 936a85f..1b3200f 100644 --- a/docs/src/appendix/Revisions.tex +++ b/docs/src/appendix/Revisions.tex @@ -1,7 +1,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % FILE : Revision.tex % SUBJECT : Revision history. -% AUTHOR : (C) Copyright 2018 by Northrop Grumman +% AUTHOR : (C) Copyright 2018 by Locusworks % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/docs/src/appendix/SeedFileAppendex.tex b/docs/src/appendix/SeedFileAppendex.tex index 4582c8c..d7d5f79 100644 --- a/docs/src/appendix/SeedFileAppendex.tex +++ b/docs/src/appendix/SeedFileAppendex.tex @@ -1,7 +1,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % FILE : ApacheAppendix.tex % SUBJECT : ApacheApendex. -% AUTHOR : (C) Copyright 2018 by Northrop Grumman +% AUTHOR : (C) Copyright 2018 by Locusworks % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/docs/src/appendix/SettingsAppendex.tex b/docs/src/appendix/SettingsAppendex.tex index 562a2fe..299d4cd 100644 --- a/docs/src/appendix/SettingsAppendex.tex +++ b/docs/src/appendix/SettingsAppendex.tex @@ -1,7 +1,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % FILE : Architecture.tex % SUBJECT : Document describing architecture issues in the entire Patch Repository system. -% AUTHOR : (C) Copyright 2018 by Northrop Grumman +% AUTHOR : (C) Copyright 2018 by Locusworks % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/docs/src/figures/portal.properties b/docs/src/figures/portal.properties index a00c650..b7da7b3 100644 --- a/docs/src/figures/portal.properties +++ b/docs/src/figures/portal.properties @@ -1,6 +1,10 @@ userExpirationDays=3650 logLevel=INFO -dbHost=localhost +dbType=h2 +h2Url=jdbc:h2:file:${portal.home}/data/portal;MODE=MySQL;DATABASE_TO_LOWER=TRUE;DEFAULT_NULL_ORDERING=HIGH;NON_KEYWORDS=VALUE;DB_CLOSE_ON_EXIT=FALSE;INIT=CREATE SCHEMA IF NOT EXISTS portal +h2Username=sa +h2Password= +dbHost=localhost dbPort=3306 dbUsername=portalAdmin dbPassword=CWg48+h4q7iK4ICGaDhRd10EMQfFgthm3FjhkLd6gis\= @@ -8,4 +12,4 @@ dbRootUser=root dbRootPassword=Em46JDIzVOWBgGFqxDrqnw\=\= caCertFile=${user.home}/cacerts.jks caCertPassword=N/OQnJ9uQh1oYxadwGC3vA== -aesSeedFile=${catalina.base}/conf/portal.tomcat \ No newline at end of file +aesSeedFile=${portal.home}/portal.tomcat diff --git a/docs/src/figures/settings.xml b/docs/src/figures/settings.xml index 38e92ed..c7921c6 100644 --- a/docs/src/figures/settings.xml +++ b/docs/src/figures/settings.xml @@ -2,19 +2,19 @@ xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.1.0 http://maven.apache.org/xsd/settings-1.1.0.xsd"> - ngas-proxy + locusworks-proxy true http - eastproxy.northgrum.com + eastproxy.locusworks.net 80 (your MyID) (your login password) - ngas-proxy2 + locusworks-proxy2 true https - eastproxy.northgrum.com + eastproxy.locusworks.net 80 (your MyID) (your login password) @@ -37,10 +37,9 @@ local-deploy - C:\development\apache-tomcat-8.5.24 - 8.5.24 + C:\development\apache-tomcat-9.0.121 http://localhost:8080 - \ No newline at end of file + diff --git a/docs/src/guides/LogLevel.tex b/docs/src/guides/LogLevel.tex index 60965ad..ddd99f7 100644 --- a/docs/src/guides/LogLevel.tex +++ b/docs/src/guides/LogLevel.tex @@ -1,7 +1,7 @@ \section{Log Level Settings} \label{logLevel} -The server utilizes loggers that logs various server events. These log are all stored in a log file on the server. If using \command{tomcat} server these logs are located at \filename{\$TOMCAT\_HOME/logs/portal.out}. +The server uses loggers for server events. These logs are stored under \filename{\$PORTAL\_HOME/logs}; by default, \filename{\$PORTAL\_HOME} is \filename{\${user.home}/.portal}. Each application component has a logger associated with it with the default log level of \command{INFO} which will show general information to highlight progress. Each log level has an assigned level of importants with \command{OFF} being the most important and \command{ALL} being the least important. When determining what the log, the event to be logged compares itself to the logger and what its level is set at. If the event being logged is less important than the current log level for the component, that event will be ignored. If it is greater than or equal to the current level, the event will be logged. @@ -27,7 +27,7 @@ The level of importances from greatest to least is \subsection{Changing log levels} The following case allows a user to change the log level for server components. Upon saving the log levels, the component will now respects its new level and log according. -NOTE: These values are presisted. Upon server restart, the server will see if there is an entry for the logger and set the log level according, otherwise; it will set it to the default value. The location for the persisted patch repo logging file is \filename{\$TOMCAT\_HOME/conf/portal-loggers.properties}. +NOTE: These values are persisted. Upon server restart, the server will see if there is an entry for the logger and set the log level accordingly; otherwise, it will use the default value. The location for the persisted portal logging file is \filename{\$PORTAL\_HOME/portal-loggers.properties}. When displaying the log levels, the levels are displayed in alphabetical order based off the component name diff --git a/docs/src/guides/Login.tex b/docs/src/guides/Login.tex index 4941d0c..f8dd208 100644 --- a/docs/src/guides/Login.tex +++ b/docs/src/guides/Login.tex @@ -20,7 +20,7 @@ The following case allows the user to authenticate with the server. See Figure~\ \end{enumerate} \end{usecase} -The default username is: \bold{\command{portalAdmin@ngc.com}} +The default username is: \bold{\command{portalAdmin@locusworks.net}} The default password is: \bold{\command{portalAdmin2017!}} diff --git a/docs/src/macros.tex b/docs/src/macros.tex index d278b41..b046b48 100644 --- a/docs/src/macros.tex +++ b/docs/src/macros.tex @@ -43,19 +43,19 @@ \end{tabular} } -\newcommand{\ngasCommonsVersion}{1.0.0-RELEASE\xspace} +\newcommand{\locusworksCommonsVersion}{1.0.0-RELEASE\xspace} \newcommand{\EclipseVersion}{Oxygen.2 Release (4.7.2)\xspace} -\newcommand{\JavaVersion}{1.8.0\xspace} +\newcommand{\JavaVersion}{21\xspace} \newcommand{\MavenVersion}{3.5.3\xspace} \newcommand{\AntVersion}{1.9.10\xspace} \newcommand{\AngularJsVersion}{1.6.9\xspace} \newcommand{\SpringVersion}{5.0.5-RELEASE\xspace} -\newcommand{\NodeVersion}{v.8.9.4\xspace} -\newcommand{\YarnVersion}{1.3.2\xspace} +\newcommand{\NodeVersion}{24.20.0\xspace} +\newcommand{\NpmVersion}{12.0.2\xspace} \newcommand{\HibernateVersion}{5.2.16.Final\xspace} \newcommand{\FlywayVersion}{5.0.7\xspace} \newcommand{\MySQLVersion}{5.7\xspace} -\newcommand{\TomcatVersion}{8.5.24\xspace} +\newcommand{\TomcatVersion}{9.0.121\xspace} \newcommand{\QuartzVerson}{2.3.0\xspace} \newcommand{\JSchVersion}{0.1.54\xspace} \newcommand{\JGitVersion}{4.11.0.201803080745-r\xspace} diff --git a/docs/src/portal.tex b/docs/src/portal.tex index 7f099db..f5d170b 100644 --- a/docs/src/portal.tex +++ b/docs/src/portal.tex @@ -81,7 +81,7 @@ %Title page %------------------- %\title{\portal Documentation} -%\author{Northrop Grumman} +%\author{Locusworks} %\date{21 March, 2018} %\maketitle \begin{titlepage} diff --git a/pipeline-settings.xml b/pipeline-settings.xml deleted file mode 100644 index 6eaea28..0000000 --- a/pipeline-settings.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - flyway-localhost - root - let_me_in - - - - - local-deploy - - true - - - D:\Development\apache-tomcat-9.0.10 - 9.0.10 - http://localhost:8080 - - - - diff --git a/pom.xml b/pom.xml index b8a061f..910d205 100644 --- a/pom.xml +++ b/pom.xml @@ -17,24 +17,69 @@ - scm://git@bitbucket.org:locus2k/portal-webapp.git + ssh://gitea@gitea.locusworks.net:7999/locusworks/portal-webapp.git + + + nexus-snapshot + ${nexus.repo}/repository/locusworks-snapshot/ + + + nexus-release + ${nexus.repo}/repository/locusworks-release/ + + + + + + locusworks-public + locusworks-public + ${nexus.repo}/repository/locusworks-public/ + + true + + + true + + + + + + + locusworks-public + ${nexus.repo}/repository/locusworks-public/ + + true + + + true + + + + - 1.8 - 5.0.7.RELEASE - 5.0.6.RELEASE + https://nexus.locusworks.net + 21 + ${java.version} + UTF-8 + UTF-8 + 4.1.1 + 11.0.25 + 26.7.0 + + false ${project.basedir} - 5.2.16.Final - 5.1.4 - 2.6.1 + 2.4.240 + 13.5.0 + 2.7.0 1.0.0-RELEASE 1.7.25 3.0.5 - 4.12 - portal - ${tomcat-deploy-url}/manager/text - tomcat-localhost + 4.13.2 + 2.0.2 + v24.20.0 + 12.0.2 jdbc:mysql://localhost:3306 flyway-localhost @@ -53,37 +98,37 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.0.0 + 3.12.0 -Xdoclint:none false - javax.interceptor - javax.interceptor-api - 1.2.1 + jakarta.interceptor + jakarta.interceptor-api + 2.2.0 - javax.annotation - javax.annotation-api - 1.3.1 + jakarta.annotation + jakarta.annotation-api + 3.0.0 - NGAS Portal Common Library + Locusworks Portal Common Library net.locusworks.portal.common* - NGAS Portal Database Library + Locusworks Portal Database Library net.locusworks.portal.database* - NGAS Portal Migration Library + Locusworks Portal Migration Library net.locusworks.portal.migration* - NGAS Portal WebApp Library + Locusworks Portal WebApp Library net.locusworks.portal.config :net.locusworks.portal.controllers @@ -130,7 +175,7 @@ org.codehaus.mojo versions-maven-plugin - 2.2 + 2.21.0 false @@ -141,14 +186,19 @@ org.owasp dependency-check-maven - 3.1.2 + 13.0.0 - ngas-proxy2 true - true + true + + ${portal.ossIndexEnabled} + + true + false false true - + e2eb1036-9b5b-4df9-95e7-0888be947011 @@ -159,38 +209,23 @@ maven-compiler-plugin - 3.1 + 3.16.0 - ${java.version} - ${java.version} + ${maven.compiler.release} true - maven-deploy-plugin - 2.5 + maven-surefire-plugin + 3.5.6 - org.apache.tomcat.maven - tomcat7-maven-plugin - 2.2 - - - org.slf4j - slf4j-nop - ${slf4j.version} - - - - ${tomcat.deploy.url} - ${tomcat.deploy.server} - target/portal.war - /portal - + maven-deploy-plugin + 3.1.4 maven-scm-plugin - 1.9.4 + 2.2.1 portal-${project.version} @@ -198,22 +233,50 @@ - - + + + + + org.apache.tomcat.embed + tomcat-embed-core + ${tomcat.version} + + + org.apache.tomcat.embed + tomcat-embed-el + ${tomcat.version} + + + org.apache.tomcat.embed + tomcat-embed-websocket + ${tomcat.version} + + + com.mysql + mysql-connector-j + ${mysql-connector.version} + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + commons-beanutils commons-beanutils - 1.9.3 + 1.11.0 commons-codec commons-codec - 1.11 + 1.22.1 commons-io commons-io - 2.6 + 2.22.0 @@ -228,74 +291,47 @@ ${junit.version} test + + com.h2database + h2 + ${h2.version} + runtime + org.apache.poi poi - 3.17 + 5.5.1 org.apache.poi poi-ooxml - 3.17 + 5.5.1 org.apache.commons commons-lang3 - 3.7 + 3.20.0 commons-fileupload commons-fileupload - 1.3.3 + 1.6.0 org.apache.commons commons-math3 3.6.1 - - org.apache.tomcat - tomcat-jdbc - ${tomcat-version} - provided - commons-validator commons-validator - 1.6 + 1.11.0 - - org.springframework - spring-core - ${spring.version} - - - org.springframework - spring-aop - ${spring.version} - - - org.springframework - spring-context - ${spring.version} - - - org.springframework - spring-jdbc - ${spring.version} - - - org.springframework - spring-tx - ${spring.version} - - - org.springframework.data - spring-data-jpa - 2.0.8.RELEASE + org.springframework.boot + spring-boot-starter @@ -304,6 +340,11 @@ ${flyway.version} jar + + org.flywaydb + flyway-mysql + ${flyway.version} + @@ -320,13 +361,42 @@ net.locusworks locusworks-commons - 1.1.0-RELEASE + 3.0.1-RELEASE + pom + + + net.locusworks + applogger + 2.0.2-RELEASE - + + + oss-index + + + portal.ossIndexEnabled + true + + + + + + org.owasp + dependency-check-maven + + oss-index + + + + + + + + portal_client portal_database portal_migration @@ -334,4 +404,4 @@ portal_webapp portal_json - \ No newline at end of file + diff --git a/portal_client/.csslintrc b/portal_client/.csslintrc deleted file mode 100644 index 75a02da..0000000 --- a/portal_client/.csslintrc +++ /dev/null @@ -1,37 +0,0 @@ -{ - "important": false, - "adjoining-classes": false, - "known-properties": true, - "box-sizing": false, - "box-model": true, - "overqualified-elements": false, - "display-property-grouping": true, - "bulletproof-font-face": true, - "compatible-vendor-prefixes": true, - "regex-selectors": true, - "errors": 2, - "duplicate-background-images": true, - "duplicate-properties": true, - "empty-rules": true, - "selector-max-approaching": true, - "gradients": true, - "fallback-colors": true, - "font-sizes": true, - "font-faces": true, - "floats": true, - "star-property-hack": false, - "outline-none": true, - "import": true, - "ids": false, - "underscore-property-hack": true, - "rules-count": true, - "qualified-headings": true, - "selector-max": true, - "shorthand": true, - "text-indent": true, - "unique-headings": true, - "universal-selector": true, - "unqualified-attributes": true, - "vendor-prefix": true, - "zero-units": true -} diff --git a/portal_client/.jshintrc b/portal_client/.jshintrc deleted file mode 100644 index 5be6b69..0000000 --- a/portal_client/.jshintrc +++ /dev/null @@ -1,62 +0,0 @@ -{ - //See: http://www.jshint.com/docs/options/ - - ////////////////////////////////////////////////////////////////////////////// - //Enforcements - ////////////////////////////////////////////////////////////////////////////// - - "bitwise": true, - "browser": true, - "camelcase": true, - "curly": true, - "eqeqeq": true, - "eqnull": true, - "freeze": true, - "immed": true, - "indent": 2, - "jasmine": true, - "latedef": "nofunc", - "laxbreak": true, - "newcap": true, - "noarg": true, - "noempty": true, - "nonbsp": true, - "nonew": true, - "quotmark": "single", - //"strict": true, //TODO: tackle this monster. Could provide speedups - //"unused": "vars", //TODO: tackle this monster - "undef": true, - - - - ////////////////////////////////////////////////////////////////////////////// - //Relaxations - ////////////////////////////////////////////////////////////////////////////// - "sub": true, //TODO: consider removing this relaxation - - - //Globals - "globals": { - "jQuery": true, - "angular": true, - "console": true, - "$": true, - "_": true, - "moment": true, - "describe": true, - "beforeEach": true, - "afterEach": true, - "module": true, - "inject": true, - "it": true, - "expect": true, - "Timeline": true, - "d3": true, - "ngGridLayoutPlugin": true, - "tinymce": true, - "SockJS": true, - "Stomp": true, - "paper": true, - "validthis": true - } -} diff --git a/portal_client/.npmrc b/portal_client/.npmrc new file mode 100644 index 0000000..4ee0485 --- /dev/null +++ b/portal_client/.npmrc @@ -0,0 +1,3 @@ +legacy-peer-deps=true +# Keep warnings and failures visible without npm's routine stderr notices. +loglevel=warn diff --git a/portal_client/Gruntfile.js b/portal_client/Gruntfile.js deleted file mode 100644 index 9d5d8bc..0000000 --- a/portal_client/Gruntfile.js +++ /dev/null @@ -1,453 +0,0 @@ -/*jslint node: true */ -'use strict'; - -var pkg = require('./package.json'); -var serveStatic = require('serve-static'); -var serveIndex = require('serve-index'); - -//Using exclusion patterns slows down Grunt significantly -//instead of creating a set of patterns like '**/*.js' and '!**/node_modules/**' -//This method assumes the website root is in the app folder. -// -//omitDirPrefix: If true, refrains from adding 'app/' to each of the patterns. -var createFolderGlobs = function (fileTypePatterns, omitDirPrefix) { - var ignore = ['yarn_components', 'tzdata']; - - //FOR DEBUGGING - //console.log('\ncreateFolderGlobs()...'); - - //Convert fileTypePatterns to array - fileTypePatterns = Array.isArray(fileTypePatterns) ? fileTypePatterns : [fileTypePatterns]; - var fs = require('fs'); - - //FOR DEBUGGING - //console.log('File Type Patterns (Computed): ' + fileTypePatterns); - - //Change from the grunt dir to the app dir - var gruntDir = process.cwd(); - process.chdir('app'); - - //FOR DEBUGGING - //console.log('CWD: ' + process.cwd()); - - //Modify - var returnPatterns = fs.readdirSync(process.cwd()) - .map(function (file) { - //console.log('Examining: ' + file); - //If this is a file, or a folder in the ignore list - if (ignore.indexOf(file) !== -1 || - file.indexOf('.') === 0 || - !fs.lstatSync(file).isDirectory()) { - - //FOR DEBUGGING - //console.log('Ignoring: ' + file); - return null; - } else { - //FOR DEBUGGING - //console.log('--> Accepting: ' + file); - return fileTypePatterns.map(function (pattern) { - return file + '/**/' + pattern; - }); - } - }) - .filter(function (patterns) { - return patterns; - }) - .concat(fileTypePatterns); - - //Change back from app dir to grunt dir - process.chdir(gruntDir); - - if (!omitDirPrefix) { - //Prepend 'app/' to each filter item - var patternsString = returnPatterns.toString(); - var csvArray = patternsString.split(','); - returnPatterns = csvArray.map(function (pattern) { - return 'app/' + pattern; - }); - } - - //FOR DEBUGGING - //console.log('RESULT: ' + returnPatterns); - - return returnPatterns; -}; //end function createFolderGlobs() - -module.exports = function (grunt) { - - require('time-grunt')(grunt); - - // load all grunt tasks with jit loading - require('jit-grunt')(grunt, { - protractor: 'grunt-protractor-runner', - configureProxies: 'grunt-connect-proxy2', - dom_munger: 'grunt-dom-munger2', - ngtemplates: 'grunt-angular-templates' - }); - - // Project configuration. - grunt.initConfig({ - connect: { - //Default options for all connect targets - options: { - port: 9000, - hostname: '127.0.0.1', - base: 'app/', - livereload: 35729, - open: 'http://127.0.0.1:9000', - middleware: function (connect, options) { - if (!Array.isArray(options.base)) { - options.base = [options.base]; - } - - // Setup the proxy - var middlewares = [require('grunt-connect-proxy2/lib/utils').proxyRequest]; - - // Serve static files. - options.base.forEach(function (base) { - middlewares.push(serveStatic(base)); - }); - - // Make directory browse-able. - var directory = options.directory || options.base[options.base.length - 1]; - middlewares.push(serveIndex(directory)); - - return middlewares; - } - }, - main: { - //See https://github.com/drewzboto/grunt-connect-proxy - proxies: [ - { - context: ['/rest', '/portal'], - host: 'localhost', - port: 8080, - ws: true, - } - ] - }, - dist: { - options: { - base: 'dist/' - }, - proxies: [ - { - context: ['/rest', '/portal'], - host: 'localhost', - port: 8080 - } - ] - } - }, - watch: { - main: { - options: { - livereload: true, - spawn: false, - debounceDelay: 250 - }, - files: [createFolderGlobs(['*.js', '*.less', '*.html', '*.css']), '!_SpecRunner.html', '!.grunt', '!*-spec.js'], - tasks: [] - }, - dist: { - options: { - livereload: true, - spawn: false - }, - files: ['app.full.min.css', 'app.full.min.js', 'index.html'], - tasks: [] //all the tasks are run dynamically during the watch event handler - } - }, - jshint: { - main: { - options: { - jshintrc: '.jshintrc' - }, - src: [createFolderGlobs('*.js'), '*.js', '!app/common/generated_code/**', '!Gruntfile.js', '!assets.js', '!webpack.config.js', '!yarn_file_copy.js'] - } - }, - csslint: { - main: { - options: { - csslintrc: '.csslintrc' - }, - src: ['<%= dom_munger.data.applintcss %>', '!app/compiled-less/**', '!app/yarn_components/**'] - } - }, - lesslint: { - main: { - options: { - csslint: { - csslintrc: '.csslintrc' - } - }, - src: ['app/*.less', '!app/compiled-less/**', '!app/yarn_components/**'] - } - }, - clean: { - before: { - src: ['dist', 'temp', 'test_results'] - }, - after: { - src: ['temp'] - }, - cleanDistTest: { - src: ['distTestFolder'] - } - }, - less: { - production: { - files: [{ - cwd: 'app', - src: ['**/*.less', '!yarn_components/**'], - dest: 'app/compiled-less/', - filter: 'isFile', - expand: true, - ext: '.less.css' - }] - } - }, - ngtemplates: { - main: { - options: { - module: pkg.name, - htmlmin: '<%= htmlmin.main.options %>' - }, - src: [createFolderGlobs('*.html', true), '!index.html', '!_SpecRunner.html'], - dest: 'temp/templates.js', - cwd: 'app/' - } - }, - copy: { - main: { - files: [ - {cwd: 'app', src: ['<%= dom_munger.data.appjsCopyList %>','<%= dom_munger.data.appcssCopyList %>'], dest: 'dist/', filter: 'isFile', expand: true}, - {cwd: 'app', src: ['yarn_components/**/*.woff'], dest: 'dist/', filter: 'isFile', expand: true}, - {cwd: 'app', src: ['yarn_components/**/*.woff2'], dest: 'dist/', filter: 'isFile', expand: true}, - {cwd: 'app', src: ['yarn_components/**/*.eot'], dest: 'dist/', filter: 'isFile', expand: true}, - {cwd: 'app', src: ['yarn_components/**/*.svg'], dest: 'dist/', filter: 'isFile', expand: true}, - {cwd: 'app', src: ['yarn_components/**/*.ttf'], dest: 'dist/', filter: 'isFile', expand: true}, - {cwd: 'app', src: ['yarn_components/**/*.png'], dest: 'dist/', filter: 'isFile', expand: true}, - {cwd: 'app', src: ['yarn_components/**/*.jpg'], dest: 'dist/', filter: 'isFile', expand: true}, - {cwd: 'app', src: ['yarn_components/**/*.gif'], dest: 'dist/', filter: 'isFile', expand: true}, - {cwd: 'app', src: ['images/**/*.svg'], dest: 'dist/', filter: 'isFile', expand: true}, - {cwd: 'app', src: ['images/**/*.png'], dest: 'dist/', filter: 'isFile', expand: true}, - {cwd: 'app', src: ['images/**/*.jpg'], dest: 'dist/', filter: 'isFile', expand: true}, - {cwd: 'app', src: ['images/**/*.gif'], dest: 'dist/', filter: 'isFile', expand: true}, - {cwd: 'app', src: ['fonts/google-md-icons/**'], dest:'dist/', filter: 'isFile', expand: true}, - {cwd: 'app', src: ['favicon.ico'], dest: 'dist/', filter: 'isFile', expand: true}, - {cwd: 'app', src: ['robots.txt'], dest: 'dist/', filter: 'isFile', expand: true}, - {cwd: 'app', src: ['404.html'], dest: 'dist/', filter: 'isFile', expand: true} - ] - }, - //Prepares a copy of the dist folder and inserts unit tests for running - //unit tests on the distribution build. - prepareDistTestFolder: { - files: [ - //Copy the dist folder's contents to the war. - //Path is relative to src/main/webapp/grunt - {cwd: 'dist', src: ['**'], dest: 'distTestFolder', filter: 'isFile', expand: true}, - {cwd: 'app', src: ['**/*-spec.js'], dest: 'distTestFolder', filter: 'isFile', expand: true} - ] - } - }, - dom_munger: { //jshint ignore: line - read: { - options: { - read: [ - {selector: 'script[data-build!="exclude"]', attribute: 'src', writeto: 'appjs', isPath: true}, - {selector: 'link[type="text/css"][data-build!="exclude"]', attribute: 'href', writeto: 'appcss', isPath: true}, - {selector: 'script[data-remove="exclude"]', attribute: 'src', writeto: 'appjsCopyList'}, - {selector: 'link[type="text/css"][data-remove="exclude"]', attribute: 'href', writeto: 'appcssCopyList'}, - {selector: 'script[data-karma-tests!="exclude"]', attribute: 'src', writeto: 'applintjs', isPath: true}, - {selector: 'link[type="text/css"]', attribute: 'href', writeto: 'applintcss', isPath: true} - ] - }, - src: 'app/index.html' - }, - update: { - options: { - remove: ['script[data-remove!="exclude"]', 'link[data-remove!="exclude"]'], - append: [ - {selector: 'body', html: ''}, - {selector: 'head', html: ''} - ] - }, - src: 'app/index.html', - dest: 'dist/index.html' - } - }, - cssmin: { - options: { - target: 'dist/'//Eg. Changes '../relative/url/path/in/bower/components' to 'app/yarn_components/...' - //root: 'app' //Eg. changes '../relative/url/path/in/bower/components' to '/yarn_components...', but the starting slash causes problems - }, - main: { - files: { - 'dist/app.full.min.css': [ - 'temp/**/*.less.css', - '<%= dom_munger.data.appcss %>' - ] - } - } - }, - concat: { - main: { - src: ['<%= dom_munger.data.appjs %>', '<%= ngtemplates.main.dest %>'], - dest: 'temp/app.full.js' - } - }, - ngAnnotate: { - main: { - src: 'temp/app.full.js', - dest: 'temp/app.full.js' - } - }, - uglify: { - main: { - files: { - 'dist/app.full.min.js': ['temp/app.full.js'] - } - }, - pretty: { - options: { - beautify: true, - preserveComments: 'all', - sourceMap: true, - sourceMapName: 'dist/app.full.min.js.map' - }, - files: { - 'dist/app.full.min.js': ['temp/app.full.js'] - } - } - }, - html2js: { - options: { - base: '.', - module: 'ui-templates', - rename: function (modulePath) { - var moduleName = modulePath.replace('app/common/partials/ui-bootstrap-tpls/', '').replace('.html', ''); - return 'template' + '/' + moduleName + '.html'; - } - }, - main: { - src: ['app/common/partials/ui-bootstrap-tpls/**/*.html'], - dest: 'app/common/generated_code/ui-templates.js' - } - }, - htmlmin: { - main: { - options: { - collapseBooleanAttributes: true, - collapseWhitespace: true, - removeAttributeQuotes: true, - removeComments: true, - removeEmptyAttributes: true, - removeScriptTypeAttributes: true, - removeStyleLinkTypeAttributes: true - }, - files: { - 'dist/index.html': 'dist/index.html' - } - } - }, - concurrent: { - build: [ - 'onlyBuild' - ], - /** - * Note: The multiCapabilities feature of protractor does not seem compatible - * with grunt concurrent, unless everything passes perfectly - */ - test: { - tasks: [ - 'unitTests', - ] - }, - serve: { - tasks: [ - 'unitTests', - 'onlyServe' - ], - options: { - logConcurrentOutput: true - } - } - } //end concurrent - - }); //end grunt.initConfig - - //Runs the linters through our code - grunt.registerTask('lintAll', [ - 'dom_munger:read', - 'jshint', - 'lesslint', - 'csslint']); - - grunt.registerTask('unitTests', [ - 'lintAll', - 'dom_munger:read', - ]); - - /** - * Used by the concurrent task to split up build task. - */ - grunt.registerTask('onlyBuild', [ - 'clean:before', - 'dom_munger', - 'less', //Compiles less files to css. Creates one css file for each less file in a respective folder in temp/path/name.css - 'ngtemplates', //creates temp/templates.js that maps templates safely for minification - 'cssmin', //minifies css into dist/app.full.min.css - 'concat', - 'ngAnnotate', //Makes AngularJS files minification safe. Reads temp/app.full.js. Writes results to temp/app.full.js - 'uglify:main', //Minifies and uglifies - 'copy:main', - 'htmlmin', - 'clean:after' - ]); - - /** - * Used by the concurrent task to split up serve task. - */ - grunt.registerTask('onlyServe', [ - 'configureProxies:main', - 'connect:main', - 'watch:main' - ]); - - //Builds and runs a live watch server using the distribution build. - grunt.registerTask('serveDist', ['build', 'connect:dist', 'watch:dist']); - - //Runs a test on the distribution build. - //NOTE: this currently fails with an undefined tinyMCE variable - // - grunt.registerTask('testDist', [ - 'build', - 'copy:prepareDistTestFolder', - 'clean:cleanDistTest' - ]); - - //############################################################################ - //############################################################################ - // The tasks below are intended for public command line use - //############################################################################ - //############################################################################ - - /** Makes the distribution build */ - grunt.registerTask('build', ['concurrent:build']); - - /** Runs a live watch server proxied between port 9000 and 8080 */ - grunt.registerTask('serve', ['concurrent:serve']); - - /** Re converts the html/js templates. */ - grunt.registerTask('runHTML2js', ['html2js']); - - /** Runs the test task, including lint, unit tests, and e2e tests */ - grunt.registerTask('test', ['concurrent:test']); - - /** By default, we run the serve task */ - grunt.registerTask('default', ['serve']); - - /** Compiles project's less files into css. */ - grunt.registerTask('makeLess', ['dom_munger', 'less']); -}; diff --git a/portal_client/README.md b/portal_client/README.md index 43892d7..17ac702 100644 --- a/portal_client/README.md +++ b/portal_client/README.md @@ -1,12 +1,23 @@ -Portal Client -== - -The portal_client contains all the client side html, javascript, and css files that will be presented to the user - -Yarn -====== -Yarn is the the new package manager used with node.js in replacement of `npm` it uses the same package.json file. - -To download a new client side library use the command `yarn add --save` This will add the files to the `node_modules` library. -Next include the appropriate file into the `assets.js` file inside `portal_client` to make sure it will be injected into the `index.html` file during run time. -The `assets.js` file specifies all the vendor libraries that have to be included into the client code during build. +# Portal client + +The portal UI is an Angular 22.1 standalone application built with Angular CLI and npm. + +## Development + +Use Node.js 24.15 or newer in the Node 24 release line and npm 12: + +```shell +npm ci +npm start +``` + +The development server serves the client locally. API and WebSocket requests target the Spring application under `/portal`. + +## Verification and production build + +```shell +npm test +npm run build +``` + +The production build is emitted to `dist`. Maven performs `npm ci`, runs the tests and build, then packages `dist` under `/portal/client/` in the Spring Boot application. diff --git a/portal_client/angular.json b/portal_client/angular.json new file mode 100644 index 0000000..6de369b --- /dev/null +++ b/portal_client/angular.json @@ -0,0 +1,92 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "cli": { + "packageManager": "npm" + }, + "newProjectRoot": "projects", + "projects": { + "portal-modern": { + "projectType": "application", + "schematics": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "root": "", + "sourceRoot": "src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular/build:application", + "options": { + "allowedCommonJsDependencies": ["sockjs-client"], + "browser": "src/main.ts", + "polyfills": [ + "src/polyfills.ts" + ], + "outputPath": { + "base": "dist", + "browser": "" + }, + "tsConfig": "tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + { + "glob": "**/*", + "input": "public" + }, + { + "glob": "sockjs.min.js", + "input": "node_modules/sockjs-client/dist", + "output": "vendor" + } + ], + "styles": [ + "src/styles.scss", + "public/fonts/google-md-icons/MaterialIcons-Regular.css" + ] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kB", + "maximumError": "1MB" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "4kB", + "maximumError": "8kB" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "builder": "@angular/build:dev-server", + "configurations": { + "production": { + "buildTarget": "portal-modern:build:production" + }, + "development": { + "buildTarget": "portal-modern:build:development" + } + }, + "defaultConfiguration": "development" + }, + "test": { + "builder": "@angular/build:unit-test" + } + } + } + } +} diff --git a/portal_client/app/app.css b/portal_client/app/app.css deleted file mode 100644 index a17a083..0000000 --- a/portal_client/app/app.css +++ /dev/null @@ -1,523 +0,0 @@ -/*csslint important: false*/ - -#mainBody { - background-color: #ff6600; - background: url(images/background.png); - background-repeat: no-repeat; - background-attachment: fixed; - background-position: center; - -webkit-background-size: cover; - -moz-background-size: cover; - -o-background-size: cover; - background-size: cover; -} - -.fill-height { - height: 100% !important; -} - -.header-container-left, -.header-container, -.header-container-right { - display: inline-block; - vertical-align: middle; - margin: 0 5px; - height: 40px; -} - -.header-container-left { - left: 0; -} - -.header-container-right { - position: absolute; - right: 0; -} - -.vertical-align-center, -.header-container-right button { - -moz-transform: translateY(-50%); - -webkit-transform: translateY(-50%); - -o-transform: translateY(-50%); - -ms-transform: translateY(-50%); - transform: translateY(-50%); - position: relative; - top: 50%; -} - -.horizontal-align-center { - position: relative; - left: 50%; - -moz-transform: translateX(-50%); - -webkit-transform: translateX(-50%); - -ms-transform: translateX(-50%); - -o-transform: translateX(-50%); - transform: translateX(-50%); -} - -.center-text { - text-align: center; -} - -#filterBoxAlignment{ - bottom: -2px; - left:1.5px; - background-color: #FFFFFF; -} -#bottomFilter{ - height: 35px; - bottom: 3px; - left: 1px; - background-color: #EBEBEB; -} -#box{ - - bottom:50px; -} -.left-text { - text-align: left; -} - -html, -body { - margin: 0; - padding: 0; - border: 0; -} - -body { - position: absolute; - width: 100%; - height: 100%; - overflow: hidden !important; -} - - -.fill-height-scroll, -.fill-height-scroll .tab-pane { - height: 100%; - overflow:auto; -} - -.fill-height-scroll-y, -.fill-height-scroll-y .tab-pane { - height: 100%; - overflow-y:auto; - overflow-x:no-content; -} - -.scroll { - overflow: auto; -} - -.box { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - width: 100%; -} - -.tab-pane { - padding: 5px; -} - -.ellipsis { - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; -} - -.margin-none { - margin: 0; -} - -.margin-sm { - margin: 3px; -} - -.margin-md { - margin: 5px; -} - -.margin-sides-xs { - margin-left: 2px; - margin-right: 2px; -} - -.margin-sides-sm { - margin-left: 4px; - margin-right: 4px; -} - -.margin-right-xs { - margin-right: 1px; -} - -.margin-right-sm { - margin-right: 3px; -} - -.margin-right-md { - margin-right: 5px; -} - -.margin-right-lg { - margin-right: 10px; -} - - -.col-padding-none, -.padding-none { - padding: 0 !important; -} - -.padding-left-none { - padding-left: 0; -} - -.padding-med { - padding: 3px; -} - -.padding-sides-small { - padding-left: 1px; - padding-right: 1px -} - -.padding-sides-med { - padding-left: 3px; - padding-right: 3px; -} - -.rounded-border { - box-sizing: border-box; - border: 1px solid #ddd; - border-radius: 8px; -} -/* -* lifecycle and ex org table css rules -*/ - -#availableLC{ - height: 194px; - width: 472px; -} -#availableOT{ - height: 430px; - width: 472px; -} - - -.thin-border { - border: 1px solid #ddd; -} - -.thin-border-top { - border-top: 1px solid #ddd; -} - -.thin-border-bottom { - border-bottom: 1px solid #ddd; -} - -.thin-border-left { - border-left: 1px solid #ddd; -} - -.thin-border-right { - border-right: 1px solid #ddd; -} - -.thin-border-sides { - border-left: 1px solid #ddd; - border-right: 1px solid #ddd; -} - -.progress-bar-label { - color: #555; - left:50%; - top:50%; - -o-transform: translate(-50%, -50%); - -ms-transform: translate(-50%, -50%); - -webkit-transform: translate(-50%, -50%); - -moz-transform: translate(-50%, -50%); - transform: translate(-50%, -50%); - position:absolute; -} - -/*Allows label to be centered in progress bar using absolute positioning*/ -.progress { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - position: relative; -} - -.progress-bar { - box-shadow: none; -} - -.tab-pane { - padding: 0; -} - -.icon-xs svg { - float: left;/*Causes vertical centering to work with svg element*/ - width: 16px; - height: 16px; -} - -.text-small { - font-size: 10px; -} - -.bold { - font-weight: bold; -} - -/* This controls the border around the buttons when they have a selection focus -button :focus { - outline: none!important; -}*/ - -.gridStyle { - box-sizing: border-box; - border: 1px solid rgb(212,212,212); -} - -.float-left { - float: left; -} - -.float-right { - float: right; -} - -.nav-tabs li:first-of-type { - padding-left: 4px; /** TODO Replace this with responsive utility*/ -} - -/* Override the default gray because it is hard to see. */ -/* TODO: possible change to a different color/shade */ -.modal-footer { - border-top-color: black; -} - -.modal-header { - border-bottom-color: black; -} - -.rotate90 { -/* Safari */ --webkit-transform: rotate(90deg); -/* Firefox */ --moz-transform: rotate(90deg); -/* IE */ --ms-transform: rotate(90deg); -/* Opera */ --o-transform: rotate(90deg); -transform: rotate(90deg); -/* One of these catches chrome */ -} - -.rotate180 { -/* Safari */ --webkit-transform: rotate(180deg); -/* Firefox */ --moz-transform: rotate(180deg); -/* IE */ --ms-transform: rotate(180deg); -/* Opera */ --o-transform: rotate(180deg); -transform: rotate(180deg); -/* One of these catches chrome */ -} - -/* Prevents drag and shift text selection */ -.unselectable { - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - cursor:default; -} - -/* -.modal.fade .modal-dialog, .modal.in .modal-dialog { - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - -moz-transform: translate(0, 0); - -o-transform: translate(0, 0); - transform: translate(0, 0); -}*/ - -#modalDialogContainer>div{ - overflow-y: hidden; - overflow-x: hidden; -} - -.modal-body { - overflow: hidden; - padding-top: 5; - padding-bottom: 0; -} - -.input-group-addon:not(:last-child), -.input-group-btn:not(:last-child), -.input-group .form-control:not(:last-child) { - border-right: none; -} - - -.input-group-btn:last-child>.btn, -.input-group-btn:last-child>.btn-group { - margin-left: 0; -} - -.no-scroll-table .ngViewport { - height: auto !important; -} - -.no-scroll-table .ngCanvas, -.no-scroll-table .ngViewport, -.no-scroll-table .ngRow, -.no-scroll-table .ngFooterPanel, -.no-scroll-table .ngTopPanel{ - width: 100% !important; -} - -.no-scroll-table .ngRow { - border-bottom: none !important; - border-radius: 5px !important; -} - -.panel-body-relative { - position: relative; -} - -.normal-filter { - background-color: white; - height: 40px; - width: 200px; - border-top-right-radius: 5px; - border-bottom-left-radius: 5px; - padding-bottom: 40px; -} - -.bottom-filter { - background-color: white; - height: 40px; - position: absolute; - bottom: 0; - width: 200px; - border-top-right-radius: 5px; - border-bottom-left-radius: 5px; -} - -.bottom-filter-pad { - padding-bottom: 40px; /** Cooresponds with .bottom-filter */ -} - -/* Causes an element to fill it's absolute container fully */ -.fill-container-absolutely { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; -} - -/** Fixes issue with loading spinner showing up in front of modal dialogues */ -.spinner { - z-index: 0 !important; -} - -/** - * Hides the pin button unless you hover over the header for ng-grid - */ -.ngUnPinnedIcon { - visibility: hidden; -} - -.ngHeaderCell:hover .ngUnPinnedIcon { - visibility: visible; -} - -.glyphicon-tile.glyphicon { - text-align: center; - font-size: 8em; - color: lightgray; -} - -.label-as-badge { - border-radius: 1em; -} -.loadingFade { - position:absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: #ababab; - z-index: 9000; - -moz-opacity: 0.8; - opacity: .70; - filter: alpha(opacity=80); -} - -.loadingModal { - position: absolute; - top: 45%; - left: 48%; - z-index: 9001; - text-align:center; -} - -.splitter{ - background: #c8c8c8; - width: 1px; -} - -.ghost { - background: #c8c8c8; - opacity: 0.5; - -} - -.ui-icon-gripsmall-diagonal-se { - right:0 !important; - bottom:0 !important; - background-position: -64px -224px !important; -} - -.hover-cursor { - cursor: pointer; - cursor: hand; -} - -.icon-grid-cell { - padding-top: 3px; - padding-left: 3px; -} - -@media (min-width: 992px) { - .modal-xl { - width: 95%; - } -} - -.ui-grid-sort-priority-number { - font-size: 0; -} - -.stretch input { - width: 100% -} - -.speech { - bottom: 0; - right: 0; - position: absolute; -} \ No newline at end of file diff --git a/portal_client/app/app.js b/portal_client/app/app.js deleted file mode 100644 index 56446d2..0000000 --- a/portal_client/app/app.js +++ /dev/null @@ -1,130 +0,0 @@ -var portal = angular.module('portal', [ - 'ui.bootstrap', - 'ui.router', - 'ui.grid', - 'ui.grid.saveState', - 'ui.grid.selection', - 'ui.grid.edit', - 'ui.grid.resizeColumns', - 'ui.grid.moveColumns', - 'ui.grid.expandable', - 'ui.grid.pinning', - 'ui.grid.autoResize', - 'ui.grid.exporter', - 'ui.grid.cellNav', - 'ui.grid.pagination', - 'ui.grid.treeView', - 'ui.tinymce', - 'ngResource', - 'ngCookies', - 'ngSanitize', - 'ngAnimate', - 'ngMessages', - 'ngMaterial', - 'ngMaterialDatePicker', - 'debounce', - 'portal.login', - 'portal.dashboard', - 'portal.dashboard.gitBank', - 'portal.dashboard.userBank', - 'portal.dashboard.credBank', - 'portal.dashboard.logBank', - 'portal.dashboard.scriptBank', - 'portal.dashboard.emailBank', - 'portal.dashboard.envBank', - 'portal.dashboard.permissionBank', - 'portal.common.constants', - 'portal.common.factories.pubsub', - 'portal.common.services.map', - 'portal.common.services.model.cache', - 'portal.common.services.model.rest', - 'portal.common.services.portalUtils', - 'portal.common.services.authorize', - 'portal.common.services.triggers', - 'portal.common.directives.portalTabset', - 'portal.common.directives.compareTo', - 'portal.common.directives.portalWebsocket', - 'portal.common.directives.permissions', - 'portal.common.partials.sessionEnd', - 'portal.common.partials.uploadpatchfile', - 'portal.common.partials.addGit', - 'portal.common.partials.addUser', - 'portal.common.partials.addDirectory', - 'portal.common.partials.addCreds', - 'portal.common.partials.addScript', - 'portal.common.partials.addEnvVars', - 'portal.common.partials.configuration', - 'portal.common.partials.fileinfo', - 'portal.common.partials.filevalidate', - 'portal.common.partials.addPermission', - 'portal.common.partials.viewScriptStatus', - 'portal.common.partials.loggerinfo', - 'portal.common.partials.smtpinfo', - 'portal.common.partials.addEmailTmpl', - 'portal.common.partials.seedinfo' -]); - -angular.module('portal').config(function ($stateProvider, $urlRouterProvider, $httpProvider) { - $urlRouterProvider.otherwise('/dashboard'); - /* Add New States Above, or else in the module, but not in both */ - $urlRouterProvider.when('', 'dashboard'); - - $httpProvider.defaults.useXDomain = true; - delete $httpProvider.defaults.headers.common['X-Requested-With']; - - $stateProvider.state('main', { - url: '/main', - pageTitle: 'Main', - templateUrl: 'main/main.html', - resolve: { - authorize: ['authorize', - function (authorize) { - return authorize.validate({ - authorities: { - account: ['USER', 'ADMIN'] - }, - redirect: 'dashboard' - }); - } - ], - } - }).state('login', { - url: '/login', - pageTitle: 'Login', - templateUrl: 'login/login.html' - }).state('prohibited', { - url: '/prohibited', - pageTitle: 'Access Denied', - templateUrl: 'prohibited/prohibited.html' - }).state('main.prohibited', { - url: '/prohibited', - pageTitle: 'Access Denied', - templateUrl: 'prohibited/prohibited.html' - }); - -}); //end angular.module.config - -angular.module('portal').run(function($rootScope, $state, $animate, $window, $location, $transitions) { - $transitions.onSuccess({to: 'dashboard.**' }, function(trans){ - $rootScope.$broadcast('$stateChangeSuccess', trans.router.globals.$current.name); - }); - - $rootScope.$on('$locationChangeSuccess', function(){ - $rootScope.actualLocation = $location.path(); - }); - - // Allows easy unregistering of listener callbacks - // See https://stackoverflow.com/a/14898930 - $rootScope.$off = function (name, listener) { - var namedListeners = $rootScope.$$listeners[name]; - if (namedListeners) { - // Loop through the array of named listeners and remove them from the array. - for (var i = 0; i < namedListeners.length; i++) { - if (namedListeners[i] === listener) { - return namedListeners.splice(i, 1); - } - } - } - }; -});//end angular.module.run - diff --git a/portal_client/app/common/constants/constants.js b/portal_client/app/common/constants/constants.js deleted file mode 100644 index dcc8306..0000000 --- a/portal_client/app/common/constants/constants.js +++ /dev/null @@ -1,43 +0,0 @@ -angular.module('portal.common.constants',[]) - .constant('Constants',{ - Permissions: { - VIEW_SCRIPT_TAB : 'VIEW_SCRIPT_TAB', - VIEW_GIT_TAB : 'VIEW_GIT_TAB', - VIEW_USER_TAB : 'VIEW_USER_TAB', - VIEW_CREDS_TAB : 'VIEW_CREDS_TAB', - VIEW_LOG_TAB : 'VIEW_LOG_TAB', - VIEW_PERMISSION_TAB : 'VIEW_PERMISSION_TAB', - VIEW_EMAIL_TAB : 'VIEW_EMAIL_TAB', - VIEW_ENV_VARS_TAB : 'VIEW_ENV_VARS_TAB', - VIEW_CONFIG : 'VIEW_CONFIG', - CHANGE_CONFIG : 'CHANGE_CONFIG', - VIEW_SMTP_CONFIG : 'VIEW_SMTP_CONFIG', - EDIT_SMTP_CONFIG : 'EDIT_SMTP_CONFIG', - VIEW_HASH_TYPES : 'VIEW_HASH_TYPES', - CHANGE_HASH_TYPES : 'CHANGE_HASH_TYPES', - ADD_USERS : 'ADD_USERS', - DELETE_USERS : 'DELETE_USERS', - PURGE_LOGS : 'PURGE_LOGS', - ADD_PERMS : 'ADD_PERMS', - DELETE_PERMS : 'DELETE_PERMS', - ADD_CREDENTIALS : 'ADD_CREDENTIALS', - DELETE_CREDENTIALS : 'DELETE_CREDENTIALS', - ADD_GIT_REPO : 'ADD_GIT_REPO', - PULL_GIT_REPO : 'PULL_GIT_REPO', - DELETE_GIT_REPO : 'DELETE_GIT_REPO', - ADD_EMAIL : 'ADD_EMAIL', - DELETE_EMAIL : 'DELETE_EMAIL', - RUN_SCRIPT : 'RUN_SCRIPT', - ADD_SCRIPT : 'ADD_SCRIPT', - DELETE_SCRIPT : 'DELETE_SCRIPT', - VIEW_SCRIPT_SCHED_STATUS : 'VIEW_SCRIPT_SCHED_STATUS', - DELETE_SCRIPT_SCHED_STATUS : 'DELETE_SCRIPT_SCHED_STATUS', - ADD_ENV_VARS : 'ADD_ENV_VARS', - DELETE_ENV_VARS : 'DELETE_ENV_VARS', - VIEW_ENV_VARS : 'VIEW_ENV_VARS', - VIEW_LOG_LEVELS : 'VIEW_LOG_LEVELS', - CHANGE_LOG_LEVELS : 'CHANGE_LOG_LEVELS', - DELETE_FILE : 'DELETE_FILE', - UPDATE_SEED_VALUE : 'UPDATE_SEED_VALUE' - } - }); \ No newline at end of file diff --git a/portal_client/app/common/directives/compare-to/compare-to.js b/portal_client/app/common/directives/compare-to/compare-to.js deleted file mode 100644 index 0e016e9..0000000 --- a/portal_client/app/common/directives/compare-to/compare-to.js +++ /dev/null @@ -1,22 +0,0 @@ -angular.module('portal.common.directives.compareTo', ['ui.router']) - .directive('compareTo', function(){ - return { - require: 'ngModel', - scope: { - otherModelValue: '=compareTo' - }, - link: function(scope, element, attributes, ngModel) { - - ngModel.$validators.compareTo = function(modelValue) { - if ((modelValue === null || modelValue === undefined) && scope.otherModelValue === null) { - return true; - } - return modelValue === scope.otherModelValue; - }; - - scope.$watch('otherModelValue', function() { - ngModel.$validate(); - }); - } - }; - }); \ No newline at end of file diff --git a/portal_client/app/common/directives/has-permission/has-permission.js b/portal_client/app/common/directives/has-permission/has-permission.js deleted file mode 100644 index ef00a4d..0000000 --- a/portal_client/app/common/directives/has-permission/has-permission.js +++ /dev/null @@ -1,32 +0,0 @@ -(function() { - 'use strict'; - - angular.module('portal.common.directives.permissions', ['ui.router']) - .directive('hasPermission', function(permissions){ - return { - link: function(scope, element, attrs) { - if (!_.isString(attrs.hasPermission)){ - throw 'hasPermission value must be a string'; - } - var value = attrs.hasPermission.trim(); - var notPermissionFlag = value[0] === '!'; - if (notPermissionFlag) { - value = value.slice(1).trim(); - } - - function toggleVisibility() { - permissions.canView({permission: value}).then(function(allowed){ - if ((allowed && !notPermissionFlag) || (!allowed && notPermissionFlag)) { - element.css('display', 'block'); - } else { - element.css('display', 'none'); - } - }); - } - - toggleVisibility(); - scope.$on('permissionsChanged', toggleVisibility); - } - }; - }); -})(); \ No newline at end of file diff --git a/portal_client/app/common/directives/portal-tab-set/portal-tab-set.html b/portal_client/app/common/directives/portal-tab-set/portal-tab-set.html deleted file mode 100644 index 96ef3f7..0000000 --- a/portal_client/app/common/directives/portal-tab-set/portal-tab-set.html +++ /dev/null @@ -1,14 +0,0 @@ - - - -
-
- {{tab.title}} -
-
-
- -
-
-
-
diff --git a/portal_client/app/common/directives/portal-tab-set/portal-tab-set.js b/portal_client/app/common/directives/portal-tab-set/portal-tab-set.js deleted file mode 100644 index 0bdf0eb..0000000 --- a/portal_client/app/common/directives/portal-tab-set/portal-tab-set.js +++ /dev/null @@ -1,129 +0,0 @@ -(function () { - 'use strict'; - - var _$state; - - /** - * Creates a tabset with a scrollable tab bar - * Based on the incredible example at http://www.bootply.com/l2ChB4vYmC - */ - angular.module('portal.common.directives.portalTabset', ['ui.router']) - .directive('portalTabSet', function ($state) { - _$state = $state; - return { - restrict: 'E', - replace: false, //Nothing shows up if you use replace: true - transclude: true, - scope: { - tabs: '=', - tabIndex: '=?', - }, - templateUrl: 'common/directives/portal-tab-set/portal-tab-set.html', - link: repoTabsetLink - }; - }); - - function repoTabsetLink(scope, element, attrs, fn) { - - //The default starting position of the tab group. - var DEFAULT_TAB_POSITION = 0; - - scope.tabIndex = scope.tabIndex === null || scope.tabIndex === undefined ? 0 : scope.tabIndex; - scope.visibleTabs = []; - - scope.$watch('tabIndex', function(value) { - if (scope.tabIndex === null || scope.tabIndex === undefined) { - return; - } - scope.tabIndex = value; - }); - - scope.tabsetSelectChange = function(index) { - scope.tabIndex = index; - scope.$emit('tabsetSelectChange', index); - }; - - scope.$on('changeTabSelection', function(value) { - scope.tabIndex = value; - }); - - /** - * Determines if the state object for a tab is active. - * - * @param {type} state A tab's state - * @returns {boolean} True if the state is active, false otherwise. - */ - function isActive(state) { - var isState = _$state.is(state); - return isState || (_$state.current.name.indexOf(state) >= 0); // allow for sub tabs. - } - - /** - * Updates the tabs after the state succesfully changes. - * - * @param {type} tabs An array of tabs. See action-pane.js for example - * @returns {undefined} - */ - function updateTabStates(tabs) { - //Update the active tag for each tab to reflect state change - var activeTab = false; - if (angular.isArray(tabs)) { - tabs.forEach(function (tab) { - tab.active = isActive(tab.state); - activeTab = activeTab || tab.active; - }); - //If no tab has been specified, activate the first tab. - if (!activeTab && angular.isDefined(tabs[0])) { - tabs[0].default = true; - tabs[0].active = true; - } - - //Now notify tabs to respect tab activation - scope.$broadcast('tabActivated'); - } - } - - scope.$on('tabsetDidChange', function (evt, tabs) { - scope.tabs = tabs; - update(); - }); - - function update() { - updateVisisbleTabls(); - updateTabStates(scope.tabs); - } - - function updateVisisbleTabls() { - for (var i = 0; i < scope.tabs.length; i++) { - var tab = scope.tabs[i]; - if (tab.visible === undefined || tab.visible) { - scope.visibleTabs[i] = tab; - } - } - } - - scope.$on('$stateChangeSuccess', function () { - updateTabStates(scope.tabs); - }); - - /** - * Changes the state to the specified tab state. If the control key was - * held when the tab was click on, opens the tab's "big" state (fullscreen) in - * a new tab. - * - * @param {$event} evt The click event. Used to determine if ctrl/cmd was held - * during the click. - * @param {type} tab The tab to activate. A tab object from $scope.tabs. - * - * @returns {undefined} - */ - scope.processTabClick = function (evt, tab, index) { - _$state.go(tab.state); - update(); - scope.tabsetSelectChange(index); - }; - - updateVisisbleTabls(); - update(); - } //end dcdTabsetLink function -})(); \ No newline at end of file diff --git a/portal_client/app/common/directives/portal-websocket/portal-websocket.html b/portal_client/app/common/directives/portal-websocket/portal-websocket.html deleted file mode 100644 index 26ef5f1..0000000 --- a/portal_client/app/common/directives/portal-websocket/portal-websocket.html +++ /dev/null @@ -1,3 +0,0 @@ -
- {{iconImage}} -
\ No newline at end of file diff --git a/portal_client/app/common/directives/portal-websocket/portal-websocket.js b/portal_client/app/common/directives/portal-websocket/portal-websocket.js deleted file mode 100644 index 3f6d9da..0000000 --- a/portal_client/app/common/directives/portal-websocket/portal-websocket.js +++ /dev/null @@ -1,357 +0,0 @@ -angular.module('portal.common.directives.portalWebsocket', ['ui.router']) -.directive('portalWebsocket', PortalWebsocket); - -function PortalWebsocket(Request, $timeout, portalUtils, PortalPubSub) { - return { - restrict: 'E', - templateUrl: 'common/directives/portal-websocket/portal-websocket.html', - link: function (scope) { - - scope.iconImage = 'import_export'; - scope.stats = 'not started'; - - var PingPong = function (msg) { - this.date = msg.date; - this.pull = msg.pull; - this.data = msg.data; - }; - - var Pinger = function () { - this.progress = 0; - this.count = 0; - this.iterations = null; - this.ping = null; - this.pong = null; - - this.bwConvert = function (bytes, msec) { - var res = bytes / msec * 1000 * 8; // bits/second; - var units; - if (res > 1000000) { - res /= 1024000; // Mbits/sec - units = 'Mbps'; - } else if (res > 1024) { - res /= 1000; // Kbits/sec - units = 'Kbps'; - } else { - units = 'bps'; - } - return this.round(res, 1) + units; - }; - - this.round = function (value, decimals) { - return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals); - }; - - this.isDone = function () { - if (this.count >= this.iterations) { - this.progress = 100; - return true; - } else { - this.progress = this.round(this.count / this.iterations * 100, 0); - return false; - } - }; - - return this; - }; - - var LatencyTask = portalUtils.inherit(function () { - Pinger.call(this); - this.iterations = 100; - this.latencySum = 0; - this.latencyMin = 0; - this.latencyAve = 0; - this.latencyMax = 0; - this.pps = 'n/a'; - - this.getPing = function () { - this.ping = new PingPong({'date': new Date().getTime(), 'pull': 0, 'data': []}); - return this.ping; - }; - - this.onPong = function (pong) { - this.pong = pong; - this.count++; - var now = new Date().getTime(); - var msec = now - this.pong.date; - this.latencySum += msec; - this.latencyAve = this.round(this.latencySum / this.count, 0); - if (this.latencyMin === 0 || msec < this.latencyMin) { - this.latencyMin = msec; - } - if (this.latencyMax === 0 || msec > this.latencyMax) { - this.latencyMax = msec; - } - // calc aggregate ppps - this.pps = this.count / this.latencySum * 1000; - this.pps = this.round(this.pps, 1); - return this.isDone(); - }; - - - return this; - }, Pinger); - - var DownloadTask = portalUtils.inherit(function (latencyTask) { - Pinger.call(this); - this.iterations = 20; - this.downloadBytes = 0; - this.downloadTime = 0; - this.download = 0; - this.pull = 10000; - - this.getPing = function () { - this.ping = new PingPong({'date': new Date().getTime(), 'pull': this.pull, 'data': []}); - return this.ping; - }; - - this.onPong = function (pong) { - this.pong = pong; - this.count++; - var now = new Date().getTime(); - var msec = now - this.pong.date - latencyTask.latencyAve / 2; - var bytes = this.pong.data.length; - this.downloadBytes += bytes; - this.downloadTime += msec; - // calc aggregate download bandwidth - this.download = this.bwConvert(this.downloadBytes, this.downloadTime); - return this.isDone(); - }; - - return this; - }, Pinger); - - var UploadTask = portalUtils.inherit(function (latencyTask, downloadTask) { - Pinger.call(this); - this.iterations = 20; - this.uploadBytes = 0; - this.uploadTime = 0; - this.upload = 0; - - this.getPing = function () { - this.ping = new PingPong({'date': new Date().getTime(), 'pull': 0, 'data': downloadTask.pong.data}); - return this.ping; - }; - - this.onPong = function (pong) { - this.pong = pong; - this.count++; - var now = new Date().getTime(); - var msec = now - this.pong.date - latencyTask.latencyAve / 2; - var bytes = this.ping.data.length; - this.uploadBytes += bytes; - this.uploadTime += msec; - this.upload = this.bwConvert(this.uploadBytes, this.uploadTime); - return this.isDone(); - }; - - return this; - }, Pinger); - - var icon = document.getElementById('icon'); - - var latencyTask = new LatencyTask(); - var downloadTask = new DownloadTask(latencyTask); - var uploadTask = new UploadTask(latencyTask, downloadTask); - var task = latencyTask; - var transport = null; - var stompClient = null; - var subscription = null; - - function onConnectionSuccess(frame) { - - transport = stompClient.ws.transport; - - // subscribe to the /info/pong queue for this user, requires controller annotations: - // @SubscribeMapping('/info/ping') - // @SendToUser('/queue/info/pong') - var headers = {/*ack: 'client'*/}; - subscription = stompClient.subscribe('/user/queue/pong', onPong, headers); - - // if not websocket scale down the number of iterations - if (transport !== 'websocket') { - var div = 5; - latencyTask.iterations /= div; - downloadTask.iterations /= div; - uploadTask.iterations /= div; - } - - // kick it off - task = latencyTask; - sendPing(); - } - - function onPong(frame) { - - // frame.ack(); - scope.$apply(function () { - var done = task.onPong(new PingPong(JSON.parse(frame.body))); - - // switch tasks when finished - if (done && task === latencyTask) { - task = downloadTask; - } else if (done && task === downloadTask) { - task = uploadTask; - } else if (done && task === uploadTask) { - task = null; - } - - if (task !== null) { - - sendPing(); - } else { - finish(); - } - - }); - } - - scope.busy = function () { - return task !== null; - }; - - function connect(transports) { - - - // create stomp client - var options = {transports: transports}; - var socket = new SockJS(Request.baseURI + '/ws/stomp', null, options); - stompClient = Stomp.over(socket); - stompClient.debug = null; - - // connect to server - scope.stats = 'connecting'; - var headers = {}; - stompClient.connect(headers, onConnectionSuccess, onConnectionFailure); - } - - function sendPing() { - setActiveStatus(); - stompClient.send('/start/ping', {}, JSON.stringify(task.getPing())); - } - - var timer = null; - - function flash() { - icon.style.color = (icon.style.color === 'green') ? 'goldenrod' : 'green'; - if (getProgress() < 100) { - timer = $timeout(flash, 250); - } - - } - - function getProgress() { - return Math.round((latencyTask.progress + uploadTask.progress + downloadTask.progress) / 3); - } - - function finish() { - $timeout.cancel(timer); - - // shutdown the websocket connection - subscription.unsubscribe(); - stompClient.disconnect(); - stompClient = null; - - if (transport === 'websocket') { - setSuccessfulStatus(); - } else { - setDegradedStatus(); - } - } - - function onConnectionFailure(error) { - $timeout.cancel(timer); - stompClient = null; // Stomp connections are closed on failure - setFailureStatus(error.toString()); - } - - - function createStats() { - var min = latencyTask.latencyMin; - var ave = latencyTask.latencyAve; - var max = latencyTask.latencyMax; - var pps = latencyTask.pps; - var upload = uploadTask.upload; - var download = downloadTask.download; - var latency = min + '/' + ave + '/' + max; - - // always start with the transport - var stats = transport; - if (latencyTask.progress > 0) { - stats += ', ' + latency + 'ms, ' + pps + 'pps'; - } - if (downloadTask.progress > 0) { - stats += ', ' + download; - } - if (uploadTask.progress > 0) { - stats += '/' + upload; - } - if (getProgress() < 100) { - stats += ', ' + getProgress() + '%'; - } - return stats; - } - - function setActiveStatus() { - - // make available to html - scope.stats = createStats(); - - // icon stays flashing - - // notify login dialog that we are not finished - PortalPubSub.publish('StompTestStatus', {status: 'active', stats: scope.stats}); - } - - - // green - function setSuccessfulStatus() { - - // make available to html - scope.stats = createStats(); - - // flashing has stopped, set green check - scope.iconImage = 'check'; - icon.style.color = 'green'; - - // publish status (to login dialog) - PortalPubSub.publish('StompTestStatus', {status: 'successful', stats: scope.stats}); - } - - // yellow - function setDegradedStatus() { - - // make available to html - scope.stats = createStats(); - - // flashing has stopped, set yellow info flag - scope.iconImage = 'info'; - icon.style.color = 'goldenrod'; - - // publish status (to login dialog) - PortalPubSub.publish('StompTestStatus', {status: 'degraded', stats: scope.stats}); - } - - //red - function setFailureStatus(msg) { - - // set hover over - scope.stats = 'failed: ' + msg; - - // flashing has stopped, set red error flag - scope.iconImage = 'error'; - icon.style.color = 'red'; - - // publish status (to login dialog) - PortalPubSub.publish('StompTestStatus', {status: 'failure', stats: scope.stats}); - - } - - // start the test - flash(); - var transports = [/*'websocket', 'xhr-streaming', 'eventsource', 'xhr-polling', 'jsonp-polling'*/]; - connect(transports); - - } - }; -} \ No newline at end of file diff --git a/portal_client/app/common/factories/portal-pubsub/portal-pubsub.js b/portal_client/app/common/factories/portal-pubsub/portal-pubsub.js deleted file mode 100644 index f339854..0000000 --- a/portal_client/app/common/factories/portal-pubsub/portal-pubsub.js +++ /dev/null @@ -1,9 +0,0 @@ -(function (module) { - 'use strict'; - module('portal.common.factories.pubsub', []).factory('PortalPubSub', [function () { - /*jshint ignore:start*/ - var pub = new PubSub(); - return pub; - /*jshint ignore:end*/ - }]); -}(angular.module)); \ No newline at end of file diff --git a/portal_client/app/common/partials/add-creds/add-creds.html b/portal_client/app/common/partials/add-creds/add-creds.html deleted file mode 100644 index e1e9052..0000000 --- a/portal_client/app/common/partials/add-creds/add-creds.html +++ /dev/null @@ -1,91 +0,0 @@ - -
- -
- {{header}} - - - close - -
-
- -
-
- - - -
-
Credentials name is required
-
-
-
-
- - - - {{cred.value}} - -
-
Credential type is required
-
-
-
-
-
- - - -
-
Username is required
-
-
- - - - -
-
Password is required
-
-
- - - remove_red_eye - View password - - -
-
- - - -
- Username on the remote system the ssh key belongs to -
User identity is required
-
-
- - - -
-
SSH Key is required
-
-
- - - - -
-
-
- -
-
- -
{{error}}
- OK - Cancel -
-
-
- diff --git a/portal_client/app/common/partials/add-creds/add-creds.js b/portal_client/app/common/partials/add-creds/add-creds.js deleted file mode 100644 index 5034f36..0000000 --- a/portal_client/app/common/partials/add-creds/add-creds.js +++ /dev/null @@ -1,60 +0,0 @@ - (function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.common.partials.addCreds', ['ui.router']).controller('AddCredsCtrl', AddUserCtrlController); - - function AddUserCtrlController($scope, modalInstance, $state, cache, $mdDialog, Account, Credentials, credentialStores, credentialProvider, portalUtils) { - - $scope.header = modalInstance.header; - - $scope.passwordType = 'password'; - - $scope.submitted = false; - - $scope.loadingBlock = false; - - $scope.isNew = modalInstance.credentials === undefined ? true : false; - - $scope.credentials = $scope.isNew ? new Credentials() : modalInstance.credentials; - - $scope.valid = false; - - $scope.mCache = cache.request([new credentialStores.CredentialTypes()]).then(function(){ - $scope.credentialTypes = $scope.mCache.credentialTypes.data.values; - }); - - /** - * OK button handler - * @returns {undefined} - */ - $scope.ok = function () { - $scope.loadingBlock = true; - var status = $scope.isNew ? 'added': 'edited'; - $scope.submitted = true; - credentialProvider.addCredentials($scope.credentials).then(function(data){ - $scope.loadingBlock = false; - portalUtils.toast('Credentials ' + status + ' successfully', ['top', 'left'], 2000); - $mdDialog.hide(); - }).catch(function(err){ - $scope.loadingBlock = false; - $scope.error = err.message; - }); - }; - - /** - * Cancel button handler. - * @returns {undefined} - */ - $scope.cancel = function () { - //Dismiss the modal - $mdDialog.cancel(); - }; - - } //end AddUserCtrlController function - -})(); \ No newline at end of file diff --git a/portal_client/app/common/partials/add-directory/add-directory.html b/portal_client/app/common/partials/add-directory/add-directory.html deleted file mode 100644 index 04770b7..0000000 --- a/portal_client/app/common/partials/add-directory/add-directory.html +++ /dev/null @@ -1,32 +0,0 @@ - - -
- {{header}} to {{currentDir}} - - - close - -
-
- -
- - - - -
-
-
- -
-
-
-
- -
- -
{{error}}
- OK - Cancel -
-
\ No newline at end of file diff --git a/portal_client/app/common/partials/add-directory/add-directory.js b/portal_client/app/common/partials/add-directory/add-directory.js deleted file mode 100644 index 6f64984..0000000 --- a/portal_client/app/common/partials/add-directory/add-directory.js +++ /dev/null @@ -1,67 +0,0 @@ - (function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.common.partials.addDirectory', ['ui.router']) - .controller('AddDirectoryCtrl', AddDirectoryCtrlController); - - function AddDirectoryCtrlController($scope, modalInstance, $state, cache, $mdDialog, fileProvider, UploadFile, portalUtils) { - - $scope.header = modalInstance.header; - $scope.currentDir = modalInstance.currentDir; - - $scope.loadingBlock = false; - - $scope.model = { }; - - $scope.valid = false; - - $scope.$watch('model', function(){ - - if ($scope.model.fileDir === undefined) { - $scope.valid = false; - return; - } - - $scope.valid = true; - - }, true); - - /** - * OK button handler - * @returns {undefined} - */ - $scope.ok = function () { - $scope.loadingBlock = true; - fileProvider.makeDirectory($scope.currentDir, $scope.model.fileDir).then(function(data) { - $scope.loadingBlock = false; - portalUtils.toast('Directory added successfully', ['top', 'left'], 2000); - $mdDialog.hide(); - }).catch(function(err) { - $scope.loadingBlock = false; - $scope.error = err.message; - }); - }; - - /** - * Cancel button handler. - * @returns {undefined} - */ - $scope.cancel = function () { - //Dismiss the modal - $mdDialog.cancel(); - }; - - $scope.$on('$destroy', function () { - if ($scope.mCache !== undefined) { - $scope.mCache.unlisten(); - } - }); - - } //end AddDirectoryCtrlController function - -})(); \ No newline at end of file diff --git a/portal_client/app/common/partials/add-email-tmpl/add-email-tmpl.html b/portal_client/app/common/partials/add-email-tmpl/add-email-tmpl.html deleted file mode 100644 index 0f94d06..0000000 --- a/portal_client/app/common/partials/add-email-tmpl/add-email-tmpl.html +++ /dev/null @@ -1,39 +0,0 @@ - -
- -
- {{header}} - - - close - -
-
- -
- - - -
-
Email template name is required
-
-
- - - -
-
Email subject is required
-
-
- Email Body - -
-
- -
{{error}}
- OK - Cancel -
-
-
- diff --git a/portal_client/app/common/partials/add-email-tmpl/add-email-tmpl.js b/portal_client/app/common/partials/add-email-tmpl/add-email-tmpl.js deleted file mode 100644 index 21a7e46..0000000 --- a/portal_client/app/common/partials/add-email-tmpl/add-email-tmpl.js +++ /dev/null @@ -1,67 +0,0 @@ -(function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.common.partials.addEmailTmpl', ['ui.router']).controller('AddEmailTmplCtrl', addEmailTmplCtrlController); - - function addEmailTmplCtrlController($scope, modalInstance, $state, cache, $mdDialog, EmailTemplate, - systemProvider, scriptStores, portalUtils, $timeout) { - - $scope.trustAsHtml = portalUtils.trustAsHtml; - - $scope.header = modalInstance.header; - - $scope.submitted = false; - - $scope.loadingBlock = false; - - $scope.isNew = modalInstance.template === undefined; - - $scope.emailTmpl = $scope.isNew ? new EmailTemplate() : new EmailTemplate(modalInstance.template); - - /*jshint ignore:start*/ - $scope.tinymceOptions = { - inline: false, - skin: 'lightgray', - theme : 'modern', - branding: false, - height: 300, - max_height: 300, - width: 600, - max_width: 600, - resize: false - }; - /*jshint ignore:end*/ - - /** - * OK button handler - * @returns {undefined} - */ - $scope.ok = function () { - $scope.loadingBlock = true; - var status = $scope.isNew ? 'Added': 'Edited'; - systemProvider.addEmailTemplate($scope.emailTmpl).then(function(data){ - portalUtils.toast('Email Template ' + status + ' Successfully', ['top', 'left'], 2000); - $mdDialog.hide(); - }).catch(function(err) { - $scope.loadingBlock = false; - $scope.error = err.message; - }); - }; - - /** - * Cancel button handler. - * @returns {undefined} - */ - $scope.cancel = function () { - //Dismiss the modal - $mdDialog.cancel(); - }; - - } //end addEmailTmplCtrlController function - -})(); \ No newline at end of file diff --git a/portal_client/app/common/partials/add-env/add-env.html b/portal_client/app/common/partials/add-env/add-env.html deleted file mode 100644 index 1ace645..0000000 --- a/portal_client/app/common/partials/add-env/add-env.html +++ /dev/null @@ -1,50 +0,0 @@ - -
- -
- {{header}} - - New Environment Variable - note_add - - - - close - -
-
- - - -
-
- - - - - - - - - -
-
-
- - Remove Environment Variable - delete - -
-
-
-
-
-
- -
{{error}}
- OK - Cancel -
-
-
- diff --git a/portal_client/app/common/partials/add-env/add-env.js b/portal_client/app/common/partials/add-env/add-env.js deleted file mode 100644 index 4d990cb..0000000 --- a/portal_client/app/common/partials/add-env/add-env.js +++ /dev/null @@ -1,86 +0,0 @@ - (function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.common.partials.addEnvVars', ['ui.router']).controller('AddEnvVarCtrl', addEnvVarCtrlController); - - function addEnvVarCtrlController($scope, modalInstance, cache, $mdDialog, scriptObjects, - systemProvider, systemStores, portalUtils) { - - $scope.header = modalInstance.header; - - $scope.submitted = false; - - $scope.loadingBlock = false; - - $scope.isNew = modalInstance.envVars.length === 0; - - $scope.envVars = []; - - if (!$scope.isNew) { - for (var i = 0; i < modalInstance.envVars.length; i++) { - $scope.envVars.push( new scriptObjects.ScriptEnvironmentVariable(modalInstance.envVars[i]) ); - } - } - - $scope.valid = false; - - /** - * OK button handler - * @returns {undefined} - */ - $scope.ok = function () { - - $scope.loadingBlock = true; - var status = $scope.isNew ? 'added': 'edited'; - $scope.submitted = true; - - systemProvider.addEnvVars($scope.envVars).then(function(data) { - $scope.loadingBlock = false; - portalUtils.toast('Script ' + status + ' successfully', ['top', 'left'], 2000); - $mdDialog.hide(); - }).catch(function(err) { - $scope.loadingBlock = false; - $scope.error = err.message; - }); - }; - - $scope.addEnvVar = function() { - var env = new scriptObjects.ScriptEnvironmentVariable(); - $scope.envVars.push(env); - }; - - $scope.moveUp = function(index, array) { - var ent1 = array[index]; - var ent2 = array[index-1]; - array[index] = ent2; - array[index-1] = ent1; - }; - - $scope.moveDown = function(index, array) { - var ent1 = array[index]; - var ent2 = array[index+1]; - array[index] = ent2; - array[index+1] = ent1; - }; - - $scope.delete = function (id, array) { - array.splice(id, 1); - }; - - /** - * Cancel button handler. - * @returns {undefined} - */ - $scope.cancel = function () { - //Dismiss the modal - $mdDialog.cancel(); - }; - - } //end addEnvVarCtrlController function - -})(); \ No newline at end of file diff --git a/portal_client/app/common/partials/add-git/add-git.html b/portal_client/app/common/partials/add-git/add-git.html deleted file mode 100644 index ad8007c..0000000 --- a/portal_client/app/common/partials/add-git/add-git.html +++ /dev/null @@ -1,74 +0,0 @@ - -
- -
- {{header}} - - - close - -
-
- -
-
- - - -
-
Name is required
-
-
-
-
- - - -
-
Git SCM url is required
-
-
-
-
- - - -
-
Git SCM url is required
-
-
-
-
- - - -
-
Checkout directory is required
-
-
-
-
- - - - {{displayKey(cred)}} - -
-
Credentials are required
-
-
-
-
-
-
- -
-
- -
{{error}}
- OK - Cancel -
-
-
- diff --git a/portal_client/app/common/partials/add-git/add-git.js b/portal_client/app/common/partials/add-git/add-git.js deleted file mode 100644 index 1126f70..0000000 --- a/portal_client/app/common/partials/add-git/add-git.js +++ /dev/null @@ -1,67 +0,0 @@ - (function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.common.partials.addGit', ['ui.router']).controller('AddGitCtrl', addGitCtrlController); - - function addGitCtrlController($scope, modalInstance, $state, cache, $mdDialog, GitInfo, Account, accountProvider, gitProvider, credentialStores, portalUtils) { - - $scope.trustAsHtml = portalUtils.trustAsHtml; - - $scope.header = modalInstance.header; - - $scope.submitted = false; - - $scope.loadingBlock = false; - - $scope.isNew = modalInstance.gitInfo === undefined ? true : false; - - $scope.git = $scope.isNew ? new GitInfo() : modalInstance.gitInfo; - - $scope.valid = false; - - $scope.mCache = cache.request([new credentialStores.Credentials()]).then(function(){ - $scope.credentials = $scope.mCache.credentials.data.values; - }); - - /** - * OK button handler - * @returns {undefined} - */ - $scope.ok = function () { - $scope.loadingBlock = true; - var status = $scope.isNew ? 'added': 'edited'; - $scope.submitted = true; - gitProvider.addGitRepo($scope.git).then(function(data){ - $scope.loadingBlock = false; - portalUtils.toast('Git ' + status + ' successfully', ['top', 'left'], 2000); - $mdDialog.hide(); - }).catch(function(err){ - $scope.loadingBlock = false; - $scope.error = err.message; - }); - }; - - $scope.displayKey = function(cred) { - if (cred === undefined) { - return ''; - } - return cred.name + (cred.credentialType === 'SSH' ? ' (SSH Key)' : ' (Username/Password)'); - }; - - /** - * Cancel button handler. - * @returns {undefined} - */ - $scope.cancel = function () { - //Dismiss the modal - $mdDialog.cancel(); - }; - - } //end addGitCtrlController function - -})(); \ No newline at end of file diff --git a/portal_client/app/common/partials/add-permission/add-permission.html b/portal_client/app/common/partials/add-permission/add-permission.html deleted file mode 100644 index 039f6e3..0000000 --- a/portal_client/app/common/partials/add-permission/add-permission.html +++ /dev/null @@ -1,67 +0,0 @@ - -
- -
- {{header}} - - - close - -
-
- -
-
- - - -
-
Unique name required
-
-
- - - -
-
Display name required
-
-
-
-
- - -

Permission Group Enabled

- - {{permission.enabled ? 'True' : 'False'}} -
-
-
-
-
- - - - - -

{{perm.displayName}}

- - {{perm.allowed ? 'Enabled' : 'Disabled'}} -
-
-
-
-
-
-
-
- -
-
- -
{{error}}
- OK - Cancel -
-
-
- diff --git a/portal_client/app/common/partials/add-permission/add-permission.js b/portal_client/app/common/partials/add-permission/add-permission.js deleted file mode 100644 index fdff87b..0000000 --- a/portal_client/app/common/partials/add-permission/add-permission.js +++ /dev/null @@ -1,92 +0,0 @@ - (function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.common.partials.addPermission', ['ui.router']).controller('AddPermissionCtrl', AddPermissionCtrlController); - - function AddPermissionCtrlController($scope, modalInstance, $state, cache, $mdDialog, permissionObjects, - permissionStores, permissionProvider, portalUtils) { - - $scope.header = modalInstance.header; - - $scope.submitted = false; - $scope.loadingBlock = false; - - $scope.isNew = modalInstance.permission === undefined ? true : false; - - $scope.permission = $scope.isNew ? new permissionObjects.PermissionGroup() : new permissionObjects.PermissionGroup(modalInstance.permission); - - $scope.valid = false; - $scope.permissionCategories = []; - - $scope.mCache = cache.request([new permissionStores.PermissionCategories()]).then(function(){ - $scope.permissionCategories = $scope.mCache.permissionCategories.data.values; - if (!$scope.isNew) { - $.each($scope.permission.permissions, function(key, value) { - for (var i = 0; i < $scope.permissionCategories.length; i++) { - var cat = $scope.permissionCategories[i]; - if (cat.name !== value.permissionCategory) { - continue; - } - for (var j = 0; j < cat.permissions.length; j++) { - var perm = cat.permissions[j]; - if (value.permissionId === perm.id) { - perm.allowed = value.allowed; - } - } - } - }); - } - }).catch(function(err){ - portalUtils.toast('Unable to get permission categories: ' + err.message, ['top', 'left'], 2000); - }); - - /** - * OK button handler - * @returns {undefined} - */ - $scope.ok = function () { - $scope.loadingBlock = true; - var status = $scope.isNew ? 'added': 'edited'; - $scope.submitted = true; - - $scope.permission.permissions = []; - $.each($scope.permissionCategories, function(key, cat) { - $.each(cat.permissions, function(key2, perm) { - var newPerm = new permissionObjects.PermissionGroupPermission({ - permissionId: perm.id, - permissionGroupId: $scope.permission.id, - name: perm.name, - displayName: perm.displayName, - allowed: perm.allowed === undefined ? false : perm.allowed - }); - $scope.permission.permissions.push(newPerm); - }); - }); - - permissionProvider.updatePermissions($scope.isNew, $scope.permission).then(function(results) { - $scope.loadingBlock = false; - portalUtils.toast('Permission ' + status + ' successfully', ['top', 'left'], 2000); - $mdDialog.hide(); - }).catch(function(err){ - $scope.loadingBlock = false; - $scope.error = err.message; - }); - }; - - /** - * Cancel button handler. - * @returns {undefined} - */ - $scope.cancel = function () { - //Dismiss the modal - $mdDialog.cancel(); - }; - - } //end AddPermissionCtrlController function - -})(); \ No newline at end of file diff --git a/portal_client/app/common/partials/add-script/add-script-bottom.html b/portal_client/app/common/partials/add-script/add-script-bottom.html deleted file mode 100644 index 67fda67..0000000 --- a/portal_client/app/common/partials/add-script/add-script-bottom.html +++ /dev/null @@ -1,63 +0,0 @@ - - -
- -
- Schedule - - - New Schedule - note_add - -
-
-
-
- - -
- - - - {{sched.value}} - - - - - - - - - - - - - - -
- - Move Up - arrow_upward - - - Move Down - arrow_downward - - - Remove Parameter - delete - -
-
-
-
-
-
-
\ No newline at end of file diff --git a/portal_client/app/common/partials/add-script/add-script-left-local.html b/portal_client/app/common/partials/add-script/add-script-left-local.html deleted file mode 100644 index 9038702..0000000 --- a/portal_client/app/common/partials/add-script/add-script-left-local.html +++ /dev/null @@ -1,9 +0,0 @@ -
- - - -
-
Script command is required
-
-
-
\ No newline at end of file diff --git a/portal_client/app/common/partials/add-script/add-script-left-remote.html b/portal_client/app/common/partials/add-script/add-script-left-remote.html deleted file mode 100644 index 5ba1576..0000000 --- a/portal_client/app/common/partials/add-script/add-script-left-remote.html +++ /dev/null @@ -1,27 +0,0 @@ -
- - - - {{displayKey(cred)}} - -
-
Credentials are required
-
-
-
-
- - - -
-
SSH URL is required
-
-
- - - -
-
SSH URL is required
-
-
-
\ No newline at end of file diff --git a/portal_client/app/common/partials/add-script/add-script-left-scp.html b/portal_client/app/common/partials/add-script/add-script-left-scp.html deleted file mode 100644 index 9601f9f..0000000 --- a/portal_client/app/common/partials/add-script/add-script-left-scp.html +++ /dev/null @@ -1,78 +0,0 @@ -
- - From Local - -
-
- - - - Host name of the machine script is copying from. For local type 'LOCAL' -
-
From host address is required
-
-
- - - - Host port of the machine script is copying from. For local type '0' -
-
From Port is required
-
-
-
-
- - - - {{displayKey(cred)}} - -
-
From credentials are required
-
-
-
-
- - To Local - -
-
- - - - Host name of the machine script is copying to. For local type 'LOCAL' -
-
To host address is required
-
-
- - - - Host port of the machine script is copying to. For local type '0' -
-
To Port is required
-
-
-
-
- - - - {{displayKey(cred)}} - -
-
From credentials are required
-
-
-
-
- - - - File name or regular expression for file to send' -
-
File name or regular expression required
-
-
-
\ No newline at end of file diff --git a/portal_client/app/common/partials/add-script/add-script-left.html b/portal_client/app/common/partials/add-script/add-script-left.html deleted file mode 100644 index eed10a5..0000000 --- a/portal_client/app/common/partials/add-script/add-script-left.html +++ /dev/null @@ -1,55 +0,0 @@ - - -
- -
- Script - -
-
-
-
- - - -
-
Name is required
-
-
-
- - - - {{st.value}} - -
-
Script type is required
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - - - Base directory to find files in - -
-
- - - - Directory to send/save the files to - -
-
-
\ No newline at end of file diff --git a/portal_client/app/common/partials/add-script/add-script-right-chain.html b/portal_client/app/common/partials/add-script/add-script-right-chain.html deleted file mode 100644 index 87de336..0000000 --- a/portal_client/app/common/partials/add-script/add-script-right-chain.html +++ /dev/null @@ -1,60 +0,0 @@ -
- -
- Script Chain - - - New Script Chain - note_add - -
-
-
-
- - -
-
- - - - {{s.name}} - -
-
Script Required
-
-
- - - - Exit status of the parent script to execute this script -
-
Exit Status is Required
-
-
- - - (Optional) How many minutes after the parent script ends should this script execute - - -
-
-
- - Move Up - arrow_upward - - - Move Down - arrow_downward - - - Remove Parameter - delete - -
-
-
-
-
-
\ No newline at end of file diff --git a/portal_client/app/common/partials/add-script/add-script-right-email.html b/portal_client/app/common/partials/add-script/add-script-right-email.html deleted file mode 100644 index 4bc1799..0000000 --- a/portal_client/app/common/partials/add-script/add-script-right-email.html +++ /dev/null @@ -1,89 +0,0 @@ -
- -
- Script Email - - - New Script Email - note_add - -
-
-
-
-
-
- - - - {{tmpl.emailName}} - -
-
Email Template Required
-
-
- - Add Recipient - add - -
- - -
- - - - {{u.username}} - -
-
Recipient Required
-
-
-
-
-
-
-
- - Confirm Email Template - check - - - Remove Email Template - delete - -
-
-
- - -
-
- - - - -
- - -
- - - - -
-
-
-
-
- - Remove Email Template - delete - -
-
-
-
-
-
\ No newline at end of file diff --git a/portal_client/app/common/partials/add-script/add-script-right-env-vars.html b/portal_client/app/common/partials/add-script/add-script-right-env-vars.html deleted file mode 100644 index 40f01c9..0000000 --- a/portal_client/app/common/partials/add-script/add-script-right-env-vars.html +++ /dev/null @@ -1,47 +0,0 @@ -
- -
- Script Environment Variables - - - New Script Environment Variable - note_add - -
-
-
-
- - -
-
- - - - - - - - - -
-
-
- - Move Up - arrow_upward - - - Move Down - arrow_downward - - - Remove Parameter - delete - -
-
-
-
-
-
diff --git a/portal_client/app/common/partials/add-script/add-script-right-parameters.html b/portal_client/app/common/partials/add-script/add-script-right-parameters.html deleted file mode 100644 index baf6a07..0000000 --- a/portal_client/app/common/partials/add-script/add-script-right-parameters.html +++ /dev/null @@ -1,41 +0,0 @@ -
- -
- {{script.scriptType !== 'LOCAL' ? 'Commands' : 'Parameters'}} - - - {{script.scriptType !== 'LOCAL' ? 'New Command' : 'New Parameter'}} - note_add - -
-
-
-
- - -
-
- - - -
-
-
- - Move Up - arrow_upward - - - Move Down - arrow_downward - - - Remove Parameter - delete - -
-
-
-
-
-
diff --git a/portal_client/app/common/partials/add-script/add-script-right.html b/portal_client/app/common/partials/add-script/add-script-right.html deleted file mode 100644 index 1e0bb9d..0000000 --- a/portal_client/app/common/partials/add-script/add-script-right.html +++ /dev/null @@ -1,21 +0,0 @@ - - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- \ No newline at end of file diff --git a/portal_client/app/common/partials/add-script/add-script.css b/portal_client/app/common/partials/add-script/add-script.css deleted file mode 100644 index 7473414..0000000 --- a/portal_client/app/common/partials/add-script/add-script.css +++ /dev/null @@ -1,19 +0,0 @@ -.add-script-even { - background-color: #f3f3f3; -} - -answerInput.md-input-container.md-input { - height: 65px !important; -} - -.md-parameter-toolbar { - background-color: rgb(219, 233, 240) !important; - color: black !important; - padding-left: 5px !important; - padding-right: 5px !important; -} - -.md-icon-default-color { - color: grey !important; - color: rgba(0, 0, 0, 0.54) !important; -} diff --git a/portal_client/app/common/partials/add-script/add-script.html b/portal_client/app/common/partials/add-script/add-script.html deleted file mode 100644 index da706ab..0000000 --- a/portal_client/app/common/partials/add-script/add-script.html +++ /dev/null @@ -1,31 +0,0 @@ - -
- -
- {{header}} - - - close - -
-
- -
-
-
- -
-
-
-
- -
-
- -
{{error}}
- OK - Cancel -
-
-
- diff --git a/portal_client/app/common/partials/add-script/add-script.js b/portal_client/app/common/partials/add-script/add-script.js deleted file mode 100644 index ffa47ce..0000000 --- a/portal_client/app/common/partials/add-script/add-script.js +++ /dev/null @@ -1,218 +0,0 @@ - (function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.common.partials.addScript', ['ui.router']).controller('AddScriptCtrl', addScriptCtrlController); - - function addScriptCtrlController($scope, modalInstance, $state, cache, $mdDialog, scriptObjects, EmailTemplate, Account, - scriptProvider, scriptStores, credentialStores, portalUtils, systemStores, accountStores) { - - $scope.trustAsHtml = portalUtils.trustAsHtml; - - $scope.header = modalInstance.header; - - $scope.submitted = false; - - $scope.loadingBlock = false; - - $scope.isNew = modalInstance.script === undefined ? true : false; - - $scope.script = $scope.isNew ? new scriptObjects.Script() : new scriptObjects.Script(modalInstance.script); - - $scope.model = { - fromLocal: $scope.isNew || $scope.script.scriptType !== 'SCP' ? false : $scope.script.scp.fromHost === 'LOCAL', - toLocal: $scope.isNew || $scope.script.scriptType !== 'SCP' ? false : $scope.script.scp.toHost === 'LOCAL', - addEmail : false, - recipients: [] - }; - - $scope.valid = false; - - $scope.mCache = cache.request([ - new scriptStores.ScriptTypes(), - new scriptStores.ScheduleFrequencies(), - new credentialStores.Credentials(), - new scriptStores.Scripts(), - new systemStores.EmailTemplates(), - new systemStores.SMTPConfig(), - new accountStores.UserPool() - ]).then(function(){ - $scope.scriptTypes = $scope.mCache.scriptTypes.data.values; - $scope.schedFreq = $scope.mCache.scheduleFrequencies.data.values; - $scope.credentials = $scope.mCache.credentials.data.values; - $scope.availScripts = $scope.mCache.scripts.data.values; - $scope.users = $scope.mCache.userPool.data.values; - $scope.emails = $scope.mCache.emailTmpls.data.values; - $.each($scope.mCache.smtpConfig.data.values, function(key, value){ - if (value.name === 'smtp.enabled') { - $scope.model.smtpEnabled = value.value === 'true' || value.value === true; - return; - } - }); - }); - - $scope.fromLocalChange = function() { - if ($scope.model.fromLocal) { - $scope.script.scp.fromHost = 'LOCAL'; - $scope.script.scp.fromPort = 0; - $scope.script.scp.fromCredentials = $scope.credentials[0]; - } else { - $scope.script.scp.fromHost = undefined; - $scope.script.scp.fromPort = undefined; - $scope.script.scp.fromCredentials = undefined; - } - }; - - $scope.toLocalChange = function() { - if ($scope.model.toLocal) { - $scope.script.scp.toHost = 'LOCAL'; - $scope.script.scp.toPort = 0; - $scope.script.scp.toCredentials = $scope.credentials[0]; - } else { - $scope.script.scp.toHost = undefined; - $scope.script.scp.toPort = undefined; - $scope.script.scp.toCredentials = undefined; - } - }; - - /** - * OK button handler - * @returns {undefined} - */ - $scope.ok = function () { - - $scope.loadingBlock = true; - var status = $scope.isNew ? 'added': 'edited'; - $scope.submitted = true; - - $.each($scope.script.schedule, function(index, value) { - $scope.script.schedule[index].startDatetime = convertTime(value.startDatetime); - $scope.script.schedule[index].endDatetime = convertTime(value.endDatetime); - $scope.script.schedule[index].lastRun = convertTime(value.lastRun); - }); - - scriptProvider.addScript($scope.script).then(function(data) { - $scope.loadingBlock = false; - portalUtils.toast('Script ' + status + ' successfully', ['top', 'left'], 2000); - $mdDialog.hide(); - }).catch(function(err) { - $scope.loadingBlock = false; - $scope.error = err.message; - }); - }; - - function convertTime(value) { - if (value === null || value === undefined) { - return undefined; - } - - var dte; - if(moment.isMoment(value)) { - dte = value.unix(); - } else if ($.isNumeric(value)) { - dte = value; - } else if (typeof value.getTime === 'function'){ - dte = value.getTime(); - } else { - //When adding a new file the return date comes back like this format Nov 2, 2017 10:53:19 AM - //We need to parse it back to a moment object to parse it to the correct format - dte = moment(value, 'MMM D, YYY h:mm:ss A').unix(); - } - - return dte; - } - - $scope.displayKey = function(cred) { - if (cred === undefined) { - return ''; - } - return cred.name + (cred.credentialType === 'SSH' ? ' (SSH Key)' : ' (Username/Password)'); - }; - - $scope.addParameter = function() { - var param = new scriptObjects.ScriptParameter(); - $scope.script.parameters.push(param); - }; - - $scope.addSchedule = function() { - var sched = new scriptObjects.ScriptSchedule(); - $scope.script.schedule.unshift(sched); - }; - - $scope.addScriptChain = function() { - var chain = new scriptObjects.ScriptChain(); - chain.parentScript = $scope.script.id; - $scope.script.scriptChain.push(chain); - }; - - $scope.addEnvVar = function() { - var env = new scriptObjects.ScriptEnvironmentVariable(); - $scope.script.scriptVariables.push(env); - }; - - $scope.addScriptEmail = function() { - $scope.model.addEmail = true; - }; - - $scope.removeTmpl = function() { - $scope.model.email = undefined; - $scope.model.recipients = []; - $scope.model.addEmail = false; - }; - - $scope.confirmTemplate = function() { - var email = new EmailTemplate($scope.model.email); - $.each($scope.model.recipients, function(key, value) { - email.recipients.push(new Account(value)); - }); - $scope.script.scriptEmails.push(email); - $scope.removeTmpl(); - }; - - $scope.emailTmpl = function(email, index) { - $scope.script.scriptEmails[index] = email; - }; - - $scope.userUpdate = function(email, recip, index) { - email.recipients[index] = recip; - }; - - $scope.addRecipient = function(email) { - var user = new Account(); - email.recipients.push(user); - }; - - $scope.moveUp = function(index, array) { - var ent1 = array[index]; - var ent2 = array[index-1]; - array[index] = ent2; - array[index-1] = ent1; - }; - - $scope.moveDown = function(index, array) { - var ent1 = array[index]; - var ent2 = array[index+1]; - array[index] = ent2; - array[index+1] = ent1; - }; - - $scope.delete = function (id, array) { - array.splice(id, 1); - }; - - /** - * Cancel button handler. - * @returns {undefined} - */ - $scope.cancel = function () { - //Dismiss the modal - $mdDialog.cancel(); - }; - - } //end addScriptCtrlController function - -})(); \ No newline at end of file diff --git a/portal_client/app/common/partials/add-user/add-user.html b/portal_client/app/common/partials/add-user/add-user.html deleted file mode 100644 index f0ab545..0000000 --- a/portal_client/app/common/partials/add-user/add-user.html +++ /dev/null @@ -1,102 +0,0 @@ - -
- -
- {{header}} - - - close - -
-
- -
-
- - - -
-
Email is required
-
Email is not in correct format
-
-
-
-
- - - -
-
Password is required
-
-
- - - remove_red_eye - View password - - - - - -
-
Passwords do not match
-
Must confirm password
-
-
- - - remove_red_eye - View password - - -
- -
- - - - - - - - - -
-
- - - - User - Administrator - -
-
Role is required
-
-
-
-
- - - - - - - - - -
-
-
-
- -
-
- -
{{error}}
- OK - Cancel -
-
-
- diff --git a/portal_client/app/common/partials/add-user/add-user.js b/portal_client/app/common/partials/add-user/add-user.js deleted file mode 100644 index d37843f..0000000 --- a/portal_client/app/common/partials/add-user/add-user.js +++ /dev/null @@ -1,85 +0,0 @@ - (function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.common.partials.addUser', ['ui.router']).controller('AddUserCtrl', AddUserCtrlController); - - function AddUserCtrlController($scope, modalInstance, $state, cache, $mdDialog, Account, accountProvider, portalUtils, - permissionStores, configStores, Triggers) { - - $scope.header = modalInstance.header; - - $scope.passwordType = 'password'; - $scope.confPasswordType = 'password'; - - $scope.requirePassword = modalInstance.requirePassword; - - $scope.submitted = false; - - $scope.loadingBlock = false; - - $scope.isNew = modalInstance.account === undefined ? true : false; - - $scope.account = $scope.isNew ? new Account() : modalInstance.account; - - $scope.valid = false; - - $scope.mCache = cache.request([new configStores.Config('userExpirationDays'), - new permissionStores.AllPermissionGroups()]).then(function(){ - $scope.expirationDays = parseInt($scope.mCache.config.data.userExpirationDays); - $scope.permissionGroups = $scope.mCache.allPermissionGroups.data.values; - }).catch(function(err){ - portalUtils.toast('Unable to get expiration days: ' + err.message, ['top', 'left'], 4000); - }); - - if ($scope.isNew) { - $scope.account.effectiveDate = new Date(); - } else { - $scope.account.effectiveDate = moment($scope.account.effectiveDate); - $scope.account.expirationDate = moment($scope.account.expirationDate); - } - - $scope.$watch('expirationDays', function(value){ - if ($scope.isNew) { - $scope.account.expirationDate = moment().add($scope.expirationDays, 'days'); - } - }); - - /** - * OK button handler - * @returns {undefined} - */ - $scope.ok = function () { - $scope.loadingBlock = true; - var status = $scope.isNew ? 'added': 'edited'; - $scope.submitted = true; - accountProvider.addUser($scope.account).then(function(data){ - $scope.loadingBlock = false; - portalUtils.toast('User ' + status + ' successfully', ['top', 'left'], 2000); - $mdDialog.hide(); - }).catch(function(err){ - $scope.loadingBlock = false; - $scope.error = err.message; - }); - }; - - /** - * Cancel button handler. - * @returns {undefined} - */ - $scope.cancel = function () { - //Dismiss the modal - $mdDialog.cancel(); - }; - - Triggers.listen([Triggers.PERMISSIONS_ADDED, Triggers.PERMISSIONS_DELETED], function(trigger, payload){ - new permissionStores.AllPermissionGroups().refresh(); - }); - - } //end AddUserCtrlController function - -})(); \ No newline at end of file diff --git a/portal_client/app/common/partials/configuration/configuration.html b/portal_client/app/common/partials/configuration/configuration.html deleted file mode 100644 index 593f68e..0000000 --- a/portal_client/app/common/partials/configuration/configuration.html +++ /dev/null @@ -1,146 +0,0 @@ - -
- - -
- Configuration - - - close - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - {{ll.name}} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - remove_red_eye - View password - -
-
-
-
-
- - - - - - - - - - - - - - - - - - -
- - - - - - remove_red_eye - View password - -
-
-
-
-
-
-
- -
{{error}}
- Save - Cancel -
-
-
\ No newline at end of file diff --git a/portal_client/app/common/partials/configuration/configuration.js b/portal_client/app/common/partials/configuration/configuration.js deleted file mode 100644 index b48d9c6..0000000 --- a/portal_client/app/common/partials/configuration/configuration.js +++ /dev/null @@ -1,73 +0,0 @@ - (function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.common.partials.configuration', ['ui.router']).controller('ConfigurationCtrl', configurationCtrlController); - - function configurationCtrlController($scope, account, $state, cache, $mdDialog, configStores, configProvider, - portalUtils, Constants, permissions) { - - $scope.logLevels= [ - {id:'OFF', name: 'Off'}, - {id:'FATAL', name: 'Fatal'}, - {id:'ERROR', name:'Error'}, - {id:'WARN', name:'Warn'}, - {id:'INFO', name:'Info'}, - {id:'DEBUG', name:'Debug'}, - {id:'TRACE', name:'Trace'}, - {id:'ALL', name: 'All'} - ]; - - $scope.saving = false; - $scope.dbPasswordType = 'password'; - $scope.dbRootPasswordType = 'password'; - $scope.canEdit = false; - $scope.mCache = cache.request([new configStores.Configs()]).then(function(){ - $scope.config = $scope.mCache.configs.data; - }); - - permissions.canView({permission: Constants.Permissions.CHANGE_CONFIG}).then(function(allowed){ - $scope.canEdit = allowed; - }); - - /** - * OK button handler - * @returns {undefined} - */ - $scope.ok = function () { - portalUtils.confirmBox('saveConfig', 'Save Configuration', - ['Are you sure you want to save the configuration values?', 'New values will not take effect until server restart'], - false, function(value) { - if (value.confirm) { - $scope.saveConfig(); - } - }); - }; - - $scope.saveConfig = function() { - configProvider.saveConfiguration($scope.config).then(function(value){ - portalUtils.toast('Configuration values saved successfully', ['top', 'left'], 2000); - new configStores.Configs().refresh(); - $mdDialog.hide(); - }).catch(function(err){ - portalUtils.toast('Failed to save configuration: ' + err.message, ['top', 'left'], 4000); - new configStores.Configs().refresh(); - }); - }; - - /** - * Cancel button handler. - * @returns {undefined} - */ - $scope.cancel = function () { - //Dismiss the modal - $mdDialog.cancel(); - }; - - } //end configurationCtrlController function - -})(); \ No newline at end of file diff --git a/portal_client/app/common/partials/file-info/file-info.html b/portal_client/app/common/partials/file-info/file-info.html deleted file mode 100644 index a330aff..0000000 --- a/portal_client/app/common/partials/file-info/file-info.html +++ /dev/null @@ -1,87 +0,0 @@ - -
- -
- {{header}} - - - close - -
-
- - - - - -
-

Please enter hash value and file location to validate the file

-
-
- -
-

Please enter new file location to move the file to

-
-
- -
- - - - - - - -
-
File location is required
-
-
- - - - -
-
- - - - -
-
Hash value required
-
-
-
- - - - - - - - - - - - - - - - - - -
-
-
-
- -
-
- -
{{error}}
- Validate - Move - Download - Close -
-
-
\ No newline at end of file diff --git a/portal_client/app/common/partials/file-info/file-info.js b/portal_client/app/common/partials/file-info/file-info.js deleted file mode 100644 index e44c8c4..0000000 --- a/portal_client/app/common/partials/file-info/file-info.js +++ /dev/null @@ -1,111 +0,0 @@ - (function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.common.partials.fileinfo', ['ui.router']).controller('FileInfoCtrl', fileInfoController); - - function fileInfoController($scope, modalInstance, $state, cache, $mdDialog, PatchFile, portalUtils, fileProvider) { - - $scope.submitted = false; - $scope.loadingBlock = false; - $scope.moveFile = modalInstance.moveFile; - - $scope.header = modalInstance.header; - $scope.originalFile = modalInstance.file; - $scope.file = new PatchFile(modalInstance.file); - if (!$scope.file.valid) { - $scope.file.md5 = ''; - $scope.file.sha1 = ''; - $scope.file.sha512 = ''; - $scope.file.fileLocation = ''; - } - - $scope.ok = function () { - $mdDialog.hide(); - }; - - $scope.download = function() { - var url = '/portal/file/download.do?hashValue=' + $scope.file.sha512; - window.open(url, ''); - }; - - $scope.relocate = function() { - portalUtils.confirmBox('relocateFile', 'Relocate File', ['Are you sure you want to relocate file:', $scope.file.fileName, 'To directory:', $scope.file.fileLocation], - false, function(value) { - if (value.confirm) { - $scope.loadingBlock = true; - fileProvider.moveFile($scope.file).then(function() { - $scope.loadingBlock = false; - portalUtils.toast('File ' + $scope.file.fileName + ' update successfully', ['top', 'left'], 2000); - }).catch(function(err) { - $scope.loadingBlock = false; - $scope.error = err.message; - }); - } - }); - }; - - $scope.validate = function() { - $scope.submitted = true; - if ($scope.file.valid) { - $mdDialog.hide(); - return true; - } - - $scope.error = ''; - if ($scope.file.fileLocation.trim() === '') { - $scope.error = 'File location needed to validate'; - return false; - } - - if ($scope.file.newHash.trim() === '') { - $scope.error = 'Hash value needed'; - return false; - } - - if ($scope.file.newHash.trim().length === 32) { - $scope.file.md5 = $scope.file.newHash; - $scope.file.sha1 = $scope.originalFile.sha1; - $scope.file.sha512 = $scope.originalFile.sha512; - } else if ($scope.file.newHash.trim().length === 40) { - $scope.file.sha1 = $scope.file.newHash; - $scope.file.sha512 = $scope.originalFile.sha512; - $scope.file.md5 = $scope.originalFile.md5; - } else if ($scope.file.newHash.trim().length === 128) { - $scope.file.sha512 = $scope.file.newHash; - $scope.file.md5 = $scope.originalFile.md5; - $scope.file.sha512 = $scope.originalFile.sha512; - } else { - $scope.error = 'Invalid hash provided'; - return false; - } - - $scope.loadingBlock = true; - fileProvider.validate($scope.file).then(function(data) { - $scope.loadingBlock = false; - portalUtils.toast('File ' + $scope.file.fileName + ' update successfully', ['top', 'left'], 2000); - $scope.ok(); - return true; - }).catch(function(err) { - $scope.loadingBlock = false; - $scope.error = err.message; - return false; - }); - }; - - /** - * Cancel button handler. - * @returns {undefined} - */ - $scope.cancel = function () { - //Dismiss the modal - $mdDialog.cancel(); - }; - - } //end fileInfoController function - -})(); \ No newline at end of file diff --git a/portal_client/app/common/partials/file-validate/file-validate.html b/portal_client/app/common/partials/file-validate/file-validate.html deleted file mode 100644 index 0dd501a..0000000 --- a/portal_client/app/common/partials/file-validate/file-validate.html +++ /dev/null @@ -1,22 +0,0 @@ - - -
- {{header}} - - - close - -
-
- - - - - - Ok - -
\ No newline at end of file diff --git a/portal_client/app/common/partials/file-validate/file-validate.js b/portal_client/app/common/partials/file-validate/file-validate.js deleted file mode 100644 index 83c8973..0000000 --- a/portal_client/app/common/partials/file-validate/file-validate.js +++ /dev/null @@ -1,41 +0,0 @@ - (function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.common.partials.filevalidate', ['ui.router']).controller('FileValidateCtrl', fileValidateController); - - function fileValidateController($scope, modalInstance, $state, $mdDialog, $sce) { - $scope.header = modalInstance.header; - $scope.getContent = function() { - var content = ''; - $.each(modalInstance.results, function(key, value) { - content += '

' + key + ':

'; - for (var i = 0; i < value.length; i++) { - content += '' + value[i] + '

'; - } - }); - $scope.content = content; - }; - - $scope.getContent(); - - $scope.trustAsHtml = function (string){ - return $sce.trustAsHtml(string); - }; - - $scope.ok = function () { - $mdDialog.hide(); - }; - - $scope.cancel = function () { - //Dismiss the modal - $mdDialog.cancel(); - }; - - } //end fileValidateController function - -})(); \ No newline at end of file diff --git a/portal_client/app/common/partials/logger-info/logger-info.html b/portal_client/app/common/partials/logger-info/logger-info.html deleted file mode 100644 index 486c2c5..0000000 --- a/portal_client/app/common/partials/logger-info/logger-info.html +++ /dev/null @@ -1,46 +0,0 @@ - - -
- Loggers - - - close - -
-
- - - - - -

All Loggers

-   - - {{ll.name}} - -
-
-
- - - - {{tab.title}} - - -

{{log.logger}}

-   - - {{ll.name}} - -
-
-
-
-
-
- -
{{error}}
- Save - Cancel -
-
\ No newline at end of file diff --git a/portal_client/app/common/partials/logger-info/logger-info.js b/portal_client/app/common/partials/logger-info/logger-info.js deleted file mode 100644 index 7df6bcf..0000000 --- a/portal_client/app/common/partials/logger-info/logger-info.js +++ /dev/null @@ -1,94 +0,0 @@ - (function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.common.partials.loggerinfo', ['ui.router']).controller('LoggerInfoCtrl', loggerInfoCtrlController); - - function loggerInfoCtrlController($scope, $state, cache, $mdDialog, loggerStores, loggerProvider, portalUtils, permissions, Constants) { - $scope.saving = false; - - permissions.canView({permission: Constants.Permissions.CHANGE_LOG_LEVELS}).then(function(allowed) { - $scope.canEdit = allowed; - }); - - $scope.tabs = []; - - $scope.model = { - logLevels: [ - {id:'OFF', name: 'Off'}, - {id:'FATAL', name: 'Fatal'}, - {id:'ERROR', name:'Error'}, - {id:'WARN', name:'Warn'}, - {id:'INFO', name:'Info'}, - {id:'DEBUG', name:'Debug'}, - {id:'TRACE', name:'Trace'}, - {id:'ALL', name: 'All'} - ] - }; - - $scope.mCache = cache.request([new loggerStores.Loggers()]).then(function(){ - $scope.loggers = $scope.mCache.loggers.data.values; - var tabIndex = -1; - for (var i = 0; i < $scope.loggers.length; i++) { - if (i % 5 === 0) { - tabIndex += 1; - $scope.tabs.push({ - title: 'Page' + (tabIndex + 1), - loggers: [] - }); - } - $scope.tabs[tabIndex].loggers.push($scope.loggers[i]); - } - }); - - $scope.setAllLoggers = function() { - $.each($scope.loggers, function(key, value) { - value.level = $scope.model.alllevel; - }); - }; - - /** - * OK button handler - * @returns {undefined} - */ - $scope.ok = function () { - portalUtils.confirmBox('saveLoggers', 'Update Log Levels', - ['Are you sure you want to change the logging level?'], - false, function(value) { - if (value.confirm) { - $scope.saveLoggingLevel(); - } - }); - }; - - $scope.saveLoggingLevel = function() { - loggerProvider.setLoggers($scope.loggers).then(function(value){ - portalUtils.toast('Log levels set successfully', ['top', 'left'], 2000); - new loggerStores.Loggers().refresh(); - $mdDialog.hide(); - }).catch(function(err){ - portalUtils.toast('Failed to set log levels: ' + err.message, ['top', 'left'], 4000); - new loggerStores.Loggers().refresh(); - }); - }; - - $scope.saveConfig = function() { - - }; - - /** - * Cancel button handler. - * @returns {undefined} - */ - $scope.cancel = function () { - //Dismiss the modal - $mdDialog.cancel(); - }; - - } //end loggerInfoCtrlController function - -})(); \ No newline at end of file diff --git a/portal_client/app/common/partials/script-status/view-script-status.html b/portal_client/app/common/partials/script-status/view-script-status.html deleted file mode 100644 index 8530867..0000000 --- a/portal_client/app/common/partials/script-status/view-script-status.html +++ /dev/null @@ -1,68 +0,0 @@ - -
- -
- {{header}} - - - close - -
-
- -
- - -
- Run {{scriptStatus.length - $index}} - - Status:  - {{status.exitStatus !== 0 ? 'Failed' : 'Success'}} - - Start: {{formatTime(status.startTime)}} - - End: {{formatTime(status.endTime)}} - - - {{ status.expanded ? 'expand_less' : 'expand_more' }} - {{status.expanded ? 'Collapse' : 'Expand'}} - -
-
-
{{status.results}}
- -

Files available for download

- - - File Name - - -
-

{{file.fileName}}

- -
- - file_download - Download File - - - delete - Delete File - -
-
-
-
-
-
-
-
- No script job status found for select script job -
-
- -
{{error}}
- Cancel -
-
-
\ No newline at end of file diff --git a/portal_client/app/common/partials/script-status/view-script-status.js b/portal_client/app/common/partials/script-status/view-script-status.js deleted file mode 100644 index fbdb5f5..0000000 --- a/portal_client/app/common/partials/script-status/view-script-status.js +++ /dev/null @@ -1,84 +0,0 @@ - (function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.common.partials.viewScriptStatus', ['ui.router']).controller('ScriptStatusCtrl', ScriptStatusCtrl); - - function ScriptStatusCtrl($scope, modalInstance, cache, $mdDialog, scriptObjects, scriptProvider, fileProvider, portalUtils, - Triggers, Constants) { - - $scope.header = modalInstance.header; - $scope.scriptStatus = []; - - - $scope.Constants = Constants; - $scope.confirmQuestionBox = true; - - $scope.init = function() { - scriptProvider.getScriptStatus(modalInstance.jobId).then(function(data){ - $scope.scriptStatus = []; - for (var i = 0; i < data.length; i++) { - $scope.scriptStatus.push(new scriptObjects.ScriptStatus(data[i])); - } - }); - }; - $scope.init(); - - $scope.formatTime = function(value) { - if (value === null || value === undefined) { - return 'None'; - } - return moment(value).format('MM/DD/Y HH:mm:ss'); - }; - - $scope.delete = function(entity) { - if ($scope.confirmQuestionBox) { - portalUtils.confirmBox('deleteFile', 'Delete File', ['Are you sure you want to delete the file', entity.fileName], - true, function(value) { - if (value.confirm) { - $scope.confirmQuestionBox = !value.checkbox; - $scope.deleteFile(entity); - } - }); - } else { - $scope.deleteFile(entity); - } - }; - - $scope.deleteFile = function(entity) { - fileProvider.deleteFile(entity).then(function() { - portalUtils.toast('File deleted successfully', ['top', 'left'], 2000); - }).catch(function(err){ - portalUtils.toast('File failed to delete: ' + err.message, ['top', 'left'], 4000); - }); - }; - - $scope.ok = function () { - - }; - - $scope.download = function(row) { - var url = '/portal/file/download.do?id=' + row.id; - window.open(url, ''); - }; - - /** - * Cancel button handler. - * @returns {undefined} - */ - $scope.cancel = function () { - //Dismiss the modal - $mdDialog.cancel(); - }; - - Triggers.listen([Triggers.FILE_DELETED], function(trigger, payload){ - $scope.init(); - }); - - } //end addEnvVarCtrlController function - -})(); \ No newline at end of file diff --git a/portal_client/app/common/partials/seed-info/seed-info.html b/portal_client/app/common/partials/seed-info/seed-info.html deleted file mode 100644 index bef6492..0000000 --- a/portal_client/app/common/partials/seed-info/seed-info.html +++ /dev/null @@ -1,26 +0,0 @@ - - -
- AES Seed - - - close - -
-
- - - - - - - - - - - -
{{error}}
- Save - Cancel -
-
\ No newline at end of file diff --git a/portal_client/app/common/partials/seed-info/seed-info.js b/portal_client/app/common/partials/seed-info/seed-info.js deleted file mode 100644 index ee4ee97..0000000 --- a/portal_client/app/common/partials/seed-info/seed-info.js +++ /dev/null @@ -1,56 +0,0 @@ - (function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.common.partials.seedinfo', ['ui.router']).controller('SeedInfoCtrl', seedInfoCtrlController); - - function seedInfoCtrlController($scope, $state, cache, $mdDialog, systemProvider, portalUtils, permissions, Constants) { - $scope.saving = false; - - permissions.canView({permission: Constants.Permissions.UPDATE_SEED_VALUE}).then(function(allowed) { - $scope.canEdit = allowed; - }); - - $scope.model = {}; - - /** - * OK button handler - * @returns {undefined} - */ - $scope.ok = function () { - portalUtils.confirmBox('updateSeed', 'Update AES Seed', - ['Are you sure you want to update the AES Seed', - 'This will go through and update all the saved encrypted values', - 'and cannot be undone once performed'], - false, function(value) { - if (value.confirm) { - $scope.updateSeed(); - } - }); - }; - - $scope.updateSeed = function() { - systemProvider.updateSeed($scope.model.seed).then(function(){ - portalUtils.toast('Seed updated successfully', ['top', 'left'], 2000); - $mdDialog.hide(); - }, function(err){ - $scope.error = err.message; - }); - }; - - /** - * Cancel button handler. - * @returns {undefined} - */ - $scope.cancel = function () { - //Dismiss the modal - $mdDialog.cancel(); - }; - - } //end SeedInfoCtrlController function - -})(); \ No newline at end of file diff --git a/portal_client/app/common/partials/session-end/session-end.html b/portal_client/app/common/partials/session-end/session-end.html deleted file mode 100644 index d745378..0000000 --- a/portal_client/app/common/partials/session-end/session-end.html +++ /dev/null @@ -1,20 +0,0 @@ - -
- -
- Alert! - -
-
- -
-
-
-
- -
{{error}}
- {{btnCnlText}} - {{btnText}} -
-
-
\ No newline at end of file diff --git a/portal_client/app/common/partials/session-end/session-end.js b/portal_client/app/common/partials/session-end/session-end.js deleted file mode 100644 index 73dd51b..0000000 --- a/portal_client/app/common/partials/session-end/session-end.js +++ /dev/null @@ -1,16 +0,0 @@ -(function () { - 'use strict'; - - angular.module('portal.common.partials.sessionEnd', ['ui.router']) - .controller('SessionEndCtrl', SessionEndCtrlController); - - function SessionEndCtrlController($scope, modalInstance, $state, cache) { - $scope.onOkay = modalInstance.onOkay; - $scope.message = modalInstance.message; - $scope.btnText = modalInstance.btnText; - - $scope.btnCnlText = modalInstance.btnCnlText; - $scope.onCancel = modalInstance.onCancel; - } //end SessionEndCtrlController function - -})(); \ No newline at end of file diff --git a/portal_client/app/common/partials/smtp-info/smtp-info.html b/portal_client/app/common/partials/smtp-info/smtp-info.html deleted file mode 100644 index 944ab99..0000000 --- a/portal_client/app/common/partials/smtp-info/smtp-info.html +++ /dev/null @@ -1,93 +0,0 @@ - - -
- SMTP Configuration - - - close - -
-
- - - - - - - -
- - - - - {{conf.value ? 'Yes' : 'No'}} -
- - - - - remove_red_eye - View password - -
-
-
-
-
-
- - - - -
- - - - - {{conf.value ? 'Yes' : 'No'}} -
- - - - - remove_red_eye - View password - -
-
-
-
-
-
- - - - -
- - - - - {{conf.value ? 'Yes' : 'No'}} -
- - - - - remove_red_eye - View password - -
-
-
-
-
-
-
-
- -
{{error}}
- Save - Cancel -
-
\ No newline at end of file diff --git a/portal_client/app/common/partials/smtp-info/smtp-info.js b/portal_client/app/common/partials/smtp-info/smtp-info.js deleted file mode 100644 index 2f79caa..0000000 --- a/portal_client/app/common/partials/smtp-info/smtp-info.js +++ /dev/null @@ -1,140 +0,0 @@ - (function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.common.partials.smtpinfo', ['ui.router']).controller('SMTPInfoCtrl', smtpInfoCtrlController); - - function smtpInfoCtrlController($scope, $state, cache, $mdDialog, systemProvider, systemStores, - portalUtils, permissions, Constants, Triggers) { - $scope.saving = false; - - permissions.canView({permission: Constants.Permissions.EDIT_SMTP_CONFIG}).then(function(allowed){ - $scope.canEdit = allowed; - }); - - $scope.smtpConfig = [ - { - name: 'smtp.enabled', - displayValue: 'SMTP Enabled', - value: false, - type: 'boolean' - },{ - name: 'mail.transport.protocol', - displayValue: 'Transport Protocol', - value: 'smtp', - type: 'text' - },{ - name: 'mail.smtp.host', - displayValue: 'SMTP Server Url', - value: '', - type: 'text' - },{ - name: 'mail.smtp.port', - displayValue: 'SMTP Server Port', - value: 0, - type: 'number' - },{ - name: 'mail.debug', - displayValue: 'Enable Mail Debug Logging', - value: false, - type: 'boolean' - },{ - name: 'mail.smtp.starttls.enable', - displayValue: 'Enable Start TLS', - value: false, - type: 'boolean' - },{ - name: 'mail.smtp.starttls.required', - displayValue: 'Require Start TLS', - value: false, - type: 'boolean' - },{ - name: 'mail.smtp.ssl.trust', - displayValue: 'SSL Trust Certificate', - value: '*', - type: 'text' - },{ - name: 'mail.smtp.auth', - displayValue: 'Require Authentication', - value: false, - type: 'boolean' - },{ - name: 'smtp.from.user', - displayValue: 'From User', - value: '', - type: 'text' - },{ - name: 'smtp.username', - displayValue: 'SMTP Username', - value: '', - type: 'text' - },{ - name: 'smtp.password', - displayValue: 'SMTP Password', - value: '', - type: 'password', - meta: 'password' - }, - ]; - - $scope.mCache = cache.request([new systemStores.SMTPConfig()]).then(function(){ - var conf = $scope.mCache.smtpConfig.data.values; - - $.each($scope.smtpConfig, function(key, value) { - $.each(conf, function(key2, value2) { - if (value.name === value2.name) { - if (value.type === 'number') { - value.value = parseInt(value2.value); - } else if (value.type === 'boolean') { - value.value = value2.value === 'true' || value2.value === true; - } else { - value.value = value2.value; - } - return; - } - }); - }); - }); - - /** - * OK button handler - * @returns {undefined} - */ - $scope.ok = function () { - portalUtils.confirmBox('saveSmtpConfig', 'Update SMTP Configuration', - ['Are you sure you want to update the smtp configuration?'], - false, function(value) { - if (value.confirm) { - $scope.saveSMTPConf(); - } - }); - }; - - $scope.saveSMTPConf = function() { - systemProvider.updateSmtpConfig($scope.smtpConfig).then(function() { - $mdDialog.hide(); - }).catch(function(err) { - $scope.error = err.message; - portalUtils.toast('Failed to save configuration: ' + err.message, ['top', 'left'], 4000); - }); - }; - - /** - * Cancel button handler. - * @returns {undefined} - */ - $scope.cancel = function () { - //Dismiss the modal - $mdDialog.cancel(); - }; - - Triggers.listen([Triggers.SMTP_CONFIG_UPDATED], function(trigger, payload) { - new systemStores.SMTPConfig().refresh(); - }); - - } //end smtpInfoCtrlController function -})(); \ No newline at end of file diff --git a/portal_client/app/common/partials/templates/confirm-window.tmpl.html b/portal_client/app/common/partials/templates/confirm-window.tmpl.html deleted file mode 100644 index 03afa10..0000000 --- a/portal_client/app/common/partials/templates/confirm-window.tmpl.html +++ /dev/null @@ -1,25 +0,0 @@ - - -
- {{confirmTitle}} - - - close - -
-
- -
- -

{{message}}

-
-
- Do not show this message again -
-
-
- - Yes - No - -
\ No newline at end of file diff --git a/portal_client/app/common/partials/templates/purge-logs.tmpl.html b/portal_client/app/common/partials/templates/purge-logs.tmpl.html deleted file mode 100644 index fe26628..0000000 --- a/portal_client/app/common/partials/templates/purge-logs.tmpl.html +++ /dev/null @@ -1,39 +0,0 @@ - - -
- {{title}} - - - close - -
-
- -
-

{{message}}

- - - - - - - - -
-
-
-
- -
- -
{{error}}
-
- Ok - Cancel -
-
-
\ No newline at end of file diff --git a/portal_client/app/common/partials/upload-patch-file/upload-patch-file.html b/portal_client/app/common/partials/upload-patch-file/upload-patch-file.html deleted file mode 100644 index b732d97..0000000 --- a/portal_client/app/common/partials/upload-patch-file/upload-patch-file.html +++ /dev/null @@ -1,31 +0,0 @@ - - -
- {{header}} to {{currentDir}} - - - close - -
-
- -
- -
-
- - - - -
-
-
- -
-
- -
{{error}}
- OK - Cancel -
-
\ No newline at end of file diff --git a/portal_client/app/common/partials/upload-patch-file/upload-patch-file.js b/portal_client/app/common/partials/upload-patch-file/upload-patch-file.js deleted file mode 100644 index ac43893..0000000 --- a/portal_client/app/common/partials/upload-patch-file/upload-patch-file.js +++ /dev/null @@ -1,73 +0,0 @@ - (function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.common.partials.uploadpatchfile', ['ui.router']) - .controller('UploadPatchFileCtrl', UploadPatchFileCtrlController); - - function UploadPatchFileCtrlController($scope, modalInstance, $state, cache, $mdDialog, fileProvider, UploadFile, portalUtils) { - - $scope.header = modalInstance.header; - $scope.currentDir = modalInstance.currentDir; - - $scope.uploadFile = undefined; - - $scope.loadingBlock = false; - - $scope.model = { }; - - $scope.valid = false; - - $scope.$watch('model', function(){ - if ($scope.model.hashValue === undefined || $scope.model.hashValue.trim() === '') { - $scope.valid = false; - return; - } - - if ($scope.uploadFile === undefined) { - $scope.valid = false; - return; - } - - $scope.valid = true; - - }, true); - - /** - * OK button handler - * @returns {undefined} - */ - $scope.ok = function () { - $scope.loadingBlock = true; - fileProvider.uploadFile([new UploadFile().init($scope.uploadFile)], $scope.model.hashValue, $scope.currentDir).then(function(data) { - $scope.loadingBlock = false; - portalUtils.toast('File uploaded successfully', ['top', 'left'], 2000); - $mdDialog.hide(); - }).catch(function(err) { - $scope.loadingBlock = false; - $scope.error = err.message; - }); - }; - - /** - * Cancel button handler. - * @returns {undefined} - */ - $scope.cancel = function () { - //Dismiss the modal - $mdDialog.cancel(); - }; - - $scope.$on('$destroy', function () { - if ($scope.mCache !== undefined) { - $scope.mCache.unlisten(); - } - }); - - } //end UploadPatchFileCtrlController function - -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/authorize/authorize.js b/portal_client/app/common/services/authorize/authorize.js deleted file mode 100644 index fef8b98..0000000 --- a/portal_client/app/common/services/authorize/authorize.js +++ /dev/null @@ -1,125 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Deferred authorization handler. - */ - angular.module('portal.common.services.authorize', ['ui.router']) - .service('authorize', authorizeService); - - function authorizeService($state, $q, cache, accountStores) { - - /** - * Defines the different types of auth checkers. - * @type type - */ - var authHandlers = { - account: function (args) { - var deferred = $q.defer(); - var mCache = cache.request([new accountStores.Account()]).once(function () { - var authorized = false; - for (var i = 0; i < args.length; i++) { - if (mCache.account.data.authoritiesMap.containsKey(args[i])) { - authorized = true; - break; - } - } - deferred.resolve(authorized); - }).catch(function () { - deferred.reject(); - }); - return deferred.promise; - }, - permission: function (args) { - var deferred = $q.defer(); - var mCache = cache.request([new accountStores.Account()]).once(function () { - var acct = mCache.account.data; - if (!acct.enabled) { - deferred.resolve(false); - return; - } - var authorized = false; - for (var i = 0; i < args.length; i++) { - if (acct.hasPermission(args[i])) { - authorized = true; - break; - } - } - deferred.resolve(authorized); - }).catch(function (err) { - deferred.reject(); - }); - return deferred.promise; - } - }; - - - /** - * Chains deferrals so we don't have to nest them. - * - * Yes, this is kind of complicated, its async recursion. Tried to help with - * comments but only so much you can do. - * - * @param {type} authorities - * @param {type} keys - * @param {type} i - * @param {type} isValid - * @returns {$q@call;defer.promise} - */ - function validate(authorities, keys, i, isValid) { - var deferred = $q.defer(); - //If still within bounds of authorities array - //call the auth handler and if we are still valid - //No point in continuing if we are no longer valid. - if (i < keys.length && isValid) { - authHandlers[keys[i]](authorities[keys[i]]).then(function (valid) { - //When the auth handler returns, chain up the next one - //by calling validate again. - //Its important to combine the valid status as we go. - return validate(authorities, keys, i + 1, isValid && valid); - }).then(function (valid) { - //calling deferred in the then allows us to close our chains. - deferred.resolve(valid); - }).catch(function(){ - deferred.reject(); - }); - } else { - //This is the last link in the chain, if we don't call resolve - //we won't start linking the rest of the chains. - deferred.resolve(isValid); - } - return deferred.promise; - } - - return { - /** - * Deferred validation routine for the ui-router resolve - * functionality. UI-router listens for the promise to be resolved - * before movingn to the next state. - * - * This avoids us having to do awkard redirects while we check - * server for status. - * - * @param {type} args - * @returns {$q@call;defer.promise} - */ - validate: function (args) { - var deferred = $q.defer(); - if (angular.isObject(args.authorities)) { - var keys = Object.keys(args.authorities); - validate(args.authorities, keys, 0, true).then(function (isValid) { - if (!isValid) { - $state.go(args.redirect); - } - deferred.resolve(); - }).catch(function () { - $state.go(args.redirect); - }); - } else { - deferred.resolve(); - } - return deferred.promise; - } - }; - } //end authorizeService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/map/map.js b/portal_client/app/common/services/map/map.js deleted file mode 100644 index 8f08b06..0000000 --- a/portal_client/app/common/services/map/map.js +++ /dev/null @@ -1,200 +0,0 @@ -(function () { - 'use strict'; - /** - * DESCRIPTION: - * - * Special map object for easy access to both an object map and an array. - * - * This object mimics maps as defined by the Java map interface. - */ - angular.module('portal.common.services.map', ['ui.router']) - .factory('Map', mapService); - - function mapService() { - - /** - * Defines a map object that allows storage of data as array and object. - * @param {type} accessor The value used on elements for the key, e.g. element.id => "id" - * @returns {map_L35.mapService.Map} - */ - function Map(accessor, groupKeys) { - var map = this; - - /** Array Storage. */ - map.values = []; - /** Object Storage. */ - map.object = {}; - /** Group Storage. */ - map.groups = {}; - /** Group keys. */ - map.groupKeys = []; - if (angular.isArray(groupKeys)) { - map.groupKeys = groupKeys.slice(); - } else if (angular.isDefined(groupKeys)) { - map.groupKeys.push(groupKeys); - } - - //Initialize Groups - for (var i = 0; i < map.groupKeys.length; i++) { - map.groups[map.groupKeys[i]] = {}; - } - - /** - * defines the part of the element that comprises the key. - * May be undefined, not guaranteed. - */ - map.accessor = accessor; - - /** - * @returns {Boolean} True if emtpy. - */ - map.isEmpty = function () { - return map.values.length === 0; - }; - - /** - * Determins if an item is stored inside based on its key. - * @param {type} key - * @returns {Boolean} True if contained. - */ - map.containsKey = function (key) { - return angular.isDefined(map.object[key]); - }; - - /** - * Searches for element, via loop. - * @param {type} value - * @returns {Boolean} True if element found. - */ - map.containsValue = function (value) { - for (var i = 0; i < map.values.length; i++) { - if (map.values[i] === value) { - return true; - } - } - return false; - }; - - /** - * @param {type} key - * @returns {type} element found by key. - */ - map.get = function (key) { - return map.object[key]; - }; - - /** - * Inserts element into both array and object storage. - * @param {type} key - * @param {type} value - */ - map.put = function (key, value) { - //Remove elements. - map.removeByKey(key); - - //Insert. - map.values.push(value); - map.object[key] = value; - - //Group - for (var i = 0; i < map.groupKeys.length; i++) { - var groupKey = map.groupKeys[i]; - var group = value[groupKey]; - if (!angular.isDefined(map.groups[groupKey][group])) { - map.groups[groupKey][group] = new Map(map.accessor); - } - map.groups[groupKey][group].put(key, value); - } - return value; - }; - - /** - * Allows access to a group map. - * Always returns a valid map, just may be empty. - * @param {type} group - * @returns {map_L35.mapService.Map} - */ - map.getGroup = function (groupKey, group) { - if (angular.isDefined(map.groups[groupKey][group])) { - return map.groups[groupKey][group]; - } - return new Map(); - }; - - /** - * Removes an element from both storage interfaces. - * @param {type} key - * @returns {Boolean} T/F if removed or not. - */ - map.removeByKey = function (key) { - if (!map.containsKey(key)) { - return false; - } - var value = map.object[key]; - //Remove from Array. - for (var i = 0; i < map.values.length; i++) { - if (map.values[i] === value) { - map.values.splice(i, 1); - break; - } - } - //Remove from object. - delete map.object[key]; - - //Remove from groups. - for (var j = 0; j < map.groupKeys.length; j++) { - var groupKey = map.groupKeys[j]; - var group = value[groupKey]; - if (angular.isDefined(map.groups[groupKey][group])) { - map.groups[groupKey][group].removeByKey(key); - } - } - return true; - }; - - /** - * Empties the storage objects. - */ - map.clear = function () { - map.object = {}; - map.values = []; - }; - - map.init = function (data, Constructor, accessor) { - map.clear(); - map.accessor = accessor; - if (angular.isArray(data)) { - for (var i = 0; i < data.length; i++) { - var obj = new Constructor(data[i]); - map.put(obj[accessor], obj); - } - } - }; - - Object.defineProperties(map, { - /** - * Returns the keys from the object. - */ - keySet: { - get: function () { - return Object.keys(map.object); - } - }, - length: { - get: function () { - return map.values.length; - } - } - }); - } - - Map.create = function (data, Constructor, accessor, groupKeys) { - var map = new Map(accessor, groupKeys); - map.init(data, Constructor, accessor); - return map; - }; - - return Map; - - } //end mapService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/box/box.js b/portal_client/app/common/services/model/cache/box/box.js deleted file mode 100644 index 9bc7e02..0000000 --- a/portal_client/app/common/services/model/cache/box/box.js +++ /dev/null @@ -1,133 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Box contains data and status for the store and cache. - */ - angular.module('portal.common.services.model.cache') - .factory('Box', boxService); - - function boxService(portalUtils, Listener, Triggers, $q) { - - /** - * Box obejct to enacupsulate the data so it can be watched. - * @returns {undefined} - */ - var Box = portalUtils.inherit(function (args) { - var box = this; - Listener.call(box); - /** - * Container for data. - */ - box.data = undefined; - /** - * Container for error. - */ - box.errorData = undefined; - /** - * Status of the data request. - */ - box.status = Box.Status.NEW; - /** Function to handle client side data processing. */ - box.processGui = args.processGui; - /** Function to handle parallel processing. */ - box.processParallel = args.processParallel; - /** Function for deferred processing, expects $q promise. */ - box.processDeferred = args.processDeferred; - - if (angular.isDefined(args.triggers)) { - Triggers.listen(args.triggers, function(trigger, payload) { - portalUtils.call(args.processTrigger, trigger, payload, box); - }); - } - - box.init = function() { - if (box.status === Box.Status.NEW) { - box.status = Box.Status.PENDING; - if (angular.isFunction(args.source)) { - args.source(args.params).then(function (payload) { - box.update(payload); - }).catch(function(payload){ - box.onError(payload); - }); - } else { - console.error('Store source function was not a function.'); - } - } - return box.listen(); - }; - - box.refresh = function () { - var deferred = $q.defer(); - if (box.status !== Box.Status.PENDING && - angular.isFunction(args.source)) { - box.status = Box.Status.PENDING; - args.source(args.params).then(function (payload) { - if (angular.isFunction(box.processDeferred)) { - box.update(payload).then(deferred.resolve); - } else { - box.update(payload); - deferred.resolve(); - } - }); - } else { - deferred.resolve(); - } - return deferred.promise; - }; - - box.update = function (_data) { - box.status = Box.Status.DONE; - var data = _data; - if (angular.isFunction(box.processParallel)) { - data = box.processParallel(data); - } - if (angular.isFunction(box.processGui)) { - data = box.processGui(data); - } - if (angular.isFunction(box.processDeferred)) { - return box.processDeferred(data).then(function(_data){ - return update(_data); - }); - } else { - return update(data); - } - }; - - box.onError = function(_data) { - box.status = Box.Status.ERROR; - box.errorData = _data; - box.notifyError(); - }; - - function update(data) { - box.data = data; - box.notify(); - } - - box.clear = function () { - box.data = undefined; - box.status = Box.Status.new; - box.notify(); - }; - - box.isDone = function () { - return box.status === Box.Status.DONE; - }; - - }, Listener); - - /** - * Status enum - */ - Box.Status = { - NEW: 0, - PENDING: 1, - DONE: 2, - ERROR: 3 - }; - - - return Box; - } //end boxService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/cache.js b/portal_client/app/common/services/model/cache/cache.js deleted file mode 100644 index d4ead1f..0000000 --- a/portal_client/app/common/services/model/cache/cache.js +++ /dev/null @@ -1,192 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Provides entry to the cache service. - */ - angular.module('portal.common.services.model.cache', ['ui.router']) - .service('cache', cacheService); - - function cacheService($cacheFactory, portalUtils, Store, Request, $rootScope, Listener) { - /** - * $cacheFactory instances for storing all cache data. Shared between tabs. - * - * This may be better placed in app.js - * - * Why are we collecting rootscopes? because when data changes on the - * shared cache we need to notify everyone via $digest. This is - * done in the Listener.digest function. - * - * @type @call;$cacheFactory - */ - var caches = {}; - var scopes = []; - if (angular.isObject(window.opener) && angular.isObject(window.opener.cacheService)) { - caches = window.opener.cacheService.caches; - scopes = window.opener.cacheService.rootScopes; - scopes.push($rootScope); - } else { - caches.data = $cacheFactory('dataCache'); - caches.http = $cacheFactory('httpCache'); - scopes = [$rootScope]; - window.cacheService = {caches: caches, rootScopes: scopes}; - } - - Store.registerCache(caches.data); - Request.registerCache(caches.http); - Listener.registerScopes(scopes); - - /** - * Mini Cache Object. - * Provides an isolated cache with only data points - * that were requested. - * @param _stores - * @returns {undefined} - */ - function MiniCache(_stores) { - var miniCache = this; - /** Stores in this cache. */ - var stores = _stores; - /** Callbacks registered on then(...) */ - var dataCallBack = null; - var errorCallback = null; - /** Parent cache in chained caches. */ - miniCache.parent = null; - /** Allows for a do once and unsubscribe. */ - var doOnce = false; - /** - * Allows tracking of first round of notifications - * to avoid multiple notify calls when all data sets are - * ready. - */ - var storesReady = {}; - - //Activate (Listen) to the stores in this minicache. - for (var i = 0; i < stores.length; i++) { - var store = stores[i]; - if (store instanceof Store) { - storesReady[store.id] = false; - store.init().then(notify(store)).catch(error(store)); - miniCache[store.id] = store.getBox(); - } - } - - /** - * Promise Accessor - * @param {type} callback - * @returns {cache_L35.cacheService.MiniCache} - */ - miniCache.then = function (callback, errorCallback) { - dataCallBack = callback; - miniCache.catch(errorCallback); - return this; - }; - - miniCache.catch = function (callback) { - errorCallback = callback; - return this; - }; - - /** - * Promise Accessor - * @param {type} callback - * @returns {undefined} - */ - miniCache.once = function (callback) { - miniCache.then(callback); - doOnce = true; - return this; - }; - - /** - * Notifies callback in .then, only called when all are ready. - * @returns {undefined} - */ - function notify(store) { - var _store = store; - //returned function is what is called by the store, - //the wrapping allows us to keep track of which stores have - //triggered once. - return function () { - storesReady[_store.id] = true; - //Verify all stores are ready before notifiying listeners. - for (var j = 0; j < stores.length; j++) { - var store = stores[j]; - if (!storesReady[store.id] || stores[j].isReady() === false) { - return; - } - } - if (doOnce) { - miniCache.unlisten(); - } - miniCache.merge(portalUtils.call(dataCallBack)); - }; - } - - function error(store) { - var _store = store; - return function () { - portalUtils.call(errorCallback, _store); - }; - } - - miniCache.merge = function (mCache) { - if (mCache instanceof MiniCache) { - mCache.parent = miniCache; - if (miniCache.parent === null) { - //Copy boxes. - var mCacheStores = mCache.getStores(); - for (var i = 0; i < mCacheStores.length; i++) { - miniCache[mCacheStores[i].id] = mCache[mCacheStores[i].id]; - } - } else { - miniCache.parent.merge(mCache); - } - } - }; - - miniCache.getStores = function () { - return stores; - }; - - /** - * Allows you to purge listeners. - * @returns {undefined} - */ - miniCache.unlisten = function () { - for (var i = 0; i < stores.length; i++) { - stores[i].unlisten(); - } - }; - } - - /* - * Public Methods - */ - return { - /** - * Allows data to be requested. - * @param {type} stores - * @returns {MiniCache} Mini cache with requested data - */ - request: function (stores) { - var storesArray = []; - //Arrayify the data points. - if (angular.isArray(stores)) { - storesArray = stores.slice(); - } else { - storesArray.push(stores); - } - return new MiniCache(storesArray); - }, - /** - * Purges the cache. - */ - flush: function () { - caches.data.removeAll(); - caches.http.removeAll(); - } - }; - - } //end cacheService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/listener/listener.js b/portal_client/app/common/services/model/cache/listener/listener.js deleted file mode 100644 index 202840c..0000000 --- a/portal_client/app/common/services/model/cache/listener/listener.js +++ /dev/null @@ -1,145 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: - */ - angular.module('portal.common.services.model.cache') - .service('Listener', listenerService); - - function listenerService(Map, $q, debounce, $rootScope) { - - var Listener = function () { - var li = this; - - var successMap = new Map(); - var errorMap = new Map(); - var subscriberId = 0; - var notified = false; - var errored = false; - var errorArgs = []; - var successArgs = []; - - li.Listen = function () { - var pr = this; - - pr.successIds = []; - pr.errorIds = []; - - pr.then = function (success, error) { - if (angular.isFunction(success)) { - pr.successIds.push(subscriberId); - successMap.put(subscriberId, success); - subscriberId++; - } - pr.catch(error); - if (notified) { - call(success, successArgs); - } - return pr; - }; - - pr.catch = function (error) { - if (angular.isFunction(error)) { - pr.errorIds.push(subscriberId); - errorMap.put(subscriberId, error); - subscriberId++; - } - if (errored) { - call(error, errorArgs); - } - return pr; - }; - - pr.unlisten = function () { - var i = 0; - for (i = 0; i < pr.successIds.length; i++) { - successMap.removeByKey(pr.successIds[i]); - } - for (i = 0; i < pr.errorIds.length; i++) { - errorMap.removeByKey(pr.errorIds[i]); - } - }; - }; - - li.listen = function () { - return new li.Listen(); - }; - - li.notify = function (timeout) { - notified = true; - successArgs = arguments; - return callMap(successMap, successArgs, timeout); - }; - - li.notifyError = function () { - errored = true; - errorArgs = arguments; - return callMap(errorMap, arguments); - }; - - function callMap(map, args, timeout) { - var promises = []; - for (var i = 0; i < map.length; i++) { - promises.push(call(map.values[i], args, timeout)); - } - return $q.all(promises); - } - - function call(callee, args, timeout) { - var deferred = $q.defer(); - if (angular.isFunction(callee)) { - window.setTimeout(function () { - callee.apply(li, args); - Listener.digest(); - deferred.resolve(); - }, timeout); - } - return deferred.promise; - } - - }; - - var scopes; - Listener.registerScopes = function(_scopes) { - scopes = _scopes; - }; - - /** - * This allows us to only digest once we settle down. - * This debounce waits 100ms if it doesn't get another - * request to digest it will digest. Every request - * resets the timer to 100ms. This prevents us from - * hammering the CPU on load. - * - * Note: I have read the many many things on the internet that say - * we shouldn't do this. That we are breaking $angular convention, and I - * am ok with that. portal is not a public facing website. - * - * We are doing this because $timeout takes about 500ms to a 1s to make - * an async call. setTimeout is significantly faster. But that takes us - * outside of a digest cycle which means angular watches won't be re-evaluated. - * We must call $digest to get them to update. - * - * Conventionally you should call $scope.$apply, but that results in the same - * delays as $setTimout. - * - * Alternatively we could make this synchronous but doing so prohibits UI - * drawing/interaction which is not conducive to a good UI. - * - */ - Listener.digest = debounce(function () { - console.log('DIGESTING'); - for (var i = 0; i < scopes.length; i++) { - try { - scopes[i].$digest(); - } catch (err){ - console.log('WARN: Digest already in progerss'); - } - } - }, 100); - - return Listener; - - } //end listenerService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/objects/account/account.js b/portal_client/app/common/services/model/cache/objects/account/account.js deleted file mode 100644 index cbac5cb..0000000 --- a/portal_client/app/common/services/model/cache/objects/account/account.js +++ /dev/null @@ -1,91 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Defines an Account object, which defines the person who has - * authenticated with the server. - */ - angular.module('portal.common.services.model.cache') - .service('Account', accountService); - - function accountService(Map, Constants) { - - function Account(data) { - var account = this; - account.id = null; - account.authoritiesMap = new Map('id'); - account.username = ''; - account.password = ''; - account.lastName = ''; - account.firstName = ''; - account.auId = null; - account.email = ''; - account.role = ''; - account.expirationDate = ''; - account.effectiveDate = ''; - account.stompTopics = []; - account.permissions = {}; - account.enabled = false; - account.fromData = function (data) { - account.id = data.id; - account.authoritiesMap = new Map('id'); - account.username = data.username; - account.password = null; - account.lastName = data.lastName; - account.firstName = data.firstName; - account.auId = data.auId; - account.email = data.email; - account.role = data.role; - account.expirationDate = data.expirationDate; - account.effectiveDate = data.effectiveDate; - account.stompTopics = data.stompTopics; - account.permissions = data.permissions; - account.enabled = data.enabled; - if (angular.isArray(data.authorities)) { - for (var i = 0; i < data.authorities.length; i++) { - var authority = Account.Authorities.getTypeFromString(data.authorities[i]); - account.authoritiesMap.put(authority.id, authority); - } - } - }; - - if (angular.isDefined(data)) { - account.fromData(data); - } - - account.hasPermission = function(key) { - return account.authoritiesMap.containsKey(key); - }; - } - - /** - * Object defining a account authority - * @param {type} id - * @param {type} name - * @returns {Account.Authority} - */ - Account.Authority = function (id, name) { - var userType = this; - userType.id = id; - userType.name = name; - }; - Account.Authority.prototype.toString = function () { - return this.id; - }; - - /** - * Defines the statically typed account Authority as an enum (of sorts) - */ - Account.Authorities = { - getTypeFromString: function (typeAsString) { - return Account.Authorities[typeAsString]; - } - }; - - $.each(Constants.Permissions, function(key, value) { - Account.Authorities[key] = new Account.Authority(key, value.replace(/_/g, ' ')); - }); - - return Account; - } //end accountService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/objects/application-log/application-log.js b/portal_client/app/common/services/model/cache/objects/application-log/application-log.js deleted file mode 100644 index 0526a2b..0000000 --- a/portal_client/app/common/services/model/cache/objects/application-log/application-log.js +++ /dev/null @@ -1,40 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Defines an Account object, which defines the person who has - * authenticated with the server. - */ - angular.module('portal.common.services.model.cache') - .service('ApplicationLog', appLogService); - - function appLogService(Map) { - - function ApplicationLog(data) { - var appLog = this; - appLog.id = ''; - appLog.eventName = ''; - appLog.event = ''; - appLog.severity = ''; - appLog.ipAddress = ''; - appLog.timestamp = ''; - appLog.loggedBy = ''; - - appLog.fromData = function (data) { - appLog.id = data.id; - appLog.loggedBy = data.loggedBy; - appLog.eventName = data.eventName; - appLog.event = data.event; - appLog.severity = data.severity; - appLog.ipAddress = data.ipAddress; - appLog.timestamp = moment(data.timestamp); - }; - - if (angular.isDefined(data)) { - appLog.fromData(data); - } - } - - return ApplicationLog; - } //end appLogService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/objects/config/config.js b/portal_client/app/common/services/model/cache/objects/config/config.js deleted file mode 100644 index cb036fb..0000000 --- a/portal_client/app/common/services/model/cache/objects/config/config.js +++ /dev/null @@ -1,44 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Defines an Account object, which defines the person who has - * authenticated with the server. - */ - angular.module('portal.common.services.model.cache') - .service('Config', configService); - - function configService(Map) { - - function Config(data) { - var config = this; - config.filepath = ''; - config.dbUsername = ''; - config.dbPassword = ''; - config.dbRootUser = ''; - config.dbRootPassword = ''; - config.dbHost = ''; - config.dbPort = 0; - config.userExpirationDays = 0; - config.logLevel = ''; - - config.fromData = function (data) { - config.filepath = data.filepath; - config.dbUsername = data.dbUsername; - config.dbPassword = data.dbPassword; - config.dbRootUser = data.dbRootUser; - config.dbRootPassword = data.dbRootPassword; - config.dbHost = data.dbHost; - config.dbPort = parseInt(data.dbPort); - config.userExpirationDays = parseInt(data.userExpirationDays); - config.logLevel = data.logLevel; - }; - - if (angular.isDefined(data)) { - config.fromData(data); - } - } - - return Config; - } //end configService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/objects/credentials/credentials.js b/portal_client/app/common/services/model/cache/objects/credentials/credentials.js deleted file mode 100644 index 3651d70..0000000 --- a/portal_client/app/common/services/model/cache/objects/credentials/credentials.js +++ /dev/null @@ -1,39 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Defines an creds object - */ - angular.module('portal.common.services.model.cache') - .service('Credentials', credentialsService); - - function credentialsService(Map) { - - function Credentials(data) { - var creds = this; - creds.id = null; - creds.uid = ''; - creds.username = ''; - creds.password = ''; - creds.name = ''; - creds.credentialType = ''; - creds.key = ''; - creds.passphrase = ''; - - creds.fromData = function (data) { - creds.id = data.id; - creds.uid = data.uid; - creds.username = data.username; - creds.name = data.name; - creds.credentialType = data.credentialType; - creds.key = ''; - creds.passphrase = ''; - }; - - if (angular.isDefined(data)) { - creds.fromData(data); - } - } - return Credentials; - } //end credentialsService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/objects/drop-down-item/drop-down-item.js b/portal_client/app/common/services/model/cache/objects/drop-down-item/drop-down-item.js deleted file mode 100644 index f766a80..0000000 --- a/portal_client/app/common/services/model/cache/objects/drop-down-item/drop-down-item.js +++ /dev/null @@ -1,30 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Defines an creds object - */ - angular.module('portal.common.services.model.cache') - .service('DropDownItem', dropDownService); - - function dropDownService(Map) { - - function DropDownItem(data) { - var creds = this; - creds.id = null; - creds.name = ''; - creds.value = ''; - - creds.fromData = function (data) { - creds.id = data.id; - creds.name = data.name; - creds.value = data.value; - }; - - if (angular.isDefined(data)) { - creds.fromData(data); - } - } - return DropDownItem; - } //end dropDownService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/objects/email-tmpl/email-tmpl.js b/portal_client/app/common/services/model/cache/objects/email-tmpl/email-tmpl.js deleted file mode 100644 index 9109c94..0000000 --- a/portal_client/app/common/services/model/cache/objects/email-tmpl/email-tmpl.js +++ /dev/null @@ -1,40 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Defines an Account object, which defines the person who has - * authenticated with the server. - */ - angular.module('portal.common.services.model.cache') - .service('EmailTemplate', emailTmplService); - - function emailTmplService(Map, Account) { - - function EmailTemplate(data) { - var emailTmpl = this; - emailTmpl.id = null; - emailTmpl.emailName = ''; - emailTmpl.emailSubject = ''; - emailTmpl.emailMessage = ''; - emailTmpl.scriptId = ''; - emailTmpl.recipients = []; - emailTmpl.fromData = function (data) { - emailTmpl.id = data.id; - emailTmpl.emailName = data.emailName; - emailTmpl.emailSubject = data.emailSubject; - emailTmpl.emailMessage = data.emailMessage; - emailTmpl.scriptId = data.scriptId; - emailTmpl.recipients = []; - $.each(data.recipients, function(key, value){ - emailTmpl.recipients.push(new Account(value)); - }); - }; - - if (angular.isDefined(data)) { - emailTmpl.fromData(data); - } - } - - return EmailTemplate; - } //end emailTmplService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/objects/git-info/git-info.js b/portal_client/app/common/services/model/cache/objects/git-info/git-info.js deleted file mode 100644 index 83521b6..0000000 --- a/portal_client/app/common/services/model/cache/objects/git-info/git-info.js +++ /dev/null @@ -1,42 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Defines an creds object - */ - angular.module('portal.common.services.model.cache') - .service('GitInfo', gitInfoService); - - function gitInfoService(Map, Credentials) { - - function GitInfo(data) { - var gitInfo = this; - gitInfo.id = null; - gitInfo.name = ''; - gitInfo.scm = ''; - gitInfo.branch = ''; - gitInfo.directory = ''; - gitInfo.lastUpdated = null; - gitInfo.createDate = null; - gitInfo.createdBy = ''; - gitInfo.credentials = null; - - gitInfo.fromData = function (data) { - gitInfo.id = data.id; - gitInfo.name = data.name; - gitInfo.scm = data.scm; - gitInfo.branch = data.branch; - gitInfo.directory = data.directory; - gitInfo.credentials = new Credentials(data.credentials); - gitInfo.lastUpdated = data.lastUpdated; - gitInfo.createDate = data.createDate; - gitInfo.createdBy = data.createdBy; - }; - - if (angular.isDefined(data)) { - gitInfo.fromData(data); - } - } - return GitInfo; - } //end gitInfoService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/objects/hash-type/hash-type.js b/portal_client/app/common/services/model/cache/objects/hash-type/hash-type.js deleted file mode 100644 index eacfbff..0000000 --- a/portal_client/app/common/services/model/cache/objects/hash-type/hash-type.js +++ /dev/null @@ -1,28 +0,0 @@ -(function () { - 'use strict'; - angular.module('portal.common.services.model.cache') - .service('HashType', hashTypeService); - - - function hashTypeService(Map) { - - function HashType(data) { - var hash = this; - hash.id = null; - hash.name = ''; - hash.displayName = ''; - hash.valid = false; - hash.length = null; - - if (angular.isDefined(data)) { - hash.id = data.id; - hash.name = data.name; - hash.displayName = data.displayName; - hash.valid = data.valid === 'true' || data.valid === true; - hash.length = parseInt(data.length); - } - } - - return HashType; - } -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/objects/logger-info/logger-info.js b/portal_client/app/common/services/model/cache/objects/logger-info/logger-info.js deleted file mode 100644 index 8890542..0000000 --- a/portal_client/app/common/services/model/cache/objects/logger-info/logger-info.js +++ /dev/null @@ -1,30 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Defines an Account object, which defines the person who has - * authenticated with the server. - */ - angular.module('portal.common.services.model.cache') - .service('LoggerInfo', loggerService); - - function loggerService(Map) { - - function LoggerInfo(data) { - var info = this; - info.logger = ''; - info.level = ''; - - info.fromData = function (data) { - info.logger = data.logger; - info.level = data.level; - }; - - if (angular.isDefined(data)) { - info.fromData(data); - } - } - - return LoggerInfo; - } //end configService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/objects/permission-object/permission-object.js b/portal_client/app/common/services/model/cache/objects/permission-object/permission-object.js deleted file mode 100644 index 3fd12a9..0000000 --- a/portal_client/app/common/services/model/cache/objects/permission-object/permission-object.js +++ /dev/null @@ -1,85 +0,0 @@ -(function () { - 'use strict'; - - angular.module('portal.common.services.model.cache') - .service('permissionObjects', permissionService); - - function permissionService(Map) { - /* jshint validthis: true */ - var permissionObjects = this; - - this.PermissionGroup = function(data) { - this.id = null; - this.name = ''; - this.displayName = ''; - this.enabled = false; - this.permissions = []; - if (data) { - this.id = data.id; - this.name = data.name; - this.displayName = data.displayName; - this.enabled = data.enabled; - this.permissions = []; - if(data.permissions) { - for (var i = 0; i < data.permissions.length; i++) { - this.permissions.push(new permissionObjects.PermissionGroupPermission(data.permissions[i])); - } - } - } - }; - - this.PermissionGroupPermission = function(data) { - this.type = 'PermissionGroupPermission'; - this.id = null; - this.permissionId = null; - this.permissionGroupId = null; - this.name = ''; - this.displayName = ''; - this.permissionCategory = ''; - this.allowed = false; - if (data) { - this.type = 'PermissionGroupPermission'; - this.id = data.id; - this.permissionId = data.permissionId; - this.permissionGroupId = data.permissionGroupId; - this.name = data.name; - this.displayName = data.displayName; - this.permissionCategory = data.permissionCategory; - this.allowed = data.allowed; - } - }; - - this.PermissionCategory = function(data) { - this.id = null; - this.name = ''; - this.displayName = ''; - this.permissions = []; - if (data) { - this.id = data.id; - this.name = data.name; - this.displayName = data.displayName; - this.permissions = []; - if (data.permissions) { - for (var i = 0; i < data.permissions.length; i++) { - this.permissions.push(new permissionObjects.Permission(data.permissions[i])); - } - } - } - }; - - this.Permission = function(data) { - this.type = 'Permission'; - this.id = null; - this.name = ''; - this.displayName = ''; - this.permissionCategory = ''; - if (data) { - this.id = data.id; - this.name = data.name; - this.displayName = data.displayName; - this.permissionCategory = data.permissionCategory; - } - }; - - } //end permissionService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/objects/resource-file/resource-file.js b/portal_client/app/common/services/model/cache/objects/resource-file/resource-file.js deleted file mode 100644 index e6def85..0000000 --- a/portal_client/app/common/services/model/cache/objects/resource-file/resource-file.js +++ /dev/null @@ -1,33 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Defines an resource file object, - */ - angular.module('portal.common.services.model.cache') - .service('ResourceFile', resourceFileService); - - function resourceFileService(Map) { - - function ResourceFile(data) { - var resourceFile = this; - resourceFile.id = ''; - resourceFile.fileName = ''; - resourceFile.fileLocation = ''; - resourceFile.fileType = ''; - resourceFile.dateCreated = ''; - resourceFile.valid = false; - - if (angular.isDefined(data)) { - resourceFile.id = data.id; - resourceFile.fileName = data.fileName; - resourceFile.fileLocation = data.fileLocation; - resourceFile.fileType = data.fileType; - resourceFile.dateCreated = data.dateCreated; - resourceFile.valid = data.valid; - } - } - - return ResourceFile; - } //end patchFileService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/objects/script/script.js b/portal_client/app/common/services/model/cache/objects/script/script.js deleted file mode 100644 index af86388..0000000 --- a/portal_client/app/common/services/model/cache/objects/script/script.js +++ /dev/null @@ -1,207 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Defines an script object - */ - angular.module('portal.common.services.model.cache') - .service('scriptObjects', scriptService); - - function scriptService(Map, Credentials, ResourceFile, EmailTemplate) { - /* jshint validthis: true */ - var scriptObjects = this; - - scriptObjects.Script = function (data) { - var script = this; - script.id = null; - script.name = ''; - script.command = ''; - script.baseDirectory = ''; - script.outputDirectory = ''; - script.scriptType = ''; - script.parameters = []; - script.schedule = []; - script.scriptVariables = []; - script.scriptChain = []; - script.scriptEmails = []; - script.remote = null; - script.scp = null; - if (data) { - script.id = data.id; - script.name = data.name; - script.command = data.command; - script.baseDirectory = data.baseDirectory; - script.outputDirectory = data.outputDirectory; - script.scriptType = data.scriptType; - script.remote = new scriptObjects.ScriptRemote(data.remote); - script.scp = new scriptObjects.ScriptScp(data.scp); - script.parameters = []; - script.schedule = []; - script.scriptVariables = []; - script.scriptEmails = []; - - $.each(data.parameters, function(key, value) { - script.parameters.push(new scriptObjects.ScriptParameter(value)); - }); - - $.each(data.schedule, function(key, value) { - script.schedule.push(new scriptObjects.ScriptSchedule(value)); - }); - - $.each(data.scriptVariables, function(key, value) { - script.scriptVariables.push(new scriptObjects.ScriptEnvironmentVariable(value)); - }); - - $.each(data.scriptChain, function(key, value) { - script.scriptChain.push(new scriptObjects.ScriptChain(value)); - }); - - $.each(data.scriptEmails, function(key, value) { - script.scriptEmails.push(new EmailTemplate(value)); - }); - } - }; - - scriptObjects.ScriptSchedule = function(data) { - var schedule = this; - schedule.id = null; - schedule.jobId = ''; - schedule.startDatetime = moment().toDate(); - schedule.endDatetime = null; - schedule.frequency = null; - schedule.maxExecutions = null; - schedule.currentExecutionCount = null; - schedule.lastRun = null; - schedule.script = null; - schedule.executionStatus = null; - if (data) { - schedule.id = data.id; - schedule.jobId = data.jobId; - schedule.startDatetime = data.startDatetime; - schedule.endDatetime = data.endDatetime; - schedule.frequency = data.frequency; - schedule.maxExecutions = data.maxExecutions; - schedule.currentExecutionCount = data.currentExecutionCount; - schedule.lastRun = data.lastRun; - schedule.script = data.script; - schedule.executionStatus = data.executionStatus; - } - }; - - scriptObjects.ScriptParameter = function(data) { - var param = this; - param.id = null; - param.parameter = ''; - param.script = ''; - if (data) { - param.id = data.id; - param.parameter = data.parameter; - param.script = data.script; - } - }; - - scriptObjects.ScriptChain = function(data) { - var chain = this; - chain.id = null; - chain.parentScript = undefined; - chain.childScript = undefined; - chain.executeAfterMin = undefined; - chain.exitStatus = undefined; - if (data) { - chain.id = data.id; - chain.parentScript = data.parentScript; - chain.childScript = data.childScript; - chain.executeAfterMin = data.executeAfterMin; - chain.exitStatus = data.exitStatus; - } - }; - - scriptObjects.ScriptEnvironmentVariable = function(data) { - var envVar = this; - envVar.id = null; - envVar.name = ''; - envVar.value = ''; - envVar.createdBy = null; - envVar.script = null; - envVar.lastUpdated = ''; - envVar.dateCreated = ''; - envVar.isNew = true; - if (data) { - envVar.id = data.id; - envVar.name = data.name; - envVar.value = data.value; - envVar.createdBy = data.createdBy; - envVar.script = data.script; - envVar.lastUpdated = data.lastUpdated; - envVar.dateCreated = data.dateCreated; - envVar.isNew = false; - } - }; - - scriptObjects.ScriptStatus = function(data) { - var status = this; - status.id = undefined; - status.exitStatus = undefined; - status.results = ''; - status.startTime = undefined; - status.endTime = undefined; - status.resourceFiles = []; - if (data) { - status.id = data.id; - status.exitStatus = data.exitStatus; - status.results = data.results; - status.startTime = data.startTime; - status.endTime = data.endTime; - if (data.resourceFiles) { - $.each(data.resourceFiles, function(key, value) { - status.resourceFiles.push(new ResourceFile(value)); - }); - } - } - }; - - scriptObjects.ScriptRemote = function(data) { - var remote = this; - remote.scriptId = undefined; - remote.scriptCredentials = null; - remote.url = undefined; - remote.port = undefined; - if (data) { - remote.scriptId = data.scriptId; - remote.url = data.url; - remote.port = data.port; - if (data.scriptCredentials) { - remote.scriptCredentials = new Credentials(data.scriptCredentials); - } - } - }; - - scriptObjects.ScriptScp = function(data) { - var scp = this; - scp.id = undefined; - scp.scriptId = undefined; - scp.fromHost = ''; - scp.fromPort = 0; - scp.toHost = ''; - scp.toPort = 0; - scp.dataRegex = ''; - scp.toCredentials = undefined; - scp.fromCredentials = undefined; - if (data) { - scp.id = data.id; - scp.scriptId = data.scriptId; - scp.fromHost = data.fromHost; - scp.fromPort = data.fromPort; - scp.toHost = data.toHost; - scp.toPort = data.toPort; - scp.dataRegex = data.dataRegex; - if (data.toCredentials) { - scp.toCredentials = new Credentials(data.toCredentials); - } - if (data.fromCredentials) { - scp.fromCredentials = new Credentials(data.fromCredentials); - } - } - }; - } //end scriptService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/objects/upload-file/upload-file.js b/portal_client/app/common/services/model/cache/objects/upload-file/upload-file.js deleted file mode 100644 index 2765226..0000000 --- a/portal_client/app/common/services/model/cache/objects/upload-file/upload-file.js +++ /dev/null @@ -1,75 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: - */ - angular.module('portal.common.services.model.cache') - .service('UploadFile', uploadFileService); - - function uploadFileService() { - - function UploadFile() { - var file = this; - file.name = ''; - file.fileSize = null; - file.guid = ''; - file.url = ''; - file.rawFile = null; - file.uploadProgress = 0; - file.percentComplete = 0; - file.uploaded = null; - file.reason = ''; - file.trackUploadProcessing = false; - file.uploadMax = 0; - - file.init = function (rawFile, trackUploadProcessing) { - file.trackUploadProcessing = trackUploadProcessing; - file.rawFile = rawFile; - file.name = rawFile.name; - file.fileSize = rawFile.size; - // The file.uploadMax represents when the file upload is complete. If tracking upload - // processing, the server sends percent complete values as triggers periodically so the max is 100 (%). - // Otherwise, just track the uploaded byte progress so the max is the file size. - file.uploadMax = trackUploadProcessing ? 100 : file.fileSize; - file.type = rawFile.type; - return file; - }; - file.uploaded = function (data, baseURI) { - file.uploaded = true; - baseURI = baseURI === undefined ? '' : baseURI; - if (data !== undefined) { - file.name = data.original_name; //jshint ignore:line - file.fileSize = data.file_size; //jshint ignore:line - file.guid = data.guid; - file.url = baseURI + data.guid; - file.uploadProgress = file.fileSize; - } - return file; - }; - file.setUploadProgress = function (uploadProgress) { - file.uploadProgress = uploadProgress; - file.percentComplete = Math.min(Math.floor((file.uploadProgress / file.fileSize) * 100), 100); - }; - file.uploadFailed = function (reason) { - file.uploaded = false; - file.reason = reason; - if (reason === undefined) { - file.reason = 'unknown failure'; - } - }; - file.finished = function () { - return file.uploaded === true ? true : false; - }; - file.inProgress = function () { - return file.upload === null; - }; - file.failed = function () { - return file.uploaded === false ? true : false; - }; - } - - return UploadFile; - - } //end uploadFileService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/store/store.js b/portal_client/app/common/services/model/cache/store/store.js deleted file mode 100644 index 21625c3..0000000 --- a/portal_client/app/common/services/model/cache/store/store.js +++ /dev/null @@ -1,137 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Defines a store, or access point to get data out of the cache and from an external source. - */ - angular.module('portal.common.services.model.cache') - .service('Store', storeService); - - function storeService($timeout, Box) { - - var cache = null; - - /** - * Store defines the information required to access data from the cache (id) and - * pull it from an external source if it hasn't been pulled. - * @param {type} args {id: '', source: function} - * @returns {store_L35.storeService.Store} - */ - function Store(args) { - var store = this; - - /**Attach the args and a few for convenience directly to the Store (below). */ - store.args = args; - /** - * Unique ID for this store, this will be the . accessor on the mini cache. - */ - store.id = args.id; - /** - * A function with registerable callback that provides the data. - */ - store.source = args.source; - /** - * Empty params object, used in conjunction with Id to generate unique key for store. - * Passed in to the source as the args. - * @type Number|Number - */ - store.params = args.params; - /** - * Key used for accessing data from the cache. - */ - store.key = getKey(); - /** - * Reference to the box accessed by the key. - */ - store.box = cache.get(store.key); - /** - * Listeners for this store to unsubscribe. - */ - store.boxListener = null; - /** - * Registers a callback to be notified of data changes. If the data has not been initialized it is - * initialized, once and only once. Subsequent data changes - * @param {type} callback - * @returns {unresolved} - */ - store.init = function () { - store.boxListener = store.box.init(); - return store.boxListener; - }; - - /** - * Forces a refresh from source. - * @returns {undefined} - */ - store.refresh = function () { - var box = store.getBox(); - return box.refresh(); - }; - - /** - * Updates store on the cache, and notifies listeners. - * Could be called to update data on trigger. - * @param {type} data - * @returns {undefined} - */ - store.update = function (data) { - store.getBox().update(data); - }; - - /** - * @returns {Boolean} True if ready, false if pending or not initialized. - */ - store.isReady = function () { - return store.getBox().isDone(); - }; - - store.getBox = function () { - return store.box; - }; - - store.unlisten = function () { - if (store.boxListener !== null) { - store.boxListener.unlisten(); - } - }; - - store.getParams = function () { - return store.params; - }; - - function getKey() { - var key = store.id; - for (var i in store.params) { - key += '_' + i + '_' + store.params[i]; - } - /** - * Init box if doesn't already exist. - * Box persists between instnaces. - */ - if (!angular.isDefined(cache.get(key))) { - cache.put(key, new Box(args)); - } - return key; - } - - } - - /** - * Static function for registering the cache. - * @param {type} _cache - * @returns {undefined} - */ - Store.registerCache = function (_cache) { - cache = _cache; - }; - - Store.notifyStores = function(stores) { - for (var i in stores) { - stores[i].getBox().notify(); - } - }; - - return Store; - - } //end storeService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/stores/account-stores/account-stores.js b/portal_client/app/common/services/model/cache/stores/account-stores/account-stores.js deleted file mode 100644 index fae8129..0000000 --- a/portal_client/app/common/services/model/cache/stores/account-stores/account-stores.js +++ /dev/null @@ -1,60 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Stores for account. - */ - angular.module('portal.common.services.model.cache') - .service('accountStores', accountStoresService); - - function accountStoresService(stores, Store, Account, accountProvider, triggerManager, Triggers, Map) { - - var accountStores = { - Account: stores.inherit('account', function () { - Store.call(this, { - id: 'account', - source: accountProvider.isLoggedIn, - processGui: function (data) { - var act = new Account(data); - triggerManager.subscribe(act.stompTopics); - return act; - }}); - }), - UserPool: stores.inherit('userPool', function(){ - Store.call(this, { - id: 'userPool', - source: accountProvider.getAllUsers, - processGui: function(data) { - return Map.create(data, Account, 'id'); - } - }); - }), - }; - - Triggers.listen([Triggers.USER_ADDED], function(trigger, payload){ - var data = payload.resources; - var users = new accountStores.UserPool(); - if (users.isReady()) { - for (var i = 0; i < data.length; i++) { - var user = new Account(data[i]); - users.getBox().data.put(user.id, user); - } - users.getBox().notify(); - } - }); - - Triggers.listen([Triggers.USER_DELETED], function(trigger, payload){ - var data = payload.resources; - var users = new accountStores.UserPool(); - if (users.isReady()) { - for (var i = 0; i < data.length; i++) { - var user = new Account(data[i]); - users.getBox().data.removeByKey(user.id, user); - } - users.getBox().notify(); - } - }); - - return accountStores; - } //end accountStoresService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/stores/application-log-stores/application-log-stores.js b/portal_client/app/common/services/model/cache/stores/application-log-stores/application-log-stores.js deleted file mode 100644 index b9d4b2f..0000000 --- a/portal_client/app/common/services/model/cache/stores/application-log-stores/application-log-stores.js +++ /dev/null @@ -1,33 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Stores for account. - */ - angular.module('portal.common.services.model.cache') - .service('appLogStores', appLogStoresService); - - function appLogStoresService(stores, Store, ApplicationLog, appLogProvider, Map, Triggers) { - - var appLogStores = { - Logs: stores.inherit('logs', function(){ - Store.call(this, { - id: 'logs', - source: appLogProvider.getAllLogs, - processGui: function(data) { - return Map.create(data, ApplicationLog, 'id'); - } - }); - }), - }; - Triggers.listen([Triggers.APP_LOGS_UPDATED, Triggers.APP_LOGS_PURGED], function(trigger, payload){ - var data = payload.resources; - var logs = new appLogStores.Logs(); - if (logs.isReady()) { - logs.getBox().refresh(); - } - }); - - return appLogStores; - } //end accountStoresService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/stores/config-stores/config-stores.js b/portal_client/app/common/services/model/cache/stores/config-stores/config-stores.js deleted file mode 100644 index 999b9d4..0000000 --- a/portal_client/app/common/services/model/cache/stores/config-stores/config-stores.js +++ /dev/null @@ -1,35 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Stores for account. - */ - angular.module('portal.common.services.model.cache') - .service('configStores', configStoresService); - - function configStoresService(stores, Store, Config, configProvider, Map) { - - var copnfigStores = { - Configs: stores.inherit('configs', function () { - Store.call(this, { - id: 'configs', - source: configProvider.getConfiguration, - processGui: function (data) { - var act = new Config(data); - return act; - }}); - }), - Config: stores.inherit('config', function (configKey) { - Store.call(this, { - id: 'config', - source: configProvider.getConfigurationValue, - params: configKey, - processGui: function (data) { - var conf = new Config(data); - return conf; - }}); - }), - }; - return copnfigStores; - } //end configStoresService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/stores/credential-stores/credential-stores.js b/portal_client/app/common/services/model/cache/stores/credential-stores/credential-stores.js deleted file mode 100644 index bfed746..0000000 --- a/portal_client/app/common/services/model/cache/stores/credential-stores/credential-stores.js +++ /dev/null @@ -1,34 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Stores for account. - */ - angular.module('portal.common.services.model.cache') - .service('credentialStores', credentialStoresService); - - function credentialStoresService(stores, Store, Credentials, credentialProvider, Map, DropDownItem) { - - var credentialsStores = { - Credentials: stores.inherit('credentials', function () { - Store.call(this, { - id: 'credentials', - source: credentialProvider.getCredentials, - processGui: function (data) { - var map = Map.create(data, Credentials, 'uid'); - return map; - }}); - }), - CredentialTypes: stores.inherit('credentialTypes', function(){ - Store.call(this, { - id: 'credentialTypes', - source: credentialProvider.getCredentialTypes, - processGui: function(data) { - return Map.create(data, DropDownItem, 'id'); - } - }); - }), - }; - return credentialsStores; - } //end credentialsStoresService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/stores/git-stores/git-stores.js b/portal_client/app/common/services/model/cache/stores/git-stores/git-stores.js deleted file mode 100644 index f0f7d7e..0000000 --- a/portal_client/app/common/services/model/cache/stores/git-stores/git-stores.js +++ /dev/null @@ -1,25 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Stores for account. - */ - angular.module('portal.common.services.model.cache') - .service('gitStores', gitStoresService); - - function gitStoresService(stores, Store, GitInfo, gitProvider, Map) { - - var gitStores = { - Repos: stores.inherit('repos', function () { - Store.call(this, { - id: 'repos', - source: gitProvider.getAllRepos, - processGui: function (data) { - var map = Map.create(data, GitInfo, 'id'); - return map; - }}); - }), - }; - return gitStores; - } //end gitStoresService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/stores/logger-stores/logger-stores.js b/portal_client/app/common/services/model/cache/stores/logger-stores/logger-stores.js deleted file mode 100644 index 56f1a1d..0000000 --- a/portal_client/app/common/services/model/cache/stores/logger-stores/logger-stores.js +++ /dev/null @@ -1,26 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Stores for account. - */ - angular.module('portal.common.services.model.cache') - .service('loggerStores', loggerStoreService); - - function loggerStoreService(stores, Store, LoggerInfo, loggerProvider, Map) { - - var loggerStores = { - Loggers: stores.inherit('loggers', function(){ - Store.call(this, { - id: 'loggers', - source: loggerProvider.getLoggers, - processGui: function(data) { - return Map.create(data, LoggerInfo, 'logger'); - } - }); - }) - }; - - return loggerStores; - } //end loggerStopresService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/stores/permission-stores/permission-stores.js b/portal_client/app/common/services/model/cache/stores/permission-stores/permission-stores.js deleted file mode 100644 index f1cbfab..0000000 --- a/portal_client/app/common/services/model/cache/stores/permission-stores/permission-stores.js +++ /dev/null @@ -1,65 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Stores for account. - */ - angular.module('portal.common.services.model.cache') - .service('permissionStores', permissionStoresService); - - function permissionStoresService(stores, Store, permissionObjects, permissionProvider, triggerManager, Triggers, Map) { - - var permissionStores = { - PermissionGroups: stores.inherit('permissionGroups', function () { - Store.call(this, { - id: 'permissionGroups', - source: permissionProvider.getPermissionGroups, - processGui: function (data) { - return Map.create(data, permissionObjects.PermissionGroup, 'id'); - }}); - }), - AllPermissionGroups: stores.inherit('allPermissionGroups', function () { - Store.call(this, { - id: 'allPermissionGroups', - source: permissionProvider.getAllPermissionGroups, - processGui: function (data) { - return Map.create(data, permissionObjects.PermissionGroup, 'id'); - }}); - }), - PermissionCategories: stores.inherit('permissionCategories', function () { - Store.call(this, { - id: 'permissionCategories', - source: permissionProvider.getPermissionCategories, - processGui: function (data) { - return Map.create(data, permissionObjects.PermissionCategory, 'id'); - }}); - }) - }; - - Triggers.listen([Triggers.PERMISSIONS_CHANGED, Triggers.PERMISSIONS_ADDED, Triggers.PERMISSIONS_UPDATED], function(trigger, payload){ - var data = payload.resources; - var permGroups = new permissionStores.PermissionGroups(); - if (permGroups.isReady()) { - for (var i = 0; i < data.length; i++) { - var permGroup = new permissionObjects.PermissionGroup(data[i]); - permGroups.getBox().data.put(permGroup.id, permGroup); - } - permGroups.getBox().notify(); - } - }); - - Triggers.listen([Triggers.PERMISSIONS_DELETED], function(trigger, payload){ - var data = payload.resources; - var permGroups = new permissionStores.PermissionGroups(); - if (permGroups.isReady()) { - for (var i = 0; i < data.length; i++) { - var permGroup = new permissionObjects.PermissionGroup(data[i]); - permGroups.getBox().data.removeByKey(permGroup.id, permGroup); - } - permGroups.getBox().notify(); - } - }); - - return permissionStores; - } //end permissionStoresService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/stores/resource-file-stores/resource-file-stores.js b/portal_client/app/common/services/model/cache/stores/resource-file-stores/resource-file-stores.js deleted file mode 100644 index 8dbc7a5..0000000 --- a/portal_client/app/common/services/model/cache/stores/resource-file-stores/resource-file-stores.js +++ /dev/null @@ -1,33 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Stores for resource file. - */ - angular.module('portal.common.services.model.cache') - .service('resourceFileStores', resourceFileStoresService); - - function resourceFileStoresService(stores, Store, ResourceFile, fileProvider, Map) { - - var resourceFileStores = { - PatchFiles: stores.inherit('patchFiles', function (args) { - Store.call(this, { - id: 'patchFiles', - source: fileProvider.getAllFiles, - processGui: function (data) { - return Map.create(data, ResourceFile, 'id'); - }}); - }), - Directories: stores.inherit('patchDirectories', function () { - Store.call(this, { - id: 'patchDirectories', - source: fileProvider.getDirectories, - processGui: function (data) { - return data; - }}); - }), - }; - - return resourceFileStores; - } //end patchFileStoresService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/stores/script-stores/script-stores.js b/portal_client/app/common/services/model/cache/stores/script-stores/script-stores.js deleted file mode 100644 index 54ea351..0000000 --- a/portal_client/app/common/services/model/cache/stores/script-stores/script-stores.js +++ /dev/null @@ -1,130 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Stores for account. - */ - angular.module('portal.common.services.model.cache') - .service('scriptStores', scriptStoresService); - - function scriptStoresService(stores, Store, scriptObjects, scriptProvider, DropDownItem, Map, Triggers, portalUtils) { - - var scriptStores = { - Scripts: stores.inherit('scripts', function(){ - Store.call(this, { - id: 'scripts', - source: scriptProvider.getAllScripts, - processGui: function(data) { - return Map.create(data, scriptObjects.Script, 'id'); - } - }); - }), - ScriptTypes: stores.inherit('scriptTypes', function(){ - Store.call(this, { - id: 'scriptTypes', - source: scriptProvider.getScriptType, - processGui: function(data) { - return Map.create(data, DropDownItem, 'id'); - } - }); - }), - ScheduleFrequencies: stores.inherit('scheduleFrequencies', function(){ - Store.call(this, { - id: 'scheduleFrequencies', - source: scriptProvider.getScheduleFrequencies, - processGui: function(data) { - return Map.create(data, DropDownItem, 'id'); - } - }); - }), - ScriptStatus: stores.inherit('scriptStatus', function(jobId){ - Store.call(this, { - id: 'scriptStatus', - source: scriptProvider.getScriptStatus, - params: jobId, - processGui: function(data) { - return Map.create(data, scriptObjects.ScriptStatus, 'id'); - } - }); - }) - }; - - Triggers.listen([Triggers.SCRIPT_ADDED, Triggers.SCRIPT_UPDATED], function(trigger, payload){ - var data = payload.resources; - var scripts = new scriptStores.Scripts(); - if (scripts.isReady()) { - for (var i = 0; i < data.length; i++) { - var script = new scriptObjects.Script(data[i]); - scripts.getBox().data.put(script.id, script); - } - scripts.getBox().notify(); - } - }); - - Triggers.listen([Triggers.SCRIPT_DELETED], function(trigger, payload){ - var data = payload.resources; - var scripts = new scriptStores.Scripts(); - if (scripts.isReady()) { - for (var i = 0; i < data.length; i++) { - var script = new scriptObjects.Script(data[i]); - scripts.getBox().data.removeByKey(script.id, script); - } - scripts.getBox().notify(); - } - }); - - Triggers.listen([Triggers.SCRIPT_SCHEDULE_DELETED], function(trigger, payload){ - var data = payload.resources; - var scripts = new scriptStores.Scripts(); - var schedule = new scriptObjects.ScriptSchedule(data[0]); - if (scripts.isReady()) { - var scriptBox = scripts.getBox().data.values; - for (var i = 0; i < scriptBox.length; i++) { - if(schedule.script === scriptBox[i].id) { - for (var j = 0; j < scriptBox[i].schedule.length; j++) { - if (schedule.jobId === scriptBox[i].schedule[j].jobId) { - scriptBox[i].schedule.splice(j, 1); - break; - } - } - break; - } - } - scripts.getBox().notify(); - } - }); - - Triggers.listen([Triggers.SCRIPT_COMPLETED], function(trigger, payload) { - if (!payload.resources) { - return; - } - - var data = payload.resources; - var scripts = new scriptStores.Scripts(); - var script = new scriptObjects.Script(data[1]); - if (scripts.isReady()) { - var scriptsBox = scripts.getBox().data.values; - for (var x = 0; x < scriptsBox.length; x++) { - if (scriptsBox[x].id === script.id) { - scriptsBox[x].schedule = script.schedule; - } - } - scripts.getBox().notify(); - } - - var scriptName = script.name; - var jobId = data[0]; - var statusStr = 'Failed'; - for (var j = 0; j < script.schedule.length; j++) { - var sched = script.schedule[j]; - if (sched.jobId === jobId && sched.executionStatus === 0) { - statusStr = 'Success'; - break; - } - } - portalUtils.toast('Script ' + scriptName +' completed with status of ' + statusStr, ['top', 'left'], 2000); - }); - - return scriptStores; - } //end scriptStoresService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/stores/stores.js b/portal_client/app/common/services/model/cache/stores/stores.js deleted file mode 100644 index 8a89430..0000000 --- a/portal_client/app/common/services/model/cache/stores/stores.js +++ /dev/null @@ -1,27 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Provides accessors to the cache(cacheService) getting data if - * it doesn't exist, providing promises to the data, and notification when - * the data changes. - * - */ - angular.module('portal.common.services.model.cache') - .service('stores', storesService); - - function storesService(Store, $log, portalUtils) { - var stores = {}; - return { - inherit: function (id, ChildStore) { - if (angular.isDefined(stores[id])) { - $log.error('Duplicate store with id - ' + id); - } else { - stores[id] = portalUtils.inherit(ChildStore, Store); - return stores[id]; - } - } - }; - - } //end storesService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/cache/stores/system-stores/system-stores.js b/portal_client/app/common/services/model/cache/stores/system-stores/system-stores.js deleted file mode 100644 index 0aafc68..0000000 --- a/portal_client/app/common/services/model/cache/stores/system-stores/system-stores.js +++ /dev/null @@ -1,92 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Stores for account. - */ - angular.module('portal.common.services.model.cache') - .service('systemStores', systemStoresService); - - function systemStoresService(stores, Store, scriptObjects, systemProvider, Map, EmailTemplate, Triggers) { - - var systemStores = { - EnvironmentVariables: stores.inherit('envvars', function(){ - Store.call(this, { - id: 'envvars', - source: systemProvider.getAllEnvVars, - processGui: function(data) { - return Map.create(data, scriptObjects.ScriptEnvironmentVariable, 'id'); - } - }); - }), - SMTPConfig: stores.inherit('smtpConfig', function(){ - Store.call(this, { - id: 'smtpConfig', - source: systemProvider.getSmtpConfig, - processGui: function(data) { - return Map.create(data, scriptObjects.ScriptEnvironmentVariable, 'id'); - } - }); - }), - EmailTemplates: stores.inherit('emailTmpls', function(){ - Store.call(this, { - id: 'emailTmpls', - source: systemProvider.getEmailTemplates, - processGui: function(data) { - return Map.create(data, EmailTemplate, 'id'); - } - }); - }), - }; - - Triggers.listen([Triggers.EMAIL_TEMPLATE_UPDATED], function(trigger, payload){ - var data = payload.resources; - var tmpls = new systemStores.EmailTemplates(); - if (tmpls.isReady()) { - for (var i = 0; i < data.length; i++) { - var tmpl = new EmailTemplate(data[i]); - tmpls.getBox().data.put(tmpl.id, tmpl); - } - tmpls.getBox().notify(); - } - }); - - Triggers.listen([Triggers.EMAIL_TEMPLATE_DELETED], function(trigger, payload){ - var data = payload.resources; - var tmpls = new systemStores.EmailTemplates(); - if (tmpls.isReady()) { - for (var i = 0; i < data.length; i++) { - var tmpl = new EmailTemplate(data[i]); - tmpls.getBox().data.removeByKey(tmpl.id, tmpl); - } - tmpls.getBox().notify(); - } - }); - - Triggers.listen([Triggers.ENV_VARS_ADDED], function(trigger, payload){ - var data = payload.resources; - var envvars = new systemStores.EnvironmentVariables(); - if (envvars.isReady()) { - for (var i = 0; i < data.length; i++) { - var envvar = new scriptObjects.ScriptEnvironmentVariable(data[i]); - envvars.getBox().data.put(envvar.id, envvar); - } - envvars.getBox().notify(); - } - }); - - Triggers.listen([Triggers.ENV_VARS_DELETED], function(trigger, payload){ - var data = payload.resources; - var envvars = new systemStores.EnvironmentVariables(); - if (envvars.isReady()) { - for (var i = 0; i < data.length; i++) { - var envvar = new scriptObjects.ScriptEnvironmentVariable(data[i]); - envvars.getBox().data.removeByKey(envvar.id, envvar); - } - envvars.getBox().notify(); - } - }); - - return systemStores; - } //end systemStoresService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/rest/account-provider/account-provider.js b/portal_client/app/common/services/model/rest/account-provider/account-provider.js deleted file mode 100644 index 72fe0db..0000000 --- a/portal_client/app/common/services/model/rest/account-provider/account-provider.js +++ /dev/null @@ -1,76 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Defines the restful calls for the account server module. - */ - angular.module('portal.common.services.model.rest') - .factory('accountProvider', accountProviderService); - - function accountProviderService(rest, Account) { - var baseUrl = '/account'; - return { - isLoggedIn: function () { - return rest.get({ - id: baseUrl + '/isLoggedIn.do', - convert: function (data) { - return new Account(data); - } - }); - }, - getAllUsers: function() { - return rest.get({ - id: baseUrl + '/getAll.do', - }); - }, - /** - * Login. - * @param {type} args password, username - * @returns {undefined} - */ - login: function (username, password) { - return rest.put({ - id: baseUrl + '/login.do', - block: true, - data: {username: username, password: password} - }); - }, - /** - * Logout. - * @param {type} - * @returns {undefined} - */ - logout: function () { - return rest.put({ - id: baseUrl + '/logout.do' - }); - }, - addUser: function(user) { - return rest.put({ - id: baseUrl + '/addUser.do', - data: user - }); - }, - deleteUser: function(user) { - return rest.put({ - id: baseUrl + '/deleteUser.do', - data: user - }); - }, - getRoleData: function(data) { - return rest.put({ - id: baseUrl + '/getRoleData.do', - data: {type: data} - }); - }, - getUserInfo: function(args) { - return rest.get({ - id: baseUrl + '/getUserInfo.do', - data: args, - cache: false - }); - } - }; - - } //end accountProviderService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/rest/application-log-provider/application-log-provider.js b/portal_client/app/common/services/model/rest/application-log-provider/application-log-provider.js deleted file mode 100644 index ef6cb9e..0000000 --- a/portal_client/app/common/services/model/rest/application-log-provider/application-log-provider.js +++ /dev/null @@ -1,26 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Defines the restful calls for the account server module. - */ - angular.module('portal.common.services.model.rest') - .factory('appLogProvider', appLogProviderService); - - function appLogProviderService(rest) { - var baseUrl = '/logs'; - return { - getAllLogs: function () { - return rest.get({ - id: baseUrl + '/getAll.do', - }); - }, - purgeLogs: function(date) { - return rest.post({ - id: baseUrl + '/purge.do', - data: date - }); - } - }; - } //end configProviderService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/rest/config-provider/config-provider.js b/portal_client/app/common/services/model/rest/config-provider/config-provider.js deleted file mode 100644 index b33fa09..0000000 --- a/portal_client/app/common/services/model/rest/config-provider/config-provider.js +++ /dev/null @@ -1,33 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Defines the restful calls for the account server module. - */ - angular.module('portal.common.services.model.rest') - .factory('configProvider', configProviderService); - - function configProviderService(rest, Config) { - var baseUrl = '/config'; - return { - getConfiguration: function () { - return rest.get({ - id: baseUrl + '/getConfiguration.do', - }); - }, - getConfigurationValue: function (value) { - return rest.get({ - id: baseUrl + '/getConfigurationValue.do', - data: value - }); - }, - saveConfiguration: function(config) { - return rest.put({ - id: baseUrl + '/saveConfiguration.do', - data:config - }); - } - }; - - } //end configProviderService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/rest/credential-provider/credential-provider.js b/portal_client/app/common/services/model/rest/credential-provider/credential-provider.js deleted file mode 100644 index 39e4b43..0000000 --- a/portal_client/app/common/services/model/rest/credential-provider/credential-provider.js +++ /dev/null @@ -1,38 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Defines the restful calls for the account server module. - */ - angular.module('portal.common.services.model.rest') - .factory('credentialProvider', credentialProviderService); - - function credentialProviderService(rest, Credentials) { - var baseUrl = '/creds'; - return { - addCredentials: function (args) { - return rest.put({ - id: baseUrl + '/add.do', - data: args, - }); - }, - getCredentials : function() { - return rest.get({ - id: baseUrl + '/get.do' - }); - }, - deleteCredentials: function(entity) { - return rest.put({ - id: baseUrl + '/delete.do', - data: entity - }); - }, - getCredentialTypes: function() { - return rest.get({ - id: baseUrl + '/getCredentialTypes.do' - }); - } - }; - - } //end accountProviderService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/rest/file-provider/file-provider.js b/portal_client/app/common/services/model/rest/file-provider/file-provider.js deleted file mode 100644 index fdedeea..0000000 --- a/portal_client/app/common/services/model/rest/file-provider/file-provider.js +++ /dev/null @@ -1,22 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Defines the restful calls for the file server module. - */ - angular.module('portal.common.services.model.rest') - .factory('fileProvider', fileProviderService); - - function fileProviderService(rest) { - var baseUrl = '/file'; - return { - deleteFile: function(resourceFile) { - return rest.put({ - id: baseUrl + '/delete.do', - data: resourceFile - }); - } - }; - - } //end fileProviderService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/rest/git-provider/git-provider.js b/portal_client/app/common/services/model/rest/git-provider/git-provider.js deleted file mode 100644 index ff360bf..0000000 --- a/portal_client/app/common/services/model/rest/git-provider/git-provider.js +++ /dev/null @@ -1,39 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Defines the restful calls for the git server module. - */ - angular.module('portal.common.services.model.rest') - .factory('gitProvider', gitProviderService); - - function gitProviderService(rest, GitInfo) { - var baseUrl = '/git'; - return { - addGitRepo: function(gitInfo) { - return rest.put({ - id: baseUrl + '/add.do', - data: gitInfo - }); - }, - getAllRepos : function() { - return rest.get({ - id: baseUrl + '/getAll.do' - }); - }, - deleteRepo: function(entity) { - return rest.put({ - id: baseUrl + '/delete.do', - data: entity - }); - }, - pullRepo: function(entity) { - return rest.put({ - id: baseUrl + '/pull.do', - data: entity - }); - } - }; - - } //end gitProviderService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/rest/logger-provider/logger-provider.js b/portal_client/app/common/services/model/rest/logger-provider/logger-provider.js deleted file mode 100644 index b4e5a6d..0000000 --- a/portal_client/app/common/services/model/rest/logger-provider/logger-provider.js +++ /dev/null @@ -1,27 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Defines the restful calls for the logger provider server module. - */ - angular.module('portal.common.services.model.rest') - .factory('loggerProvider', loggerProviderSerice); - - function loggerProviderSerice(rest, Config) { - var baseUrl = '/logger'; - return { - getLoggers: function () { - return rest.get({ - id: baseUrl + '/getLoggers.do', - }); - }, - setLoggers: function(loggers) { - return rest.put({ - id: baseUrl + '/setLoggers.do', - data: loggers - }); - } - }; - - } //end loggerProviderSerice function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/rest/permission-provider/permission-provider.js b/portal_client/app/common/services/model/rest/permission-provider/permission-provider.js deleted file mode 100644 index 395377d..0000000 --- a/portal_client/app/common/services/model/rest/permission-provider/permission-provider.js +++ /dev/null @@ -1,42 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Defines the restful calls for the permissions server module. - */ - angular.module('portal.common.services.model.rest') - .factory('permissionProvider', permissionProviderService); - - function permissionProviderService(rest) { - var baseUrl = '/permissions'; - return { - getPermissionGroups: function () { - return rest.get({ - id: baseUrl + '/getPermissionGroups.do', - }); - }, - getAllPermissionGroups: function () { - return rest.get({ - id: baseUrl + '/getAll.do', - }); - }, - getPermissionCategories: function () { - return rest.get({ - id: baseUrl + '/getPermissionCategories.do', - }); - }, - updatePermissions: function (isNew, args) { - return rest.put({ - id: baseUrl + (isNew ? '/addPermssionCategory.do' : '/updatePermissionCategory.do'), - data: args - }); - }, - deletePermissionGroup: function (args) { - return rest.put({ - id: baseUrl + '/deletePermissionGroup.do', - data: args - }); - } - }; - } //end permissionProviderService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/rest/request/request.js b/portal_client/app/common/services/model/rest/request/request.js deleted file mode 100644 index 6ff2eea..0000000 --- a/portal_client/app/common/services/model/rest/request/request.js +++ /dev/null @@ -1,177 +0,0 @@ -(function () { - 'use strict'; - - - /** - * DESCRIPTION: Describes a server rest request. - * Defines the promise where data is returned. - */ - angular.module('portal.common.services.model.rest') - .factory('Request', requestService); - - function requestService($http, $q, $rootScope, $window) { - /** - * Request Object and promise. - * @param {type} requestData {id, params, data} - */ - function Request(args) { - var request = this; - var deferred = $q.defer(); - request.id = args.id; - request.params = args.params; - request.data = args.data; - request.process = args.process; - request.cache = args.cache ? true : false; - request.payload = null; - request.block = args.block; - - function apply() { - if (request.block) { - $rootScope.loadingBlock = true; - } - //angular.toJson(request.data); - $http({ - method: 'POST', - url: Request.baseURI + request.id, - params: request.params, - headers: {'Content-Type': Request.jsonContentType, 'dataType': Request.jsonDataType}, - data: request.data, - cache: request.cache - }).then(onSuccess, onError).catch(onError); - return deferred.promise; - } - - /** - * Handler for the $http request. - * @param {type} returnData - * @returns {undefined} - */ - function onSuccess(returnData, status, header, config) { - if (returnData.data) { - if (returnData.data.hasOwnProperty('body')) { - doSuccessSequence(returnData.data.body); - } else { - doSuccessSequence(returnData.data); - } - } else { - doErrorSequence(returnData.data, returnData.status); - } - $rootScope.loadingBlock = false; - } - /** - * Handles the sequence of callbacks for the success path. - * @param {type} data - * @returns {undefined} - */ - function doSuccessSequence(data) { - request.payload = data; - if (request.process) { - request.payload = request.process(data); - } - deferred.resolve(request.payload); - } - - /** - * Handler for $http request. - * @param {type} data - * @returns {undefined} - */ - function onError(data, status, header, config) { - doErrorSequence(data.data, data.status); - $rootScope.loadingBlock = false; - } - - /** - * Handles the sequence of callbacks for the error path. - * @param {type} data - * @returns {undefined} - */ - function doErrorSequence(data, status) { - request.payload = data; - // if we've made a rest call and go to the login page, redirect - if (!data.hasOwnProperty('success') && status !== 400) { - $window.location.reload(); - } - deferred.reject(request.payload); - } - - /** - * Puts the data on the server. - * @returns {request_L35.requestService.Request} - */ - request.put = function () { - return apply(); - }; - - /** - * Gets data from the server. (could retry in the future). - * @returns {request_L35.requestService.Request} - */ - request.get = function () { - return apply(); - }; - - request.upload = function () { - var promises = []; - var files = request.data; - var params = request.params; - //Angular doesn't support progress, so we use JQUERY instead. - function sendUpload(file) { - var deferred = $q.defer(); - var formData = new FormData(); - formData.append('file', file.rawFile); - if (params !== undefined) { - $.each(params, function(key, value) { - formData.append(key, value); - }); - } - - $http({ - method: 'POST', - url: Request.baseURI + request.id, - data: formData, - cache: false, - transformRequest: angular.identity, - headers: {'Content-Type': undefined, 'dataType': undefined} - }).then(onUploadSuccess, onUploadError).catch(onUploadError); - - function onUploadError(data, status, header, config) { - file.uploadFailed(data.data.message); - deferred.reject(angular.fromJson(data.data)); - } - - function onUploadSuccess(data, status, header, config) { - var returnData = data.data; - if (returnData.success) { - if (returnData.body.length === 0) { - return; - } - file.uploaded(returnData.body[0], Request.baseURI + '/'); - file.response = returnData.body; - deferred.resolve(file); - } else { - file.uploadFailed(returnData.message); - deferred.reject(); - } - } - return deferred.promise; - } - //Server only supports a single file. - for (var i = 0; i < files.length; i++) { - promises.push(sendUpload(files[i])); - } - return $q.all(promises); - }; - } - - Request.registerCache = function (cache) { - $http.defaults.cache = cache; - }; - // TEMPORARY: should be unneeded when this file is being served from baseURI - Request.baseURI = '/portal'; - Request.jsonContentType = 'application/json; charset=utf-8'; - Request.jsonDataType = 'json'; - return Request; - - } //end requestService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/rest/rest.js b/portal_client/app/common/services/model/rest/rest.js deleted file mode 100644 index 4811d80..0000000 --- a/portal_client/app/common/services/model/rest/rest.js +++ /dev/null @@ -1,38 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Contains wrappers for the request obejct to simplify/force - * the different calls to pick either get/put and facilitate different behavior for each of them. - */ - angular.module('portal.common.services.model.rest', ['ui.router']) - .service('rest', restService); - - function restService(Request) { - return { - /** - * Wraps/creates a request that gets data from the server. - * @param {type} request - * @returns {unresolved} - */ - get: function (args) { - return new Request(args).get(); - }, - /** - * Wraps/creates a request that commits data to the server. - * @param {type} request - * @returns {unresolved} - */ - put: function (args) { - return new Request(args).put(); - }, - post: function(args) { - return new Request(args).put(); - }, - upload: function (args) { - return new Request(args).upload(); - } - }; - - } //end restService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/rest/script-provider/script-provider.js b/portal_client/app/common/services/model/rest/script-provider/script-provider.js deleted file mode 100644 index 8cee308..0000000 --- a/portal_client/app/common/services/model/rest/script-provider/script-provider.js +++ /dev/null @@ -1,64 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Defines the restful calls for the account server module. - */ - angular.module('portal.common.services.model.rest') - .factory('scriptProvider', scriptProviderService); - - function scriptProviderService(rest, scriptObjects) { - var baseUrl = '/scripts'; - return { - runScript: function(script) { - return rest.put({ - id: baseUrl + '/runScript.do', - data: script - }); - }, - addScript: function(script) { - var endPoint = '/addScript.do'; - if (script.id !== undefined && script.id !== null) { - endPoint = '/updateScript.do'; - } - return rest.put({ - id: baseUrl + endPoint, - data: script - }); - }, - getScriptStatus: function(jobId) { - return rest.put({ - id: baseUrl + '/getScriptScheduleStatus.do', - data: jobId - }); - }, - deleteScript: function(script) { - return rest.put({ - id: baseUrl + '/deleteScript.do', - data: script - }); - }, - deleteScriptSchedule: function(scriptSched) { - return rest.put({ - id: baseUrl + '/deleteScriptSchedule.do', - data: scriptSched - }); - }, - getAllScripts: function() { - return rest.get({ - id: baseUrl + '/getAll.do' - }); - }, - getScheduleFrequencies: function() { - return rest.get({ - id: baseUrl + '/getScheduleFrequencies.do' - }); - }, - getScriptType: function() { - return rest.get({ - id: baseUrl + '/getScriptType.do' - }); - } - }; - } //end scriptProviderService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/model/rest/system-provider/system-provider.js b/portal_client/app/common/services/model/rest/system-provider/system-provider.js deleted file mode 100644 index d672071..0000000 --- a/portal_client/app/common/services/model/rest/system-provider/system-provider.js +++ /dev/null @@ -1,90 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: Defines the restful calls for the account server module. - */ - angular.module('portal.common.services.model.rest') - .factory('systemProvider', scriptProviderService); - - function scriptProviderService(rest, scriptObjects) { - var baseUrl = '/system'; - return { - addEnvVars: function(envVars) { - var endPoint = '/addEnvVars.do'; - var arrayItems = []; - if (!angular.isArray(envVars)) { - arrayItems.push(envVars); - } else { - arrayItems = envVars; - } - - return rest.put({ - id: baseUrl + endPoint, - data: arrayItems - }); - }, - updateSeed: function(seed) { - var endPoint = '/updateSeed.do'; - return rest.put({ - id: baseUrl + endPoint, - data: seed - }); - }, - updateSmtpConfig: function(smtpConf) { - var endPoint = '/updateSmtpConfig.do'; - var arrayItems = []; - if (!angular.isArray(smtpConf)) { - arrayItems.push(smtpConf); - } else { - arrayItems = smtpConf; - } - return rest.put({ - id: baseUrl + endPoint, - data: arrayItems - }); - }, - deleteEnvVar: function(envVars) { - var endPoint = '/deleteEnvVars.do'; - var arrayItems = []; - if (!angular.isArray(envVars)) { - arrayItems.push(envVars); - } else { - arrayItems = envVars; - } - - return rest.put({ - id: baseUrl + endPoint, - data: arrayItems - }); - }, - getAllEnvVars: function() { - return rest.get({ - id: baseUrl + '/getAll.do' - }); - }, - getSmtpConfig: function() { - return rest.get({ - id: baseUrl + '/getSmtpConfig.do' - }); - }, - addEmailTemplate: function(tmpl) { - return rest.get({ - id: baseUrl + '/addEmailTemplate.do', - data: tmpl - }); - }, - getEmailTemplates: function() { - return rest.get({ - id: baseUrl + '/getEmailTemplates.do' - }); - }, - deleteEmailTemplates: function(tmpl) { - return rest.get({ - id: baseUrl + '/deleteEmailTemplate.do', - data: tmpl - }); - }, - }; - } //end scriptProviderService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/permissions/permissions.js b/portal_client/app/common/services/permissions/permissions.js deleted file mode 100644 index 4ab749b..0000000 --- a/portal_client/app/common/services/permissions/permissions.js +++ /dev/null @@ -1,40 +0,0 @@ -angular.module('portal').factory('permissions', permissionFactory); - -function permissionFactory($rootScope, $state, portalUtils, $q, cache, accountStores, Triggers) { - - Triggers.listen([Triggers.PERMISSIONS_CHANGED], function(trigger, payload){ - new accountStores.Account().refresh(); - $rootScope.$broadcast('permissionsChanged'); - }); - - var permissions = { - canView: function (attrs) { - var deferred = $q.defer(); - //Nothing defined (always true) - if (angular.isDefined(attrs) === false) { - deferred.resolve(true); - } else { - var mCache = cache.request([new accountStores.Account()]).then(function () { - var validRole = verifyRole(mCache, attrs); - deferred.resolve(validRole); - }); - } - return deferred.promise; - } - }; - - /** - * Check that the user is one of the passed in roles - * @param {type} attrs attributes to check against - * @returns {Boolean} - */ - function verifyRole(mCache, attrs) { - var show = true; - if (angular.isDefined(attrs.permission)) { - show = mCache.account.data.hasPermission(attrs.permission); - } - return show; - } - - return permissions; -} \ No newline at end of file diff --git a/portal_client/app/common/services/triggers/trigger-manager.js b/portal_client/app/common/services/triggers/trigger-manager.js deleted file mode 100644 index 52fe26a..0000000 --- a/portal_client/app/common/services/triggers/trigger-manager.js +++ /dev/null @@ -1,160 +0,0 @@ -(function () { - 'use strict'; - /** - * Manages the STOMP connections. - * @type String - */ - - angular.module('portal.common.services.triggers').factory('triggerManager', function ($log, Triggers, $rootScope, Map, Request, portalUtils, $mdDialog, $state, cache, $window) { - - var subscriptions = new Map(); - var stompClient = null; - var allTopics = []; - var showTimeout = true; - var retryCounter = 0; - var useStomp = true; - - function reconnect(onSuccess) { - if (stompClient !== null && stompClient.connected) { - stompClient.disconnect(); - } - console.log('Reconnecting....'); - subscriptions = new Map(); - stompClient = null; - stompClient = null; - connect(onSuccess); - } - - function connect(onSuccess) { - if (stompClient === null) { - var socket = new SockJS(Request.baseURI + '/ws/stomp'); - stompClient = Stomp.over(socket); - // turns off printing out the contents of all messages - stompClient.debug = null; - } - if (!stompClient.connected) { - stompClient.connect({}, function (frame) { - $log.log('Stomp connection success'); - portalUtils.call(onSuccess); - retryCounter = 0; - }, function (error) { - // this is called if the connection closes or times out. - // Should we display a notice to the user? auto-reconnect? - $log.log('Stomp connection error: ' + error); - - if (retryCounter < 6) { - setTimeout(function() { reconnect(onSuccess); }, 5000); - retryCounter++; - } - - else if (showTimeout) { - var modal = $mdDialog.show({ - templateUrl: 'common/partials/session-end/session-end.html', - controller: 'SessionEndCtrl', - clickOutsideToClose: false, - escapeToClose: false, - locals: { - modalInstance: { - message: 'Session lost. Please click below to connect', - btnText: 'Connect', - onOkay: function() { - stompClient = null; - retryCounter = 0; - reconnect(onSuccess); - $mdDialog.cancel(); - } - } - - } - }); - } - showTimeout = true; - }); - } else { - portalUtils.call(onSuccess); - } - } - - function disconnect(callback) { - subscriptions = new Map(); - if (stompClient !== null) { - showTimeout = false; - stompClient = null; - } else { - portalUtils.call(callback); - } - } - - function stompMsgReceived(message) { - var trigger = angular.fromJson(message.body); - //$log.log('Received Trigger: ' + trigger.type + '\n' + message.body); - processTrigger(trigger); - } - - function processTrigger(trigger) { - //This function comes from stomp, which comes in on a non-angular javascript turn. - //That means we need to call apply ourselves. If we are ever in a digest - //cycle at this point in the code, something is wrong - $rootScope.$apply(function () { - Triggers.notify(Triggers[trigger.type], trigger); - }); - } - - function subscribe() { - if (stompClient === null || stompClient === undefined || !stompClient.connected) { - connect(function () { - subscribe(); - }); - } else { - for (var x = 0; x < allTopics.length; x++) { - var topic = allTopics[x]; - if (!subscriptions.containsKey(topic)) { - var subscription = stompClient.subscribe(topic, stompMsgReceived); - subscription.topic = topic; - subscriptions.put(topic, subscription); - } - } - } - } - - function unsubscribe(topic) { - var subscription = subscriptions.get(topic); - if (subscription !== undefined) { - subscription.unsubscribe(); - } - subscriptions.removeByKey(topic); - - var index = allTopics.indexOf(topic); - if (index > -1) { - allTopics.splice(index, 1); - } - } - - function unsubscribeAll() { - for (var i = 0; i < subscriptions.length; i++) { - var sub = subscriptions.values[i]; - sub.unsubscribe(); - subscriptions.removeByKey(sub.topic); - } - allTopics.length = 0; - } - - return { - subscribe: function (topics) { - //unsubscribeAll(); //For now unsubscribe all, eventually want to support listening for more than one. - for (var x = 0; x < topics.length; x++) { - var index = allTopics.indexOf(topics[x]); - if (index < 0) { - allTopics.push(topics[x]); - } - } - connect(function () { - subscribe(); - }); - }, - unsubscribe: unsubscribe, - disconnect: disconnect, - unsubscribeAll: unsubscribeAll - }; - }); -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/triggers/triggers.js b/portal_client/app/common/services/triggers/triggers.js deleted file mode 100644 index a53d814..0000000 --- a/portal_client/app/common/services/triggers/triggers.js +++ /dev/null @@ -1,168 +0,0 @@ -(function () { - 'use strict'; - - /** - * DESCRIPTION: - */ - angular.module('portal.common.services.triggers', ['ui.router']) - .factory('Triggers', triggersService); - - function triggersService($log, portalUtils, Map) { - - function Trigger(id, validatorFn, preCall) { - var trigger = this; - trigger.id = id; - trigger.validate = validatorFn; - if (!angular.isFunction(trigger.validate)) { - trigger.validate = function () { - return true; - }; - } - Object.defineProperties(trigger, { - isValid: { - get: trigger.validate - } - }); - trigger.preCall = true; - if (angular.isDefined(preCall)) { - trigger.preCall = preCall; - } - } - - Trigger.prototype.toString = function () { - return this.id; - }; - - var triggers = { - APP_LOGS_UPDATED: new Trigger('APP_LOGS_UPDATED', undefined, false), - APP_LOGS_PURGED: new Trigger('APP_LOGS_PURGED', undefined, false), - SCRIPT_COMPLETED: new Trigger('SCRIPT_COMPLETED', undefined, false), - SCRIPT_DELETED: new Trigger('SCRIPT_DELETED', undefined, false), - SCRIPT_ADDED: new Trigger('SCRIPT_ADDED', undefined, false), - SCRIPT_UPDATED: new Trigger('SCRIPT_UPDATED', undefined, false), - SCRIPT_SCHEDULE_DELETED: new Trigger('SCRIPT_SCHEDULE_DELETED', undefined, false), - USER_ADDED: new Trigger('USER_ADDED', undefined, false), - USER_DELETED: new Trigger('USER_DELETED', undefined, false), - HASH_TYPES_CHANGED: new Trigger('HASH_TYPES_CHANGED', undefined, false), - PERMISSIONS_DELETED: new Trigger('PERMISSIONS_DELETED', undefined, false), - PERMISSIONS_CHANGED: new Trigger('PERMISSIONS_CHANGED', undefined, false), - PERMISSIONS_UPDATED: new Trigger('PERMISSIONS_UPDATED', undefined, false), - PERMISSIONS_ADDED: new Trigger('PERMISSIONS_ADDED', undefined, false), - FILE_DELETED: new Trigger('FILE_DELETED', undefined, false), - ENV_VARS_ADDED: new Trigger('ENV_VARS_ADDED', undefined, false), - ENV_VARS_DELETED: new Trigger('ENV_VARS_DELETED', undefined, false), - EMAIL_TEMPLATE_UPDATED: new Trigger('EMAIL_TEMPLATE_UPDATED', undefined, false), - EMAIL_TEMPLATE_DELETED: new Trigger('EMAIL_TEMPLATE_DELETED', undefined, false), - SMTP_CONFIG_UPDATED: new Trigger('SMTP_CONFIG_UPDATED', undefined, false), - SEED_UPDATED: new Trigger('SEED_UPDATED', undefined, false), - }; - - triggers.Trigger = Trigger; - - - /** - * Registers to be notified when the passed in triggers are fired. - * @param {type} params {required:array[Trigger],optional:array[Trigger]} - * @param {type} callback - * @returns {cache_L40.listen.cacheAnonym$4|undefined} - */ - triggers.listen = function (params, callback) { - var optional = []; - var ids = []; - - if (angular.isArray(params)) { - optional = params.slice(); - } else if (params instanceof Trigger) { - optional.push(params); - } - - //Warn if data is incorrect. - if (optional.length === 0) { - $log.error('Attempting to listen for triggers without correct parameters'); - return; - } - for (var j = 0; j < optional.length; j++) { - ids.push(subscribe(optional[j], callback)); - } - - return {unlisten: function () { - unsubscribe(ids); - }}; - }; - - /** - * Starting subscriber id for new listeners - * @type Number - */ - var subscriberId = 0; - /** - * - * @type cache_L40.MapMap of listeners. - */ - var subscribersMap = new Map('id', 'trigger'); - /** - * Defines a subscriber object. - * @param {type} trigger - * @param {type} callback - * @param {type} id - * @returns {undefined} - */ - function Subscriber(trigger, callback, id) { - var subscriber = this; - subscriber.trigger = trigger; - subscriber.callback = callback; - subscriber.id = id; - } - /** - * Function for managing subscription map. - * @param {type} trigger - * @param {type} callback - * @param {type} now - * @returns {Number} - */ - function subscribe(trigger, callback) { - if (trigger instanceof Trigger) { - subscribersMap.put(subscriberId, new Subscriber(trigger, callback, subscriberId)); - return subscriberId++; - } else { - $log.error('Failed to listen on invalid trigger.'); - } - } - /** - * Function for itterating over ids and unsubscribing. - * @param {type} ids - * @returns {undefined} - */ - function unsubscribe(ids) { - for (var i = 0; i < ids.length; i++) { - subscribersMap.removeByKey(ids[i]); - } - } - - /** - * Notifies cache listeners of an event, propagates the data passed in. - * @param {type} trigger - * @param {type} data - * @returns {undefined} - */ - triggers.notify = function (trigger, data) { - if (trigger instanceof Trigger) { - var subsMap = subscribersMap.getGroup('trigger', trigger); - for (var i = 0; i < subsMap.length; i++) { - var sub = subsMap.values[i]; - call(sub.callback, trigger, data); - } - } else { - $log.error('Failed to notify on invalid trigger.'); - } - }; - - function call(callback, trigger, data) { - window.setTimeout(function () { - portalUtils.call(callback, trigger, data); - }, 0); - } - - return triggers; - } //end triggersService function -})(); \ No newline at end of file diff --git a/portal_client/app/common/services/utils/portalUtils.js b/portal_client/app/common/services/utils/portalUtils.js deleted file mode 100644 index 1bdad0b..0000000 --- a/portal_client/app/common/services/utils/portalUtils.js +++ /dev/null @@ -1,276 +0,0 @@ -angular.module('portal.common.services.portalUtils', ['ui.router']) - .service('portalUtils', function ($sce, $window, $mdToast, $mdDialog) { - - this.trustAsHtml = function (string){ - return $sce.trustAsHtml(string); - }; - - this.setScopeValue = function(scope, key, value, recurse) { - if (scope === undefined || scope === null) { - return; - } - if (key in scope) { - scope[key] = value; - return; - } - if (recurse) { - this.setScopeValue(scope.$parent, key, value, recurse); - } - }; - - this.hashSize = function(hash) { - var size = 0, key; - for (key in hash) { - if (hash.hasOwnProperty(key)) { - size++; - } - } - return size; - }; - - this.stripHtml = function(htmlStr) { - var newStr = htmlStr.replace(/<(?:.|\n)*?>/gm, ''); - return newStr; - }; - - function inArray(array, comparer) { - for (var i = 0; i < array.length; i++) { - if (comparer(array[i])) { - return true; - } - } - return false; - } - - /** - * Push a value onto an array if it doesnt exist - */ - this.arrayPushIfNotExist = function(array, element, comparer) { - if (!inArray(array, comparer)) { - array.push(element); - } - }; - - this.isIE = function() { - var sAgent = $window.navigator.userAgent; - var idx = sAgent.indexOf('MSIE'); - - // If IE, return version number. - if (idx > 0) { - return true; - } - // If IE 11 then look for Updated user agent string. - else if (sAgent.match(/Trident\/7\./)) { - return true; - } - else { - return false; //It is not IE - } - }; - - this.confirmBox = function(id, title, msg, showConfirm, returnFunction, newTemplate) { - var template, size; - - if(newTemplate !== null && newTemplate !== undefined) { - template = newTemplate; - } else { - template = 'common/partials/templates/confirm-window.tmpl.html'; - } - - $mdDialog.show({ - templateUrl: template, - skipHide: true, - multiple: true, - locals: { - modalInstance: { - btnId: id, - confirmTitle: title, - confirmMessage: msg, - showConfirmMessage: showConfirm - } - }, - controller: ['$scope', 'modalInstance' , '$mdDialog', function($scope, modalInstance, $mdDialog) { - - $scope.confirmTitle = modalInstance.confirmTitle; - $scope.confirmMessage = []; - if (angular.isArray(modalInstance.confirmMessage)) { - $scope.confirmMessage = modalInstance.confirmMessage; - } else { - $scope.confirmMessage.push(modalInstance.confirmMessage); - } - $scope.showConfirmMessage = modalInstance.showConfirmMessage; - $scope.btnId = modalInstance.btnId; - - $scope.data = { - checkbox: false, - confirm: false, - choice: 'merge' - }; - - $scope.confirm = function() { - $scope.data.confirm = true; - $mdDialog.hide($scope.data); - }; - - $scope.cancel = function() { - $scope.data.confirm = false; - $mdDialog.hide($scope.data); - }; - - }] - }).then(function(disabledConfirm) { - returnFunction(disabledConfirm); - }); - }; - - var toastPos = { - bottom: false, - top: false, - left: false, - right: false - }; - - function validPosition(position) { - return toastPos[position] !== undefined; - } - - /** - * Allows for a toast message to be displayed on screen - * @param message: The message to be displayed - * @param position: The Position of the toast box (valid values are ['top'|'bottom'|'left'|'right']) - * @param duration: How long the toast message should be displayed - */ - this.toast = function(message, position, duration) { - toastPos.bottom = false; - toastPos.top = false; - toastPos.left = false; - toastPos.right = false; - - if (Array.isArray(position)) { - for (var i = 0; i < position.length; i++) { - if (validPosition(position[i])) { - toastPos[position[i]] = true; - } - } - } else if (validPosition(position)) { - toastPos[position] = true; - } - - var toastPosition = angular.extend({}, toastPos); - - var pinTo = Object.keys(toastPosition) - .filter(function(pos) { return toastPosition[pos]; }) - .join(' '); - - $mdToast.show( - $mdToast.simple() - .textContent(message) - .position(pinTo) - .hideDelay(duration) - ); - }; - - /** - * Converts space separated string to title case. - * - * See: http://stackoverflow.com/a/196991/1516011 - * - * @param {type} str Any 'space separated string' - * @returns {undefined} returns 'space separated string' as 'Space Separated String' - */ - this.toTitleCase = function (str) { - if (str === null) { - return; - } - return str.replace(/\w\S*/g, function (txt) { - return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); - }); - }; - - /** - * Helper function to make calls to possibly undefined functions. - * First argument is the function to call. - * Rest of the arguements get passed to the callee - * @returns {undefined} - */ - this.call = function (callee) { - if (angular.isFunction(callee)) { - var calleeArgs = Array.prototype.slice.call(arguments, 1); - return callee.apply(this, calleeArgs); - } - }; - - this.createHash = function(array, Constructor, keyField) { - var hash = {}; - for (var i in array) { - var obj = new Constructor(array[i]); - hash[obj[keyField]] = obj; - } - return hash; - } ; - - /** - * Create an array - * - * @param {type} array An array of server objects; - * @param {type} Constructor A constructor to wrap the given data. - * @returns {Array} A wrapped array of the given type. - */ - this.createArray = function (array, Constructor) { - var objectArray = []; - for (var i in array) { - objectArray.push(new Constructor(array[i])); - } - return objectArray; - }; - - this.validEmail = function(text) { - var EMAIL_REGEX = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; - var test = EMAIL_REGEX.test(text); - return test; - }; - - /** - * Allows for quick and easy inheritance of a parent class. - * @param {type} sub - * @param {type} parent - * @returns {unresolved} - */ - this.inherit = function (sub, parent) { - sub.prototype = Object.create(parent.prototype); //Available in Chrome (5), FF (4), IE (9), Safari (5). - sub.prototype.constructor = sub; - return sub; - }; - - this.arrayLength = function(array) { - return Object.keys(array).length; - }; - - this.createMap = function(data, Constructor, accessor) { - var map = {}; - if (angular.isArray(data)) { - for (var i = 0; i < data.length; i++) { - var obj = new Constructor(data[i]); - map[obj[accessor]] = obj; - } - } - return map; - }; - - /* jshint ignore:start */ - this.sortHashTable = function(hash) { - var tmpArray = []; - $.each(hash, function(key, value){ - tmpArray[key] = value; - }); - - tmpArray = tmpArray.sort(); - var tmpHash = {}; - for (var index in tmpArray) { - tmpHash[index] = tmpArray[index]; - } - return tmpHash; - }; - /* jshint ignore:end */ - - }); \ No newline at end of file diff --git a/portal_client/app/custom/portal-material-override.css b/portal_client/app/custom/portal-material-override.css deleted file mode 100644 index 5405d4b..0000000 --- a/portal_client/app/custom/portal-material-override.css +++ /dev/null @@ -1,208 +0,0 @@ -.md-portal { background-color: #FF6600 !important; } -.md-portal-fore { color: rgb(70, 138, 172) !important; } - -.md-portal-dark { background-color: rgba(67, 136, 221, 0.7) !important; } -.md-portal-grey { background-color: rgb(67, 136, 221) !important;} -.md-portal-light-grey { background-color: #FF6600 !important;} -.md-portal-grey-opaque { - /* The top is the fallback color */ - background-color: rgb(126, 140, 154) !important; - background-color: rgba(126, 140, 154, 0.8) !important; -} -.md-portal-light { - background-color: #b7d3e1 !important; /* Fall back color in case rgba isnt compatible */ - background-color: rgba(70, 138, 172, 0.5) !important; -} - -.md-portal-disabled { - color: #969696; -} - -.play-green { color: rgb(51, 204, 51); } -.play-green-inactive { color: rgba(51, 204, 51, 0.26); } - -.stop-red { color: rgb(204, 41, 0); } -.stop-red-inactive { color: rgba(204, 41, 0, 0.26);} - -/* Google's meterial-design-icons */ -/* Rules for sizing the icon. */ -.material-icons.md-10 { font-size: 10px; } -.material-icons.md-12 { font-size: 12px; } -.material-icons.md-14 { font-size: 14px; } -.material-icons.md-16 { font-size: 16px; } -.material-icons.md-18 { font-size: 18px; } -.material-icons.md-20 { font-size: 20px; } -.material-icons.md-22 { font-size: 22px; } -.material-icons.md-24 { font-size: 24px; } -.material-icons.md-36 { font-size: 36px; } -.material-icons.md-48 { font-size: 48px; } -.material-icons.md-auto { - height: auto !important; - width: auto !important; -} - -.md-button.md-sm { - height: 26px; - line-height: 26px; - min-height: 26px; - min-width: 1%; - font-size: 16px; - vertical-align: bottom; -} - -.md-button.md-xs { - height: 20px; - line-height: 20px; - min-height: 20px; - min-width: 1%; - font-size: 10px; - vertical-align: bottom; -} - -.md-button.md-lg { - height: 58px; - line-height: 58px; - min-height: 58px; - min-width: 1%; - font-size: 48px; - vertical-align: center; -} - -/* Rules for using icons as black on a light background. */ -.material-icons.md-dark { color: rgba(0, 0, 0, 0.54); } -.material-icons.md-dark.md-inactive { color: rgba(0, 0, 0, 0.26); } - -/* Rules for using icons as white on a dark background. */ -.material-icons.md-light { color: rgba(255, 255, 255, 1); } -.material-icons.md-light.md-inactive { color: rgba(255, 255, 255, 0.3); } - -/* Rules for icon coloring */ -.material-icons.play-green { color: rgb(51, 204, 51); } -.material-icons.play-green-inactive { color: rgba(51, 204, 51, 0.26); } - -.material-icons.stop-red { color: rgb(204, 41, 0); } -.material-icons.stop-red-inactive { color: rgba(204, 41, 0, 0.26);} - -.material-icons.portal-blue { color: rgb(70, 138, 172); } -.material-icons.portal-blue-inactive { color: rgb(70, 138, 172, 0.26); } - -md-icon.portal-green { color: #4CAF50} - -md-toast { - z-index: 99999 !important; -} - -md-tabs.stretch-height md-tab-content>div, -md-tabs.stretch-height md-tab-body { - margin: 0; - width: 100%; - min-height: 100%; - height: 100%; -} - -md-menu-content.max-height { - height:30vh; -} - -.vertical-divide { - border-top-width: 0; - border-right-width: 1px; - border-right-style: solid; - margin-left: 5px; - margin-right: 5px; -} - -.flex-min-width-85 { - min-width: 85% !important; -} - -.flex-min-height-85 { - min-height: 85% !important; -} - -.flex-min-width-75 { - min-width: 75% !important; -} - -.flex-min-height-75 { - min-height: 75% !important; -} - -.flex-min-width-50 { - min-width: 50% !important; -} - -.flex-min-width-40 { - min-width: 40% !important; -} - -md-input-container.md-input-invalid .md-auto-hide .md-input-message-animation:not(.ng-animate) { - opacity: 1 !important; - margin-top: 0 !important; -} - -md-input-container.md-input-invalid [ng-messages] { - max-height: 19px !important; -} - -md-input-container .md-input-message-animation:not(.ng-animate) { - opacity: 1 !important; - margin-top: 0px !important; -} -md-input-container.md-block { - display: block !important; - width: 100% !important; -} - -md-card .md-media-sm { - height: 80px !important; - width: 80px !important; -} - -md-badge{ - margin: 0 0 0 8px; - background-color: red; - color: white; - padding: 2px 4px; - border-radius: 4px; - position: relative; - left: 0px; - top: -35px; -} - -md-toolbar.md-toolbar-small { - height:44px; - min-height: 44px; - max-height: 44px; -} -md-toolbar.md-toolbar-small .md-toolbar-tools { - vertical-align: middle; - font-size: 16px; -} - -input.md-disabled-input { - color: rgba(0,0,0,1) !important; - background: none !important; -} - -.dtp table.dtp-picker-days tr > td > a.selected, -.dtp table.dtp-picker-days tr > td > a.selected.hilite, -.dtp div.dtp-date, .dtp div.dtp-time, .dtp .dtp-hand.on, -.dtp .dtp-actual-meridien a.selected, -.dtp .dtp-picker-time > a.dtp-select-hour.selected { - background: #FF6600; -} - -.dtp table.dtp-picker-days tr > td > a.hilite:not(.selected), -.dtp div.dtp-actual-time.p60 span.selected { - color: #FF6600; -} - -.dtp div.dtp-year-btn, .dtp div.dtp-actual-year, .dtp div.dtp-actual-maxtime { - color: #b7d3e1; -} - -.dtp > .dtp-content > .dtp-date-view > header.dtp-header { - background: rgb(67, 136, 221); -} - diff --git a/portal_client/app/login/login.css b/portal_client/app/login/login.css deleted file mode 100644 index 87d07e3..0000000 --- a/portal_client/app/login/login.css +++ /dev/null @@ -1,46 +0,0 @@ -#moreinfo-view { - text-align: center; -} - -#ngLogo-content { - width: 25%; -} - -.loginTextbox { - color: white !important; -} - -input[placeholder], [placeholder], *[placeholder].loginTextbox { - color: white !important; -} - -.loginBox { - max-width: 90%; - width: 40%; -} - -#ngLogo-img { - width: 40%; - height: auto; - display: inline-block; -} - -#logo-img { - width: 35%; - height: auto; -} - -#forgotPass { - font-style: italic; - font-size: smaller; -} - - -#errorField { - margin-top: 3%; -} - -.center { - display:inline-block; - margin: 0 auto; -} \ No newline at end of file diff --git a/portal_client/app/login/login.html b/portal_client/app/login/login.html deleted file mode 100644 index 9fe3c88..0000000 --- a/portal_client/app/login/login.html +++ /dev/null @@ -1,24 +0,0 @@ -
- portal -
- - account_circle - - -
-
- - lock - - - - remove_red_eye - View password - -
-
-
- - Login -
-
\ No newline at end of file diff --git a/portal_client/app/login/login.js b/portal_client/app/login/login.js deleted file mode 100644 index 5c59a08..0000000 --- a/portal_client/app/login/login.js +++ /dev/null @@ -1,80 +0,0 @@ -angular.module('portal.login', - ['ui.router']).controller('LoginCtrl', function ($scope, $state, $window, cache, accountStores, - accountProvider, PortalPubSub, triggerManager) { - - $scope.mCache = cache.request([new accountStores.Account()]); - $scope.errorMsg = ''; - $scope.errorColor = 'text-danger'; - $scope.processing = false; - $scope.passwordType = 'password'; - - $scope.login = function () { - if ($scope.stompSuccess !== true) { - return; - } - - $scope.processing = true; - accountProvider.login($scope.username, $scope.password).then(function(data){ - if (data && data.message) { - $scope.errorMsg = data.message; - $scope.errorColor = 'text-danger'; - $scope.processing = false; - return; - } - $scope.mCache.account.update(data); - var act = $scope.mCache.account.data; - triggerManager.subscribe(act.stompTopics); - $state.go(data.page,{}); - $scope.processing = false; - }).catch(function(data) { - $scope.errorMsg = 'Unable to login ' + data; - $scope.errorColor = 'text-danger'; - $scope.processing = false; - }); - }; - - $scope.stompSuccess = false; - $scope.subscription = PortalPubSub.subscribe('StompTestStatus', function (topic, status) { - - var success = ''; - var failed = 'Communications to the Portal server cannot be established. '; - var degraded = 'Communication with the Portal server has been established in a fall-back mode. ' - + 'Portal will function properly but performance will be degraded. '; - var support = 'isaac.parenteau@ngc.com'; - var body; - - if (topic.status=== 'successful') { - - $scope.stompSuccess = true; - $scope.errorMsg = success; - $scope.errorColor = 'text-success'; - - } else if (topic.status === 'degraded') { - - $scope.stompSuccess = true; - body = encodeURIComponent('Please help me with this warning: \n\n\"' + degraded + '\"' - + '\n\nInfo to help resolve this: ' + status.stats); - $scope.errorMsg = degraded + 'Please contact ' - + support + ' for further assistance.'; - $scope.errorColor = 'text-warning'; - - } else if (topic.status === 'failure') { - - $scope.stompSuccess = false; - body = encodeURIComponent('Please help me with this error: \n\n\"' + failed + '\"' - + '\n\nInfo to help resolve this: ' + status.stats); - - $scope.errorMsg = failed + 'Please contact ' - + support + ' for further assistance.'; - $scope.errorColor = 'text-danger'; - } - }); - - $scope.$on('$destroy', function () { - PortalPubSub.unsubscribe($scope.subscription); - }); -}); \ No newline at end of file diff --git a/portal_client/app/main/cred-bank/cell-templates/cred-actions.html b/portal_client/app/main/cred-bank/cell-templates/cred-actions.html deleted file mode 100644 index 377d21a..0000000 --- a/portal_client/app/main/cred-bank/cell-templates/cred-actions.html +++ /dev/null @@ -1,12 +0,0 @@ -
- - edit - Edit Credential - - - - delete - Delete Credential - - -
\ No newline at end of file diff --git a/portal_client/app/main/cred-bank/cred-bank.html b/portal_client/app/main/cred-bank/cred-bank.html deleted file mode 100644 index 00f70f1..0000000 --- a/portal_client/app/main/cred-bank/cred-bank.html +++ /dev/null @@ -1,21 +0,0 @@ -
- - - -
- Credentials - - - filter - Filter Credentials - - - add - Add Credentials - -
-
-
-
-
-
\ No newline at end of file diff --git a/portal_client/app/main/cred-bank/cred-bank.js b/portal_client/app/main/cred-bank/cred-bank.js deleted file mode 100644 index 2705d55..0000000 --- a/portal_client/app/main/cred-bank/cred-bank.js +++ /dev/null @@ -1,115 +0,0 @@ -(function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.dashboard.credBank', ['ui.router']) - .controller('CredBankCtrl', credBankCtrlController); - - function credBankCtrlController($scope, cache, credentialProvider, credentialStores, $mdDialog, uiGridConstants, portalUtils, Constants) { - - $scope.Permissions = Constants.Permissions; - $scope.confirmQuestionBox = true; - - $scope.mCache = cache.request([new credentialStores.Credentials()]).then(function(){ - $scope.credentials = $scope.mCache.credentials.data.values; - }); - - $scope.credsGrid = { - data: 'credentials', - paginationPageSizes: [28, 56, 84, 102], - paginationPageSize: 28, - enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER, - toggleModifierKeysToMultiSelect : true, - enableRowHeaderSelection: true, - multiSelect: true, - noUnselect: false, - onRegisterApi: function (gridApi) { - gridApi.selection.setModifierKeysToMultiSelect(true); - $scope.credsGridApi = gridApi; - }, - columnDefs: [ - {field: 'name', displayName: 'Credential Name', width: '*'}, - {field: 'useSSH', displayName: 'Credential Type', width: '*', - cellTemplate: '
{{row.entity.credentialType === "SSH" ? "SSH Key" : "Username/Password"}}
'}, - {field: 'uid', displayName: 'Actions', width: '100', enableColumnMenu: false, enableFiltering: false, enableHiding: false, - cellTemplate: 'main/cred-bank/cell-templates/cred-actions.html'} - ], - }; - - $scope.$on('$destroy', function () { - $scope.mCache.unlisten(); - }); - - $scope.toggleFiltering = function() { - $scope.credsGridApi.enableFiltering = !$scope.credsGridApi.enableFiltering; - $scope.credsGridApi.core.notifyDataChange( uiGridConstants.dataChange.COLUMN ); - }; - - var originatorEv; - $scope.openMenu = function($mdOpenMenu, ev) { - originatorEv = ev; - $mdOpenMenu(ev); - }; - - $scope.delete = function(entity) { - if ($scope.confirmQuestionBox) { - portalUtils.confirmBox('deleteCreds', 'Delete Credentials', ['Are you sure you want to delete the credential', entity.name], - true, function(value) { - if (value.confirm) { - $scope.confirmQuestionBox = !value.checkbox; - $scope.deleteCreds(entity); - } - }); - } else { - $scope.deleteCreds(entity); - } - }; - - $scope.deleteCreds = function(entity) { - credentialProvider.deleteCredentials(entity).then(function() { - portalUtils.toast('Credentials deleted successfully', ['top', 'left'], 2000); - new credentialStores.Credentials().refresh(); - }).catch(function(err){ - portalUtils.toast('Unable to delete credentials: ' + err.message, ['top', 'left'], 4000); - new credentialStores.Credentials().refresh(); - }); - }; - - $scope.edit = function(entity) { - $mdDialog.show({ - templateUrl: 'common/partials/add-creds/add-creds.html', - controller: 'AddCredsCtrl', - escapeToClose: false, - locals: { - modalInstance: { - header: 'Edit Credentials', - credentials: entity - } - } - }).then(function(){ - new credentialStores.Credentials().refresh(); - }); - }; - - $scope.addCredentials = function() { - $mdDialog.show({ - templateUrl: 'common/partials/add-creds/add-creds.html', - controller: 'AddCredsCtrl', - escapeToClose: false, - locals: { - modalInstance: { - header: 'Add Credentials', - } - } - }).then(function(){ - new credentialStores.Credentials().refresh(); - }); - }; - - } //end UserBankCtrlController function - -})(); \ No newline at end of file diff --git a/portal_client/app/main/dashboard.css b/portal_client/app/main/dashboard.css deleted file mode 100644 index 15478fa..0000000 --- a/portal_client/app/main/dashboard.css +++ /dev/null @@ -1,21 +0,0 @@ -#portal-logo { - width: 75px; - height: auto; -} - -.account-md-menu{ - text-align: center; -} - -#accountMenu { - margin-top: 7px; -} -/* Centers icon in ripple container */ -#iconAccountMenu { - margin-right: 11px; - margin-bottom: 13px; -} - -.username-banner { - margin-top: 10px; -} \ No newline at end of file diff --git a/portal_client/app/main/dashboard.html b/portal_client/app/main/dashboard.html deleted file mode 100644 index bc9aaa2..0000000 --- a/portal_client/app/main/dashboard.html +++ /dev/null @@ -1,60 +0,0 @@ -
- - -
- - -
Welcome {{ mCache.account.data.firstName }} {{mCache.account.data.lastName}}
- - - - -
-
- -
-
\ No newline at end of file diff --git a/portal_client/app/main/dashboard.js b/portal_client/app/main/dashboard.js deleted file mode 100644 index 31a271b..0000000 --- a/portal_client/app/main/dashboard.js +++ /dev/null @@ -1,215 +0,0 @@ -(function () { - 'use strict'; - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.dashboard', ['ui.router', 'portal.common.constants']).config(DashboardConfig) - .controller('DashboardCtrl', DashboardCtrlController); - - function DashboardConfig($stateProvider, Constants) { - $stateProvider.state('dashboard', { - url: '/dashboard', - pageTitle: 'Dashboard', - templateUrl: 'main/dashboard.html', - resolve: { - authorize: ['authorize', - function (authorize) { - return authorize.validate({ - authorities: { - permission: [ - Constants.Permissions.VIEW_SCRIPT_TAB, - Constants.Permissions.VIEW_GIT_TAB, - Constants.Permissions.VIEW_USER_TAB, - Constants.Permissions.VIEW_CREDS_TAB, - Constants.Permissions.VIEW_LOG_TAB, - ] - }, - redirect: 'login' - }); - } - ] - } - }).state('dashboard.scripts', { - url: '/scripts', - pageTitle: 'Scripts', - templateUrl: 'main/script-bank/script-bank.html' - }).state('dashboard.repos', { - url: '/repos', - pageTitle: 'Git Repositories', - templateUrl: 'main/git-bank/git-bank.html' - }).state('dashboard.credentials', { - url: '/credentials', - pageTitle: 'Credentials', - templateUrl: 'main/cred-bank/cred-bank.html' - }).state('dashboard.emails', { - url: '/emails', - pageTitle: 'Emails', - templateUrl: 'main/email-bank/email-bank.html' - }).state('dashboard.users', { - url: '/users', - pageTitle: 'Users', - templateUrl: 'main/user-bank/user-bank.html' - }).state('dashboard.permissions', { - url: '/permissions', - pageTitle: 'Permissions', - templateUrl: 'main/permission-bank/permission-bank.html' - }).state('dashboard.envars', { - url: '/envars', - pageTitle: 'Environment Variables', - templateUrl: 'main/env-bank/env-bank.html' - }).state('dashboard.syslogs', { - url: '/syslogs', - pageTitle: 'System Logs', - templateUrl: 'main/log-bank/log-bank.html' - }); - } - - function DashboardCtrlController($state, $scope, cache, accountStores, accountProvider, - $window, $mdDialog, Constants) { - - var originatorEv; - $scope.openMenu = function($mdMenu, ev) { - originatorEv = ev; - $mdMenu.open(ev); - }; - - $scope.Constants = Constants; - - $scope.loadingBlock = false; - - $scope.userRole = ''; - $scope.tabs = [{ - title: 'Scripts', - source: 'main/script-bank/script-bank.html', - state: 'dashboard.scripts', - leftItem: 'description', - active: true, - default: false, - canView: Constants.Permissions.VIEW_SCRIPT_TAB - },{ - title: 'Git Repositories', - source: 'main/git-bank/git-bank.html', - state: 'dashboard.repos', - leftItem: 'computer', - active: true, - default: true, - canView: Constants.Permissions.VIEW_GIT_TAB - },{ - title: 'Credentials', - source: 'main/cred-bank/cred-bank.html', - state: 'dashboard.credentials', - leftItem: 'vpn_key', - active: false, - default: false, - canView: Constants.Permissions.VIEW_CREDS_TAB - },{ - title: 'Email Templates', - source: 'main/email-bank/email-bank.html', - state: 'dashboard.emails', - leftItem: 'email', - active: false, - default: false, - canView: Constants.Permissions.VIEW_EMAIL_TAB - },{ - title: 'Users', - source: 'main/user-bank/user-bank.html', - state: 'dashboard.users', - leftItem: 'people', - active: false, - default: false, - canView: Constants.Permissions.VIEW_USER_TAB - },{ - title: 'Permissions', - source: 'main/permission-bank/permission-bank.html', - state: 'dashboard.permissions', - leftItem: 'lock_open', - active: false, - default: false, - canView: Constants.Permissions.VIEW_PERMISSION_TAB - },{ - title: 'Environment Variables', - source: 'main/env-bank/env-bank.html', - state: 'dashboard.envars', - leftItem: 'storage', - active: false, - default: false, - canView: Constants.Permissions.VIEW_ENV_VARS_TAB - },{ - title: 'System Logs', - source: 'main/log-bank/log-bank.html', - state: 'dashboard.syslogs', - leftItem: 'description', - active: false, - default: false, - canView: Constants.Permissions.VIEW_LOG_TAB - }]; - - $scope.mCache = cache.request([new accountStores.Account()]).then(function(){ - $scope.allowedTabs = []; - $.each($scope.tabs, function(i, tab){ - if ($scope.mCache.account.data.hasPermission(tab.canView)) { - $scope.allowedTabs.push(tab); - } - }); - $scope.$broadcast('tabsetDidChange', $scope.allowedTabs); - }).catch(function(err){ }); - - $scope.$on('$destroy', function () { - $scope.mCache.unlisten(); - }); - - $scope.logout = function() { - accountProvider.logout().then(function (data) { - cache.flush(); - $state.go('login'); - $window.location.href = '#/login'; - $window.location.reload(); - }).catch(function (data) { - $state.go('login'); - }); - }; - - $scope.openConfiguration = function() { - $mdDialog.show({ - controller: 'ConfigurationCtrl', - templateUrl: 'common/partials/configuration/configuration.html', - clickOutsideToClose: false, - escapeToClose: false, - locals: { - account: $scope.mCache.account - } - }); - }; - - $scope.openSeed = function() { - $mdDialog.show({ - controller: 'SeedInfoCtrl', - templateUrl: 'common/partials/seed-info/seed-info.html', - clickOutsideToClose: false, - escapeToClose: false, - }); - }; - - $scope.openLogLevel = function() { - $mdDialog.show({ - controller: 'LoggerInfoCtrl', - templateUrl: 'common/partials/logger-info/logger-info.html', - clickOutsideToClose: false, - escapeToClose: false, - }); - }; - - $scope.openSMTPConfig = function() { - $mdDialog.show({ - controller: 'SMTPInfoCtrl', - templateUrl: 'common/partials/smtp-info/smtp-info.html', - clickOutsideToClose: false, - escapeToClose: false, - }); - }; - - } //end DashboardCtrlController function - -})(); \ No newline at end of file diff --git a/portal_client/app/main/email-bank/cell-templates/email-actions.html b/portal_client/app/main/email-bank/cell-templates/email-actions.html deleted file mode 100644 index 5599207..0000000 --- a/portal_client/app/main/email-bank/cell-templates/email-actions.html +++ /dev/null @@ -1,12 +0,0 @@ -
- - edit - Edit Email Template - - - - delete - Delete Email Template - - -
\ No newline at end of file diff --git a/portal_client/app/main/email-bank/email-bank.html b/portal_client/app/main/email-bank/email-bank.html deleted file mode 100644 index 849ac29..0000000 --- a/portal_client/app/main/email-bank/email-bank.html +++ /dev/null @@ -1,21 +0,0 @@ -
- - - -
- Available Email Templates - - - filter - Filter - - - add - Add New Email Template - -
-
-
-
-
-
\ No newline at end of file diff --git a/portal_client/app/main/email-bank/email-bank.js b/portal_client/app/main/email-bank/email-bank.js deleted file mode 100644 index 16e8bfe..0000000 --- a/portal_client/app/main/email-bank/email-bank.js +++ /dev/null @@ -1,111 +0,0 @@ -(function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.dashboard.emailBank', ['ui.router']) - .controller('EmailBankCtrl', EmailBankCtrlController); - - function EmailBankCtrlController($scope, cache, systemProvider, systemStores, $mdDialog, - uiGridConstants, portalUtils, Constants) { - - $scope.confirmQuestionBox = true; - - $scope.scripts = []; - - $scope.userRole = ''; - - $scope.Constants = Constants; - - $scope.mCache = cache.request([ - new systemStores.EmailTemplates() - ]).then(function(){ - $scope.emailTemplates = $scope.mCache.emailTmpls.data.values; - }); - - $scope.emailGrid = { - data: 'emailTemplates', - paginationPageSizes: [25, 50, 75, 100, 125, 150, 175, 200], - paginationPageSize: 25, - enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER, - toggleModifierKeysToMultiSelect : true, - enableRowHeaderSelection: true, - multiSelect: false, - noUnselect: false, - onRegisterApi: function (gridApi) { - $scope.emailTmplGridApi = gridApi; - }, - columnDefs: [ - {field: 'emailName', displayName: 'Name', width: '*'}, - {field: 'emailSubject', displayName: 'Subject', width: '**' }, - {field: 'id', displayName: 'Actions', width: '125', enableColumnMenu: false, enableFiltering: false, enableHiding: false, - cellTemplate: 'main/email-bank/cell-templates/email-actions.html' - } - ], - }; - - - $scope.edit = function(entity) { - $mdDialog.show({ - templateUrl: 'common/partials/add-email-tmpl/add-email-tmpl.html', - controller: 'AddEmailTmplCtrl', - escapeToClose: false, - locals: { - modalInstance: { - header: 'Edit Email Template', - template: entity - } - } - }); - }; - - $scope.addEmail = function() { - $mdDialog.show({ - templateUrl: 'common/partials/add-email-tmpl/add-email-tmpl.html', - controller: 'AddEmailTmplCtrl', - escapeToClose: false, - locals: { - modalInstance: { - header: 'Add New Email Template', - } - } - }); - }; - - $scope.delete = function(entity) { - if ($scope.confirmQuestionBox) { - portalUtils.confirmBox('deleteTmpl', 'Delete Email Template', ['Are you sure you want to delete the template', entity.emailName], - true, function(value) { - if (value.confirm) { - $scope.confirmQuestionBox = !value.checkbox; - $scope.deleteTmpl(entity); - } - }); - } else { - $scope.deleteTmpl(entity); - } - }; - - $scope.deleteTmpl = function(entity) { - systemProvider.deleteEmailTemplates(entity).then(function() { - portalUtils.toast('Email Template deleted successfully', ['top', 'left'], 2000); - },function(err){ - portalUtils.toast('Unable to delete email Template: ' + err.message, ['top', 'left'], 4000); - }); - }; - - $scope.toggleFiltering = function() { - $scope.scriptGrid.enableFiltering = !$scope.scriptGrid.enableFiltering; - $scope.emailTmplGridApi.core.notifyDataChange( uiGridConstants.dataChange.COLUMN ); - }; - - /* $scope.$on('$destroy', function () { - $scope.mCache.unlisten(); - });*/ - - } //end EmailBankCtrlController function - -})(); \ No newline at end of file diff --git a/portal_client/app/main/env-bank/env-bank.html b/portal_client/app/main/env-bank/env-bank.html deleted file mode 100644 index 8cbd9df..0000000 --- a/portal_client/app/main/env-bank/env-bank.html +++ /dev/null @@ -1,29 +0,0 @@ -
- - - -
- Available Environment Variables - - - filter - Filter - - - add - Add New Environment Variable - - - edit - Edit Selected Environment Variable - - - delete - Delete Selected Environment Variable - -
-
-
-
-
-
\ No newline at end of file diff --git a/portal_client/app/main/env-bank/env-bank.js b/portal_client/app/main/env-bank/env-bank.js deleted file mode 100644 index a419fbc..0000000 --- a/portal_client/app/main/env-bank/env-bank.js +++ /dev/null @@ -1,117 +0,0 @@ -(function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.dashboard.envBank', ['ui.router']) - .controller('EnvBankCtrl', EnvBankCtrlController); - - function EnvBankCtrlController($scope, cache, systemStores, systemProvider, uiGridConstants, $timeout, $mdDialog, portalUtils, Constants) { - - $scope.envars = []; - $scope.Constants = Constants; - $scope.mCache = cache.request([new systemStores.EnvironmentVariables()]).then(function(){ - $scope.envars = $scope.mCache.envvars.data.values; - }); - - $scope.envarGrid = { - data: 'envars', - paginationPageSizes: [25, 50, 75, 100, 125, 150, 175, 200], - paginationPageSize: 25, - enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER, - toggleModifierKeysToMultiSelect : true, - enableRowHeaderSelection: true, - enableColumnMenus: true, - enableGridMenu: true, - multiSelect: true, - noUnselect: false, - onRegisterApi: function (gridApi) { - gridApi.selection.setModifierKeysToMultiSelect(true); - $scope.envGridApi = gridApi; - }, - columnDefs: [ - {field: 'name', displayName: 'Environment Name'}, - {field: 'value', displayName: 'Environment Value'}, - ], - }; - - $scope.$on('$destroy', function () { - $scope.mCache.unlisten(); - }); - - $scope.toggleFiltering = function() { - $scope.envGridApi.enableFiltering = !$scope.envGridApi.enableFiltering; - $scope.envGridApi.core.notifyDataChange( uiGridConstants.dataChange.COLUMN ); - }; - - var originatorEv; - $scope.openMenu = function($mdOpenMenu, ev) { - originatorEv = ev; - $mdOpenMenu(ev); - }; - - $scope.delete = function() { - var messages = ['Are you sure you want to delete the following environment variables?']; - - var selectedEnvVars = $scope.envGridApi.selection.getSelectedRows(); - for (var i = 0; i < selectedEnvVars.length; i++) { - messages.push(selectedEnvVars[i].name); - } - - portalUtils.confirmBox('deleteEnVars', 'Delete Environment Variables', messages, false, function(value) { - if (value.confirm) { - $scope.deleteEnvVars(selectedEnvVars); - } - }); - }; - - $scope.deleteEnvVars = function(selectedEnvVars) { - systemProvider.deleteEnvVar(selectedEnvVars).then(function() { - portalUtils.toast('Environment Variables deleted successfully', ['top', 'left'], 2000); - }).catch(function(err){ - portalUtils.toast('Unable to delete environment variables: ' + err.message, ['top', 'left'], 4000); - }); - }; - - $scope.edit = function() { - $mdDialog.show({ - templateUrl: 'common/partials/add-env/add-env.html', - controller: 'AddEnvVarCtrl', - escapeToClose: false, - locals: { - modalInstance: { - header: 'Edit Environment Variables', - envVars: $scope.envGridApi.selection.getSelectedRows() - } - } - }); - }; - - $scope.addEnvVar = function() { - $mdDialog.show({ - templateUrl: 'common/partials/add-env/add-env.html', - controller: 'AddEnvVarCtrl', - escapeToClose: false, - locals: { - modalInstance: { - header: 'Add New Environment Variables', - envVars: [] - } - } - }); - }; - - $scope.selectedCount = function() { - try { - return $scope.envGridApi.selection.getSelectedRows().length; - } catch(err) { - return 0; - } - }; - - } //end EnvBankCtrlController function - -})(); \ No newline at end of file diff --git a/portal_client/app/main/git-bank/cell-templates/git-actions.html b/portal_client/app/main/git-bank/cell-templates/git-actions.html deleted file mode 100644 index 6b51f4e..0000000 --- a/portal_client/app/main/git-bank/cell-templates/git-actions.html +++ /dev/null @@ -1,17 +0,0 @@ -
- - edit - Edit - - - - play_arrow - Issue pull request - - - - delete - Delete Repository - - -
\ No newline at end of file diff --git a/portal_client/app/main/git-bank/git-bank.html b/portal_client/app/main/git-bank/git-bank.html deleted file mode 100644 index dfc52df..0000000 --- a/portal_client/app/main/git-bank/git-bank.html +++ /dev/null @@ -1,21 +0,0 @@ -
- - - -
- Available Git Repositories - - - filter - Filter - - - add - Add Git Repository - -
-
-
-
-
-
\ No newline at end of file diff --git a/portal_client/app/main/git-bank/git-bank.js b/portal_client/app/main/git-bank/git-bank.js deleted file mode 100644 index 9111f97..0000000 --- a/portal_client/app/main/git-bank/git-bank.js +++ /dev/null @@ -1,151 +0,0 @@ -(function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.dashboard.gitBank', ['ui.router']) - .controller('GitBankCtrl', GitBankCtrlController); - - function GitBankCtrlController($scope, cache, gitProvider, gitStores, Constants, - accountStores, $mdDialog, uiGridConstants, portalUtils) { - - $scope.confirmQuestionBox = true; - $scope.Permissions = Constants.Permissions; - $scope.repos = []; - - $scope.userRole = ''; - - $scope.dirs = {}; - - $scope.mCache = cache.request([ - new accountStores.Account(), - new gitStores.Repos() - ]).then(function(){ - $scope.userRole = $scope.mCache.account.data.role; - $scope.repos = $scope.mCache.repos.data.values; - }); - - $scope.repoGrid = { - data: 'repos', - paginationPageSizes: [25, 50, 75, 100, 125, 150, 175, 200], - paginationPageSize: 25, - enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER, - toggleModifierKeysToMultiSelect : true, - enableRowHeaderSelection: true, - enableColumnMenus: true, - enableGridMenu: true, - exporterMenuCsv: true, - multiSelect: false, - noUnselect: false, - onRegisterApi: function (gridApi) { - $scope.repoGridApi = gridApi; - }, - columnDefs: [ - {field: 'name', displayName: 'Name', width: '*'}, - {field: 'scm', displayName: 'SCM', width: '**' }, - {field: 'branch', displayName: 'Branch', width: '**' }, - {field: 'directory', displayName: 'Directory', width: '**' }, - {field: 'lastUpdated', displayName: 'Last Updated', width: '**', - cellTemplate: '
{{grid.appScope.formatTimeLong(row.entity.lastUpdated)}}
'}, - {field: 'createDate', displayName: 'Create Date', width: '*', - cellTemplate: '
{{grid.appScope.formatTimeShort(row.entity.createDate)}}
'}, - {field: 'id', displayName: 'Actions', width: '125', enableColumnMenu: false, enableFiltering: false, enableHiding: false, - cellTemplate: 'main/git-bank/cell-templates/git-actions.html' - } - ], - }; - - $scope.formatTimeLong = function(value) { - return moment(value).format('MM/DD/Y HH:mm:ss'); - }; - - $scope.formatTimeShort = function(value) { - return moment(value).format('MM/DD/Y'); - }; - - $scope.$on('$destroy', function () { - $scope.mCache.unlisten(); - }); - - $scope.toggleFiltering = function() { - $scope.repoGrid.enableFiltering = !$scope.repoGrid.enableFiltering; - $scope.repoGridApi.core.notifyDataChange( uiGridConstants.dataChange.COLUMN ); - }; - - $scope.pull = function(entity) { - portalUtils.confirmBox('updateRepo', 'Update Repository', ['Issue a pull request for', entity.name], - true, function(value) { - if (value.confirm) { - gitProvider.pullRepo(entity).then(function() { - portalUtils.toast('Repository updated successfully', ['top', 'left'], 2000); - new gitStores.Repos().refresh(); - }).catch(function(err){ - portalUtils.toast('Unable to update repository: ' + err.message, ['top', 'left'], 4000); - new gitStores.Repos().refresh(); - }); - } - }); - }; - - $scope.delete = function(entity) { - if ($scope.confirmQuestionBox) { - portalUtils.confirmBox('deleteRepo', 'Delete Repository', ['Are you sure you want to delete the repository', entity.name], - true, function(value) { - if (value.confirm) { - $scope.confirmQuestionBox = !value.checkbox; - $scope.deleteRepo(entity); - } - }); - } else { - $scope.deleteRepo(entity); - } - }; - - $scope.deleteRepo = function(entity) { - gitProvider.deleteRepo(entity).then(function() { - portalUtils.toast('Repository deleted successfully', ['top', 'left'], 2000); - new gitStores.Repos().refresh(); - }).catch(function(err){ - portalUtils.toast('Unable to delete repository: ' + err.message, ['top', 'left'], 4000); - new gitStores.Repos().refresh(); - }); - }; - - $scope.edit = function(entity) { - $mdDialog.show({ - templateUrl: 'common/partials/add-git/add-git.html', - controller: 'AddGitCtrl', - escapeToClose: false, - locals: { - modalInstance: { - header: 'Edit Git Repository', - gitInfo: entity - } - } - }).then(function() { - new gitStores.Repos().refresh(); - }); - }; - - $scope.addRepo = function() { - $mdDialog.show({ - templateUrl: 'common/partials/add-git/add-git.html', - controller: 'AddGitCtrl', - escapeToClose: false, - locals: { - modalInstance: { - header: 'Add Git Repository', - } - } - }).then(function() { - new gitStores.Repos().refresh(); - }); - }; - - - } //end GitBankCtrlController function - -})(); \ No newline at end of file diff --git a/portal_client/app/main/log-bank/log-bank.html b/portal_client/app/main/log-bank/log-bank.html deleted file mode 100644 index a9c6ea7..0000000 --- a/portal_client/app/main/log-bank/log-bank.html +++ /dev/null @@ -1,22 +0,0 @@ -
- - - -
- System Logs - - - delete_sweep - Purge Logs - - - filter - Filter Logs - -
-
-
- -
-
-
\ No newline at end of file diff --git a/portal_client/app/main/log-bank/log-bank.js b/portal_client/app/main/log-bank/log-bank.js deleted file mode 100644 index c668bc3..0000000 --- a/portal_client/app/main/log-bank/log-bank.js +++ /dev/null @@ -1,126 +0,0 @@ -(function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.dashboard.logBank', ['ui.router']) - .controller('LogBankCtrl', LogBankCtrlController); - - function LogBankCtrlController($scope, cache, appLogStores, uiGridConstants, $timeout, $mdDialog, Constants) { - - $scope.logs = []; - - $scope.Constants = Constants; - - $scope.mCache = cache.request([new appLogStores.Logs()]).then(function(){ - $scope.logs = $scope.mCache.logs.data.values; - for (var i = 0; i < $scope.logs.length; i++) { - $scope.logs[i].formattedTime = moment($scope.logs[i].timestamp).format('MM/DD/Y HH:mm:ss'); - } - }); - - $scope.logGrid = { - data: 'logs', - paginationPageSizes: [25, 50, 75, 100, 125, 150, 175, 200], - paginationPageSize: 25, - enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER, - toggleModifierKeysToMultiSelect : true, - enableRowHeaderSelection: true, - enableColumnMenus: true, - enableGridMenu: true, - exporterCsvFilename: 'RepoLogs.csv', - exporterMenuCsv: true, - multiSelect: true, - noUnselect: false, - onRegisterApi: function (gridApi) { - gridApi.selection.setModifierKeysToMultiSelect(true); - $scope.logGridApi = gridApi; - }, - columnDefs: [ - {field: 'loggedBy', displayName: 'Logged By', width: '*'}, - {field: 'eventName', displayName: 'Event Type'}, - {field: 'event', displayName: 'Event', width: '*****'}, - {field: 'severity', displayName: 'Severity'}, - {field: 'ipAddress', displayName: 'IP Address', width: '*' }, - {field: 'formattedTime', displayName: 'Timestamp', width: '*' }, - ], - }; - - $scope.$on('$destroy', function () { - $scope.mCache.unlisten(); - }); - - $scope.toggleFiltering = function() { - $scope.logGridApi.enableFiltering = !$scope.logGridApi.enableFiltering; - $scope.logGridApi.core.notifyDataChange( uiGridConstants.dataChange.COLUMN ); - }; - - var originatorEv; - $scope.openMenu = function($mdOpenMenu, ev) { - originatorEv = ev; - $mdOpenMenu(ev); - }; - - $scope.purge = function() { - $mdDialog.show({ - templateUrl: 'common/partials/templates/purge-logs.tmpl.html', - multipe: true, - skipHide: true, - locals: { - modalInstance: { - 'title': 'Purge Logs', - 'message': 'Select the date to purge logs before' - } - }, - controller: ['$scope', 'modalInstance', '$mdDialog', 'portalUtils', 'appLogProvider', - function($scope, modalInstance, $mdDialog, portalUtils, appLogProvider) { - $scope.title = modalInstance.title; - $scope.message = modalInstance.message; - $scope.loadingBlock = false; - - $scope.model = {}; - - $scope.confirm = function() { - $scope.error = ''; - if ($scope.model.purgeStartDate === undefined) { - $scope.error = 'Purge start date is required'; - return; - } - if ($scope.model.purgeEndDate === undefined) { - $scope.error = 'Purge end date is required'; - return; - } - portalUtils.confirmBox('purgeConfirm', 'Confirm Purge', - ['Are you sure you want to purge files between', - moment($scope.model.purgeStartDate).format('MMMM Do, Y') - + ' and ' + moment($scope.model.purgeEndDate).format('MMMM Do, Y')], false, - function(value) { - if (value.confirm) { - $scope.loadingBlock = true; - appLogProvider.purgeLogs($scope.model).then(function(value) { - $scope.loadingBlock = false; - portalUtils.toast('Successfully purged ' + value + ' logs', ['top', 'left'], 2000); - $mdDialog.hide(); - }).catch(function(err) { - $scope.loadingBlock = false; - portalUtils.toast('Unable to purge logs: ' + err.message, ['top', 'left'], 4000); - }); - } - }); - }; - - $scope.cancel = function() { - $mdDialog.cancel(); - }; - }] - }).then(function() { - new appLogStores.Logs().refresh(); - }); - }; - - } //end LogBankCtrlController function - -})(); \ No newline at end of file diff --git a/portal_client/app/main/permission-bank/cell-templates/permission-actions.html b/portal_client/app/main/permission-bank/cell-templates/permission-actions.html deleted file mode 100644 index 39cbcc6..0000000 --- a/portal_client/app/main/permission-bank/cell-templates/permission-actions.html +++ /dev/null @@ -1,12 +0,0 @@ -
- - edit - Edit Permission - - - - delete - Delete Permission - - -
\ No newline at end of file diff --git a/portal_client/app/main/permission-bank/permission-bank.html b/portal_client/app/main/permission-bank/permission-bank.html deleted file mode 100644 index f3e0770..0000000 --- a/portal_client/app/main/permission-bank/permission-bank.html +++ /dev/null @@ -1,21 +0,0 @@ -
- - - -
- Permissions - - - filter - Filter Permissions - - - add_circle - Add Permissions - -
-
-
-
-
-
\ No newline at end of file diff --git a/portal_client/app/main/permission-bank/permission-bank.js b/portal_client/app/main/permission-bank/permission-bank.js deleted file mode 100644 index 680c3e6..0000000 --- a/portal_client/app/main/permission-bank/permission-bank.js +++ /dev/null @@ -1,132 +0,0 @@ -(function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.dashboard.permissionBank', ['ui.router']) - .controller('PermissionBankCtrl', PermissionBankCtrlController); - - function PermissionBankCtrlController($scope, cache, permissionStores, permissionProvider, $mdDialog, - uiGridConstants, portalUtils, Constants) { - - $scope.confirmQuestionBox = true; - $scope.permissions = []; - $scope.Constants = Constants; - - $scope.mCache = cache.request([new permissionStores.PermissionGroups()]).then(function(){ - $scope.permissions = $scope.mCache.permissionGroups.data.values; - }); - - portalUtils.setScopeValue($scope, 'loadingBlock', false, true); - - $scope.permGrid = { - data: 'permissions', - paginationPageSizes: [28, 56, 84, 102], - paginationPageSize: 28, - enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER, - toggleModifierKeysToMultiSelect : true, - enableRowHeaderSelection: true, - enableColumnMenus: true, - enableGridMenu: true, - exporterCsvFilename: 'Files.csv', - exporterMenuCsv: true, - multiSelect: true, - noUnselect: false, - onRegisterApi: function (gridApi) { - gridApi.selection.setModifierKeysToMultiSelect(true); - $scope.permGridApi = gridApi; - }, - columnDefs: [ - {field: 'displayName', displayName: 'Permission Group', width: '*'}, - {field: 'enabled', displayName: 'Enabled', width: '*'}, - {field: 'permissions', displayName: 'Allowed Permissions', width: '***', - cellTemplate: '
{{grid.appScope.formatPermissions(row.entity.permissions)}}
'}, - {field: 'id', displayName: 'Actions', width: '100', enableColumnMenu: false, enableFiltering: false, enableHiding: false, - cellTemplate: 'main/permission-bank/cell-templates/permission-actions.html'} - ], - }; - - $scope.formatPermissions = function(perms) { - var p = []; - for (var i = 0; i < perms.length; i++) { - var perm = perms[i]; - if (perm.allowed) { - p.push(perm.displayName); - } - } - return p.join(', '); - }; - - $scope.$on('$destroy', function () { - $scope.mCache.unlisten(); - }); - - $scope.toggleFiltering = function() { - $scope.permGrid.enableFiltering = !$scope.permGrid.enableFiltering; - $scope.permGridApi.core.notifyDataChange( uiGridConstants.dataChange.COLUMN ); - }; - - var originatorEv; - $scope.openMenu = function($mdOpenMenu, ev) { - originatorEv = ev; - $mdOpenMenu(ev); - }; - - $scope.delete = function(entity) { - if ($scope.confirmQuestionBox) { - portalUtils.confirmBox('deletePermissionGroup', 'Delete Permission Group', ['Are you sure you want to delete the permission group', entity.displayName], - true, function(value) { - if (value.confirm) { - $scope.confirmQuestionBox = !value.checkbox; - $scope.deletePermission(entity); - } - }); - } else { - $scope.deletePermission(entity); - } - }; - - $scope.deletePermission = function(entity) { - portalUtils.setScopeValue($scope, 'loadingBlock', true, true); - permissionProvider.deletePermissionGroup(entity).then(function(data) { - portalUtils.toast('Successfully deleted permission group ' + entity.displayName, ['top', 'left'], 2000); - portalUtils.setScopeValue($scope, 'loadingBlock', false, true); - }).catch(function(err){ - portalUtils.toast('Unable to delete permission group: ' + err.message, ['top', 'left'], 4000); - portalUtils.setScopeValue($scope, 'loadingBlock', false, true); - }); - }; - - $scope.edit = function(entity) { - $mdDialog.show({ - templateUrl: 'common/partials/add-permission/add-permission.html', - controller: 'AddPermissionCtrl', - escapeToClose: false, - locals: { - modalInstance: { - header: 'Edit Permission Group', - permission: entity, - } - } - }); - }; - - $scope.addPermissions = function() { - $mdDialog.show({ - templateUrl: 'common/partials/add-permission/add-permission.html', - controller: 'AddPermissionCtrl', - escapeToClose: false, - locals: { - modalInstance: { - header: 'Add Permissions', - } - } - }); - }; - - } //end PermissionBankCtrlController function - -})(); \ No newline at end of file diff --git a/portal_client/app/main/script-bank/cell-templates/script-actions.html b/portal_client/app/main/script-bank/cell-templates/script-actions.html deleted file mode 100644 index 651f5af..0000000 --- a/portal_client/app/main/script-bank/cell-templates/script-actions.html +++ /dev/null @@ -1,17 +0,0 @@ -
- - edit - Edit Script - - - - play_arrow - Manual Run of script - - - - delete - Delete Script - - -
\ No newline at end of file diff --git a/portal_client/app/main/script-bank/cell-templates/script-sched-actions.html b/portal_client/app/main/script-bank/cell-templates/script-sched-actions.html deleted file mode 100644 index 4af6901..0000000 --- a/portal_client/app/main/script-bank/cell-templates/script-sched-actions.html +++ /dev/null @@ -1,10 +0,0 @@ -
- - remove_red_eye - View Status Results - - - delete - Delete Schedule - -
\ No newline at end of file diff --git a/portal_client/app/main/script-bank/cell-templates/script-sched-status.html b/portal_client/app/main/script-bank/cell-templates/script-sched-status.html deleted file mode 100644 index 5117b6f..0000000 --- a/portal_client/app/main/script-bank/cell-templates/script-sched-status.html +++ /dev/null @@ -1,7 +0,0 @@ -
- {{grid.appScope.formatStatus(row.entity)}} -
\ No newline at end of file diff --git a/portal_client/app/main/script-bank/script-bank.html b/portal_client/app/main/script-bank/script-bank.html deleted file mode 100644 index eed240e..0000000 --- a/portal_client/app/main/script-bank/script-bank.html +++ /dev/null @@ -1,21 +0,0 @@ -
- - - -
- Available Scripts - - - filter - Filter - - - add - Add New Script - -
-
-
-
-
-
\ No newline at end of file diff --git a/portal_client/app/main/script-bank/script-bank.js b/portal_client/app/main/script-bank/script-bank.js deleted file mode 100644 index d94c388..0000000 --- a/portal_client/app/main/script-bank/script-bank.js +++ /dev/null @@ -1,234 +0,0 @@ -(function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.dashboard.scriptBank', ['ui.router']) - .controller('ScriptBankCtrl', ScriptBankCtrlController); - - function ScriptBankCtrlController($scope, cache, scriptStores, scriptProvider, - accountStores, $mdDialog, uiGridConstants, portalUtils, $log, Triggers, Constants) { - - $scope.confirmQuestionBox = true; - - $scope.scripts = []; - - $scope.userRole = ''; - - $scope.Constants = Constants; - - $scope.mCache = cache.request([ - new accountStores.Account(), - new scriptStores.Scripts() - ]).then(function(){ - $scope.acct = $scope.mCache.account.data; - $scope.scripts = $scope.mCache.scripts.data.values; - for (var i = 0; i < $scope.scripts.length; i++) { - $scope.scripts[i].subGridOptions = { - data: $scope.scripts[i].schedule, - columnDefs: [ - {field: 'jobId', displayName: 'Job Id', width: '**'}, - {field: 'startDatetime', displayName: 'Start Date/Time', width: '*', - cellTemplate: '
{{grid.appScope.formatTimeSub(row.entity.startDatetime)}}
'}, - {field: 'endDatetime', displayName: 'End Date/Time', width: '*', - cellTemplate: '
{{grid.appScope.formatTimeSub(row.entity.endDatetime)}}
'}, - {field: 'frequency', displayName: 'Frequency', width: '*'}, - {field: 'maxExecutions', displayName: 'Max Executions', width: '*'}, - {field: 'currentExecutionCount', displayName: 'Current Count', width: '*'}, - {field: 'lastRun', displayName: 'Last Ran', width: '*', - cellTemplate: '
{{grid.appScope.formatTimeSub(row.entity.lastRun)}}
'}, - {field: 'executionStatus', displayName: 'Status', width: '*', - cellTemplate: 'main/script-bank/cell-templates/script-sched-status.html'}, - {field: 'id', displayName: '', width: '100', enableColumnMenu: false, enableFiltering: false, enableHiding: false, - cellTemplate: 'main/script-bank/cell-templates/script-sched-actions.html'}, - ] - }; - } - }); - - $scope.scriptGrid = { - data: 'scripts', - expandableRowTemplate:'
', - expandableRowScope: { - Constants : $scope.Constants, - formatTimeSub : function(value) { - if (value === null || value === undefined || value === 0) { - return 'None'; - } - return $scope.formatTime(value); - }, - deleteSchedule: function(entity) { - $scope.deleteSchedule(entity); - }, - formatStatus: function(entity) { - return $scope.formatScriptStatus(entity); - }, - viewStatus: function(entity) { - $scope.viewScriptStatus(entity); - } - }, - paginationPageSizes: [25, 50, 75, 100, 125, 150, 175, 200], - paginationPageSize: 25, - enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER, - toggleModifierKeysToMultiSelect : true, - enableRowHeaderSelection: true, - enableColumnMenus: true, - enableGridMenu: true, - exporterMenuCsv: true, - multiSelect: false, - noUnselect: false, - onRegisterApi: function (gridApi) { - $scope.scriptGridApi = gridApi; - }, - columnDefs: [ - {field: 'name', displayName: 'Name', width: '*'}, - {field: 'command', displayName: 'Command', width: '**' }, - {field: 'parameters', displayName: 'Parameters', width: '**', - cellTemplate: '
{{grid.appScope.formatParameters(row.entity.parameters)}}
'}, - {field: 'schedule', displayName: 'Schedule Count', width: '*', - cellTemplate: '
{{row.entity.schedule.length}}
'}, - {field: 'id', displayName: 'Actions', width: '125', enableColumnMenu: false, enableFiltering: false, enableHiding: false, - cellTemplate: 'main/script-bank/cell-templates/script-actions.html' - } - ], - }; - - $scope.formatScriptStatus = function(entity) { - if (entity.currentExecutionCount === null) { - return 'Not Ran'; - } - - if (entity.executionStatus !== 0) { - return 'Failed'; - } - - return 'Success'; - }; - - $scope.formatParameters = function(parameters) { - var params = ''; - - for (var i = 0; i < parameters.length; i++) { - params += parameters[i].parameter + ' '; - } - return params; - }; - - $scope.formatTime = function(value) { - return moment(value).format('MMM D, YYYY hh:mm:ss A'); - }; - - $scope.run = function(entity) { - portalUtils.confirmBox('run', 'Run Script', ['Are you sure you want to manually run the script', entity.name], - true, function(value) { - if (value.confirm) { - $scope.confirmQuestionBox = !value.checkbox; - $scope.runScript(entity); - } - }); - }; - - $scope.runScript = function(entity) { - scriptProvider.runScript(entity).then(function() { - portalUtils.toast('Script scheduled to run', ['top', 'left'], 2000); - }, function(err){ - portalUtils.toast('Unable to run script: ' + err.message, ['top', 'left'], 4000); - new scriptStores.Scripts().refresh(); - }); - }; - - $scope.deleteSchedule = function(entity) { - portalUtils.confirmBox('deleteSched', 'Delete Schedule', ['Are you sure you want to delete the schedule', entity.jobId], - false, function(value) { - if (value.confirm) { - $scope.deleteSched(entity); - } - }); - }; - - $scope.deleteSched = function(entity) { - scriptProvider.deleteScriptSchedule(entity).then(function(){ - portalUtils.toast('Script schedule deleted successfully', ['top', 'left'], 2000); - }, function(err){ - portalUtils.toast('Unable to delete script : ' + err.message, ['top', 'left'], 4000); - }); - }; - - $scope.delete = function(entity) { - if ($scope.confirmQuestionBox) { - portalUtils.confirmBox('deleteScript', 'Delete Script', ['Are you sure you want to delete the script', entity.name], - true, function(value) { - if (value.confirm) { - $scope.confirmQuestionBox = !value.checkbox; - $scope.deleteScript(entity); - } - }); - } else { - $scope.deleteScript(entity); - } - }; - - $scope.deleteScript = function(entity) { - scriptProvider.deleteScript(entity).then(function() { - portalUtils.toast('Script deleted successfully', ['top', 'left'], 2000); - },function(err){ - portalUtils.toast('Unable to delete script: ' + err.message, ['top', 'left'], 4000); - }); - }; - - $scope.edit = function(entity) { - $mdDialog.show({ - templateUrl: 'common/partials/add-script/add-script.html', - controller: 'AddScriptCtrl', - escapeToClose: false, - locals: { - modalInstance: { - header: 'Edit Script', - script: entity - } - } - }); - }; - - $scope.addScript = function() { - $mdDialog.show({ - templateUrl: 'common/partials/add-script/add-script.html', - controller: 'AddScriptCtrl', - escapeToClose: false, - locals: { - modalInstance: { - header: 'Add New Script', - } - } - }); - }; - - $scope.viewScriptStatus = function(entity) { - $mdDialog.show({ - templateUrl: 'common/partials/script-status/view-script-status.html', - controller: 'ScriptStatusCtrl', - escapeToClose: false, - locals: { - modalInstance: { - jobId: entity.jobId, - header: 'Script Status' - } - } - }); - }; - - $scope.toggleFiltering = function() { - $scope.scriptGrid.enableFiltering = !$scope.scriptGrid.enableFiltering; - $scope.scriptGridApi.core.notifyDataChange( uiGridConstants.dataChange.COLUMN ); - }; - - $scope.$on('$destroy', function () { - $scope.mCache.unlisten(); - }); - - } //end ScriptBankCtrlController function - -})(); \ No newline at end of file diff --git a/portal_client/app/main/user-bank/cell-templates/user-actions.html b/portal_client/app/main/user-bank/cell-templates/user-actions.html deleted file mode 100644 index 3384f36..0000000 --- a/portal_client/app/main/user-bank/cell-templates/user-actions.html +++ /dev/null @@ -1,12 +0,0 @@ -
- - edit - Edit User - - - - delete - Delete User - - -
\ No newline at end of file diff --git a/portal_client/app/main/user-bank/user-bank.html b/portal_client/app/main/user-bank/user-bank.html deleted file mode 100644 index 6eaa38b..0000000 --- a/portal_client/app/main/user-bank/user-bank.html +++ /dev/null @@ -1,21 +0,0 @@ -
- - - -
- Users - - - filter - Filter Users - - - person_add - Add User - -
-
-
-
-
-
\ No newline at end of file diff --git a/portal_client/app/main/user-bank/user-bank.js b/portal_client/app/main/user-bank/user-bank.js deleted file mode 100644 index 0ff1406..0000000 --- a/portal_client/app/main/user-bank/user-bank.js +++ /dev/null @@ -1,126 +0,0 @@ -(function () { - 'use strict'; - - /** - * MODULE DESCRIPTION: - * - * TODO: Write description here. - */ - angular.module('portal.dashboard.userBank', ['ui.router']) - .controller('UserBankCtrl', UserBankCtrlController); - - function UserBankCtrlController($scope, cache, accountStores, accountProvider, $mdDialog, uiGridConstants, portalUtils, Constants) { - - $scope.confirmQuestionBox = true; - $scope.Constants = Constants; - $scope.users = []; - - $scope.mCache = cache.request([new accountStores.Account(), new accountStores.UserPool()]).then(function(){ - $scope.userRole = $scope.mCache.account.data.role; - $scope.users = $scope.mCache.userPool.data.values; - }); - - $scope.userGrid = { - data: 'users', - paginationPageSizes: [28, 56, 84, 102], - paginationPageSize: 28, - enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER, - toggleModifierKeysToMultiSelect : true, - enableRowHeaderSelection: true, - enableColumnMenus: true, - enableGridMenu: true, - exporterCsvFilename: 'Files.csv', - exporterMenuCsv: true, - multiSelect: true, - noUnselect: false, - onRegisterApi: function (gridApi) { - gridApi.selection.setModifierKeysToMultiSelect(true); - $scope.userGridApi = gridApi; - }, - columnDefs: [ - {field: 'username', displayName: 'User Name', width: '*'}, - {field: 'firstName', displayName: 'First Name', width: '*', }, - {field: 'lastName', displayName: 'Last Name', width: '**'}, - {field: 'role', displayName: 'Role', width: '**' }, - {field: 'id', displayName: 'Actions', width: '100', enableColumnMenu: false, enableFiltering: false, enableHiding: false, - cellTemplate: 'main/user-bank/cell-templates/user-actions.html'} - ], - }; - - - $scope.$on('$destroy', function () { - $scope.mCache.unlisten(); - }); - - $scope.toggleFiltering = function() { - $scope.userGrid.enableFiltering = !$scope.userGrid.enableFiltering; - $scope.userGridApi.core.notifyDataChange( uiGridConstants.dataChange.COLUMN ); - }; - - var originatorEv; - $scope.openMenu = function($mdOpenMenu, ev) { - originatorEv = ev; - $mdOpenMenu(ev); - }; - - $scope.delete = function(entity) { - if ($scope.confirmQuestionBox) { - portalUtils.confirmBox('deleteUser', 'Delete User', ['Are you sure you want to delete the user', entity.email], - true, function(value) { - if (value.confirm) { - $scope.confirmQuestionBox = !value.checkbox; - $scope.deleteUser(entity); - } - }); - } else { - $scope.deleteUser(entity); - } - - }; - - $scope.deleteUser = function(entity) { - accountProvider.deleteUser(entity).then(function() { - portalUtils.toast('User deleted successfully', ['top', 'left'], 2000); - new accountStores.UserPool().refresh(); - }).catch(function(err){ - portalUtils.toast('Unable to delete user: ' + err.message, ['top', 'left'], 4000); - new accountStores.UserPool().refresh(); - }); - }; - - $scope.edit = function(entity) { - $mdDialog.show({ - templateUrl: 'common/partials/add-user/add-user.html', - controller: 'AddUserCtrl', - escapeToClose: false, - locals: { - modalInstance: { - header: 'Edit User', - account: entity, - requirePassword: false, - } - } - }).then(function(){ - new accountStores.UserPool().refresh(); - }); - }; - - $scope.addUser = function() { - $mdDialog.show({ - templateUrl: 'common/partials/add-user/add-user.html', - controller: 'AddUserCtrl', - escapeToClose: false, - locals: { - modalInstance: { - header: 'Add User', - requirePassword: true - } - } - }).then(function(){ - new accountStores.UserPool().refresh(); - }); - }; - - } //end RepoBankCtrlController function - -})(); \ No newline at end of file diff --git a/portal_client/assets.js b/portal_client/assets.js deleted file mode 100644 index 8686a52..0000000 --- a/portal_client/assets.js +++ /dev/null @@ -1,57 +0,0 @@ -//File containing all the 3rd party css/js/font that need to be packaged with the application -const CSS = [ - 'bootstrap/dist/css/bootstrap.min.css', - 'jquery-ui-dist/jquery-ui.min.css', - 'jquery-ui-dist/jquery-ui.theme.min.css', - 'angular-material/angular-material.min.css', - 'angular-ui-grid/ui-grid.min.css', - 'ng-material-datetimepicker/dist/material-datetimepicker.min.css', - 'tinymce/skins/lightgray/content.min.css', - 'tinymce/skins/lightgray/skin.min.css' -]; - -const JS = [ - 'jquery/dist/jquery.min.js', - 'jquery-ui-dist/jquery-ui.min.js', - 'underscore/underscore-min.js', - 'moment/min/moment.min.js', - 'angular/angular.min.js', - 'angular-animate/angular-animate.min.js', - 'angular-sanitize/angular-sanitize.min.js', - '@uirouter/angularjs/release/angular-ui-router.min.js', - 'angular-resource/angular-resource.min.js', - 'angular-bootstrap/ui-bootstrap-tpls.min.js', - 'angular-aria/angular-aria.min.js', - 'angular-material/angular-material.min.js', - 'angular-messages/angular-messages.min.js', - 'angular-cookies/angular-cookies.min.js', - 'ng-debounce/dist/ng-debounce.js', - 'angular-ui-grid/ui-grid.min.js', - 'PubSub/dist/pubsub.min.js', - 'sockjs-client/dist/sockjs.min.js', - 'stomp-websocket-js/lib/stomp.js', - 'ng-material-datetimepicker/dist/angular-material-datetimepicker.min.js', - 'tinymce/tinymce.min.js', - 'tinymce/jquery.tinymce.min.js', - 'tinymce/themes/modern/theme.min.js', - 'angular-ui-tinymce/dist/tinymce.min.js' -]; - -const FONTS = [ - 'bootstrap/dist/fonts/glyphicons-halflings-regular.eot', - 'bootstrap/dist/fonts/glyphicons-halflings-regular.svg', - 'bootstrap/dist/fonts/glyphicons-halflings-regular.ttf', - 'bootstrap/dist/fonts/glyphicons-halflings-regular.woff', - 'bootstrap/dist/fonts/glyphicons-halflings-regular.woff2', - 'angular-ui-grid/fonts/ui-grid.eot', - 'angular-ui-grid/fonts/ui-grid.svg', - 'angular-ui-grid/fonts/ui-grid.ttf', - 'angular-ui-grid/fonts/ui-grid.woff', - 'tinymce/skins/lightgray/fonts/tinymce.eot', - 'tinymce/skins/lightgray/fonts/tinymce.svg', - 'tinymce/skins/lightgray/fonts/tinymce.ttf', - 'tinymce/skins/lightgray/fonts/tinymce.woff' -]; - - -module.exports =[...JS, ...CSS, ...FONTS]; \ No newline at end of file diff --git a/portal_client/index.html b/portal_client/index.html deleted file mode 100644 index 97c2bec..0000000 --- a/portal_client/index.html +++ /dev/null @@ -1,125 +0,0 @@ - - - - NGAS Portal - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- -
-
- - \ No newline at end of file diff --git a/portal_client/package-lock.json b/portal_client/package-lock.json new file mode 100644 index 0000000..5244063 --- /dev/null +++ b/portal_client/package-lock.json @@ -0,0 +1,8125 @@ +{ + "name": "portal-client", + "version": "1.0.0-RELEASE", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "portal-client", + "version": "1.0.0-RELEASE", + "dependencies": { + "@angular/cdk": "^22.1.5", + "@angular/common": "^22.1.0", + "@angular/compiler": "^22.1.0", + "@angular/core": "^22.1.0", + "@angular/forms": "^22.1.0", + "@angular/material": "^22.1.5", + "@angular/platform-browser": "^22.1.0", + "@angular/router": "^22.1.0", + "@stomp/stompjs": "^7.3.0", + "rxjs": "~7.8.0", + "sockjs-client": "^1.6.1", + "tslib": "^2.3.0" + }, + "devDependencies": { + "@angular/build": "^22.1.7", + "@angular/cli": "^22.1.7", + "@angular/compiler-cli": "^22.1.0", + "@types/sockjs-client": "^1.5.4", + "jsdom": "^28.0.0", + "prettier": "^3.8.1", + "typescript": "~6.0.2", + "vitest": "^4.0.8" + } + }, + "node_modules/@acemir/cssom": { + "version": "0.9.31", + "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.31.tgz", + "integrity": "sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@angular-devkit/architect": { + "version": "0.2201.7", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2201.7.tgz", + "integrity": "sha512-qffChB0+3WuLcwDk9gx3p/Vl3zYJDomweui5zsLESDMzvJ8zsbKRkgohTieOngajx+XBsklp0gKcxjiVn4NvWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "22.1.7", + "rxjs": "7.8.2" + }, + "bin": { + "architect": "bin/cli.js" + }, + "engines": { + "node": "^22.22.3 || ^24.15.0 || >=26.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/core": { + "version": "22.1.7", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-22.1.7.tgz", + "integrity": "sha512-RKayeOOjhcIe/iBOM1fmtI5pjXwBEJh+u55VnSeIwYvFNXyxI0/jdRw4T6uhwusQ+1bzyya4d8q1mT9oaOQ/5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.20.0", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.5", + "rxjs": "7.8.2", + "source-map": "0.7.6" + }, + "engines": { + "node": "^22.22.3 || ^24.15.0 || >=26.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^5.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/schematics": { + "version": "22.1.7", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-22.1.7.tgz", + "integrity": "sha512-KOcVeT4MCsoPt6AMnXH7AbWZnzlKXhMyua2ITWij4UbLaNWCDwfIug/xrZssYLHUFwebCIqsR8iuG/BPH8Cz2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "22.1.7", + "jsonc-parser": "3.3.1", + "magic-string": "1.0.0", + "ora": "9.4.1", + "rxjs": "7.8.2" + }, + "engines": { + "node": "^22.22.3 || ^24.15.0 || >=26.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/build": { + "version": "22.1.7", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-22.1.7.tgz", + "integrity": "sha512-YNZL3R2YS1qZud9zbJfW3ZSeEB0xAURBJEE0cf7WRCCwkn7NFlH7xXLW/zR+WRBwtcCBRsLrM2/ix3Y8FoKX9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "2.3.0", + "@angular-devkit/architect": "0.2201.7", + "@babel/core": "8.0.1", + "@babel/helper-annotate-as-pure": "8.0.0", + "@babel/helper-split-export-declaration": "7.24.7", + "@inquirer/confirm": "6.1.1", + "@vitejs/plugin-basic-ssl": "2.3.0", + "beasties": "0.4.3", + "browserslist": "^4.26.0", + "esbuild": "0.28.2", + "https-proxy-agent": "9.1.0", + "jsonc-parser": "3.3.1", + "listr2": "11.0.0", + "magic-string": "1.0.0", + "mrmime": "2.0.1", + "oxc-parser": "0.142.0", + "parse5-html-rewriting-stream": "8.0.1", + "picomatch": "4.0.5", + "piscina": "5.2.0", + "rolldown": "1.2.0", + "sass": "1.101.0", + "semver": "7.8.5", + "source-map-support": "0.5.21", + "tinyglobby": "0.2.17", + "vite": "8.1.5", + "watchpack": "2.5.2" + }, + "engines": { + "node": "^22.22.3 || ^24.15.0 || >=26.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "optionalDependencies": { + "lmdb": "3.5.6" + }, + "peerDependencies": { + "@angular/compiler": "^22.0.0", + "@angular/compiler-cli": "^22.0.0", + "@angular/core": "^22.0.0", + "@angular/localize": "^22.0.0", + "@angular/platform-browser": "^22.0.0", + "@angular/platform-server": "^22.0.0", + "@angular/service-worker": "^22.0.0", + "@angular/ssr": "^22.1.7", + "istanbul-lib-instrument": "^6.0.0", + "karma": "^6.4.0", + "less": "^4.2.0", + "ng-packagr": "^22.0.0", + "postcss": "^8.4.0", + "rollup": "^4.0.0", + "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0", + "tslib": "^2.3.0", + "typescript": ">=6.0 <6.1", + "vitest": "^4.0.8" + }, + "peerDependenciesMeta": { + "@angular/core": { + "optional": true + }, + "@angular/localize": { + "optional": true + }, + "@angular/platform-browser": { + "optional": true + }, + "@angular/platform-server": { + "optional": true + }, + "@angular/service-worker": { + "optional": true + }, + "@angular/ssr": { + "optional": true + }, + "istanbul-lib-instrument": { + "optional": true + }, + "karma": { + "optional": true + }, + "less": { + "optional": true + }, + "ng-packagr": { + "optional": true + }, + "postcss": { + "optional": true + }, + "rollup": { + "optional": true + }, + "tailwindcss": { + "optional": true + }, + "vitest": { + "optional": true + } + } + }, + "node_modules/@angular/cdk": { + "version": "22.1.5", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-22.1.5.tgz", + "integrity": "sha512-1tYAeI5KKIqNGNvyDuMM0Drs2FU3M4B25Q1BlAnwtZe3wvrpVETAGXgHaBX3Hs/pvWfgMNwgbcHkxlKVUBNXMA==", + "license": "MIT", + "dependencies": { + "parse5": "^8.0.0", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": "^22.0.0 || ^23.0.0", + "@angular/core": "^22.0.0 || ^23.0.0", + "@angular/forms": "^22.0.0 || ^23.0.0", + "@angular/platform-browser": "^22.0.0 || ^23.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/cli": { + "version": "22.1.7", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-22.1.7.tgz", + "integrity": "sha512-dsOAAPHTXSrTvH5jIdZsFhqmcrTU9+aLXPSYSkQ1afMxPUT/JDjWH228xURYmCaM3ml0vVaT9R2p7/FrS7CJmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/architect": "0.2201.7", + "@angular-devkit/core": "22.1.7", + "@angular-devkit/schematics": "22.1.7", + "@inquirer/prompts": "8.5.2", + "@listr2/prompt-adapter-inquirer": "4.2.5", + "@modelcontextprotocol/sdk": "1.30.0", + "@schematics/angular": "22.1.7", + "jsonc-parser": "3.3.1", + "listr2": "11.0.0", + "npm-package-arg": "14.0.0", + "parse5-html-rewriting-stream": "8.0.1", + "semver": "7.8.5", + "yargs": "18.1.0", + "zod": "4.4.3" + }, + "bin": { + "ng": "bin/ng.js" + }, + "engines": { + "node": "^22.22.3 || ^24.15.0 || >=26.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/common": { + "version": "22.1.5", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-22.1.5.tgz", + "integrity": "sha512-KgB+MTDotlTn67YK4sCTNFLja+G+EMCqHo5bB1cvRKw7Gd9AtAi5kgDmYzMk7ftJ9qJ2O30zXR56Hpw37J2CTQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^22.22.3 || ^24.15.0 || >=26.0.0" + }, + "peerDependencies": { + "@angular/core": "22.1.5", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/compiler": { + "version": "22.1.5", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-22.1.5.tgz", + "integrity": "sha512-GvM0oNCuI09Up5Lk0ZQCX5yA2cGyHYB/rZsa/EGTnzwuxgLDlhOOa19QaVaoxDCo9vO43Ix9rG7SLppEv+qd1w==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^22.22.3 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@angular/compiler-cli": { + "version": "22.1.5", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-22.1.5.tgz", + "integrity": "sha512-XyeLlCqngUiZK8EMQo2DFfDxDoFdlsOe98eK7++N9Cs7qETTaMM3mu8iZbT2o6KhEwzjabW+mqipts1/ecEhyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "8.0.1", + "@jridgewell/sourcemap-codec": "^1.4.14", + "chokidar": "^5.0.0", + "convert-source-map": "^1.5.1", + "reflect-metadata": "^0.2.0", + "semver": "^7.0.0", + "tslib": "^2.3.0", + "yargs": "^18.0.0" + }, + "bin": { + "ng-xi18n": "bundles/src/bin/ng_xi18n.js", + "ngc": "bundles/src/bin/ngc.js" + }, + "engines": { + "node": "^22.22.3 || ^24.15.0 || >=26.0.0" + }, + "peerDependencies": { + "@angular/compiler": "22.1.5", + "typescript": ">=6.0 <6.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@angular/core": { + "version": "22.1.5", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-22.1.5.tgz", + "integrity": "sha512-uiL+xVL4264NEuc3E5ILd6meSv9I4Xt82VQHvYlAVYlcjHlWY49yVe0/apzncUOGxUKzvK8/GDbyFEH7WfJYFw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^22.22.3 || ^24.15.0 || >=26.0.0" + }, + "peerDependencies": { + "@angular/compiler": "22.1.5", + "rxjs": "^6.5.3 || ^7.4.0", + "zone.js": "~0.15.0 || ~0.16.0" + }, + "peerDependenciesMeta": { + "@angular/compiler": { + "optional": true + }, + "zone.js": { + "optional": true + } + } + }, + "node_modules/@angular/forms": { + "version": "22.1.5", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-22.1.5.tgz", + "integrity": "sha512-E7pDEKtSvO1MNw222ZcvphzT4GAQ9D725v2Rq7ft8orT2qvHS6RlVnEc5ioPDhYTAD0HmbwDmutxkcuxqc16VA==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "tslib": "^2.3.0", + "zod": "^4.0.10" + }, + "engines": { + "node": "^22.22.3 || ^24.15.0 || >=26.0.0" + }, + "peerDependencies": { + "@angular/common": "22.1.5", + "@angular/core": "22.1.5", + "@angular/platform-browser": "22.1.5", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/material": { + "version": "22.1.5", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-22.1.5.tgz", + "integrity": "sha512-CeXPascggzu5w0xKETYVQhxlyYU+Vcj/DCY4JdND2veRr6/bmPM8uA/xY4jEvsFccz3HQ9OrkY+V+sNai2h++g==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/cdk": "22.1.5", + "@angular/common": "^22.0.0 || ^23.0.0", + "@angular/core": "^22.0.0 || ^23.0.0", + "@angular/forms": "^22.0.0 || ^23.0.0", + "@angular/platform-browser": "^22.0.0 || ^23.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/platform-browser": { + "version": "22.1.5", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-22.1.5.tgz", + "integrity": "sha512-xRX7TvHzFcur5bhZUqT7QPkezcSuWRzcltcsrqh3UsZnEJ2p+olilFyLq5yAneO13hffNifFkxngoSxVwKwnHw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^22.22.3 || ^24.15.0 || >=26.0.0" + }, + "peerDependencies": { + "@angular/animations": "22.1.5", + "@angular/common": "22.1.5", + "@angular/core": "22.1.5" + }, + "peerDependenciesMeta": { + "@angular/animations": { + "optional": true + } + } + }, + "node_modules/@angular/router": { + "version": "22.1.5", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-22.1.5.tgz", + "integrity": "sha512-RYgL2iTGpMFcqZtXjcjxGVqGraDfOdk/epbLK8z/vy5cI+W2uVdiu5ait7xhv82KoaWT8lUU3sDc4jdI17qHcg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^22.22.3 || ^24.15.0 || >=26.0.0" + }, + "peerDependencies": { + "@angular/common": "22.1.5", + "@angular/core": "22.1.5", + "@angular/platform-browser": "22.1.5", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@asamuzakjp/css-color": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.11.tgz", + "integrity": "sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@csstools/css-calc": "^3.2.0", + "@csstools/css-color-parser": "^4.1.0", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/dom-selector": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.8.1.tgz", + "integrity": "sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/nwsapi": "^2.3.9", + "bidi-js": "^1.0.3", + "css-tree": "^3.1.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.2.6" + } + }, + "node_modules/@asamuzakjp/generational-cache": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/generational-cache/-/generational-cache-1.0.1.tgz", + "integrity": "sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/nwsapi": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", + "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/code-frame": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-8.0.0.tgz", + "integrity": "sha512-dYYg153EyN2Ekbqw2zAsbd6/JR+9N2SEoC7YV2GyyqMM7x9bLDTjBD6XBhSMLH0wtIVyJj03jWNriQhaN+eoCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^8.0.0", + "js-tokens": "^10.0.0" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-8.0.0.tgz", + "integrity": "sha512-DOjnob/cXOUgDOozCDeq/aK2p5y8dUIVdf6tNhEV1HQRd6I8aQ4f4fbtHRVEvb6lP3BGomrKHiS8ICAASSVQSw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/core": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-8.0.1.tgz", + "integrity": "sha512-5FgxM4dLQpMJHSiVATk8foW263dVHQHBVpXYiimNECVWG01f4nFyEbQixeT6Mwvg7TayREJ2gpKl3o2RoMdnqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^8.0.0", + "@babel/generator": "^8.0.0", + "@babel/helper-compilation-targets": "^8.0.0", + "@babel/helpers": "^8.0.0", + "@babel/parser": "^8.0.0", + "@babel/template": "^8.0.0", + "@babel/traverse": "^8.0.0", + "@babel/types": "^8.0.0", + "@types/gensync": "^1.0.5", + "convert-source-map": "^2.0.0", + "empathic": "^2.0.1", + "gensync": "^1.0.0-beta.2", + "import-meta-resolve": "^4.2.0", + "json5": "^2.2.3", + "obug": "^2.1.1", + "semver": "^7.7.3" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/generator": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-8.0.0.tgz", + "integrity": "sha512-NT9NrVwJsbSV6Y2FSstWa71EETOnzrjkL5/wX3D2mYHtKM+qvqB1DvR4D0Setb/gDBsHzRICifwEWMO8CnTF6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^8.0.0", + "@babel/types": "^8.0.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "@types/jsesc": "^2.5.0", + "jsesc": "^3.0.2" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-8.0.0.tgz", + "integrity": "sha512-NSpMkMsvvZqzThJ0p1B02cbtA2ObEyfBvq950bmNkyxsxvcxwhvvCB036rKhlEnuBBo30bOrk13u3FzlKSoRrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^8.0.0" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-8.0.0.tgz", + "integrity": "sha512-JwculLABZvyPvyLBpwU/E/IbH2uM3mnxNtIJpxnIfb24y1PrdVxK5Dqjle4DpgqpGRnwgC7G8IkzPdSXZrO1Ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^8.0.0", + "@babel/helper-validator-option": "^8.0.0", + "browserslist": "^4.24.0", + "lru-cache": "^11.0.0", + "semver": "^7.7.3" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-8.0.0.tgz", + "integrity": "sha512-lLozHOM6sWWlxNo8CYqHy4MBZeTvHXNgVPBfPOGsjPKUzHC2Az9QwB6gxdQmpwHl6GlQtbGgS+lj5887guDiLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration/node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration/node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration/node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0.tgz", + "integrity": "sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz", + "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-8.0.0.tgz", + "integrity": "sha512-U4Dybxh4WESWHt5XhBeExi4DrY0/DNK1aHpQbsrQXCUbFHuMweT0TpLEWKvaraV2Y6fS+ZXunsZ8zIuZIgvF2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/helpers": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-8.0.0.tgz", + "integrity": "sha512-wfbi91pM3py96oIiJEz7qIpyXDytgr9zQC1HEWwlGNVRAEmItuU/0a41ZUKu1sJGyhhOIpc4t5vk4PYzt8wpsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^8.0.0", + "@babel/types": "^8.0.0" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/parser": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.4.tgz", + "integrity": "sha512-srpptsAkEbbNIC/q8nT7o+m6CQe8CJUTV/t7MYc9NnWlgYVtHOb7JH6SorxMhN0kuRJjVqXbKClG6xSbPtzz+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^8.0.4" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/template": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-8.0.0.tgz", + "integrity": "sha512-eAD0QW/AlbamBbw0FeGiwasbCVPq5ncW0HNVyLP3B9czqLyh4gvw+5JTSNt6le9+ziAU7mqDZsKTHf3jTb4chQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^8.0.0", + "@babel/parser": "^8.0.0", + "@babel/types": "^8.0.0" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/traverse": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-8.0.4.tgz", + "integrity": "sha512-bZnmqzGG8UZneG1lLxBoWIH0G6Gr1D846Yu4/3XnY6FhCndMR49u26nTY08u/dAxWmLWF9vGQOuC+84FfIUoeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^8.0.0", + "@babel/generator": "^8.0.0", + "@babel/helper-globals": "^8.0.0", + "@babel/parser": "^8.0.4", + "@babel/template": "^8.0.0", + "@babel/types": "^8.0.4", + "obug": "^2.1.1" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/types": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.4.tgz", + "integrity": "sha512-eY+Yn3dCqTGmyiq2QRU66lA5FL8lqqqvecHt0fF3uHONIa7ToYsaCiWV8lOKqAs0Rb2SjixiKFROngnulPtt2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^8.0.0", + "@babel/helper-validator-identifier": "^8.0.4" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@bramus/specificity": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^3.0.0" + }, + "bin": { + "specificity": "bin/cli.js" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.1.1.tgz", + "integrity": "sha512-gLNsunvwf3mCi5u5o46/Z/JcJMnhbHSaZ69rkgPzNM3J4s8hWwpPUQB6/tt0EDFyCiWzxANlx+2LJwpYj4zS1w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@csstools/css-calc": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.3.0.tgz", + "integrity": "sha512-c5ihYsPkdG6JCkU2zTMm4+k6r7RXuGxtWYhu5DHMIiF1FHzrfmHL5so11AoFpUv/tu61xfcmT4AmKoFfMPoqdQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.2.2.tgz", + "integrity": "sha512-3QKjR/vxyjcSXBLgb6lP0S3MGdvwbmqSsvLPbYdVORqPDc8FX1HAJ0Spk38bxaRXgvENTA47tlhhbb5Z2e8hEg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^6.1.1", + "@csstools/css-calc": "^3.3.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.12.tgz", + "integrity": "sha512-3vLQK+dXxhBMR2Wx99PTCifE+vHtW2ndZWyla8yK813ev6oGhyn8Lja8jCyGAWTJ+LEYZK7EVtJxrDj8ztevJw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@exodus/bytes": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.1.tgz", + "integrity": "sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, + "node_modules/@harperfast/extended-iterable": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@harperfast/extended-iterable/-/extended-iterable-1.0.3.tgz", + "integrity": "sha512-sSAYhQca3rDWtQUHSAPeO7axFIUJOI6hn1gjRC5APVE1a90tuyT8f5WIgRsFhhWA7htNkju2veB9eWL6YHi/Lw==", + "dev": true, + "license": "Apache-2.0", + "optional": true + }, + "node_modules/@hono/node-server": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-2.1.1.tgz", + "integrity": "sha512-ELuehkj5VCBdgEw9zs+ivkKwyzzUCSQuE96YmiPvn1ECBoZCczbFXJLeEGMTYjphP6gydh4pHMqEYPVMYUVgQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "hono": "^4" + } + }, + "node_modules/@inquirer/ansi": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.8.tgz", + "integrity": "sha512-WpQM+Ti6Z40EFwwt+uL2p4UabT+W179zHp6HhLVOzfbwnVn05IPO/eXIZXGNqcT1jbQ15SujNLzQ39k4QPPxBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + } + }, + "node_modules/@inquirer/checkbox": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.2.4.tgz", + "integrity": "sha512-oKT5RNeO9oKYizSyOxKb66IrKUsYVMQD2tnjllYW4wmSOe9WawfL3OE2p82JuvAyo+/nDIEem5P4Bm/ZIVYVew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.8", + "@inquirer/core": "^12.0.2", + "@inquirer/figures": "^2.0.9", + "@inquirer/type": "4.1.1" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/checkbox/node_modules/@inquirer/core": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.2.tgz", + "integrity": "sha512-9pBhkxE14uUlnHhs8lOt7qVPtS4caRY6CjADl8COejl9Mf7w8i6Uoe3DrljCqYtmYM3Iv2Q6EmPxx/oTYbvTAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.8", + "@inquirer/figures": "^2.0.9", + "@inquirer/type": "4.1.1", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/confirm": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.1.1.tgz", + "integrity": "sha512-eb8DBZcz/2qHWQda4rk2JiQk5h9QV/cVHi1yjt0f69WFZMRFn0sJTye3EAP8icut8UDMjQPsaH5KbcOogefrFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-11.2.1.tgz", + "integrity": "sha512-Qd6GJT1yVyrZZCfN8W2qKF5ApmqryXRhRKCuip8h01x2w/esJQ2XIYc6f9abMIHgKQdBfFTSOdbHRLAhuM09UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.7", + "@inquirer/figures": "^2.0.7", + "@inquirer/type": "^4.0.7", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/editor": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.3.2.tgz", + "integrity": "sha512-7ruKO5d/wxhGHxdCQ3eyP/aBNrPTZ+Ju7ERtnAwuIsu0RSLs6kotlTRkOxHatbD6sDaEEdwsD82pzFiT9ESIyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^12.0.2", + "@inquirer/external-editor": "^3.0.5", + "@inquirer/type": "4.1.1" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/editor/node_modules/@inquirer/core": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.2.tgz", + "integrity": "sha512-9pBhkxE14uUlnHhs8lOt7qVPtS4caRY6CjADl8COejl9Mf7w8i6Uoe3DrljCqYtmYM3Iv2Q6EmPxx/oTYbvTAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.8", + "@inquirer/figures": "^2.0.9", + "@inquirer/type": "4.1.1", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/expand": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.1.4.tgz", + "integrity": "sha512-12o4aYnjWouoq0fyVhYIL+hwXAaga+kntA/wrijFmVvn2heinkdvkbEXRt1Ob/9IOJ285US5tntjfI/Ukt2YkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^12.0.2", + "@inquirer/type": "4.1.1" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/expand/node_modules/@inquirer/core": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.2.tgz", + "integrity": "sha512-9pBhkxE14uUlnHhs8lOt7qVPtS4caRY6CjADl8COejl9Mf7w8i6Uoe3DrljCqYtmYM3Iv2Q6EmPxx/oTYbvTAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.8", + "@inquirer/figures": "^2.0.9", + "@inquirer/type": "4.1.1", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-3.0.5.tgz", + "integrity": "sha512-f3QQJRIX5ZEneBHNUIuPjmbdzHnmRFJA8r2dkcb8q+OM5Uv5KtnuAttQumnrjcBVBM3mcTX1CkmtAkU58VRZxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.2" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/figures": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.9.tgz", + "integrity": "sha512-EAWgUTGQ/Umgga51dE3B2PUHbufuXarDfg86uVgoSgNHNNQnyFKcOrQLWVqYMghuSyHh8+2HUH0Js9cTC1WAdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + } + }, + "node_modules/@inquirer/input": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.1.5.tgz", + "integrity": "sha512-2MkYYFD1Owt1eRBwHhsLSutysRodWasA4DVpl42KJKGmzwBTXRYAIXujisrt0UW0UohUlMjNjLfMDbw4emRbfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^12.0.2", + "@inquirer/type": "4.1.1" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/input/node_modules/@inquirer/core": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.2.tgz", + "integrity": "sha512-9pBhkxE14uUlnHhs8lOt7qVPtS4caRY6CjADl8COejl9Mf7w8i6Uoe3DrljCqYtmYM3Iv2Q6EmPxx/oTYbvTAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.8", + "@inquirer/figures": "^2.0.9", + "@inquirer/type": "4.1.1", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/number": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.2.2.tgz", + "integrity": "sha512-tjW1gMIQsFb/9Ie11i8SpuPARBdyCVfC5XOeVugWovrdm8CpjzN+A1CBX5QwCCN2mtNmpgDDCnuLCCT94cQ5zA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^12.0.2", + "@inquirer/type": "4.1.1" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/number/node_modules/@inquirer/core": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.2.tgz", + "integrity": "sha512-9pBhkxE14uUlnHhs8lOt7qVPtS4caRY6CjADl8COejl9Mf7w8i6Uoe3DrljCqYtmYM3Iv2Q6EmPxx/oTYbvTAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.8", + "@inquirer/figures": "^2.0.9", + "@inquirer/type": "4.1.1", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/password": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.2.1.tgz", + "integrity": "sha512-InA6nJxMCXPavPBiTKYHIsYiWz/mkIsk1rkI6pKp5w18gVawqrZOj7eSzSmPJa3j0pVxXm6RlrFP1BE9YeOixA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.8", + "@inquirer/core": "^12.0.2", + "@inquirer/type": "4.1.1" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/password/node_modules/@inquirer/core": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.2.tgz", + "integrity": "sha512-9pBhkxE14uUlnHhs8lOt7qVPtS4caRY6CjADl8COejl9Mf7w8i6Uoe3DrljCqYtmYM3Iv2Q6EmPxx/oTYbvTAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.8", + "@inquirer/figures": "^2.0.9", + "@inquirer/type": "4.1.1", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/prompts": { + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.5.2.tgz", + "integrity": "sha512-IYR/3C/paEVVQYQvdDlFZVjRCJVYHHON0XXMH91KO9GSxs0TdKYWlUdvfQl2EfAHDxUaN3IBffkE/BDTh5nJ6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^5.2.1", + "@inquirer/confirm": "^6.1.1", + "@inquirer/editor": "^5.2.2", + "@inquirer/expand": "^5.1.1", + "@inquirer/input": "^5.1.2", + "@inquirer/number": "^4.1.1", + "@inquirer/password": "^5.1.1", + "@inquirer/rawlist": "^5.3.1", + "@inquirer/search": "^4.2.1", + "@inquirer/select": "^5.2.1" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/rawlist": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.3.4.tgz", + "integrity": "sha512-c4fDwOpQsjJDHjXdHJE1/xXH6w9/BAiyu3QKzH9Ww5Xm1q37mzyUNa20L7qdtM1ECi4e+oUEKjhK8hR37OMAMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^12.0.2", + "@inquirer/type": "4.1.1" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/rawlist/node_modules/@inquirer/core": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.2.tgz", + "integrity": "sha512-9pBhkxE14uUlnHhs8lOt7qVPtS4caRY6CjADl8COejl9Mf7w8i6Uoe3DrljCqYtmYM3Iv2Q6EmPxx/oTYbvTAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.8", + "@inquirer/figures": "^2.0.9", + "@inquirer/type": "4.1.1", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.3.2.tgz", + "integrity": "sha512-YIaEhWmfkdHEWOKwhF/oJar35FFTTrAdzNbJDo9lSsRT6E/obRPx9oVm4rkTMtlcJSqGYttNtLbcHQef9Qw2yw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^12.0.2", + "@inquirer/figures": "^2.0.9", + "@inquirer/type": "4.1.1" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search/node_modules/@inquirer/core": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.2.tgz", + "integrity": "sha512-9pBhkxE14uUlnHhs8lOt7qVPtS4caRY6CjADl8COejl9Mf7w8i6Uoe3DrljCqYtmYM3Iv2Q6EmPxx/oTYbvTAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.8", + "@inquirer/figures": "^2.0.9", + "@inquirer/type": "4.1.1", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.2.4.tgz", + "integrity": "sha512-L9ubNaJdoBsiom/AfPKq0QLHTkhhCFCtszzdVidGremrlJjPZfGlmvp+IULKIbnYjtVFWnvb4mhiEdNTZ12ugA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.8", + "@inquirer/core": "^12.0.2", + "@inquirer/figures": "^2.0.9", + "@inquirer/type": "4.1.1" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select/node_modules/@inquirer/core": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.2.tgz", + "integrity": "sha512-9pBhkxE14uUlnHhs8lOt7qVPtS4caRY6CjADl8COejl9Mf7w8i6Uoe3DrljCqYtmYM3Iv2Q6EmPxx/oTYbvTAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.8", + "@inquirer/figures": "^2.0.9", + "@inquirer/type": "4.1.1", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/type": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.1.1.tgz", + "integrity": "sha512-yJoHYrMnxIsJZCY+0Vb66Dy3he3kL3e2wOBKhoSwWWAzZAY82emlxwgprCtp6yRixvNRNq9ztfRWQYPNr3Go7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@listr2/prompt-adapter-inquirer": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-4.2.5.tgz", + "integrity": "sha512-pYGy9dTdTwXdasPgyohkr0HoQ4FrkAzFnsUZl/gcnadDArbpZ8e+fgr+F9WBdNEl2y00mb9bCM4WgmoBkZJ27A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/type": "^4.0.7" + }, + "engines": { + "node": ">=22.13.0" + }, + "peerDependencies": { + "@inquirer/prompts": ">= 3 < 9", + "listr2": "11.0.0" + } + }, + "node_modules/@lmdb/lmdb-darwin-arm64": { + "version": "3.5.6", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.5.6.tgz", + "integrity": "sha512-mY5FG4TjPAkY4P0w+OhHaUka5mDh2TX2WKYIwuKzJ1zeW3VvRgxdam/lGJTquI+bthTx5CSHDW+BAQCnNAzkEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-darwin-x64": { + "version": "3.5.6", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.5.6.tgz", + "integrity": "sha512-foa+pwitysO8k+xhs7psBFfTKnVgR69NlZRRTHaFVDqphh7AdGpLeyRzKw/ofatr/sN6TiHRRW6mmop0ZrrppQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm": { + "version": "3.5.6", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.5.6.tgz", + "integrity": "sha512-QR4YRyR5h5Z8eGXrNQjiyo2NNDfqi3tCc9dQG5Is1blCt+qWw1ZoBWhlWAr5d+jshkifMIJjVHzHGKbkKzF8Tw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm64": { + "version": "3.5.6", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.5.6.tgz", + "integrity": "sha512-HmiyFFdJa38s1heCMSooSPaBSFTHJ3C+ERPp28xAPlDX1YiALJVOgbry065nXd8Y7KISWjnw05zpG1RX8IfftA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-linux-x64": { + "version": "3.5.6", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.5.6.tgz", + "integrity": "sha512-ADzCuCF2cTNiX9kDScqcz1fjnAkxPpQNneV3KFTdV3wWtVlI2sTGzySoMTgDpinkMMFj1NTJlxA6XR8fwc4hlA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-win32-arm64": { + "version": "3.5.6", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-arm64/-/lmdb-win32-arm64-3.5.6.tgz", + "integrity": "sha512-J7A9aEQsQiv0TYtBGL7NDIPp2lOS8nnl+zm4sWZm1xlsTTaQ4PgD096Adzdrk27rw3UxCkDXdCUa4ax41oztBQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@lmdb/lmdb-win32-x64": { + "version": "3.5.6", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.5.6.tgz", + "integrity": "sha512-1g7G0knRX2iV/voDu54yxrGqw5Dk0w2oIYb7dgJq8IkOi+m7wbD8Q3QpPFjh0C01G58S88dqGn03len6UPCXsg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.30.0.tgz", + "integrity": "sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9 || ^2.0.5", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.4.tgz", + "integrity": "sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.4.tgz", + "integrity": "sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.4.tgz", + "integrity": "sha512-Tg3yX65f5GbtXLkrYEHE5oibZG9epyYWas7FogTTEJeDEF9JlXJzKgXaNhT3UXlTOeA+AfZpYZYZ0uPj7Cfquw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.4.tgz", + "integrity": "sha512-dgX0P/9wGPJeHFBG+ZmhgE6bmtMt7NP5CRBGyyktpopdk/mW4POnrpQsSLtKI1dwpc+pPLuXHDh6vvskyQE/sw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.4.tgz", + "integrity": "sha512-8TNXMEjJc3QEy7R/x1INhgiU+XakDAFUzBhaz7+Rbrs8NH5UQeHQxxmzsSBJGyV6I1jW79undiQm8tOI+D+8FQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.4.tgz", + "integrity": "sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@napi-rs/nice": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.1.1.tgz", + "integrity": "sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@napi-rs/nice-android-arm-eabi": "1.1.1", + "@napi-rs/nice-android-arm64": "1.1.1", + "@napi-rs/nice-darwin-arm64": "1.1.1", + "@napi-rs/nice-darwin-x64": "1.1.1", + "@napi-rs/nice-freebsd-x64": "1.1.1", + "@napi-rs/nice-linux-arm-gnueabihf": "1.1.1", + "@napi-rs/nice-linux-arm64-gnu": "1.1.1", + "@napi-rs/nice-linux-arm64-musl": "1.1.1", + "@napi-rs/nice-linux-ppc64-gnu": "1.1.1", + "@napi-rs/nice-linux-riscv64-gnu": "1.1.1", + "@napi-rs/nice-linux-s390x-gnu": "1.1.1", + "@napi-rs/nice-linux-x64-gnu": "1.1.1", + "@napi-rs/nice-linux-x64-musl": "1.1.1", + "@napi-rs/nice-openharmony-arm64": "1.1.1", + "@napi-rs/nice-win32-arm64-msvc": "1.1.1", + "@napi-rs/nice-win32-ia32-msvc": "1.1.1", + "@napi-rs/nice-win32-x64-msvc": "1.1.1" + } + }, + "node_modules/@napi-rs/nice-android-arm-eabi": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.1.1.tgz", + "integrity": "sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-android-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.1.1.tgz", + "integrity": "sha512-blG0i7dXgbInN5urONoUCNf+DUEAavRffrO7fZSeoRMJc5qD+BJeNcpr54msPF6qfDD6kzs9AQJogZvT2KD5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-darwin-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-arm64/-/nice-darwin-arm64-1.1.1.tgz", + "integrity": "sha512-s/E7w45NaLqTGuOjC2p96pct4jRfo61xb9bU1unM/MJ/RFkKlJyJDx7OJI/O0ll/hrfpqKopuAFDV8yo0hfT7A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-darwin-x64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.1.1.tgz", + "integrity": "sha512-dGoEBnVpsdcC+oHHmW1LRK5eiyzLwdgNQq3BmZIav+9/5WTZwBYX7r5ZkQC07Nxd3KHOCkgbHSh4wPkH1N1LiQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-freebsd-x64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.1.1.tgz", + "integrity": "sha512-kHv4kEHAylMYmlNwcQcDtXjklYp4FCf0b05E+0h6nDHsZ+F0bDe04U/tXNOqrx5CmIAth4vwfkjjUmp4c4JktQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm-gnueabihf": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.1.1.tgz", + "integrity": "sha512-E1t7K0efyKXZDoZg1LzCOLxgolxV58HCkaEkEvIYQx12ht2pa8hoBo+4OB3qh7e+QiBlp1SRf+voWUZFxyhyqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.1.1.tgz", + "integrity": "sha512-CIKLA12DTIZlmTaaKhQP88R3Xao+gyJxNWEn04wZwC2wmRapNnxCUZkVwggInMJvtVElA+D4ZzOU5sX4jV+SmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm64-musl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.1.1.tgz", + "integrity": "sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-ppc64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.1.1.tgz", + "integrity": "sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-riscv64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.1.1.tgz", + "integrity": "sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-s390x-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.1.1.tgz", + "integrity": "sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-x64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.1.1.tgz", + "integrity": "sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-x64-musl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.1.1.tgz", + "integrity": "sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-openharmony-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-openharmony-arm64/-/nice-openharmony-arm64-1.1.1.tgz", + "integrity": "sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-arm64-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.1.1.tgz", + "integrity": "sha512-uoTb4eAvM5B2aj/z8j+Nv8OttPf2m+HVx3UjA5jcFxASvNhQriyCQF1OB1lHL43ZhW+VwZlgvjmP5qF3+59atA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-ia32-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.1.1.tgz", + "integrity": "sha512-CNQqlQT9MwuCsg1Vd/oKXiuH+TcsSPJmlAFc5frFyX/KkOh0UpBLEj7aoY656d5UKZQMQFP7vJNa1DNUNORvug==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-x64-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.1.1.tgz", + "integrity": "sha512-vB+4G/jBQCAh0jelMTY3+kgFy00Hlx2f2/1zjMoH821IbplbWZOkLiTYXQkygNTzQJTq5cvwBDgn2ppHD+bglQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.3.tgz", + "integrity": "sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", + "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" + } + }, + "node_modules/@oxc-parser/binding-android-arm-eabi": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm-eabi/-/binding-android-arm-eabi-0.142.0.tgz", + "integrity": "sha512-ZiRGDutGsv1G6bL/ozy/koC0Sv39T1DqyoC4KD1DOy9ZoACm1O5UWhEK2c02Qdk+4lfLVkvFa/mQ0fm/4h1BtQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-android-arm64": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.142.0.tgz", + "integrity": "sha512-WZkvGRLNQTz8lR9zP5nLjUdlroRCopBu3g9zF1p/laE6DzT1UbQo8Rdz5MWhaJUPYg/6gp+jo7HUgsyKaN1FtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-darwin-arm64": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.142.0.tgz", + "integrity": "sha512-l4khS8LQOOVYsGRVARo1gSaCT/aBSceUVXgtovWc2+drnxVuDr082WA3OCHVdVzIz5JIrP/y9CWsSKxBDNmYGg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-darwin-x64": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.142.0.tgz", + "integrity": "sha512-QBsNF3nqlXmcH2B1YOPqQYmCJoy4HuIjUxGbBO/k5JAJUl68ghU2psRY2zPk+RyBaWqKP/qfL4oaFgEMCdwskA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-freebsd-x64": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.142.0.tgz", + "integrity": "sha512-b7Q7m4Cqc6XqNhri3R+QhU+GVy646Pn+bkdhrDdWym/Fdi0ZUa+d73H9dm5H91JtbtAQ/z1d8XKMW3oOV8a4tQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm-gnueabihf": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.142.0.tgz", + "integrity": "sha512-3riVS5IhdH3uCZj1Y9ftDQlR0dvLsIlw/edrRqk8JhgNd5K0XSs+UBtgh50N13CAlW9/TXj6sVGXaKNBocd0Yg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm-musleabihf": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.142.0.tgz", + "integrity": "sha512-NmXUOpgpTSkhl795TiXmWppTwmSJ92RC1qvD6e4XOF+slgmo3e6Ah+kEu+6AN8s7NAOEwqGmir58MgSQSWmBSA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm64-gnu": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.142.0.tgz", + "integrity": "sha512-gc0EXsKtXgerujmU2Bql3u1L1HsSQ2774R83idq/FoNMPVV/RY/1ErFsvnit7KoiP/sLvzQixeUo4Ut0ic0wmw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm64-musl": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.142.0.tgz", + "integrity": "sha512-F2XvmWSE0uWpie+jHKKIFgdVOe9ypGhkEZxKx5DuW215K6cbAC274yYaPkcM7EqY4Df3Weyhpcz3lsURyH2LVg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-ppc64-gnu": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.142.0.tgz", + "integrity": "sha512-wLMbT21U/QxknQsk+VvNF0b9D2/aGWhcaQQQ+VYlE8FwD5+GoWZIPPXNzyHmkYyhm0KB3itL+TBavjMatqNnYA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-riscv64-gnu": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.142.0.tgz", + "integrity": "sha512-+G8F/4ckwT7FCJV4H2bt09xEzJbjNCfuL4Sp1AYNaFtFMVtgIGMuJlteT82U+K0UIZ/DzAR/LDlMFnEuajG7Kw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-riscv64-musl": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.142.0.tgz", + "integrity": "sha512-hTsHtTLxMAfCo+rpF5K3qZJKW2NpPN/CHd4mYB3y7XlSdspHkd2gehDIofP64AacA9nWQw2tY3O7wR6UY8IVOA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-s390x-gnu": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.142.0.tgz", + "integrity": "sha512-6y7qYY3TCUDYjqswImdTGl92y+KA/80twALegQPN27kfY+bG7Ib1+L3jbmrCZQx6wrVnai9IPsEZp07I0hx7JQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-x64-gnu": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.142.0.tgz", + "integrity": "sha512-i69kAWU+2LgoH5bR+zWiiu+UzAw7Oxkwv7COeJTeY19pn4e70nKQcr9Pm6cL2Z0Z54d+gl9qADlK/0yyuCPiBA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-x64-musl": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.142.0.tgz", + "integrity": "sha512-4SQs678MmjYVrmhAgCWD4o0vpaFszXw9xLX5p2Z9MMFcltxiLkA88wQjh80YHjPrXtpyZ2CWI5m+1yNKM0m2Pw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-openharmony-arm64": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-openharmony-arm64/-/binding-openharmony-arm64-0.142.0.tgz", + "integrity": "sha512-YHpx9N7Ln3a++Tc8rv+H7mrK1zyJQOAwCFg8LZ3lTs1T5afGWeZrLPhPT9HLnIwSjCyJqPWVMIrMxbjcmBr2oQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-wasm32-wasi": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.142.0.tgz", + "integrity": "sha512-3pLDyY3+oogW73RM5uehNgAiR/Xfb7fvO2Q1Z1gIqZ2+50XDVQmBVlRkHXZTU4gKnQHpwETNsYQVsJ3joVB2iA==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.2", + "@emnapi/runtime": "1.11.2", + "@napi-rs/wasm-runtime": "^1.1.6" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz", + "integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@oxc-parser/binding-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", + "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@oxc-parser/binding-win32-arm64-msvc": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.142.0.tgz", + "integrity": "sha512-Had/VeVY28Oyb0K+Q4FV8KCzoBycIh93oDK6pCbya9lkzdq+ikMHMgBubsdqqlybjJmQRawCQRrnBRHyQwYvcQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-win32-ia32-msvc": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.142.0.tgz", + "integrity": "sha512-GGi3+YphVHavvgs6gum2UXoNCqzHAmPt/nXkn8ZQZstV2Q1qZD1Mn8fz/nWrDkefHQtrG/+1/XrbMxsBTo6Svw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-win32-x64-msvc": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.142.0.tgz", + "integrity": "sha512-Ny/Wv4Us1LGC/ljwNTp+Hx3r/pH15EFfeDF0p+n898gt+TtRd6C9SccHcuUhDiNTb8s5tt7jdeAMDRQZ4Vq6hg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.142.0.tgz", + "integrity": "sha512-7W+2q5AKQVU36fkaryontrHn3YDt1RyUYXatw9i5H8ocYe2sPKSFB6eS8WNPeRKiN1qAWWZUPm7gwFzJGrccqQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.6.0.tgz", + "integrity": "sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.6.0", + "@parcel/watcher-darwin-arm64": "2.6.0", + "@parcel/watcher-darwin-x64": "2.6.0", + "@parcel/watcher-freebsd-x64": "2.6.0", + "@parcel/watcher-linux-arm-glibc": "2.6.0", + "@parcel/watcher-linux-arm-musl": "2.6.0", + "@parcel/watcher-linux-arm64-glibc": "2.6.0", + "@parcel/watcher-linux-arm64-musl": "2.6.0", + "@parcel/watcher-linux-x64-glibc": "2.6.0", + "@parcel/watcher-linux-x64-musl": "2.6.0", + "@parcel/watcher-win32-arm64": "2.6.0", + "@parcel/watcher-win32-x64": "2.6.0" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.6.0.tgz", + "integrity": "sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.6.0.tgz", + "integrity": "sha512-Y3QV0gl7Q1zbfueunkWIERICbEojQFCgpyG7YqOGNFLsckXyI1xu9mAIUpKY9QBYzBtSkN8dBPwd3yiAO9ovMw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.6.0.tgz", + "integrity": "sha512-Ohv6OpzhUfKYD7Beb8kDvG0jbIxORCYY1JRdZnaBtnjjkJxgD7ZVL0nw2sCYd0yTMKTvz3nnTnOF3cDifK+kvw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.6.0.tgz", + "integrity": "sha512-5HmXvDgs8VK+74jF9y9/2FE3/OnlcKmc56tjmSrEuZjpSZOGL+fvAu+HKJBdPs9uwoP2hE6TlSUpXZ/C5jUFmQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.6.0.tgz", + "integrity": "sha512-Ps/hui3A+vMbjdqlqAowK2ZL8+BO8dBjxeWXj6npTBs3jx4wWmbPpaLuqwrQrSqIVMCnpWo238bJ1U37GhQOYg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.6.0.tgz", + "integrity": "sha512-9c6AUHgHoG+IY88MRIHupztQiQnrbqHYQjkM2btA+Bf/wQnQMuiD0Wfk1EVv3TlNT3x41uU71rn6E4xh/+zvkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.6.0.tgz", + "integrity": "sha512-yHRqS2owEXe6Hic9z6Mh1ECsCd+ODVOGvZDyciqRd21+v+o+DnXMOrw50DSpIG2sb8GPEaPPmfeCAWKPJdq46g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.6.0.tgz", + "integrity": "sha512-WhB2e/V7rqdHHWZusBSPuy5Ei8S6lSz6FE5TKKQz5h3a0O+C+mhY7vxU9b/stqvMb8beLnPY82ZrFTLKs+SrKA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.6.0.tgz", + "integrity": "sha512-ulGE6x6Oz6iAwg75T8YQSoguBWasniIbX+QWpaYPcCnDOpdWX3k+4xbEYPZVLxOuoJI+svJJPD3sEj8G7lrQ3A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.6.0.tgz", + "integrity": "sha512-tkBYKt7YQrjIJWYDnto2YgO8MRkjlMTSNoRHzsXinBqbLdeOM3L32wPZJvIZxqaLMfSlS/4sUjH/6STVP/XDLw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.6.0.tgz", + "integrity": "sha512-gIZAP23jaHjGWasY/TY6yL7NHFClf0Ga7FN+iINvk+KN94rhm94lYZhFsbYFNcA04/onvGD9kKmiJLJB2HbNwQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.6.0.tgz", + "integrity": "sha512-cA+/pXV2YkfxlIcXOQ5fSWqAzzPyD78/x5qbK/I0vUkrlYHA8TIz+MXjAbGouguKVSI4bOmkTSJ1/poVSsgt+A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher/node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.0.tgz", + "integrity": "sha512-9yB1l95IrJuNGDFdOYe79vdApdz6WWBCObE+rQ2LUliYUlcyFwSYIb2xb5/Ifw7dAtMy2ZqNyd8QTSOc7duAKw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.0.tgz", + "integrity": "sha512-pexNaW9ACLUOaBITOpU6qVu4VrsOFIjTv6bzgu0YUATo4eUJx0V605PxwZfndpPOn0ilqGqvGQ0M8UW0IE24jg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.0.tgz", + "integrity": "sha512-NqKYaq0355ZmNMG4QGpxtEDxsc7tGDhjhCm4PpE0cwnBW+5Il95LJyq414niEiaKLVjnVHBEjSo1wngKxJNiFw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.0.tgz", + "integrity": "sha512-3vPoHzh6eBTz9IbB0/qZdSr0Qeks2echn+I4cHu2joV74VriPDdldswksEDzrl1mBB+oPRi+67+3Ib59paxIPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.0.tgz", + "integrity": "sha512-E6NNefZ1bUVmKJq2tJkf45J4Zyczj7qm9rUT7NY+Xo2474Y13qWAwc2tvBt0BAVbmtXR1llkxXg0Ou1jbDf2SQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.0.tgz", + "integrity": "sha512-D+TgkdgM1vu+7/Fpf8+v0ARW+RXEP9Ccazgm8zQ4JFFd9Q7SrYQ2TakU5S5ihazQDgpKyAgZDOcIFsvoHmTZ8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.0.tgz", + "integrity": "sha512-wUqdwJBbAv0APN87GecstdMUtLjjNTs0hBALpxETD73mccFxdmt/XeizXDtN5RAlBwNKmI+Tg+blect2G+8IeQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.0.tgz", + "integrity": "sha512-9DtF35qR9/NrfhM4oxLplCzVVjE+KKm8Pjemi0i/sdhAWkUasjmSo8WTTubNJClhSHCfyk2yeyoXDQEDPtDAAw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.0.tgz", + "integrity": "sha512-RzuHrBh8X8Hntd2N4VR02QGEciq/9JhcZoTpR/Cee6otRrlILGCf3cg2ygHuih+ZebUnWmMrDX6ITI85btO6rQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.0.tgz", + "integrity": "sha512-MK7L0018jjh1jR3mh21G2j1zAVcpscJBlPo2z19pRjv2XOYGRhaV4LyiD8HO6nCDdZln9IFgCMIV5yt4E3klGQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.0.tgz", + "integrity": "sha512-gyrxLQ9NfGb/9LoVnC4kb9miUghw1mghnkfYvNHSnVIXriabnfgGPUP4RLcJm87q3KgYz4FYUG8IDiWUT+CpSw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.0.tgz", + "integrity": "sha512-/6VFMQGRmrhP77KXDC+StIxGzcNp5JOIyYtw0CQ8gPlzhpiIRucYfoM5FaFamHd5BJYIdH86yfP46l1p3WdrFA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.2.0.tgz", + "integrity": "sha512-rwdbUL465kisF24WEJLvP3JrEG6E5GRuIHt5wpMwHGERtHe4Wm2CIvtf5gTBgr2tGOHKh5NdKEAFS2VkOPE91g==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.2", + "@emnapi/runtime": "1.11.2", + "@napi-rs/wasm-runtime": "^1.1.6" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz", + "integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", + "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.0.tgz", + "integrity": "sha512-+5suHwRiKGmhwyUaNT8a5QbrBvLFh2DbO910TEmGRH1aSxwrCezodvGQnulv4uiWEIv1Kq4ypRsJ5+O+ry1DiA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.0.tgz", + "integrity": "sha512-WfFv6/qGufotqBSBzBYwgpCkJBk8Nj7697LL9vTz/XWc67e0r3oewu8iMRwQj3AUL45GVD7wVsPjCsAAtW66Wg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@schematics/angular": { + "version": "22.1.7", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-22.1.7.tgz", + "integrity": "sha512-acBv147JjnwtWFgC8Af0KFBzPpb/TWaYxoWN/Ou3pXtUhYiEqnrdJeoFz3ssDw26eKFIdWnVBLB/dHORBykPBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "22.1.7", + "@angular-devkit/schematics": "22.1.7", + "jsonc-parser": "3.3.1", + "typescript": "6.0.3" + }, + "engines": { + "node": "^22.22.3 || ^24.15.0 || >=26.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/@stomp/stompjs": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@stomp/stompjs/-/stompjs-7.3.0.tgz", + "integrity": "sha512-nKMLoFfJhrQAqkvvKd1vLq/cVBGCMwPRCD0LqW7UT1fecRx9C3GoKEIR2CYwVuErGeZu8w0kFkl2rlhPlqHVgQ==", + "license": "Apache-2.0" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/gensync": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/gensync/-/gensync-1.0.5.tgz", + "integrity": "sha512-MbsRCT7mTikHwKZ0X+LVUTLRrZZRLipTuXEO9qOYO+zmjMVk81axyClMROf6uoPD9MRVu46bx8zoR0Ad9q3NAg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jsesc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@types/jsesc/-/jsesc-2.5.1.tgz", + "integrity": "sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/sockjs-client": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/sockjs-client/-/sockjs-client-1.5.4.tgz", + "integrity": "sha512-zk+uFZeWyvJ5ZFkLIwoGA/DfJ+pYzcZ8eH4H/EILCm2OBZyHH6Hkdna1/UWL/CFruh5wj6ES7g75SvUB0VsH5w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitejs/plugin-basic-ssl": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.3.0.tgz", + "integrity": "sha512-bdyo8rB3NnQbikdMpHaML9Z1OZPBu6fFOBo+OtxsBlvMJtysWskmBcnbIDhUqgC8tcxNv/a+BcV5U+2nQMm1OQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "peerDependencies": { + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@vitest/expect": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz", + "integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz", + "integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.11", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/mocker/node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz", + "integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.11.tgz", + "integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.11", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.11.tgz", + "integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.11", + "@vitest/utils": "4.1.11", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot/node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.11.tgz", + "integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.11.tgz", + "integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.11", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/agent-base": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-9.0.0.tgz", + "integrity": "sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.21", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.21.tgz", + "integrity": "sha512-uh8vpY/1/YyFkunIDFH/12p7/7VdPKA1hejMVEbdkEaWnUz0Hesvx5EbiU6XxjyHZIOju+ZMbQJkRh+es3/spQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/beasties": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/beasties/-/beasties-0.4.3.tgz", + "integrity": "sha512-fIIeLOcbAB/K1kb1HBVJoiq1alHL4RCYBSo5e7HzrNkkgMggXR1Vqt/Z9JWnkfe/qdCo66Ux3QRwZioAIBdWRA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "css-select": "^6.0.0", + "css-what": "^7.0.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "htmlparser2": "^10.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.49", + "postcss-media-query-parser": "^0.2.3", + "postcss-safe-parser": "^7.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, + "node_modules/body-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^2.0.0", + "debug": "^4.4.3", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", + "on-finished": "^2.4.1", + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/browserslist": { + "version": "4.28.9", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.9.tgz", + "integrity": "sha512-EWazOblFYUvlGZcfGhPUPmYh3nikUxBVb+y9MJun5f3hBi812X+8MSQTujLBtgK3cf51fJWbWfOjyeO954d+Eg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.11.20", + "caniuse-lite": "^1.0.30001810", + "electron-to-chromium": "^1.5.420", + "node-releases": "^2.0.54", + "update-browserslist-db": "^1.3.2" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001810", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chardet": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.2.0.tgz", + "integrity": "sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA==", + "dev": true, + "license": "MIT" + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-3.4.0.tgz", + "integrity": "sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-6.1.1.tgz", + "integrity": "sha512-06p9vyLahLa4zkGcgsGxU6iEkSOiuI4fhCH6Emhe2lPAcoUv73n72DnODsnHA+5wwXGnV0n9M9/qOQJSjYhFhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^9.0.0", + "string-width": "^8.2.0" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, + "node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-6.0.0.tgz", + "integrity": "sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^7.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "nth-check": "^2.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-7.0.0.tgz", + "integrity": "sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssstyle": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-6.2.0.tgz", + "integrity": "sha512-Fm5NvhYathRnXNVndkUsCCuR63DCLVVwGOOwQw782coXFi5HhkXdu289l59HlXZBawsyNccXfWRYvLzcDCdDig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^5.0.1", + "@csstools/css-syntax-patches-for-csstree": "^1.0.28", + "css-tree": "^3.1.0", + "lru-cache": "^11.2.6" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/data-urls": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", + "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.422", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.422.tgz", + "integrity": "sha512-UvA/32XqrLDdZSn7Jllo1AYNcWji/G0d5M0GTViE7KoGBiMunw3a34Sb2KO4ZZyrSEhqsxFoVhWWJshdyfKqJA==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/empathic": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.1.tgz", + "integrity": "sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.1.1.tgz", + "integrity": "sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.7.0.tgz", + "integrity": "sha512-hOwV7WOxXfjRpAM1DSJWZDXx3GhplwD8IfwuwvogD8i1Qnkgosw/H45s4ZnFAUHDAhPjlY9hLBvJhKmGMyY26g==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "ip-address": "^10.2.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-string-truncated-width": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", + "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-string-width": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", + "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-string-truncated-width": "^3.0.2" + } + }, + "node_modules/fast-uri": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz", + "integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fast-wrap-ansi": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", + "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-string-width": "^3.0.2" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "license": "Apache-2.0", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hono": { + "version": "4.13.5", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.5.tgz", + "integrity": "sha512-O6+/eCYRkzzzy0rPWwKLiGBR1nFuUPZynnwjxN1MBA62NNqbT0wQEzQyK2gSO5yDIDB336sXQleAhOHrzlYyKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/hosted-git-info": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-10.1.1.tgz", + "integrity": "sha512-DeOnSPAvOndYKfw075gt8yZzQ7S2hNztw34zBTfhIzLhmBTswIBg5/y+pqu/VD5cYWm5goAFTusDmUEmKZ0PEQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^11.1.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", + "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.6.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/htmlparser2": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", + "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "entities": "^7.0.1" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", + "license": "MIT" + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-9.1.0.tgz", + "integrity": "sha512-ag87y7cJJ9/3+GxFr8Oy4O5faDsGRGnBGsJj/YjOSsSx/5eadKLYTMPlzuR6obgoCDDm0abAAZitXXQkMOPSpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "9.0.0", + "debug": "^4.3.4", + "proxy-agent-negotiate": "1.1.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/immutable": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.9.tgz", + "integrity": "sha512-m8nVez3rwrgmWxtLMt1ZYXB2Lv7OKYn/disyxAlSDYAlKSlFoPPfIAmAM/M5xqL4m4C/wAPw7S2/CNaUii1Hxg==", + "dev": true, + "license": "MIT" + }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ip-address": { + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.0.tgz", + "integrity": "sha512-BGFsyJd5mpXp3rK6jIdADLNgpJUK1jnjzvYF8lK+VyDab9JAmqN0YOKDdP17HlgKb2+ehPgDc8EtnRLbGCAMhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jose": { + "version": "6.2.11", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.11.tgz", + "integrity": "sha512-A5NPn7g8EAzGU3IzRs+Yiq8K5n3ypYS75M5+KKiVHdUexfpWK1kP4ZMq7QnTGDoMj6TJ1dtcEJjW60yZDXS4hg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", + "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsdom": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-28.1.0.tgz", + "integrity": "sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@acemir/cssom": "^0.9.31", + "@asamuzakjp/dom-selector": "^6.8.1", + "@bramus/specificity": "^2.4.2", + "@exodus/bytes": "^1.11.0", + "cssstyle": "^6.0.1", + "data-urls": "^7.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^6.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "parse5": "^8.0.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^6.0.0", + "undici": "^7.21.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^8.0.1", + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/jsdom/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/listr2": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-11.0.0.tgz", + "integrity": "sha512-8K88S0aSrcSXdJfiZtEy5BQMnR+TyjrCGLcgAvQs6ta0NEnIm0RJ72/Pv67Jvg07cfBhDbuN74V81lSSVYEFEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^6.1.1", + "log-update": "^8.0.0", + "wrap-ansi": "^10.0.0" + }, + "engines": { + "node": ">=22.13.0" + } + }, + "node_modules/lmdb": { + "version": "3.5.6", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.5.6.tgz", + "integrity": "sha512-j3uE8ReKNyUWDjhfEFSJqE/1DLtfTR5Z8yFzVHvBjAk37wNg7HdScjcv8ttPHRvrdgPQMPWxFFI0SsdBzI5lBw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@harperfast/extended-iterable": "^1.0.3", + "msgpackr": "^1.11.2", + "node-addon-api": "^6.1.0", + "node-gyp-build-optional-packages": "5.2.2", + "ordered-binary": "^1.5.3", + "weak-lru-cache": "^1.2.2" + }, + "bin": { + "download-lmdb-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@lmdb/lmdb-darwin-arm64": "3.5.6", + "@lmdb/lmdb-darwin-x64": "3.5.6", + "@lmdb/lmdb-linux-arm": "3.5.6", + "@lmdb/lmdb-linux-arm64": "3.5.6", + "@lmdb/lmdb-linux-x64": "3.5.6", + "@lmdb/lmdb-win32-arm64": "3.5.6", + "@lmdb/lmdb-win32-x64": "3.5.6" + } + }, + "node_modules/log-symbols": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-7.0.1.tgz", + "integrity": "sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0", + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-8.0.0.tgz", + "integrity": "sha512-lddSgOt3bPASrylL54ZSpy8nBHns+vBVSoILlVOx+dei300pnLRN958rj/EdlVLKuWlSESU3qdnDZdAI7FXYGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.3.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^9.0.0", + "string-width": "^8.2.0", + "strip-ansi": "^7.2.0", + "wrap-ansi": "^10.0.0" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/magic-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.0.0.tgz", + "integrity": "sha512-CGvjzMN08iv6w1mm4/x3Gh1hLb4VnyRUA15FFpl6CsCIGGoe36k7kY5KNz9QDbSBN5I/fWHM6ZlIkUTa5xdUEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/media-typer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.1.tgz", + "integrity": "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/msgpackr": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.12.1.tgz", + "integrity": "sha512-4EUH9tQHnMmEgzW/MdAP0KIfa1T9AF+htl0ffe2n5vb2EKn9y2co8ccpgWko6S52Jy1PQZKwRnx5/KkYjtd9MQ==", + "dev": true, + "license": "MIT", + "optional": true, + "optionalDependencies": { + "msgpackr-extract": "^3.0.2" + } + }, + "node_modules/msgpackr-extract": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.4.tgz", + "integrity": "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.2.2" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" + } + }, + "node_modules/mute-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz", + "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.1.0.tgz", + "integrity": "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "content-type": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/negotiator/node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", + "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.1" + }, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, + "node_modules/node-releases": { + "version": "2.0.54", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.54.tgz", + "integrity": "sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/npm-package-arg": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-14.0.0.tgz", + "integrity": "sha512-69XQh3k+dtGa1p+7RaR57IuG3rCko96xr/nUfN4yDYBXbTYICiWcOpsFKLN2GtGE9cyIljE+f1exnaYt9MvM+Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^10.1.0", + "proc-log": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^8.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obug": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", + "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-9.4.1.tgz", + "integrity": "sha512-6VlU9MLXbjVQD04AZCMX28hVtA5bUoadvUqO76MUCVA0ilwJbMiHsITRPfyVm6p/BC0Av/BXMujx39WCe1LEqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.6.2", + "cli-cursor": "^5.0.0", + "cli-spinners": "^3.2.0", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.1.0", + "log-symbols": "^7.0.1", + "stdin-discarder": "^0.3.2", + "string-width": "^8.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ordered-binary": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.6.1.tgz", + "integrity": "sha512-QkCdPooczexPLiXIrbVOPYkR3VO3T6v2OyKRkR1Xbhpy7/LAVXwahnRCgRp78Oe/Ehf0C/HATAxfSr6eA1oX+w==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/oxc-parser": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.142.0.tgz", + "integrity": "sha512-kKR+jPiRJYJDexVoziIg/FVGvr1fT1FZSSJOk6tVoMKKSlsf1Cso+cgGCJkOEDWOP174vRntCPFKg+AS7InWvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "^0.142.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxc-parser/binding-android-arm-eabi": "0.142.0", + "@oxc-parser/binding-android-arm64": "0.142.0", + "@oxc-parser/binding-darwin-arm64": "0.142.0", + "@oxc-parser/binding-darwin-x64": "0.142.0", + "@oxc-parser/binding-freebsd-x64": "0.142.0", + "@oxc-parser/binding-linux-arm-gnueabihf": "0.142.0", + "@oxc-parser/binding-linux-arm-musleabihf": "0.142.0", + "@oxc-parser/binding-linux-arm64-gnu": "0.142.0", + "@oxc-parser/binding-linux-arm64-musl": "0.142.0", + "@oxc-parser/binding-linux-ppc64-gnu": "0.142.0", + "@oxc-parser/binding-linux-riscv64-gnu": "0.142.0", + "@oxc-parser/binding-linux-riscv64-musl": "0.142.0", + "@oxc-parser/binding-linux-s390x-gnu": "0.142.0", + "@oxc-parser/binding-linux-x64-gnu": "0.142.0", + "@oxc-parser/binding-linux-x64-musl": "0.142.0", + "@oxc-parser/binding-openharmony-arm64": "0.142.0", + "@oxc-parser/binding-wasm32-wasi": "0.142.0", + "@oxc-parser/binding-win32-arm64-msvc": "0.142.0", + "@oxc-parser/binding-win32-ia32-msvc": "0.142.0", + "@oxc-parser/binding-win32-x64-msvc": "0.142.0" + } + }, + "node_modules/parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "license": "MIT", + "dependencies": { + "entities": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-html-rewriting-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-8.0.1.tgz", + "integrity": "sha512-NaRku2aMpUN1Sh1Gyk1KWUh2A7EJx2c6qYzvwsPtqhoHoaURshdrceYK3LunVCm3WHhm6FS7Vcczbvdh3/UIVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^8.0.0", + "parse5": "^8.0.0", + "parse5-sax-parser": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-html-rewriting-stream/node_modules/entities": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/parse5-sax-parser": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-8.0.0.tgz", + "integrity": "sha512-/dQ8UzHZwnrzs3EvDj6IkKrD/jIZyTlB+8XrHJvcjNgRdmWruNdN9i9RK/JtxakmlUdPwKubKPTCqvbTgzGhrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse5": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/piscina": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-5.2.0.tgz", + "integrity": "sha512-DszUCKeVN/5G5QKo6jAVHL8fmKnkJvQ0ACiVgY7YGCq3TUB2oznAOayvZPIAdEThvhczkXR+qm3IHsNXpFCYfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.x" + }, + "optionalDependencies": { + "@napi-rs/nice": "^1.0.4" + } + }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/postcss": { + "version": "8.5.28", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz", + "integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.18", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-media-query-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", + "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", + "dev": true, + "license": "MIT" + }, + "node_modules/postcss-safe-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.1.0.tgz", + "integrity": "sha512-1WzZxRLaAFwEh6Do+zyGpjWV3nGJNxxhuh7Ubu/q1ICImMgZJnLwhoaEpRbG4pJppp2Y1ncL9ffA2f+LhrefQg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/prettier": { + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.6.tgz", + "integrity": "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/proc-log": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-7.0.0.tgz", + "integrity": "sha512-FYgfaA69XZ93zaXLoMNQ+ViDXGGBgR8aLh03txzcFhV+9xOXx7+8DLCULrKKpR9+GsH9ZfHm82aSUPpozX0Ztg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-agent-negotiate": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-agent-negotiate/-/proxy-agent-negotiate-1.1.0.tgz", + "integrity": "sha512-N8IBcM3UgCVzz2L2Lqv8DVntDnnC8/hiV4nEDUPkqq72TPUgYWjQc+bdZlBPZK9LzPAvOY//gAt0S0DApoOXWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "kerberos": "^2.0.0" + }, + "peerDependenciesMeta": { + "kerberos": { + "optional": true + } + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", + "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz", + "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/readdirp": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", + "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT" + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rolldown": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.0.tgz", + "integrity": "sha512-u7tgm5l4Yw1iTqUL4EcYOAt7fFvCgQMLeidrnD4GALlC6aOznCjezYajgxeyKw27u0Q5N7fwgCzjVyPIWzwuBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.140.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.2.0", + "@rolldown/binding-darwin-arm64": "1.2.0", + "@rolldown/binding-darwin-x64": "1.2.0", + "@rolldown/binding-freebsd-x64": "1.2.0", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.0", + "@rolldown/binding-linux-arm64-gnu": "1.2.0", + "@rolldown/binding-linux-arm64-musl": "1.2.0", + "@rolldown/binding-linux-ppc64-gnu": "1.2.0", + "@rolldown/binding-linux-s390x-gnu": "1.2.0", + "@rolldown/binding-linux-x64-gnu": "1.2.0", + "@rolldown/binding-linux-x64-musl": "1.2.0", + "@rolldown/binding-openharmony-arm64": "1.2.0", + "@rolldown/binding-wasm32-wasi": "1.2.0", + "@rolldown/binding-win32-arm64-msvc": "1.2.0", + "@rolldown/binding-win32-x64-msvc": "1.2.0" + } + }, + "node_modules/rolldown/node_modules/@oxc-project/types": { + "version": "0.140.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.140.0.tgz", + "integrity": "sha512-h5LUOzGArYemnW1NMz/DuuQhBi96J6JL2Bk8zE4kvqxB5Sg3jxmCiH4uyOWHDkiKSt5vWlG4FIwCR/DbstcNRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sass": { + "version": "1.101.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.101.0.tgz", + "integrity": "sha512-OL3GoQyoUdDt843DpVmDO6y2k1sc5IhUDSpu8XucEI+35neq5QivZ1iuegnpraEVTJXlQGK1gl27zKcTLEPbQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^5.0.0", + "immutable": "^5.1.5", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=20.19.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slice-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-9.0.0.tgz", + "integrity": "sha512-SO/3iYL5S3W57LLEniscOGPZgOqZUPCx6d3dB+52B80yJ0XstzsC/eV8gnA4tM3MHDrKz+OCFSLNjswdSC+/bA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.3", + "is-fullwidth-code-point": "^5.1.0" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/sockjs-client": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.6.1.tgz", + "integrity": "sha512-2g0tjOR+fRs0amxENLi/q5TiJTqY+WXFOzb5UwXndlK6TO3U/mirZznpx6w34HVMoc3g7cY24yC/ZMIYnDlfkw==", + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "eventsource": "^2.0.2", + "faye-websocket": "^0.11.4", + "inherits": "^2.0.4", + "url-parse": "^1.5.10" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://tidelift.com/funding/github/npm/sockjs-client" + } + }, + "node_modules/sockjs-client/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/sockjs-client/node_modules/eventsource": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", + "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", + "dev": true, + "license": "MIT" + }, + "node_modules/stdin-discarder": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.3.2.tgz", + "integrity": "sha512-eCPu1qRxPVkl5605OTWF8Wz40b4Mf45NY5LQmVPQ599knfs5QhASUm9GbJ5BDMDOXgrnh0wyEdvzmL//YMlw0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.2.tgz", + "integrity": "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz", + "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyrainbow": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", + "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "7.4.11", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.11.tgz", + "integrity": "sha512-aBiNayCfTQxuIJBm06M+xR14cYaYlDlSXZbgsnKzKNxDKUVq7KFwTjwBSsb7m9Y5xO8WfPnBc63WaYFMTGlvqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^7.4.11" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "7.4.11", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.11.tgz", + "integrity": "sha512-CW3WN2rIIE/Of21mulhgnGOwoDyEFNygyIBOONSdyAuSATgMMUCpLeUlB+E8sAwA5xRV9hYPl+kyZ9citHCaKg==", + "dev": true, + "license": "MIT" + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.2.tgz", + "integrity": "sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-is": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", + "dev": true, + "license": "MIT", + "dependencies": { + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.1.tgz", + "integrity": "sha512-RYONW2MeafgYlkVOKYKkA/Ag7BmXqgIWCa8t1m0JcxrQg9pI9lEqRhAOruOBCbAohOa/gkCF+iPi9hrgvTzu6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz", + "integrity": "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-8.0.0.tgz", + "integrity": "sha512-SCv6OOV6Xj2/3cXy3dGmADluJTNcL3o7hZAglNPTe+WYuEuvxgJzxPrSDLZhF+CwyQOubqgecjMmTJGMVLWjYQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vite": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.5.tgz", + "integrity": "sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.5", + "postcss": "^8.5.17", + "rolldown": "~1.1.5", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.3.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/@emnapi/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/vite/node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/vite/node_modules/@oxc-project/types": { + "version": "0.139.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.139.0.tgz", + "integrity": "sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-android-arm64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.5.tgz", + "integrity": "sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.5.tgz", + "integrity": "sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-darwin-x64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.5.tgz", + "integrity": "sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.5.tgz", + "integrity": "sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.5.tgz", + "integrity": "sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.5.tgz", + "integrity": "sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.5.tgz", + "integrity": "sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.5.tgz", + "integrity": "sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.5.tgz", + "integrity": "sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.5.tgz", + "integrity": "sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.5.tgz", + "integrity": "sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.5.tgz", + "integrity": "sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.5.tgz", + "integrity": "sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.1", + "@emnapi/runtime": "1.11.1", + "@napi-rs/wasm-runtime": "^1.1.6" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.5.tgz", + "integrity": "sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.5.tgz", + "integrity": "sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/rolldown": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.5.tgz", + "integrity": "sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.139.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.1.5", + "@rolldown/binding-darwin-arm64": "1.1.5", + "@rolldown/binding-darwin-x64": "1.1.5", + "@rolldown/binding-freebsd-x64": "1.1.5", + "@rolldown/binding-linux-arm-gnueabihf": "1.1.5", + "@rolldown/binding-linux-arm64-gnu": "1.1.5", + "@rolldown/binding-linux-arm64-musl": "1.1.5", + "@rolldown/binding-linux-ppc64-gnu": "1.1.5", + "@rolldown/binding-linux-s390x-gnu": "1.1.5", + "@rolldown/binding-linux-x64-gnu": "1.1.5", + "@rolldown/binding-linux-x64-musl": "1.1.5", + "@rolldown/binding-openharmony-arm64": "1.1.5", + "@rolldown/binding-wasm32-wasi": "1.1.5", + "@rolldown/binding-win32-arm64-msvc": "1.1.5", + "@rolldown/binding-win32-x64-msvc": "1.1.5" + } + }, + "node_modules/vitest": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz", + "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.11", + "@vitest/mocker": "4.1.11", + "@vitest/pretty-format": "4.1.11", + "@vitest/runner": "4.1.11", + "@vitest/snapshot": "4.1.11", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.11", + "@vitest/browser-preview": "4.1.11", + "@vitest/browser-webdriverio": "4.1.11", + "@vitest/coverage-istanbul": "4.1.11", + "@vitest/coverage-v8": "4.1.11", + "@vitest/ui": "4.1.11", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/vitest/node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/watchpack": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.2.tgz", + "integrity": "sha512-6i/00NBjP4yGPs+caKSyRfpTF/8Torsu0MOW3mMzIbhgISFder8i7xbqgHlLMwJrdiN8ndBV3UA1/AfzPSr+jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/weak-lru-cache": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", + "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/webidl-conversions": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.5.tgz", + "integrity": "sha512-ZL2+3c7kMBdIRCMz6l8jQMHyGVxj+UL+xVk74Ombiciboca8rHa15L86B19E5oh1pL9Ii/uj54gtsIrZGMo6zA==", + "license": "Apache-2.0", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-url": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", + "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.11.0", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-10.0.1.tgz", + "integrity": "sha512-M0N4xzyzosiIok3svYlEo1sdLZts/8FPgYH/GPC3wvlmPoRvnoManGMrE54waYj3tISA8w6lsdesfVv67qSr8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.3", + "string-width": "^8.2.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.1.0.tgz", + "integrity": "sha512-2rAgRKu54VsHkqI0/tYkmluGXHD4KW7yZoycuqDQ15QOTnc2VVfy0nN/1eMhnQLO00A+dwtK20xuCnc1YGeUyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^8.2.1", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yoctocolors": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.2.0.tgz", + "integrity": "sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.2", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "dev": true, + "license": "ISC", + "peerDependencies": { + "zod": "^3.25.28 || ^4" + } + } + } +} diff --git a/portal_client/package.json b/portal_client/package.json index e09809a..21e33e0 100644 --- a/portal_client/package.json +++ b/portal_client/package.json @@ -1,69 +1,43 @@ -{ - "name": "portal", - "version": "0.0.0", - "private": true, - "dependencies": { - "@uirouter/angularjs": "^1.0.18", - "PubSub": "^3.4.0", - "angular": "^1.7.2", - "angular-animate": "^1.7.2", - "angular-aria": "^1.7.2", - "angular-bootstrap": "^0.12.2", - "angular-cookies": "^1.7.2", - "angular-material": "^1.1.10", - "angular-messages": "^1.7.2", - "angular-mocks": "^1.7.2", - "angular-resource": "^1.7.2", - "angular-route": "^1.7.2", - "angular-sanitize": "^1.7.2", - "angular-ui-grid": "^4.6.1", - "angular-ui-tinymce": "^0.0.19", - "angular-ui-utils": "^0.1.1", - "bootstrap": "^3.3.7", - "jquery": "^3.3.1", - "jquery-ui-dist": "^1.12.1", - "moment": "^2.22.2", - "ng-debounce": "^1.0.1", - "ng-material-datetimepicker": "^1.16.0", - "sockjs-client": "^1.1.5", - "stomp-websocket-js": "^1.0.0", - "tinymce": "^4.7.13", - "underscore": "^1.9.1" - }, - "devDependencies": { - "coffee": "^4.1.0", - "copy-webpack-plugin": "^4.3.1", - "css-loader": "^0.28.8", - "file-loader": "^1.1.6", - "grunt": "~1.0.1", - "grunt-angular-templates": "^1.1.0", - "grunt-cli": "^1.2.0", - "grunt-concurrent": "^2.3.1", - "grunt-connect-proxy2": "~2.0.0", - "grunt-contrib-clean": "^1.1.0", - "grunt-contrib-concat": "~1.0.1", - "grunt-contrib-connect": "~1.0.2", - "grunt-contrib-copy": "~1.0.0", - "grunt-contrib-csslint": "^2.0.0", - "grunt-contrib-cssmin": "^2.2.1", - "grunt-contrib-htmlmin": "^2.4.0", - "grunt-contrib-jshint": "^1.1.0", - "grunt-contrib-less": "^1.4.1", - "grunt-contrib-uglify": "^3.1.0", - "grunt-contrib-watch": "~1.0.0", - "grunt-dom-munger2": "~4.0.1", - "grunt-html2js": "^0.5.1", - "grunt-lesslint": "^4.0.0", - "grunt-ng-annotate": "^3.0.0", - "jit-grunt": "^0.10.0", - "serve-index": "^1.9.1", - "serve-static": "^1.13.1", - "style-loader": "^0.19.1", - "time-grunt": "^1.4.0", - "url-loader": "^0.6.2", - "webpack": "^3.10.0" - }, - "scripts": { - "webpack": "webpack" - } -} +{ + "name": "portal-client", + "version": "1.0.0-RELEASE", + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build", + "watch": "ng build --watch --configuration development", + "test": "ng test --watch=false" + }, + "private": true, + "packageManager": "npm@12.0.2", + "dependencies": { + "@angular/cdk": "^22.1.5", + "@angular/common": "^22.1.0", + "@angular/compiler": "^22.1.0", + "@angular/core": "^22.1.0", + "@angular/forms": "^22.1.0", + "@angular/material": "^22.1.5", + "@angular/platform-browser": "^22.1.0", + "@angular/router": "^22.1.0", + "@stomp/stompjs": "^7.3.0", + "rxjs": "~7.8.0", + "sockjs-client": "^1.6.1", + "tslib": "^2.3.0" + }, + "devDependencies": { + "@angular/build": "^22.1.7", + "@angular/cli": "^22.1.7", + "@angular/compiler-cli": "^22.1.0", + "@types/sockjs-client": "^1.5.4", + "jsdom": "^28.0.0", + "prettier": "^3.8.1", + "typescript": "~6.0.2", + "vitest": "^4.0.8" + }, + "allowScripts": { + "@parcel/watcher@2.6.0": true, + "esbuild@0.28.2": true, + "lmdb@3.5.6": true, + "msgpackr-extract@3.0.4": true + } +} diff --git a/portal_client/pom.xml b/portal_client/pom.xml index 72329ce..68634b3 100644 --- a/portal_client/pom.xml +++ b/portal_client/pom.xml @@ -13,9 +13,7 @@ portal_client Portal Web Client pom - The Portal client which houses all the css, html and javascript files for the client. It uses AngularJS 1.x with Angular-Material. Data is sent/received to/from the server via rest requests as json. - -Vendor packages are retrieved via yarn and nodejs. They are compiled and injected into the index.html before the whole application is minimized + Angular portal client, built with Angular CLI and npm and packaged into the Spring Boot application. ${project.parent.basedir} @@ -31,7 +29,7 @@ Vendor packages are retrieved via yarn and nodejs. They are compiled and injecte maven-clean-plugin - 2.6.1 + 3.5.0 @@ -40,97 +38,60 @@ Vendor packages are retrieved via yarn and nodejs. They are compiled and injecte **/* - - app/yarn_components - - **/* - - com.github.eirslett frontend-maven-plugin - 1.6 + ${frontend-maven-plugin.version} - - - install node and yarn - initialize - - install-node-and-yarn - - - set strict-ssl false - v8.11.3 - v1.7.0 + + + install node and npm + initialize + + install-node-and-npm + + + ${node.version} + ${npm.version} + + + + + + npm install + generate-sources + + npm + + + ci - - - yarn install - generate-sources - - yarn - - - install - - - - - webpack build - - webpack - - - - generate-sources - - - - -p - - - - - - grunt build - compile - - grunt - - - build - - - - - - grunt test - compile - - grunt - - - unitTests - - - - - - grunt clean - compile - - grunt - - - build - + + npm build + compile + + npm + + + run build + + + + + npm test + test + + npm + + + test + @@ -139,40 +100,6 @@ Vendor packages are retrieved via yarn and nodejs. They are compiled and injecte - - - - debug - - - - maven-clean-plugin - 2.6.1 - - clean - - - dist - - **/* - - - - - - - delete-dist - clean - - clean - - - - - - - diff --git a/portal_client/app/favicon.ico b/portal_client/public/favicon.ico similarity index 100% rename from portal_client/app/favicon.ico rename to portal_client/public/favicon.ico diff --git a/portal_client/app/fonts/google-md-icons/MaterialIcons-Regular.css b/portal_client/public/fonts/google-md-icons/MaterialIcons-Regular.css similarity index 52% rename from portal_client/app/fonts/google-md-icons/MaterialIcons-Regular.css rename to portal_client/public/fonts/google-md-icons/MaterialIcons-Regular.css index 80e5910..12f048a 100644 --- a/portal_client/app/fonts/google-md-icons/MaterialIcons-Regular.css +++ b/portal_client/public/fonts/google-md-icons/MaterialIcons-Regular.css @@ -2,19 +2,16 @@ font-family: 'Material Icons'; font-style: normal; font-weight: 400; - src: url('MaterialIcons-Regular.eot') - url('fonts/google-md-icons/MaterialIcons-Regular.eot'); + src: url('MaterialIcons-Regular.eot'); src: url('MaterialIcons-Regular.woff2') format('woff2'), - url('MaterialIcons-Regular.woff') format('woff'), - url('fonts/google-md-icons/MaterialIcons-Regular.woff2') format('woff2'), - url('fonts/google-md-icons/MaterialIcons-Regular.woff') format('woff'); + url('MaterialIcons-Regular.woff') format('woff'); } .material-icons { font-family: 'Material Icons'; font-weight: normal; font-style: normal; - font-size: 24px; /* Preferred icon size */ + font-size: 24px; display: inline-block; line-height: 1; text-transform: none; @@ -22,15 +19,8 @@ word-wrap: normal; white-space: nowrap; direction: ltr; - - /* Support for all WebKit browsers. */ -webkit-font-smoothing: antialiased; - /* Support for Safari and Chrome. */ text-rendering: optimizeLegibility; - - /* Support for Firefox. */ -moz-osx-font-smoothing: grayscale; - - /* Support for IE. */ font-feature-settings: 'liga'; -} \ No newline at end of file +} diff --git a/portal_client/app/fonts/google-md-icons/MaterialIcons-Regular.eot b/portal_client/public/fonts/google-md-icons/MaterialIcons-Regular.eot similarity index 100% rename from portal_client/app/fonts/google-md-icons/MaterialIcons-Regular.eot rename to portal_client/public/fonts/google-md-icons/MaterialIcons-Regular.eot diff --git a/portal_client/app/fonts/google-md-icons/MaterialIcons-Regular.woff b/portal_client/public/fonts/google-md-icons/MaterialIcons-Regular.woff similarity index 100% rename from portal_client/app/fonts/google-md-icons/MaterialIcons-Regular.woff rename to portal_client/public/fonts/google-md-icons/MaterialIcons-Regular.woff diff --git a/portal_client/app/fonts/google-md-icons/MaterialIcons-Regular.woff2 b/portal_client/public/fonts/google-md-icons/MaterialIcons-Regular.woff2 similarity index 100% rename from portal_client/app/fonts/google-md-icons/MaterialIcons-Regular.woff2 rename to portal_client/public/fonts/google-md-icons/MaterialIcons-Regular.woff2 diff --git a/portal_client/app/images/NGLogo.png b/portal_client/public/images/NGLogo.png similarity index 100% rename from portal_client/app/images/NGLogo.png rename to portal_client/public/images/NGLogo.png diff --git a/portal_client/app/images/background.png b/portal_client/public/images/background.png similarity index 100% rename from portal_client/app/images/background.png rename to portal_client/public/images/background.png diff --git a/portal_client/app/images/portal.png b/portal_client/public/images/portal.png similarity index 100% rename from portal_client/app/images/portal.png rename to portal_client/public/images/portal.png diff --git a/portal_client/src/app/app.config.ts b/portal_client/src/app/app.config.ts new file mode 100644 index 0000000..c1f9921 --- /dev/null +++ b/portal_client/src/app/app.config.ts @@ -0,0 +1,13 @@ +import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core'; +import { provideRouter, withHashLocation } from '@angular/router'; +import { provideHttpClient, withInterceptors } from '@angular/common/http'; +import { routes } from './app.routes'; +import { authInterceptor } from './core/auth.interceptor'; + +export const appConfig: ApplicationConfig = { + providers: [ + provideBrowserGlobalErrorListeners(), + provideRouter(routes, withHashLocation()), + provideHttpClient(withInterceptors([authInterceptor])) + ] +}; diff --git a/portal_client/src/app/app.html b/portal_client/src/app/app.html new file mode 100644 index 0000000..67e7bd4 --- /dev/null +++ b/portal_client/src/app/app.html @@ -0,0 +1 @@ + diff --git a/portal_client/src/app/app.routes.spec.ts b/portal_client/src/app/app.routes.spec.ts new file mode 100644 index 0000000..7ee17bc --- /dev/null +++ b/portal_client/src/app/app.routes.spec.ts @@ -0,0 +1,36 @@ +import { signal } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import { Router } from '@angular/router'; +import { RouterTestingHarness } from '@angular/router/testing'; +import { throwError } from 'rxjs'; +import { appConfig } from './app.config'; +import { PortalApiService } from './core/portal-api.service'; +import { RealtimeService } from './core/realtime.service'; + +describe('Lazy portal routes', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + ...appConfig.providers, + { provide: PortalApiService, useValue: { + request: () => throwError(() => new Error('Not authenticated')) + } }, + { provide: RealtimeService, useValue: { + status: signal('disconnected'), connect: () => undefined + } } + ] + }); + }); + + it('renders the lazy login page with the production Material providers', async () => { + const harness = await RouterTestingHarness.create('/login'); + expect(harness.routeNativeElement?.querySelector('input[formControlName="username"]')).toBeTruthy(); + expect(harness.routeNativeElement?.querySelector('input[type="password"]')).toBeTruthy(); + }); + + it('redirects an unauthenticated dashboard request to the lazy login page', async () => { + const harness = await RouterTestingHarness.create('/dashboard/repos'); + expect(TestBed.inject(Router).url).toBe('/login'); + expect(harness.routeNativeElement?.querySelector('form')).toBeTruthy(); + }); +}); diff --git a/portal_client/src/app/app.routes.ts b/portal_client/src/app/app.routes.ts new file mode 100644 index 0000000..fc89169 --- /dev/null +++ b/portal_client/src/app/app.routes.ts @@ -0,0 +1,14 @@ +import { Routes } from '@angular/router'; +import { authGuard } from './core/auth.guard'; +import { FEATURES } from './core/models'; +import { permissionGuard } from './core/permission.guard'; + +export const routes: Routes = [ + { path: 'login', loadComponent: () => import('./login/login').then(m => m.LoginComponent), title: 'Portal Login' }, + { path: 'dashboard', loadComponent: () => import('./dashboard/dashboard').then(m => m.DashboardComponent), canActivate: [authGuard], canActivateChild: [permissionGuard], children: [ + { path: '', pathMatch: 'full', redirectTo: 'repos' }, + ...FEATURES.map(feature => ({ path: feature.path, loadComponent: () => import('./features/feature-page').then(m => m.FeaturePageComponent), data: { feature: feature.path, permission: feature.permission }, title: feature.title })) + ] }, + { path: '', pathMatch: 'full', redirectTo: 'dashboard' }, + { path: '**', redirectTo: 'dashboard' } +]; diff --git a/portal_client/src/app/app.scss b/portal_client/src/app/app.scss new file mode 100644 index 0000000..e69de29 diff --git a/portal_client/src/app/app.spec.ts b/portal_client/src/app/app.spec.ts new file mode 100644 index 0000000..70b4578 --- /dev/null +++ b/portal_client/src/app/app.spec.ts @@ -0,0 +1,24 @@ +import { TestBed } from '@angular/core/testing'; +import { App } from './app'; + +describe('App', () => { + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [App], + }) + .compileComponents(); + }); + + it('should create the app', () => { + const fixture = TestBed.createComponent(App); + const app = fixture.componentInstance; + expect(app).toBeTruthy(); + }); + + it('should render the application router outlet', async () => { + const fixture = TestBed.createComponent(App); + await fixture.whenStable(); + const compiled = fixture.nativeElement as HTMLElement; + expect(compiled.querySelector('router-outlet')).toBeTruthy(); + }); +}); diff --git a/portal_client/src/app/app.ts b/portal_client/src/app/app.ts new file mode 100644 index 0000000..f3baf18 --- /dev/null +++ b/portal_client/src/app/app.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; +import { RouterOutlet } from '@angular/router'; + +@Component({ + imports: [RouterOutlet], + selector: 'app-root', + styleUrl: './app.scss', + templateUrl: './app.html', +}) +export class App { +} diff --git a/portal_client/src/app/core/auth.guard.ts b/portal_client/src/app/core/auth.guard.ts new file mode 100644 index 0000000..a2d5d4a --- /dev/null +++ b/portal_client/src/app/core/auth.guard.ts @@ -0,0 +1,11 @@ +import { inject } from '@angular/core'; +import { CanActivateFn, Router } from '@angular/router'; +import { catchError, map, of } from 'rxjs'; +import { Account } from './models'; +import { PortalApiService } from './portal-api.service'; +import { SessionService } from './session.service'; +export const authGuard: CanActivateFn = () => { + const session = inject(SessionService), api = inject(PortalApiService), router = inject(Router); + if (session.authenticated()) return true; + return api.request('/account/isLoggedIn.do').pipe(map(account => { session.setAccount(account); return true; }), catchError(() => of(router.createUrlTree(['/login'])))); +}; diff --git a/portal_client/src/app/core/auth.interceptor.ts b/portal_client/src/app/core/auth.interceptor.ts new file mode 100644 index 0000000..792009a --- /dev/null +++ b/portal_client/src/app/core/auth.interceptor.ts @@ -0,0 +1,20 @@ +import { HttpInterceptorFn } from '@angular/common/http'; +import { inject } from '@angular/core'; +import { Router } from '@angular/router'; +import { catchError, throwError } from 'rxjs'; +import { RealtimeService } from './realtime.service'; +import { SessionService } from './session.service'; + +export const authInterceptor: HttpInterceptorFn = (request, next) => { + const session = inject(SessionService); + const realtime = inject(RealtimeService); + const router = inject(Router); + return next(request).pipe(catchError(error => { + if ((error.status === 401 || error.status === 403) && session.authenticated()) { + session.clear(); + realtime.disconnect(); + void router.navigate(['/login']); + } + return throwError(() => error); + })); +}; diff --git a/portal_client/src/app/core/models.ts b/portal_client/src/app/core/models.ts new file mode 100644 index 0000000..a118d2d --- /dev/null +++ b/portal_client/src/app/core/models.ts @@ -0,0 +1,14 @@ +export interface PortalResponse { success?: boolean; message?: string; body?: T; } +export interface Account { id?: number; username?: string; firstName?: string; lastName?: string; page?: string; authorities?: string[]; permissions?: Record; stompTopics?: string[]; [key: string]: unknown; } +export type FeatureEditor = 'git' | 'credentials' | 'email' | 'user' | 'environment' | 'permission' | 'script'; +export interface FeatureDefinition { path: string; title: string; icon: string; permission: string; loadEndpoint: string; deleteEndpoint?: string; deletePermission?: string; executeEndpoint?: string; executePermission?: string; editor?: FeatureEditor; saveEndpoint?: string; savePermission?: string; } +export const FEATURES: FeatureDefinition[] = [ + { path: 'scripts', title: 'Scripts', icon: 'description', permission: 'VIEW_SCRIPT_TAB', loadEndpoint: '/scripts/getAll.do', editor: 'script', saveEndpoint: '/scripts/addScript.do', savePermission: 'ADD_SCRIPT', deleteEndpoint: '/scripts/deleteScript.do', deletePermission: 'DELETE_SCRIPT', executeEndpoint: '/scripts/runScript.do', executePermission: 'RUN_SCRIPT' }, + { path: 'repos', title: 'Git Repositories', icon: 'computer', permission: 'VIEW_GIT_TAB', loadEndpoint: '/git/getAll.do', editor: 'git', saveEndpoint: '/git/add.do', savePermission: 'ADD_GIT_REPO', deleteEndpoint: '/git/delete.do', deletePermission: 'DELETE_GIT_REPO', executeEndpoint: '/git/pull.do', executePermission: 'PULL_GIT_REPO' }, + { path: 'credentials', title: 'Credentials', icon: 'vpn_key', permission: 'VIEW_CREDS_TAB', loadEndpoint: '/creds/get.do', editor: 'credentials', saveEndpoint: '/creds/add.do', savePermission: 'ADD_CREDENTIALS', deleteEndpoint: '/creds/delete.do', deletePermission: 'DELETE_CREDENTIALS' }, + { path: 'emails', title: 'Email Templates', icon: 'email', permission: 'VIEW_EMAIL_TAB', loadEndpoint: '/system/getEmailTemplates.do', editor: 'email', saveEndpoint: '/system/addEmailTemplate.do', savePermission: 'ADD_EMAIL', deleteEndpoint: '/system/deleteEmailTemplate.do', deletePermission: 'DELETE_EMAIL' }, + { path: 'users', title: 'Users', icon: 'people', permission: 'VIEW_USER_TAB', loadEndpoint: '/account/getAll.do', editor: 'user', saveEndpoint: '/account/addUser.do', savePermission: 'ADD_USERS', deleteEndpoint: '/account/deleteUser.do', deletePermission: 'DELETE_USERS' }, + { path: 'permissions', title: 'Permissions', icon: 'lock_open', permission: 'VIEW_PERMISSION_TAB', loadEndpoint: '/permissions/getPermissionGroups.do', editor: 'permission', saveEndpoint: '/permissions/addPermssionCategory.do', savePermission: 'ADD_PERMS', deleteEndpoint: '/permissions/deletePermissionGroup.do', deletePermission: 'DELETE_PERMS' }, + { path: 'envars', title: 'Environment Variables', icon: 'storage', permission: 'VIEW_ENV_VARS_TAB', loadEndpoint: '/system/getAll.do', editor: 'environment', saveEndpoint: '/system/addEnvVars.do', savePermission: 'ADD_ENV_VARS', deleteEndpoint: '/system/deleteEnvVars.do', deletePermission: 'DELETE_ENV_VARS' }, + { path: 'syslogs', title: 'System Logs', icon: 'receipt_long', permission: 'VIEW_LOG_TAB', loadEndpoint: '/logs/getAll.do' } +]; diff --git a/portal_client/src/app/core/permission.guard.ts b/portal_client/src/app/core/permission.guard.ts new file mode 100644 index 0000000..fe62965 --- /dev/null +++ b/portal_client/src/app/core/permission.guard.ts @@ -0,0 +1,13 @@ +import { inject } from '@angular/core'; +import { CanActivateChildFn, Router } from '@angular/router'; +import { FEATURES } from './models'; +import { SessionService } from './session.service'; + +export const permissionGuard: CanActivateChildFn = route => { + const session = inject(SessionService); + const router = inject(Router); + const permission = route.data['permission'] as string | undefined; + if (!permission || session.hasPermission(permission)) return true; + const fallback = FEATURES.find(feature => session.hasPermission(feature.permission)); + return fallback ? router.createUrlTree(['/dashboard', fallback.path]) : router.createUrlTree(['/login']); +}; diff --git a/portal_client/src/app/core/portal-api.service.spec.ts b/portal_client/src/app/core/portal-api.service.spec.ts new file mode 100644 index 0000000..a48dc1f --- /dev/null +++ b/portal_client/src/app/core/portal-api.service.spec.ts @@ -0,0 +1,29 @@ +import { provideHttpClient } from '@angular/common/http'; +import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing'; +import { TestBed } from '@angular/core/testing'; +import { PortalApiService } from './portal-api.service'; + +describe('PortalApiService', () => { + let service: PortalApiService; + let http: HttpTestingController; + beforeEach(() => { + TestBed.configureTestingModule({providers:[provideHttpClient(),provideHttpClientTesting()]}); + service=TestBed.inject(PortalApiService); http=TestBed.inject(HttpTestingController); + }); + afterEach(()=>http.verify()); + + it('posts to the portal context and unwraps Success bodies', () => { + let result: unknown; + service.request('/scripts/getAll.do').subscribe(value=>result=value); + const request=http.expectOne('/portal/scripts/getAll.do'); + expect(request.request.method).toBe('POST'); expect(request.request.withCredentials).toBe(true); + request.flush({success:true,body:[{id:1,name:'test'}]}); + expect(result).toEqual([{id:1,name:'test'}]); + }); + + it('turns unsuccessful envelopes into errors', () => { + let message=''; service.request('/test.do').subscribe({error:error=>message=error.message}); + http.expectOne('/portal/test.do').flush({success:false,message:'Denied'}); + expect(message).toBe('Denied'); + }); +}); diff --git a/portal_client/src/app/core/portal-api.service.ts b/portal_client/src/app/core/portal-api.service.ts new file mode 100644 index 0000000..c5d0710 --- /dev/null +++ b/portal_client/src/app/core/portal-api.service.ts @@ -0,0 +1,29 @@ +import { HttpClient, HttpErrorResponse, HttpParams } from '@angular/common/http'; +import { Injectable, inject } from '@angular/core'; +import { Observable, catchError, map, throwError } from 'rxjs'; +import { PortalResponse } from './models'; + +@Injectable({ providedIn: 'root' }) +export class PortalApiService { + private readonly http = inject(HttpClient); + private readonly baseUrl = '/portal'; + request(endpoint: string, data?: unknown, params?: Record): Observable { + return this.http.post | T>(`${this.baseUrl}${endpoint}`, data ?? null, { params: new HttpParams({ fromObject: params ?? {} }), withCredentials: true }).pipe( + map(response => this.unwrap(response)), + catchError((error: HttpErrorResponse) => throwError(() => new Error(error.error?.message ?? error.message ?? 'Portal request failed'))) + ); + } + upload(endpoint: string, file: File, fields: Record = {}): Observable { + const body = new FormData(); body.append('file', file); + Object.entries(fields).forEach(([key, value]) => body.append(key, value)); + return this.http.post | T>(`${this.baseUrl}${endpoint}`, body, { withCredentials: true }).pipe(map(response => this.unwrap(response))); + } + private unwrap(response: PortalResponse | T): T { + if (response && typeof response === 'object' && ('body' in response || 'success' in response)) { + const envelope = response as PortalResponse; + if (envelope.success === false) throw new Error(envelope.message ?? 'Portal request failed'); + return ('body' in envelope ? envelope.body : response) as T; + } + return response as T; + } +} diff --git a/portal_client/src/app/core/realtime.service.ts b/portal_client/src/app/core/realtime.service.ts new file mode 100644 index 0000000..ff06c2d --- /dev/null +++ b/portal_client/src/app/core/realtime.service.ts @@ -0,0 +1,39 @@ +import { Injectable, OnDestroy, signal } from '@angular/core'; +import { Client, IMessage, StompSubscription } from '@stomp/stompjs'; +import SockJS from 'sockjs-client'; +import { Subject } from 'rxjs'; + +export interface PortalTrigger { type: string; [key: string]: unknown; } +export type ConnectionStatus = 'connecting' | 'connected' | 'disconnected' | 'failed'; + +@Injectable({ providedIn: 'root' }) +export class RealtimeService implements OnDestroy { + readonly status = signal('disconnected'); + readonly triggers = new Subject(); + private subscriptions: StompSubscription[] = []; + private readonly client = new Client({ + webSocketFactory: () => new SockJS('/portal/ws/stomp') as WebSocket, + reconnectDelay: 5000, + heartbeatIncoming: 10000, + heartbeatOutgoing: 10000, + debug: () => undefined + }); + + constructor() { + this.client.onConnect = () => this.status.set('connected'); + this.client.onWebSocketClose = () => this.status.set('disconnected'); + this.client.onStompError = () => this.status.set('failed'); + } + connect(topics: string[] = []): void { + this.client.onConnect = () => { this.status.set('connected'); this.subscribe(topics); }; + if (!this.client.active) { this.status.set('connecting'); this.client.activate(); } + else if (this.client.connected) this.subscribe(topics); + } + subscribe(topics: string[]): void { + this.subscriptions.forEach(subscription => subscription.unsubscribe()); this.subscriptions = []; + topics.forEach(topic => this.subscriptions.push(this.client.subscribe(topic, message => this.receive(message)))); + } + disconnect(): void { this.subscriptions.forEach(subscription => subscription.unsubscribe()); this.subscriptions = []; void this.client.deactivate(); } + ngOnDestroy(): void { this.disconnect(); this.triggers.complete(); } + private receive(message: IMessage): void { try { this.triggers.next(JSON.parse(message.body) as PortalTrigger); } catch { /* ignore malformed server events */ } } +} diff --git a/portal_client/src/app/core/session.service.spec.ts b/portal_client/src/app/core/session.service.spec.ts new file mode 100644 index 0000000..6e6eeab --- /dev/null +++ b/portal_client/src/app/core/session.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; +import { SessionService } from './session.service'; + +describe('SessionService', () => { + let service: SessionService; + beforeEach(() => { TestBed.configureTestingModule({}); service = TestBed.inject(SessionService); }); + + it('starts unauthenticated', () => { expect(service.authenticated()).toBe(false); }); + it('exposes authorities as permissions', () => { + service.setAccount({username:'admin',authorities:['VIEW_SCRIPT_TAB','ADD_SCRIPT']}); + expect(service.authenticated()).toBe(true); + expect(service.hasPermission('ADD_SCRIPT')).toBe(true); + expect(service.hasPermission('DELETE_SCRIPT')).toBe(false); + }); + it('clears authentication state', () => { service.setAccount({username:'admin'}); service.clear(); expect(service.account()).toBeNull(); }); +}); diff --git a/portal_client/src/app/core/session.service.ts b/portal_client/src/app/core/session.service.ts new file mode 100644 index 0000000..5c08dcf --- /dev/null +++ b/portal_client/src/app/core/session.service.ts @@ -0,0 +1,11 @@ +import { Injectable, computed, signal } from '@angular/core'; +import { Account } from './models'; +@Injectable({ providedIn: 'root' }) +export class SessionService { + private readonly accountState = signal(null); + readonly account = this.accountState.asReadonly(); + readonly authenticated = computed(() => this.accountState() !== null); + setAccount(account: Account): void { this.accountState.set(account); } + clear(): void { this.accountState.set(null); } + hasPermission(permission: string): boolean { return this.accountState()?.authorities?.includes(permission) ?? false; } +} diff --git a/portal_client/src/app/dashboard/admin-dialog.ts b/portal_client/src/app/dashboard/admin-dialog.ts new file mode 100644 index 0000000..1784202 --- /dev/null +++ b/portal_client/src/app/dashboard/admin-dialog.ts @@ -0,0 +1,108 @@ +import { Component, Inject, OnInit, inject, signal } from '@angular/core'; +import { FormsModule, ReactiveFormsModule, FormBuilder, Validators } from '@angular/forms'; +import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; +import { MatButtonModule } from '@angular/material/button'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { MatSelectModule } from '@angular/material/select'; +import { MatSlideToggleModule } from '@angular/material/slide-toggle'; +import { MatTabsModule } from '@angular/material/tabs'; +import { PortalApiService } from '../core/portal-api.service'; +import { SessionService } from '../core/session.service'; +import { Observable } from 'rxjs'; + +export type AdminDialogKind = 'configuration' | 'loggers' | 'seed' | 'smtp'; +interface AdminDialogData { kind: AdminDialogKind; } +interface LoggerSetting { logger: string; level: string; } +interface SmtpSetting { name: string; displayValue: string; value: string | number | boolean; type: 'text' | 'number' | 'boolean' | 'password'; } +const LEVELS = ['OFF', 'FATAL', 'ERROR', 'WARN', 'INFO', 'DEBUG', 'TRACE', 'ALL']; +const SMTP_DEFAULTS: SmtpSetting[] = [ + {name:'smtp.enabled',displayValue:'SMTP Enabled',value:false,type:'boolean'}, {name:'mail.transport.protocol',displayValue:'Transport Protocol',value:'smtp',type:'text'}, + {name:'mail.smtp.host',displayValue:'SMTP Server URL',value:'',type:'text'}, {name:'mail.smtp.port',displayValue:'SMTP Server Port',value:0,type:'number'}, + {name:'mail.debug',displayValue:'Enable Mail Debug Logging',value:false,type:'boolean'}, {name:'mail.smtp.starttls.enable',displayValue:'Enable Start TLS',value:false,type:'boolean'}, + {name:'mail.smtp.starttls.required',displayValue:'Require Start TLS',value:false,type:'boolean'}, {name:'mail.smtp.ssl.trust',displayValue:'SSL Trust Certificate',value:'*',type:'text'}, + {name:'mail.smtp.auth',displayValue:'Require Authentication',value:false,type:'boolean'}, {name:'smtp.from.user',displayValue:'From User',value:'',type:'text'}, + {name:'smtp.username',displayValue:'SMTP Username',value:'',type:'text'}, {name:'smtp.password',displayValue:'SMTP Password',value:'',type:'password'} +]; + +@Component({ + selector: 'app-admin-dialog', + imports: [FormsModule, ReactiveFormsModule, MatButtonModule, MatDialogModule, MatFormFieldModule, MatInputModule, MatProgressSpinnerModule, MatSelectModule, MatSlideToggleModule, MatTabsModule], + template: ` +

{{ title }}

+ + @if (loading()) { } @else { + @switch (data.kind) { + @case ('configuration') { +
+ File path + Default log level@for(level of levels;track level){{{level}}} + User expiration days + Database typeH2 (local)MySQL + @if (configForm.controls.dbType.value === 'h2') { + H2 JDBC URL + H2 username + H2 password + } @else { + MySQL host + MySQL port + MySQL username + MySQL password + MySQL root username + MySQL root password + } +
+ } + @case ('seed') {
New AES seed

Changing the seed re-encrypts all stored encrypted values and cannot be undone.

} + @case ('loggers') { + @if (canEdit()) { Set all loggers@for(level of levels;track level){{{level}}} } +
@for(item of loggers();track item.logger){
{{item.logger}}@for(level of levels;track level){{{level}}}
}
+ } + @case ('smtp') { + @for(group of smtpGroups;track group.label){
@for(item of smtp().slice(group.start,group.end);track item.name){
{{item.displayValue}}@if(item.type==='boolean'){}@else{}
}
}
+ } + } + @if (error()) {

{{error()}}

} + } +
+ @if(canEdit()){}`, + styles: [`mat-dialog-content{min-width:min(50rem,82vw);max-height:70vh}.fields{display:grid;grid-template-columns:1fr 1fr;gap:0 1rem}.settings>div{display:grid;grid-template-columns:minmax(15rem,1fr) minmax(10rem,14rem);align-items:center;gap:1rem}.settings mat-form-field,form mat-form-field{width:100%}.warning{color:#a34b00}.error{color:#b00020}`] +}) +export class AdminDialogComponent implements OnInit { + private readonly fb = inject(FormBuilder); + private readonly api = inject(PortalApiService); + private readonly session = inject(SessionService); + readonly levels = LEVELS; + readonly loading = signal(true); readonly error = signal(''); + readonly loggers = signal([]); readonly smtp = signal(SMTP_DEFAULTS.map(item => ({...item}))); + readonly smtpGroups = [{label:'General',start:0,end:5},{label:'Start TLS',start:5,end:8},{label:'Authentication',start:8,end:12}]; + readonly configForm = this.fb.group({filepath:[''],logLevel:[''],userExpirationDays:[0],dbType:['h2'],h2Url:[''],h2Username:['sa'],h2Password:[''],dbHost:[''],dbPort:[0],dbUsername:[''],dbPassword:[''],dbRootUser:[''],dbRootPassword:['']}); + readonly seedForm = this.fb.group({seed:['',Validators.required]}); + readonly title: string; + + constructor(@Inject(MAT_DIALOG_DATA) readonly data: AdminDialogData, private readonly ref: MatDialogRef) { this.title = {configuration:'Configuration',loggers:'Log Levels',seed:'AES Seed',smtp:'SMTP Configuration'}[data.kind]; } + ngOnInit(): void { + const request: Observable | null = this.data.kind === 'configuration' ? this.api.request>('/config/getConfiguration.do') + : this.data.kind === 'loggers' ? this.api.request('/logger/getLoggers.do') + : this.data.kind === 'smtp' ? this.api.request>('/system/getSmtpConfig.do') : null; + if (!request) { this.loading.set(false); return; } + request.subscribe({next: value => { this.applyLoaded(value); this.loading.set(false); },error: error => {this.error.set(error.message);this.loading.set(false);}}); + } + canEdit(): boolean { return this.session.hasPermission({configuration:'CHANGE_CONFIG',loggers:'CHANGE_LOG_LEVELS',seed:'UPDATE_SEED_VALUE',smtp:'EDIT_SMTP_CONFIG'}[this.data.kind]); } + setAll(level: string): void { this.loggers.update(items => items.map(item => ({...item,level}))); } + save(): void { + if (!this.canEdit()) return; + const endpoints = {configuration:'/config/saveConfiguration.do',loggers:'/logger/setLoggers.do',seed:'/system/updateSeed.do',smtp:'/system/updateSmtpConfig.do'}; + const payload = this.data.kind === 'configuration' ? this.configForm.getRawValue() : this.data.kind === 'loggers' ? this.loggers() : this.data.kind === 'seed' ? this.seedForm.value.seed : this.smtp(); + if (this.data.kind === 'seed' && this.seedForm.invalid) return; + if (!confirm(`Save ${this.title.toLowerCase()}?`)) return; + this.loading.set(true); this.api.request(endpoints[this.data.kind], payload).subscribe({next:()=>this.ref.close(true),error:error=>{this.error.set(error.message);this.loading.set(false);}}); + } + private applyLoaded(value: unknown): void { + if (this.data.kind === 'configuration') this.configForm.patchValue(value as never); + else if (this.data.kind === 'loggers') this.loggers.set(value as LoggerSetting[]); + else if (this.data.kind === 'smtp') { const loaded = new Map((value as Array<{name:string;value:unknown}>).map(item=>[item.name,item.value])); this.smtp.update(items=>items.map(item=>({...item,value:this.convertSmtp(item,loaded.get(item.name))}))); } + } + private convertSmtp(item:SmtpSetting,value:unknown):string|number|boolean { if(value==null)return item.value;if(item.type==='boolean')return value===true||value==='true';if(item.type==='number')return Number(value);return String(value); } +} diff --git a/portal_client/src/app/dashboard/dashboard.ts b/portal_client/src/app/dashboard/dashboard.ts new file mode 100644 index 0000000..22d632a --- /dev/null +++ b/portal_client/src/app/dashboard/dashboard.ts @@ -0,0 +1,45 @@ +import { Component, computed, inject } from '@angular/core'; +import { Router, RouterLink, RouterLinkActive, RouterOutlet } from '@angular/router'; +import { MatButtonModule } from '@angular/material/button'; +import { MatDialog } from '@angular/material/dialog'; +import { MatIconModule } from '@angular/material/icon'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatSidenavModule } from '@angular/material/sidenav'; +import { MatToolbarModule } from '@angular/material/toolbar'; +import { FEATURES } from '../core/models'; +import { PortalApiService } from '../core/portal-api.service'; +import { SessionService } from '../core/session.service'; +import { RealtimeService } from '../core/realtime.service'; +import type { AdminDialogKind } from './admin-dialog'; + +@Component({ + selector: 'app-dashboard', + imports: [RouterOutlet, RouterLink, RouterLinkActive, MatButtonModule, MatIconModule, MatMenuModule, MatSidenavModule, MatToolbarModule], + template: ` + PortalPortal + Welcome {{session.account()?.firstName}} {{session.account()?.lastName}} + + + @if(session.hasPermission('VIEW_CONFIG')){} + @if(session.hasPermission('VIEW_LOG_LEVELS')){} + @if(session.hasPermission('UPDATE_SEED_VALUE')){} + @if(session.hasPermission('VIEW_SMTP_CONFIG')){} + + + + @for(feature of visibleFeatures();track feature.path){{{feature.icon}}{{feature.title}}}`, + styles: [`mat-toolbar{background:#455a64;color:#fff}mat-toolbar img{height:42px;margin-right:1rem}.spacer{flex:1}.welcome{font-size:14px;margin-right:1rem}mat-sidenav-container{height:calc(100vh - 64px)}mat-sidenav{width:230px;padding:.75rem}mat-sidenav a{display:flex;justify-content:flex-start;width:100%;margin:.2rem 0}.active{background:#dde7eb}mat-sidenav-content{padding:1.25rem}`] +}) +export class DashboardComponent { + readonly session = inject(SessionService); + private readonly api = inject(PortalApiService); + private readonly router = inject(Router); + private readonly realtime = inject(RealtimeService); + private readonly dialog = inject(MatDialog); + readonly visibleFeatures = computed(() => FEATURES.filter(feature => this.session.hasPermission(feature.permission))); + + constructor() { this.realtime.connect(this.session.account()?.stompTopics ?? []); } + async openAdmin(kind: AdminDialogKind): Promise { const { AdminDialogComponent } = await import('./admin-dialog'); this.dialog.open(AdminDialogComponent, {data:{kind},disableClose:true,width:'min(56rem,95vw)'}); } + logout(): void { this.api.request('/account/logout.do').subscribe({next:()=>this.finishLogout(),error:()=>this.finishLogout()}); } + private finishLogout(): void { this.realtime.disconnect(); this.session.clear(); void this.router.navigate(['/login']); } +} diff --git a/portal_client/src/app/features/entity-dialog.ts b/portal_client/src/app/features/entity-dialog.ts new file mode 100644 index 0000000..a1c9ce4 --- /dev/null +++ b/portal_client/src/app/features/entity-dialog.ts @@ -0,0 +1,134 @@ +import { Component, Inject, OnInit, inject, signal } from '@angular/core'; +import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms'; +import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; +import { MatButtonModule } from '@angular/material/button'; +import { MatDatepickerModule } from '@angular/material/datepicker'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { MatNativeDateModule } from '@angular/material/core'; +import { MatOptionModule } from '@angular/material/core'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { MatSelectModule } from '@angular/material/select'; +import { forkJoin, of } from 'rxjs'; +import { FeatureDefinition } from '../core/models'; +import { PortalApiService } from '../core/portal-api.service'; + +interface DialogData { feature: FeatureDefinition; row?: Record; } +interface Choice { name?: string; value?: string; uid?: string; credentialType?: string; } + +@Component({ + selector: 'app-entity-dialog', + imports: [ReactiveFormsModule, MatButtonModule, MatDatepickerModule, MatDialogModule, MatFormFieldModule, + MatInputModule, MatNativeDateModule, MatOptionModule, MatProgressSpinnerModule, MatSelectModule], + template: ` +

{{ isNew ? 'Add' : 'Edit' }} {{ singularTitle }}

+
+ + @if (loading()) { } + @else { + @switch (data.feature.editor) { + @case ('git') { + Name + Git SCM URL + Branch + Local checkout directory + Credentials + @for (choice of choices(); track choice.uid) { {{ credentialLabel(choice) }} } + + } + @case ('credentials') { + Credential name + Credential type + @for (choice of choices(); track choice.name) { {{ choice.value }} } + + Username / identity + @if (form.controls.credentialType.value === 'SSH') { + SSH private key + Passphrase + } @else { + Password + } + } + @case ('email') { + Name + Subject + Message + } + @case ('user') { + Email address +
First name + Last name
+
Password + Confirm password
+ RoleUserAdministrator +
Effective date + Expiration date
+ } + } + @if (error()) {

{{ error() }}

} + } +
+ +
`, + styles: [`mat-dialog-content{display:flex;flex-direction:column;min-width:min(34rem,75vw);padding-top:.5rem}mat-form-field{width:100%}.pair{display:flex;gap:1rem}.pair>*{flex:1}.error{color:#b00020}`] +}) +export class EntityDialogComponent implements OnInit { + private readonly fb = inject(FormBuilder); + private readonly api = inject(PortalApiService); + readonly loading = signal(true); + readonly error = signal(''); + readonly choices = signal([]); + readonly isNew: boolean; + readonly singularTitle: string; + readonly form = this.fb.group({ + id: [null as unknown], uid: [''], name: [''], scm: [''], branch: [''], directory: [''], credentials: [null as Choice | null], + credentialType: [''], username: [''], password: [''], key: [''], passphrase: [''], + emailName: [''], emailSubject: [''], emailMessage: [''], + email: ['', Validators.email], firstName: [''], lastName: [''], confPassword: [''], role: [''], effectiveDate: [null as Date | null], expirationDate: [null as Date | null] + }); + + constructor(@Inject(MAT_DIALOG_DATA) readonly data: DialogData, private readonly ref: MatDialogRef) { + this.isNew = !data.row; + this.singularTitle = data.feature.title.replace(/ies$/, 'y').replace(/s$/, ''); + } + + ngOnInit(): void { + const requiredByEditor: Record = { + git: ['name', 'scm', 'branch', 'directory', 'credentials'], + credentials: ['name', 'credentialType', 'username'], + email: ['emailName', 'emailSubject', 'emailMessage'], + user: ['email', 'role'] + }; + for (const name of requiredByEditor[this.data.feature.editor!] ?? []) this.form.get(name)?.addValidators(Validators.required); + this.form.patchValue(this.normalizedRow()); + if (this.data.feature.editor === 'user') { + const password = this.form.controls.password; + const confirmation = this.form.controls.confPassword; + if (this.isNew) { password.addValidators(Validators.required); confirmation.addValidators(Validators.required); } + this.form.controls.effectiveDate.setValue(this.dateValue(this.data.row?.['effectiveDate']) ?? new Date()); + this.form.controls.expirationDate.setValue(this.dateValue(this.data.row?.['expirationDate']) ?? this.defaultExpiration()); + } + const auxiliary = this.data.feature.editor === 'git' ? this.api.request('/creds/get.do') + : this.data.feature.editor === 'credentials' ? this.api.request('/creds/getCredentialTypes.do') : of([]); + const expiration = this.data.feature.editor === 'user' && this.isNew + ? this.api.request<{userExpirationDays?: number}>('/config/getConfigurationValue.do', 'userExpirationDays') : of(null); + forkJoin([auxiliary, expiration]).subscribe({next: ([choices, configuration]) => { + this.choices.set(choices ?? []); + if (configuration?.userExpirationDays) this.form.controls.expirationDate.setValue(this.defaultExpiration(configuration.userExpirationDays)); + this.loading.set(false); + }, error: error => { this.error.set(error.message); this.loading.set(false); }}); + } + + save(): void { + if (this.form.invalid || !this.data.feature.saveEndpoint) return; + if (this.data.feature.editor === 'user' && this.form.value.password !== this.form.value.confPassword) { this.error.set('Passwords do not match.'); return; } + this.loading.set(true); + const payload = { ...this.data.row, ...this.form.getRawValue() }; + this.api.request(this.data.feature.saveEndpoint, payload).subscribe({next: () => this.ref.close(true), error: error => { this.error.set(error.message); this.loading.set(false); }}); + } + + credentialLabel(choice: Choice): string { return `${choice.name ?? ''}${choice.credentialType === 'SSH' ? ' (SSH Key)' : ' (Username/Password)'}`; } + private normalizedRow(): Record { const row = { ...(this.data.row ?? {}) }; delete row['password']; delete row['key']; delete row['passphrase']; return row; } + private dateValue(value: unknown): Date | null { const date = value ? new Date(String(value)) : null; return date && !Number.isNaN(date.getTime()) ? date : null; } + private defaultExpiration(days = 3650): Date { const date = new Date(); date.setDate(date.getDate() + days); return date; } +} diff --git a/portal_client/src/app/features/environment-dialog.ts b/portal_client/src/app/features/environment-dialog.ts new file mode 100644 index 0000000..cbb04b0 --- /dev/null +++ b/portal_client/src/app/features/environment-dialog.ts @@ -0,0 +1,54 @@ +import { Component, Inject, inject, signal } from '@angular/core'; +import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms'; +import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; +import { MatButtonModule } from '@angular/material/button'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { FeatureDefinition } from '../core/models'; +import { PortalApiService } from '../core/portal-api.service'; + +interface DialogData { feature: FeatureDefinition; row?: Record; } + +@Component({ + selector: 'app-environment-dialog', + imports: [ReactiveFormsModule, MatButtonModule, MatDialogModule, MatFormFieldModule, MatIconModule, MatInputModule], + template: ` +

{{ data.row ? 'Edit' : 'Add' }} Environment Variables

+
+ + @for (group of variables.controls; track group; let index = $index) { +
+ Variable name + Variable value + +
+ } + + @if (error()) {

{{ error() }}

} +
+ +
`, + styles: [`mat-dialog-content{min-width:min(40rem,80vw)}.variable{display:grid;grid-template-columns:1fr 1fr auto;gap:1rem;align-items:start}.error{color:#b00020}`] +}) +export class EnvironmentDialogComponent { + private readonly fb = inject(FormBuilder); + private readonly api = inject(PortalApiService); + readonly error = signal(''); + readonly saving = signal(false); + readonly variables = this.fb.array([this.variableGroup()]); + readonly form = this.fb.group({ variables: this.variables }); + + constructor(@Inject(MAT_DIALOG_DATA) readonly data: DialogData, private readonly ref: MatDialogRef) { + if (data.row) this.variables.at(0).patchValue(data.row); + } + + add(value?: Record): void { this.variables.push(this.variableGroup(value)); } + remove(index: number): void { this.variables.removeAt(index); } + save(): void { + if (this.form.invalid || !this.data.feature.saveEndpoint) return; + this.saving.set(true); + this.api.request(this.data.feature.saveEndpoint, this.variables.getRawValue()).subscribe({next: () => this.ref.close(true), error: error => { this.error.set(error.message); this.saving.set(false); }}); + } + private variableGroup(value?: Record) { return this.fb.group({ id: [value?.['id'] ?? null], name: [String(value?.['name'] ?? ''), Validators.required], value: [String(value?.['value'] ?? ''), Validators.required] }); } +} diff --git a/portal_client/src/app/features/feature-page.ts b/portal_client/src/app/features/feature-page.ts new file mode 100644 index 0000000..692c495 --- /dev/null +++ b/portal_client/src/app/features/feature-page.ts @@ -0,0 +1,103 @@ +import { Component, DestroyRef, computed, inject, signal } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { ActivatedRoute } from '@angular/router'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCardModule } from '@angular/material/card'; +import { MatDialog, MatDialogModule } from '@angular/material/dialog'; +import { MatIconModule } from '@angular/material/icon'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { MatTableModule } from '@angular/material/table'; +import { FEATURES } from '../core/models'; +import { PortalApiService } from '../core/portal-api.service'; +import { RealtimeService } from '../core/realtime.service'; +import { SessionService } from '../core/session.service'; + +@Component({ + selector: 'app-feature-page', + imports: [MatButtonModule, MatCardModule, MatDialogModule, MatFormFieldModule, MatIconModule, MatInputModule, MatProgressSpinnerModule, MatTableModule], + template: ` +
+

{{ feature().title }}

Manage {{ feature().title.toLowerCase() }}

+
+ Filtersearch + @if (feature().path === 'syslogs' && session.hasPermission('PURGE_LOGS')) { } + @if (canSave()) { } + +
+
+ @if (loading()) { } + @else if (error()) { {{ error() }} } + @else if (rows().length === 0) { No records found. } + @else { +
+ @for (column of dataColumns(); track column) { + + } + @if (hasActions()) { + + } + +
{{ label(column) }}{{ display(row[column]) }}Actions + @if (canSave()) { } + @if (feature().path === 'scripts' && (session.hasPermission('VIEW_SCRIPT_SCHED_STATUS') || session.hasPermission('DELETE_SCRIPT_SCHED_STATUS'))) { } + @if (canExecute()) { } + @if (canDelete()) { } +
+ }`, + styles: [`header{display:flex;align-items:center;justify-content:space-between;margin-bottom:1rem}h1{margin:0}p{color:#607d8b}.toolbar{display:flex;gap:.5rem}.table-container{overflow:auto}table{width:100%}.error{color:#b00020;padding:1rem}.empty{padding:2rem;text-align:center}`] +}) +export class FeaturePageComponent { + private readonly route = inject(ActivatedRoute); + private readonly api = inject(PortalApiService); + private readonly realtime = inject(RealtimeService); + readonly session = inject(SessionService); + private readonly dialog = inject(MatDialog); + private readonly destroyRef = inject(DestroyRef); + readonly loading = signal(true); + readonly error = signal(''); + readonly rows = signal[]>([]); + readonly filter = signal(''); + readonly displayedRows = computed(() => { const term=this.filter().trim().toLowerCase(); return term ? this.rows().filter(row=>Object.values(row).some(value=>String(value??'').toLowerCase().includes(term))) : this.rows(); }); + readonly feature = computed(() => FEATURES.find(feature => feature.path === this.route.snapshot.data['feature'])!); + readonly dataColumns = computed(() => Object.keys(this.rows()[0] ?? {}).filter(key => typeof this.rows()[0]?.[key] !== 'object').slice(0, 8)); + readonly columns = computed(() => this.hasActions() ? [...this.dataColumns(), 'actions'] : this.dataColumns()); + + constructor() { this.load(); this.realtime.triggers.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => this.load()); } + hasActions(): boolean { return this.canSave() || this.canDelete() || this.canExecute() || (this.feature().path === 'scripts' && (this.session.hasPermission('VIEW_SCRIPT_SCHED_STATUS') || this.session.hasPermission('DELETE_SCRIPT_SCHED_STATUS'))); } + canSave(): boolean { return !!this.feature().editor && !!this.feature().saveEndpoint && this.session.hasPermission(this.feature().savePermission!); } + canDelete(): boolean { return !!this.feature().deleteEndpoint && this.session.hasPermission(this.feature().deletePermission!); } + canExecute(): boolean { return !!this.feature().executeEndpoint && this.session.hasPermission(this.feature().executePermission!); } + + load(): void { + this.loading.set(true); this.error.set(''); + this.api.request(this.feature().loadEndpoint).subscribe({ + next: data => { this.rows.set(Array.isArray(data) ? data : (data ? [data as Record] : [])); this.loading.set(false); }, + error: error => { this.error.set(error.message); this.loading.set(false); } + }); + } + + async edit(row?: Record): Promise { + const config = { data: { feature: this.feature(), row }, disableClose: true, width: 'min(52rem, 95vw)' }; + if (this.feature().editor === 'environment') { + const { EnvironmentDialogComponent } = await import('./environment-dialog'); + this.dialog.open(EnvironmentDialogComponent, config).afterClosed().subscribe(saved => { if (saved) this.load(); }); + } else if (this.feature().editor === 'permission') { + const { PermissionDialogComponent } = await import('./permission-dialog'); + this.dialog.open(PermissionDialogComponent, config).afterClosed().subscribe(saved => { if (saved) this.load(); }); + } else if (this.feature().editor === 'script') { + const { ScriptDialogComponent } = await import('./script-dialog'); + this.dialog.open(ScriptDialogComponent, config).afterClosed().subscribe(saved => { if (saved) this.load(); }); + } else { + const { EntityDialogComponent } = await import('./entity-dialog'); + this.dialog.open(EntityDialogComponent, config).afterClosed().subscribe(saved => { if (saved) this.load(); }); + } + } + remove(row: Record): void { if (confirm(`Delete this ${this.feature().title} record?`)) this.api.request(this.feature().deleteEndpoint!, this.feature().editor === 'environment' ? [row] : row).subscribe({ next: () => this.load(), error: error => this.error.set(error.message) }); } + execute(row: Record): void { const verb=this.feature().path==='scripts'?'run':'pull';if(!confirm(`Are you sure you want to ${verb} ${String(row['name']??'this item')}?`))return;this.api.request(this.feature().executeEndpoint!, row).subscribe({ next: () => this.load(), error: error => this.error.set(error.message) }); } + async purgeLogs(): Promise { const {PurgeLogsDialogComponent}=await import('./purge-logs-dialog');this.dialog.open(PurgeLogsDialogComponent,{disableClose:true}).afterClosed().subscribe(count=>{if(count!==undefined)this.load();}); } + async openScriptStatus(row:Record):Promise{const {ScriptStatusDialogComponent}=await import('./script-status-dialog');this.dialog.open(ScriptStatusDialogComponent,{data:{script:row},width:'min(70rem,96vw)'}).afterClosed().subscribe(()=>this.load());} + label(value: string): string { return value.replace(/([A-Z])/g, ' $1').replace(/^./, character => character.toUpperCase()); } + display(value: unknown): string { return value == null ? '' : String(value); } +} diff --git a/portal_client/src/app/features/permission-dialog.ts b/portal_client/src/app/features/permission-dialog.ts new file mode 100644 index 0000000..923ccb0 --- /dev/null +++ b/portal_client/src/app/features/permission-dialog.ts @@ -0,0 +1,77 @@ +import { Component, Inject, OnInit, inject, signal } from '@angular/core'; +import { FormBuilder, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'; +import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { MatSlideToggleModule } from '@angular/material/slide-toggle'; +import { MatTabsModule } from '@angular/material/tabs'; +import { FeatureDefinition } from '../core/models'; +import { PortalApiService } from '../core/portal-api.service'; + +interface Permission { id: number; name: string; displayName: string; permissionCategory?: string; allowed?: boolean; } +interface Category { name: string; displayName: string; permissions: Permission[]; } +interface DialogData { feature: FeatureDefinition; row?: Record; } + +@Component({ + selector: 'app-permission-dialog', + imports: [FormsModule, ReactiveFormsModule, MatButtonModule, MatCheckboxModule, MatDialogModule, MatFormFieldModule, MatInputModule, MatProgressSpinnerModule, MatSlideToggleModule, MatTabsModule], + template: ` +

{{ data.row ? 'Edit' : 'Add' }} Permission Group

+
+ + @if (loading()) { } @else { +
+ Unique name + Display name + Enabled +
+ + @for (category of categories(); track category.name) { +
+ @for (permission of category.permissions; track permission.id) { {{ permission.displayName }} } +
+ } +
+ @if (error()) {

{{ error() }}

} + } +
+ +
`, + styles: [`mat-dialog-content{min-width:min(48rem,82vw)}.heading{display:grid;grid-template-columns:1fr 1fr auto;gap:1rem;align-items:center}.permissions{display:grid;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));gap:.75rem;padding:1rem}.error{color:#b00020}`] +}) +export class PermissionDialogComponent implements OnInit { + private readonly fb = inject(FormBuilder); + private readonly api = inject(PortalApiService); + readonly loading = signal(true); + readonly error = signal(''); + readonly categories = signal([]); + readonly form = this.fb.group({ id: [null as unknown], name: ['', Validators.required], displayName: ['', Validators.required], enabled: [false] }); + + constructor(@Inject(MAT_DIALOG_DATA) readonly data: DialogData, private readonly ref: MatDialogRef) { this.form.patchValue(data.row ?? {}); } + + ngOnInit(): void { + this.api.request('/permissions/getPermissionCategories.do').subscribe({ + next: categories => { this.categories.set(this.mergeSelections(categories ?? [])); this.loading.set(false); }, + error: error => { this.error.set(error.message); this.loading.set(false); } + }); + } + + save(): void { + if (this.form.invalid) return; + this.loading.set(true); + const permissions = this.categories().flatMap(category => category.permissions.map(permission => ({ + type: 'PermissionGroupPermission', permissionId: permission.id, permissionGroupId: this.form.value.id, + name: permission.name, displayName: permission.displayName, allowed: !!permission.allowed + }))); + const endpoint = this.data.row ? '/permissions/updatePermissionCategory.do' : '/permissions/addPermssionCategory.do'; + this.api.request(endpoint, { ...this.form.getRawValue(), permissions }).subscribe({next: () => this.ref.close(true), error: error => { this.error.set(error.message); this.loading.set(false); }}); + } + + private mergeSelections(categories: Category[]): Category[] { + const selected = new Map((this.data.row?.['permissions'] as Array<{permissionId: number; allowed: boolean}> | undefined)?.map(item => [item.permissionId, item.allowed]) ?? []); + return categories.map(category => ({ ...category, permissions: category.permissions.map(permission => ({ ...permission, allowed: selected.get(permission.id) ?? false })) })); + } +} diff --git a/portal_client/src/app/features/purge-logs-dialog.ts b/portal_client/src/app/features/purge-logs-dialog.ts new file mode 100644 index 0000000..a4f428f --- /dev/null +++ b/portal_client/src/app/features/purge-logs-dialog.ts @@ -0,0 +1,24 @@ +import { Component, inject, signal } from '@angular/core'; +import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatDatepickerModule } from '@angular/material/datepicker'; +import { MatDialogModule, MatDialogRef } from '@angular/material/dialog'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { MatNativeDateModule } from '@angular/material/core'; +import { PortalApiService } from '../core/portal-api.service'; + +@Component({ + selector: 'app-purge-logs-dialog', + imports: [ReactiveFormsModule, MatButtonModule, MatDatepickerModule, MatDialogModule, MatFormFieldModule, MatInputModule, MatNativeDateModule], + template: `

Purge Logs

Select the inclusive date range to purge.

+ Start date + End date + @if(error()){

{{error()}}

}
`, + styles: [`mat-dialog-content{display:grid;min-width:min(28rem,75vw)}.error{color:#b00020}`] +}) +export class PurgeLogsDialogComponent { + private readonly fb=inject(FormBuilder); private readonly api=inject(PortalApiService); private readonly ref=inject(MatDialogRef); + readonly saving=signal(false); readonly error=signal(''); readonly form=this.fb.group({purgeStartDate:[null as Date|null,Validators.required],purgeEndDate:[null as Date|null,Validators.required]}); + purge():void{if(this.form.invalid)return;const {purgeStartDate,purgeEndDate}=this.form.getRawValue();if(purgeStartDate!>purgeEndDate!){this.error.set('Start date must be on or before end date.');return;}if(!confirm('Permanently purge logs in this date range?'))return;this.saving.set(true);this.api.request('/logs/purge.do',this.form.getRawValue()).subscribe({next:count=>this.ref.close(count),error:error=>{this.error.set(error.message);this.saving.set(false);}});} +} diff --git a/portal_client/src/app/features/script-dialog.ts b/portal_client/src/app/features/script-dialog.ts new file mode 100644 index 0000000..234cea4 --- /dev/null +++ b/portal_client/src/app/features/script-dialog.ts @@ -0,0 +1,66 @@ +import { Component, Inject, OnInit, inject, signal } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { MatSelectModule } from '@angular/material/select'; +import { MatTabsModule } from '@angular/material/tabs'; +import { forkJoin } from 'rxjs'; +import { FeatureDefinition } from '../core/models'; +import { PortalApiService } from '../core/portal-api.service'; + +interface DialogData { feature: FeatureDefinition; row?: Record; } +interface Choice { id?:number; uid?:string; name?:string; value?:string; emailName?:string; email?:string; username?:string; firstName?:string; lastName?:string; } +type Item = any; + +@Component({ + selector:'app-script-dialog', + imports:[FormsModule,MatButtonModule,MatCheckboxModule,MatDialogModule,MatFormFieldModule,MatIconModule,MatInputModule,MatProgressSpinnerModule,MatSelectModule,MatTabsModule], + template:`

{{data.row?'Edit':'Add'}} Script

+ @if(loading()){}@else{ + +
+ Name + Type@for(type of scriptTypes();track type.name){{{type.value}}} + Base directory + Output directory + Command +
+ @if(script.scriptType==='REMOTE'){
+ HostPort + Credentials@for(cred of credentials();track cred.uid){{{cred.name}}} +
} + @if(script.scriptType==='SCP'){
+ From host (LOCAL supported)From port + From credentials@for(cred of credentials();track cred.uid){{{cred.name}}} + To host (LOCAL supported)To port + To credentials@for(cred of credentials();track cred.uid){{{cred.name}}} + Data regex +
} +
@for(item of script.parameters;track item;let i=$index){
Parameter
}
+
@for(item of script.scriptVariables;track item;let i=$index){
NameValue
}
+
@for(item of script.schedule;track item;let i=$index){
Frequency@for(freq of frequencies();track freq.name){{{freq.value}}}StartEndMax executions (0 = unlimited)
}
+
@for(item of script.scriptChain;track item;let i=$index){
Child script@for(child of availableScripts();track child.id){{{child.name}}}Required exit statusDelay minutes
}
+
@for(item of script.scriptEmails;track item;let i=$index){
Template@for(email of emails();track email.id){{{email.emailName}}}Recipients@for(user of users();track user.id){{{user.email||user.username}}}
}
+
@if(error()){

{{error()}}

}} +
`, + styles:[`mat-dialog-content{min-width:min(70rem,88vw);height:min(45rem,72vh)}.grid{display:grid;grid-template-columns:1fr 1fr;gap:0 1rem;padding:1rem}.wide{grid-column:1/-1}.collection{padding:1rem}.collection>div{display:flex;gap:1rem;align-items:start}.collection mat-form-field{flex:1}.schedule{display:grid!important;grid-template-columns:repeat(4,1fr) auto}.error{color:#b00020}`] +}) +export class ScriptDialogComponent implements OnInit{ + private readonly api=inject(PortalApiService);private readonly ref=inject(MatDialogRef);readonly loading=signal(true);readonly error=signal(''); + readonly scriptTypes=signal([]);readonly frequencies=signal([]);readonly credentials=signal([]);readonly availableScripts=signal([]);readonly emails=signal([]);readonly users=signal([]); + readonly script:Item; + constructor(@Inject(MAT_DIALOG_DATA)readonly data:DialogData){this.script=this.normalize(data.row);} + ngOnInit():void{forkJoin({types:this.api.request('/scripts/getScriptType.do'),freq:this.api.request('/scripts/getScheduleFrequencies.do'),creds:this.api.request('/creds/get.do'),scripts:this.api.request('/scripts/getAll.do'),emails:this.api.request('/system/getEmailTemplates.do'),users:this.api.request('/account/getAll.do')}).subscribe({next:value=>{this.scriptTypes.set(value.types);this.frequencies.set(value.freq);this.credentials.set(value.creds);this.availableScripts.set(value.scripts.filter(item=>item.id!==this.script.id));this.emails.set(value.emails);this.users.set(value.users);this.loading.set(false);},error:error=>{this.error.set(error.message);this.loading.set(false);}});} + add(key:string,item:Item):void{this.script[key].push(item);} remove(array:Item[],index:number):void{array.splice(index,1);} + addSchedule():void{this.script.schedule.unshift({id:null,jobId:'',startDatetime:this.localDate(new Date()),endDatetime:null,frequency:null,maxExecutions:0,currentExecutionCount:0,lastRun:null,script:this.script.id,executionStatus:null});} + selectEmail(target:Item,id:number):void{const source=this.emails().find(item=>item.id===id);if(source)Object.assign(target,structuredClone(source),{scriptId:this.script.id,recipients:target.recipients??[]});} + save():void{if(!this.script.name||!this.script.command||!this.script.scriptType){this.error.set('Name, type, and command are required.');return;}const payload=structuredClone(this.script);payload.schedule=payload.schedule.map((item:Item)=>({...item,startDatetime:this.timestamp(item.startDatetime),endDatetime:this.timestamp(item.endDatetime),lastRun:this.timestamp(item.lastRun)}));this.loading.set(true);this.api.request(payload.id==null?'/scripts/addScript.do':'/scripts/updateScript.do',payload).subscribe({next:()=>this.ref.close(true),error:error=>{this.error.set(error.message);this.loading.set(false);}});} + private normalize(row?:Record):Item{const value=structuredClone(row??{}) as Item;const result:Item={id:null,name:'',command:'',scriptType:'',baseDirectory:'',outputDirectory:'',...value};result.remote={scriptId:value.id??null,scriptCredentials:null,url:'',port:22,...value.remote};result.scp={id:null,scriptId:value.id??null,fromHost:'',fromPort:22,fromCredentials:null,toHost:'',toPort:22,toCredentials:null,dataRegex:'',...value.scp};result.parameters=value.parameters??[];result.schedule=(value.schedule??[]).map((item:Item)=>({...item,startDatetime:this.localDate(item.startDatetime),endDatetime:this.localDate(item.endDatetime)}));result.scriptVariables=value.scriptVariables??[];result.scriptChain=value.scriptChain??[];result.scriptEmails=value.scriptEmails??[];return result;} + private timestamp(value:unknown):number|undefined{if(value==null||value==='')return undefined;if(typeof value==='number')return value;const result=new Date(String(value)).getTime();return Number.isNaN(result)?undefined:result;} + private localDate(value:unknown):string{if(!value)return'';const date=new Date(typeof value==='number'&&value<1e12?value*1000:value as string|number|Date);if(Number.isNaN(date.getTime()))return'';const offset=date.getTimezoneOffset()*60000;return new Date(date.getTime()-offset).toISOString().slice(0,16);} +} diff --git a/portal_client/src/app/features/script-status-dialog.ts b/portal_client/src/app/features/script-status-dialog.ts new file mode 100644 index 0000000..a75ec31 --- /dev/null +++ b/portal_client/src/app/features/script-status-dialog.ts @@ -0,0 +1,38 @@ +import { Component, Inject, inject, signal } from '@angular/core'; +import { DatePipe } from '@angular/common'; +import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCardModule } from '@angular/material/card'; +import { MatExpansionModule } from '@angular/material/expansion'; +import { MatIconModule } from '@angular/material/icon'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { PortalApiService } from '../core/portal-api.service'; +import { SessionService } from '../core/session.service'; + +interface DialogData { script: Record; } + +@Component({ + selector:'app-script-status-dialog', + imports:[DatePipe,MatButtonModule,MatCardModule,MatDialogModule,MatExpansionModule,MatIconModule,MatProgressSpinnerModule], + template:`

Schedules — {{data.script['name']}}

+
@for(schedule of schedules();track schedule['id']){
{{schedule['jobId']||'Unscheduled'}}{{schedule['frequency']}}{{schedule['startDatetime']|date:'medium'}}{{statusLabel(schedule)}} + @if(canViewStatus()&&schedule['jobId']){} + @if(canDeleteSchedule()){}
}@empty{

No schedules configured.

}
+ @if(loading()){}@else if(selectedJob()){ +

Runs for {{selectedJob()}}

@for(run of runs();track run['id'];let index=$index){Run {{runs().length-index}}{{run['exitStatus']===0?'Success':'Failed'}} · {{run['startTime']|date:'medium'}}
{{run['results']}}
+ @if(run['resourceFiles']?.length){

Generated files

@for(file of run['resourceFiles'];track file['id']){
{{file['fileName']}}download@if(canDeleteFile()){}
}}
}@empty{

No run status found.

} + }@if(error()){

{{error()}}

} +
`, + styles:[`mat-dialog-content{min-width:min(65rem,86vw);max-height:75vh}.schedules mat-card{padding:.65rem;margin:.4rem 0}.schedules mat-card>div{display:grid;grid-template-columns:2fr 1fr 2fr 1fr auto auto;align-items:center;gap:.75rem}.failed,.error{color:#b00020}pre{white-space:pre-wrap;max-height:20rem;overflow:auto}.file{display:flex;align-items:center}.file span{flex:1}`] +}) +export class ScriptStatusDialogComponent{ + private readonly api=inject(PortalApiService);readonly session=inject(SessionService); + readonly schedules=signal[]>([]);readonly runs=signal[]>([]);readonly selectedJob=signal('');readonly loading=signal(false);readonly error=signal(''); + constructor(@Inject(MAT_DIALOG_DATA)readonly data:DialogData){this.schedules.set(data.script['schedule']??[]);} + canViewStatus():boolean{return this.session.hasPermission('VIEW_SCRIPT_SCHED_STATUS');}canDeleteSchedule():boolean{return this.session.hasPermission('DELETE_SCRIPT_SCHED_STATUS');}canDeleteFile():boolean{return this.session.hasPermission('DELETE_FILE');} + statusLabel(schedule:Record):string{return schedule['currentExecutionCount']==null?'Not run':schedule['executionStatus']===0?'Success':'Failed';} + loadStatus(schedule:Record):void{this.loading.set(true);this.error.set('');this.selectedJob.set(String(schedule['jobId']));this.api.request[]>('/scripts/getScriptScheduleStatus.do',schedule['jobId']).subscribe({next:runs=>{this.runs.set(runs??[]);this.loading.set(false);},error:error=>{this.error.set(error.message);this.loading.set(false);}});} + deleteSchedule(schedule:Record):void{if(!confirm(`Delete schedule ${schedule['jobId']}?`))return;this.api.request('/scripts/deleteScriptSchedule.do',schedule).subscribe({next:()=>this.schedules.update(items=>items.filter(item=>item!==schedule)),error:error=>this.error.set(error.message)});} + deleteFile(file:Record):void{if(!confirm(`Delete ${file['fileName']}?`))return;this.api.request('/file/delete.do',file).subscribe({next:()=>this.runs.update(runs=>runs.map(run=>({...run,resourceFiles:(run['resourceFiles']??[]).filter((item:Record)=>item['id']!==file['id'])}))),error:error=>this.error.set(error.message)});} + downloadUrl(file:Record):string{return `/portal/file/download.do?id=${encodeURIComponent(file['id'])}`;} +} diff --git a/portal_client/src/app/login/login.ts b/portal_client/src/app/login/login.ts new file mode 100644 index 0000000..540c038 --- /dev/null +++ b/portal_client/src/app/login/login.ts @@ -0,0 +1,38 @@ +import { Component, inject, signal } from '@angular/core'; +import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; +import { Router } from '@angular/router'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCardModule } from '@angular/material/card'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { Account } from '../core/models'; +import { PortalApiService } from '../core/portal-api.service'; +import { SessionService } from '../core/session.service'; +import { RealtimeService } from '../core/realtime.service'; + +@Component({ + selector: 'app-login', + imports: [ReactiveFormsModule, MatButtonModule, MatCardModule, MatFormFieldModule, MatIconModule, MatInputModule], + template: `
Portal

Portal

+
+ Usernameaccount_circle + Passwordlock +

Server connection: {{ realtime.status() }}

@if (error()) {

{{ error() }}

} + +
`, + styles: [`.login-page{min-height:100vh;display:grid;place-items:center;background:#eceff1}mat-card{width:min(420px,90vw);padding:2rem;text-align:center}img{max-width:180px;margin:auto}form{display:grid;gap:.75rem}.error{color:#b00020}`] +}) +export class LoginComponent { + private readonly api = inject(PortalApiService); private readonly session = inject(SessionService); private readonly router = inject(Router); readonly realtime = inject(RealtimeService); + readonly processing = signal(false); readonly error = signal(''); + readonly form = new FormGroup({ username: new FormControl('', { nonNullable: true, validators: Validators.required }), password: new FormControl('', { nonNullable: true, validators: Validators.required }) }); + constructor() { this.realtime.connect(); } + login(): void { + if (this.form.invalid) return; this.processing.set(true); this.error.set(''); + this.api.request('/account/login.do', this.form.getRawValue()).subscribe({ + next: account => { if (account['message']) { this.error.set(String(account['message'])); this.processing.set(false); return; } this.session.setAccount(account); this.realtime.connect(account.stompTopics ?? []); void this.router.navigate(['/dashboard']); }, + error: error => { this.error.set(error.message); this.processing.set(false); } + }); + } +} diff --git a/portal_client/src/index.html b/portal_client/src/index.html new file mode 100644 index 0000000..0740cc3 --- /dev/null +++ b/portal_client/src/index.html @@ -0,0 +1,13 @@ + + + + + Portal + + + + + + + + diff --git a/portal_client/src/main.ts b/portal_client/src/main.ts new file mode 100644 index 0000000..5df75f9 --- /dev/null +++ b/portal_client/src/main.ts @@ -0,0 +1,6 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { appConfig } from './app/app.config'; +import { App } from './app/app'; + +bootstrapApplication(App, appConfig) + .catch((err) => console.error(err)); diff --git a/portal_client/src/polyfills.ts b/portal_client/src/polyfills.ts new file mode 100644 index 0000000..2f3d229 --- /dev/null +++ b/portal_client/src/polyfills.ts @@ -0,0 +1,3 @@ +// sockjs-client still expects the Node-style `global` alias in a browser. +// Define it before Angular loads the application bundle. +(globalThis as typeof globalThis & { global: typeof globalThis }).global = globalThis; diff --git a/portal_client/src/styles.scss b/portal_client/src/styles.scss new file mode 100644 index 0000000..a8b7e36 --- /dev/null +++ b/portal_client/src/styles.scss @@ -0,0 +1,5 @@ +@use '@angular/material' as mat; + +html { @include mat.theme((color: (primary: mat.$azure-palette, tertiary: mat.$blue-palette), typography: Arial, density: 0)); } +html, body { height: 100%; margin: 0; font-family: Arial, sans-serif; background: #f4f6f7; } +* { box-sizing: border-box; } diff --git a/portal_client/tsconfig.app.json b/portal_client/tsconfig.app.json new file mode 100644 index 0000000..cb151e1 --- /dev/null +++ b/portal_client/tsconfig.app.json @@ -0,0 +1,14 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "types": [] + }, + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "src/**/*.spec.ts" + ] +} diff --git a/portal_client/tsconfig.json b/portal_client/tsconfig.json new file mode 100644 index 0000000..0f86dc5 --- /dev/null +++ b/portal_client/tsconfig.json @@ -0,0 +1,35 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "compileOnSave": false, + "compilerOptions": { + // stompjs 7.3 selects its UMD bundle for browsers; use its shipped ESM entry. + "paths": { + "@stomp/stompjs": ["./node_modules/@stomp/stompjs/esm6/index"] + }, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "skipLibCheck": true, + "isolatedModules": true, + "experimentalDecorators": true, + "importHelpers": true, + "target": "ES2022", + "module": "preserve" + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true + }, + "files": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/portal_client/tsconfig.spec.json b/portal_client/tsconfig.spec.json new file mode 100644 index 0000000..37861f7 --- /dev/null +++ b/portal_client/tsconfig.spec.json @@ -0,0 +1,17 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "types": [ + "vitest/globals" + ] + }, + "files": [ + "src/polyfills.ts" + ], + "include": [ + "src/**/*.d.ts", + "src/**/*.spec.ts" + ] +} diff --git a/portal_client/webpack.config.js b/portal_client/webpack.config.js deleted file mode 100644 index 8f74016..0000000 --- a/portal_client/webpack.config.js +++ /dev/null @@ -1,43 +0,0 @@ -const path = require('path'); -const webpack = require('webpack'); -const CopyWebpackPlugin = require('copy-webpack-plugin'); - -const YarnFileCopy = require('./yarn_file_copy'); - -// assets.js -const Assets = require('./assets'); -module.exports = { - module: { - rules: [ - { - test: /\.(png|woff|woff2|eot|ttf|svg|css|js)$/, - loader: 'file-loader', - options: { - emitFile: false - } - } - ] - }, - entry: Assets, - output: { - path: __dirname + "/app/yarn_components/", - filename: "ignore_me.js" - }, - plugins: [ - new CopyWebpackPlugin( - Assets.map(asset => { - return { - from: path.resolve(__dirname, `./node_modules/${asset}`), - to: path.resolve(__dirname, `./app/yarn_components/${asset}`) - }; - }) - ), - new YarnFileCopy({ - assets: Assets, - indexFile: 'index.html', - outputDir: 'app', - jsDir: 'yarn_components', - cssDir: 'yarn_components', - }) - ] -}; \ No newline at end of file diff --git a/portal_client/yarn_file_copy.js b/portal_client/yarn_file_copy.js deleted file mode 100644 index c733abf..0000000 --- a/portal_client/yarn_file_copy.js +++ /dev/null @@ -1,110 +0,0 @@ -function YarnFileCopy(options = {}) { - - if (!options.assets === undefined || !Array.isArray(options.assets)) { - throw new Error('No assets defined or assets are not in an array'); - }; - - if (options.indexFile === undefined) { - throw new Error('No index file set. Please specify options.indexFile'); - } - - options.outputDir = options.outputDir || '.'; - options.jsDir = options.jsDir || '.'; - options.cssDir = options.cssDir || '.'; - - //Defaults debug level to 'warning' - options.debug = options.debug || 'warning'; - - // Defaults debugging to info if only true is specified - if (options.debug === true) { - options.debug = 'info'; - } - - const debugLevels = ['warning', 'info', 'debug']; - const debugLevelIndex = debugLevels.indexOf(options.debug); - function log(msg, level) { - if (level === 0) { - msg = `WARNING - ${msg}`; - } else { - level = level || 1; - } - if (level <= debugLevelIndex) { - console.log('[YarnFileCopy] ' + msg); // eslint-disable-line no-console - } - } - - function warning(msg) { - log(msg, 0); - } - - function info(msg) { - log(msg, 1); - } - - function debug(msg) { - log(msg, 2); - } - - const apply = (compiler) => { - compiler.plugin('emit', (compilation, cb) => { - debug('starting emit'); - const callback = () => { - debug('finishing emit'); - cb(); - }; - var fs = require('fs'), - readline = require('readline'), - instream = fs.createReadStream(options.indexFile), - outstream = new(require('stream'))(), - rl = readline.createInterface(instream, outstream); - - var content = ''; - rl.on('line', (line) => { - debug(line); - if (line.indexOf('yarn:css') > -1) { - options.assets - .filter(asset => asset.endsWith('.css')) - .forEach((asset) => { - content += ' \n'; - }); - } else if (line.indexOf('yarn:js') > -1) { - options.assets - .filter(asset => asset.endsWith('.js')) - .forEach((asset) => { - content += ' \n'; - }); - } else { - content += line + '\n'; - } - }); - - rl.on('close', (line) => { - var file = require('fs'); - file.writeFile(options.outputDir + '/index.html', content, (err) =>{ - if (err) { - throw err; - } - debug('new index saved'); - }); - }); - - callback(); - }); - - compiler.plugin('after-emit', (compilation, cb) => { - debug('starting after-emit'); - const callback = () => { - debug('finishing after-emit'); - cb(); - }; - - callback(); - }); - } - - return { - apply - }; -} - -module.exports = YarnFileCopy; \ No newline at end of file diff --git a/portal_common/pom.xml b/portal_common/pom.xml index c366aa8..11fc8f6 100644 --- a/portal_common/pom.xml +++ b/portal_common/pom.xml @@ -14,9 +14,6 @@ ${project.parent.basedir} - 2.9.4 - 2.5.0 - 2.9.1 @@ -41,12 +38,12 @@ org.apache.httpcomponents httpclient - 4.5.5 + 4.5.14 org.apache.httpcomponents httpmime - 4.5.5 + 4.5.14 @@ -57,12 +54,12 @@ org.apache.commons commons-dbcp2 - 2.4.0 + 2.14.0 org.apache.commons commons-pool2 - 2.6.0 + 2.13.1 @@ -83,4 +80,4 @@ - \ No newline at end of file + diff --git a/portal_common/src/main/java/net/locusworks/portal/common/PortalDataSource.java b/portal_common/src/main/java/net/locusworks/portal/common/PortalDataSource.java index 50f53f3..2ce6661 100644 --- a/portal_common/src/main/java/net/locusworks/portal/common/PortalDataSource.java +++ b/portal_common/src/main/java/net/locusworks/portal/common/PortalDataSource.java @@ -1,6 +1,7 @@ package net.locusworks.portal.common; -import java.util.HashMap; +import java.time.Duration; +import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; @@ -25,8 +26,8 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.portal.common.services.ConfigurationService; /*** @@ -40,8 +41,14 @@ public class PortalDataSource { private static ApplicationLogger logger = ApplicationLoggerFactory.getLogger(PortalDataSource.class); - private static final String DRIVER = "com.mysql.cj.jdbc.Driver"; - private static final String JNDI_STRING = "jdbc:mysql://%s:%d%s"; + private static final String MYSQL_DRIVER = "com.mysql.cj.jdbc.Driver"; + private static final String MYSQL_JDBC_URL = "jdbc:mysql://%s:%d%s"; + private static final String H2_DRIVER = "org.h2.Driver"; + + public static final String DATABASE_DRIVER_PROPERTY = "portal.database.driver"; + public static final String DATABASE_URL_PROPERTY = "portal.database.url"; + public static final String DATABASE_USERNAME_PROPERTY = "portal.database.username"; + public static final String DATABASE_PASSWORD_PROPERTY = "portal.database.password"; private static Map mysqlProperties; static { @@ -88,20 +95,22 @@ public class PortalDataSource { * @return A Datasource representing the connection * @throws Exception */ - private static DataSource createDataSource(String url, String userName, String password) throws Exception { - Class.forName(DRIVER).newInstance(); + private static DataSource createDataSource(String driver, String url, String userName, String password) throws Exception { + Class.forName(driver).getDeclaredConstructor().newInstance(); Properties props = new Properties(); props.setProperty("user", userName); props.setProperty("password", password); - List params = mysqlProperties - .entrySet() - .stream() - .map(prop -> String.format("%s=%s", prop.getKey(), prop.getValue())) - .collect(Collectors.toList()); - - url = String.format("%s?%s", url, StringUtils.join(params, "&")); + if (MYSQL_DRIVER.equals(driver)) { + List params = mysqlProperties + .entrySet() + .stream() + .map(prop -> String.format("%s=%s", prop.getKey(), prop.getValue())) + .collect(Collectors.toList()); + + url = String.format("%s?%s", url, StringUtils.join(params, "&")); + } //Create a connection factory that the pool will use to create connections ConnectionFactory cf = new DriverManagerConnectionFactory(url, props); @@ -115,7 +124,7 @@ public class PortalDataSource { poolConfig.setMaxTotal(100); AbandonedConfig abandonConfig = new AbandonedConfig(); - abandonConfig.setRemoveAbandonedTimeout(60); + abandonConfig.setRemoveAbandonedTimeout(Duration.ofSeconds(60)); abandonConfig.setLogAbandoned(false); abandonConfig.setRemoveAbandonedOnBorrow(true); abandonConfig.setRemoveAbandonedOnMaintenance(true); @@ -124,8 +133,8 @@ public class PortalDataSource { GenericObjectPool connectionPool = new GenericObjectPool<>(pcf, poolConfig); connectionPool.setTestOnBorrow(true); connectionPool.setTestWhileIdle(true); - connectionPool.setTimeBetweenEvictionRunsMillis(10000); - connectionPool.setMinEvictableIdleTimeMillis(1000); + connectionPool.setDurationBetweenEvictionRuns(Duration.ofSeconds(10)); + connectionPool.setMinEvictableIdleDuration(Duration.ofSeconds(1)); connectionPool.setAbandonedConfig(abandonConfig); pcf.setPool(connectionPool); @@ -140,13 +149,28 @@ public class PortalDataSource { * @return * @throws Exception */ - private DataSource createDataSource(Jndi jndi) throws Exception { + private DataSource createDataSource(Jndi jndi) throws Exception { if (dataSources.containsKey(jndi)) { return dataSources.get(jndi); } - String tail = null; + String configuredUrl = System.getProperty(DATABASE_URL_PROPERTY); + if (StringUtils.isNotBlank(configuredUrl)) { + String driver = System.getProperty(DATABASE_DRIVER_PROPERTY, "org.h2.Driver"); + String userName = System.getProperty(DATABASE_USERNAME_PROPERTY, "sa"); + String password = System.getProperty(DATABASE_PASSWORD_PROPERTY, ""); + dataSources.put(jndi, createDataSource(driver, configuredUrl, userName, password)); + return dataSources.get(jndi); + } + + if (configurationService.isH2Database()) { + dataSources.put(jndi, createDataSource(H2_DRIVER, configurationService.getH2Url(), + configurationService.getH2Username(), configurationService.getH2Password())); + return dataSources.get(jndi); + } + + String tail = null; boolean isRoot = false; switch (jndi) { case PORTAL_ROOT: @@ -163,9 +187,9 @@ public class PortalDataSource { String userName = isRoot ? configurationService.getDatabaseRootUsername() : configurationService.getDatabaseUsername(); String passwd = isRoot? configurationService.getDatabaseRootPassword() : configurationService.getDatabasePassword(); - String url = String.format(JNDI_STRING, configurationService.getDatabaseHost(), configurationService.getDatabasePort(), tail); - - dataSources.put(jndi, createDataSource(url, userName, passwd)); + String url = String.format(MYSQL_JDBC_URL, configurationService.getDatabaseHost(), configurationService.getDatabasePort(), tail); + + dataSources.put(jndi, createDataSource(MYSQL_DRIVER, url, userName, passwd)); return dataSources.get(jndi); } diff --git a/portal_common/src/main/java/net/locusworks/portal/common/enums/Configuration.java b/portal_common/src/main/java/net/locusworks/portal/common/enums/Configuration.java index 860040e..9e9be2f 100644 --- a/portal_common/src/main/java/net/locusworks/portal/common/enums/Configuration.java +++ b/portal_common/src/main/java/net/locusworks/portal/common/enums/Configuration.java @@ -6,8 +6,12 @@ package net.locusworks.portal.common.enums; * @since 1.0.0-RELEASE * @version 1.0 */ -public enum Configuration { - DB_ROOT_USER("dbRootUser"), +public enum Configuration { + DB_TYPE("dbType"), + H2_URL("h2Url"), + H2_USER("h2Username"), + H2_PASSWORD("h2Password"), + DB_ROOT_USER("dbRootUser"), DB_ROOT_PASSWORD("dbRootPassword"), DB_USER("dbUsername"), DB_PASSWORD("dbPassword"), @@ -105,4 +109,4 @@ public enum Configuration { public static boolean notIn(String value, Configuration... confTypes) { return !in(value, confTypes); } -} \ No newline at end of file +} diff --git a/portal_common/src/main/java/net/locusworks/portal/common/http/HttpClientHelper.java b/portal_common/src/main/java/net/locusworks/portal/common/http/HttpClientHelper.java index 0cf97f5..3d9e533 100644 --- a/portal_common/src/main/java/net/locusworks/portal/common/http/HttpClientHelper.java +++ b/portal_common/src/main/java/net/locusworks/portal/common/http/HttpClientHelper.java @@ -18,8 +18,8 @@ import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.util.EntityUtils; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; /** * Class to handle http(s) connections diff --git a/portal_common/src/main/java/net/locusworks/portal/common/services/AESService.java b/portal_common/src/main/java/net/locusworks/portal/common/services/AESService.java index 16b37ca..759faf7 100644 --- a/portal_common/src/main/java/net/locusworks/portal/common/services/AESService.java +++ b/portal_common/src/main/java/net/locusworks/portal/common/services/AESService.java @@ -1,13 +1,13 @@ package net.locusworks.portal.common.services; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import org.apache.commons.io.IOUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Service; -import net.locusworks.common.crypto.AES; +import net.locusworks.crypto.AES; import net.locusworks.common.utils.Utils; import net.locusworks.portal.common.triggers.SeedTrigger; @@ -50,9 +50,8 @@ public class AESService implements ApplicationListener{ */ @PostConstruct public void init() { - try { - confService.init(); //initialize our conf file to pick up the latest changes if any - //Check to see if the environment variable is set first + try { + //Check to see if the environment variable is set first seedLoc = System.getProperty(PORTAL_AES_SEED) == null ? System.getenv(PORTAL_AES_SEED) : System.getProperty(PORTAL_AES_SEED); if (seedLoc == null) { //If it can't find it in the environment variable load it from the properties file @@ -176,6 +175,6 @@ public class AESService implements ApplicationListener{ @Override public void onApplicationEvent(SeedTrigger event) { String seed = event.getSeed(); - this.aes.setSeed(seed); + this.aes = AES.createInstance(seed); } -} \ No newline at end of file +} diff --git a/portal_common/src/main/java/net/locusworks/portal/common/services/ConfigurationService.java b/portal_common/src/main/java/net/locusworks/portal/common/services/ConfigurationService.java index aedd784..fb8089b 100644 --- a/portal_common/src/main/java/net/locusworks/portal/common/services/ConfigurationService.java +++ b/portal_common/src/main/java/net/locusworks/portal/common/services/ConfigurationService.java @@ -1,22 +1,25 @@ package net.locusworks.portal.common.services; -import static net.locusworks.portal.common.utils.Constants.PROPERTIES_FILE; +import static net.locusworks.portal.common.utils.Constants.PROPERTIES_FILE; +import static net.locusworks.portal.common.utils.Constants.getPortalHome; import java.io.File; -import java.io.IOException; -import java.lang.reflect.Field; -import java.util.Enumeration; +import java.io.IOException; +import java.lang.reflect.Field; +import java.nio.file.Files; +import java.util.Enumeration; import java.util.Map; import java.util.Properties; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; import net.locusworks.common.configuration.PropertiesManager; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.portal.common.enums.Configuration; import net.locusworks.portal.common.exceptions.PortalException; import net.locusworks.portal.json.ConfigurationRequest; @@ -41,8 +44,9 @@ public final class ConfigurationService { private static ApplicationLogger logger = ApplicationLoggerFactory.getLogger(ConfigurationService.class); - @Autowired - private AESService aesService; + @Autowired + @Lazy + private AESService aesService; /** * Initialize the configuration service @@ -61,19 +65,14 @@ public final class ConfigurationService { throw ex; } - // create portalConf File object - portalConf = new File(String.format("%s/conf/%s", System.getProperty("catalina.base"), PROPERTIES_FILE)); - - //Create a temporary key directory - keyDir = String.format("%s/keys", System.getProperty("catalina.base")); - File keyDirFile = new File(keyDir); - if (!keyDirFile.exists()) { - try { - keyDirFile.mkdirs(); - } catch (Exception ex) { - throw ex; - } - } + // create portalConf File object + File portalHome = getPortalHome().toFile(); + Files.createDirectories(portalHome.toPath()); + portalConf = new File(portalHome, PROPERTIES_FILE); + + // Create the directory used for temporary private keys. + keyDir = new File(portalHome, "keys").getAbsolutePath(); + Files.createDirectories(new File(keyDir).toPath()); // initial config load loadConf(); } @@ -88,7 +87,7 @@ public final class ConfigurationService { // and all default items will be added below and the file created logger.info("Loading config file: " + portalConf); try { - configuration = PropertiesManager.loadConfiguration(portalConf); + configuration = PropertiesManager.loadConfiguration(portalConf.toPath()); } catch (Exception e) { logger.info("Config file: " + portalConf + " will be created from template"); configuration = new Properties(); @@ -107,7 +106,7 @@ public final class ConfigurationService { } if (changed) { - PropertiesManager.saveConfiguration(configuration, portalConf, "Patch Repository properties file"); + PropertiesManager.saveConfiguration(configuration, portalConf.toPath(), "Patch Repository properties file"); } lastModified = portalConf.lastModified(); @@ -118,8 +117,9 @@ public final class ConfigurationService { * @param confs Configuration property values to save * @throws Exception general exception */ - public void saveToConf(Properties confs) throws Exception { - PropertiesManager.saveConfiguration(confs, portalConf, "Patch Repository properties file"); + public void saveToConf(Properties confs) throws Exception { + Files.createDirectories(portalConf.toPath().getParent()); + PropertiesManager.saveConfiguration(confs, portalConf.toPath(), "Patch Repository properties file"); logger.info("Saved config file: " + portalConf + ", " + confs.size() + " entries"); loadConf(); } @@ -130,10 +130,35 @@ public final class ConfigurationService { * then checks the patchrepo.properties file * @return root database username */ - public String getDatabaseRootUsername() { + public String getDatabaseRootUsername() { String rootUser = System.getProperty(DB_ROOT_USER_PROPERTY); return rootUser != null ? rootUser : configuration.getProperty(Configuration.DB_ROOT_USER.getValue()); - } + } + + public String getDatabaseType() { + String dbType = configuration.getProperty(Configuration.DB_TYPE.getValue(), "h2").trim().toLowerCase(); + if (!dbType.equals("h2") && !dbType.equals("mysql")) { + throw new IllegalArgumentException("Unsupported dbType '" + dbType + "'; expected h2 or mysql"); + } + return dbType; + } + + public boolean isH2Database() { + return "h2".equals(getDatabaseType()); + } + + public String getH2Url() { + return replaceProperties(configuration.getProperty(Configuration.H2_URL.getValue())); + } + + public String getH2Username() { + return configuration.getProperty(Configuration.H2_USER.getValue(), "sa"); + } + + public String getH2Password() { + String password = configuration.getProperty(Configuration.H2_PASSWORD.getValue(), ""); + return StringUtils.isBlank(password) ? "" : aesService.decrypt(password); + } /** * Get the database root user password @@ -264,7 +289,19 @@ public final class ConfigurationService { for (Configuration type : types) { String key = type.getValue(); String value = this.configuration.getProperty(key); - switch(type) { + switch(type) { + case DB_TYPE: + cr.setDbType(value); + break; + case H2_URL: + cr.setH2Url(value); + break; + case H2_USER: + cr.setH2Username(value); + break; + case H2_PASSWORD: + cr.setH2Password(value); + break; case CA_CERT_FILE: cr.setCaCertFile(value); break; @@ -330,15 +367,18 @@ public final class ConfigurationService { return lastModified; } - public void updateEncryption(String newSeed) throws Exception { - String newDBRootPassword = aesService.changeEncryptionValue(configuration.getProperty(Configuration.DB_ROOT_PASSWORD.getValue()), newSeed); - String newDBPassword = aesService.changeEncryptionValue(configuration.getProperty(Configuration.DB_PASSWORD.getValue()), newSeed); - String newCACertPassword = aesService.changeEncryptionValue(configuration.getProperty(Configuration.CA_CERT_PASSWORD.getValue()), newSeed); + public void updateEncryption(String newSeed) throws Exception { + String newDBRootPassword = aesService.changeEncryptionValue(configuration.getProperty(Configuration.DB_ROOT_PASSWORD.getValue()), newSeed); + String newDBPassword = aesService.changeEncryptionValue(configuration.getProperty(Configuration.DB_PASSWORD.getValue()), newSeed); + String h2Password = configuration.getProperty(Configuration.H2_PASSWORD.getValue(), ""); + String newH2Password = StringUtils.isBlank(h2Password) ? "" : aesService.changeEncryptionValue(h2Password, newSeed); + String newCACertPassword = aesService.changeEncryptionValue(configuration.getProperty(Configuration.CA_CERT_PASSWORD.getValue()), newSeed); ConfigurationRequest cr = getConfigurations(Configuration.values()); cr.setCaCertPassword(newCACertPassword); - cr.setDbRootPassword(newDBRootPassword); - cr.setDbPassword(newDBPassword); + cr.setDbRootPassword(newDBRootPassword); + cr.setDbPassword(newDBPassword); + cr.setH2Password(newH2Password); saveConfiguration(cr, false); } @@ -388,7 +428,9 @@ public final class ConfigurationService { changed = true; - fieldValue = encryptCreds && conf.is(Configuration.DB_ROOT_PASSWORD, Configuration.DB_PASSWORD, Configuration.CA_CERT_PASSWORD) ? aesService.encrypt(fieldValue) : fieldValue; + fieldValue = encryptCreds && conf.is(Configuration.DB_ROOT_PASSWORD, Configuration.DB_PASSWORD, + Configuration.H2_PASSWORD, Configuration.CA_CERT_PASSWORD) && StringUtils.isNotBlank(fieldValue) + ? aesService.encrypt(fieldValue) : fieldValue; props.setProperty(fieldName, fieldValue); } @@ -417,4 +459,4 @@ public final class ConfigurationService { } return tmp; } -} \ No newline at end of file +} diff --git a/portal_common/src/main/java/net/locusworks/portal/common/utils/Constants.java b/portal_common/src/main/java/net/locusworks/portal/common/utils/Constants.java index c498a94..9391d78 100644 --- a/portal_common/src/main/java/net/locusworks/portal/common/utils/Constants.java +++ b/portal_common/src/main/java/net/locusworks/portal/common/utils/Constants.java @@ -1,6 +1,7 @@ package net.locusworks.portal.common.utils; -import java.io.File; +import java.io.File; +import java.nio.file.Path; import org.apache.commons.io.FilenameUtils; @@ -22,6 +23,21 @@ public class Constants { public static final String TRUST_STORE_PATH = "javax.net.ssl.trustStore"; public static final String TRUST_STORE_PASSWORD = "javax.net.ssl.trustStorePassword"; - public static final String PROPERTIES_FILE = "portal.properties"; - -} + public static final String PROPERTIES_FILE = "portal.properties"; + + public static final String PORTAL_HOME_PROPERTY = "portal.home"; + + public static final String PORTAL_HOME_ENVIRONMENT = "PORTAL_HOME"; + + public static Path getPortalHome() { + String portalHome = System.getProperty(PORTAL_HOME_PROPERTY); + if (portalHome == null || portalHome.isBlank()) { + portalHome = System.getenv(PORTAL_HOME_ENVIRONMENT); + } + if (portalHome == null || portalHome.isBlank()) { + portalHome = Path.of(System.getProperty("user.home"), ".portal").toString(); + } + return Path.of(portalHome).toAbsolutePath().normalize(); + } + +} diff --git a/portal_common/src/test/java/net/locusworks/portal/common/PortalDataSourceTest.java b/portal_common/src/test/java/net/locusworks/portal/common/PortalDataSourceTest.java new file mode 100644 index 0000000..0beffbe --- /dev/null +++ b/portal_common/src/test/java/net/locusworks/portal/common/PortalDataSourceTest.java @@ -0,0 +1,50 @@ +package net.locusworks.portal.common; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class PortalDataSourceTest { + + private PortalDataSource portalDataSource; + + @Before + public void setUp() { + System.setProperty(PortalDataSource.DATABASE_DRIVER_PROPERTY, "org.h2.Driver"); + System.setProperty(PortalDataSource.DATABASE_URL_PROPERTY, + "jdbc:h2:mem:portal-test;MODE=MySQL;DATABASE_TO_LOWER=TRUE;DB_CLOSE_DELAY=-1"); + System.setProperty(PortalDataSource.DATABASE_USERNAME_PROPERTY, "sa"); + System.setProperty(PortalDataSource.DATABASE_PASSWORD_PROPERTY, ""); + portalDataSource = new PortalDataSource(); + } + + @After + public void tearDown() { + portalDataSource.closeDataSources(); + System.clearProperty(PortalDataSource.DATABASE_DRIVER_PROPERTY); + System.clearProperty(PortalDataSource.DATABASE_URL_PROPERTY); + System.clearProperty(PortalDataSource.DATABASE_USERNAME_PROPERTY); + System.clearProperty(PortalDataSource.DATABASE_PASSWORD_PROPERTY); + } + + @Test + public void createsInMemoryH2DataSourceForTests() throws Exception { + try (Connection connection = portalDataSource.getPortalDataSource().getConnection(); + Statement statement = connection.createStatement()) { + assertTrue(connection.getMetaData().getDatabaseProductName().startsWith("H2")); + statement.execute("CREATE TABLE datasource_smoke_test (id INT PRIMARY KEY, name VARCHAR(50))"); + statement.executeUpdate("INSERT INTO datasource_smoke_test (id, name) VALUES (1, 'portal')"); + try (ResultSet results = statement.executeQuery("SELECT name FROM datasource_smoke_test WHERE id = 1")) { + assertTrue(results.next()); + assertEquals("portal", results.getString(1)); + } + } + } +} diff --git a/portal_database/pom.xml b/portal_database/pom.xml index 8d84a89..86e4b29 100644 --- a/portal_database/pom.xml +++ b/portal_database/pom.xml @@ -11,7 +11,6 @@ ${project.parent.basedir} - 8.0.11 portal_database @@ -41,23 +40,23 @@ org.apache.maven.plugins maven-antrun-plugin - 1.8 + 3.2.0 - Set author to NGAS + Set author to Locusworks - + + dir="src/main/java/net/locusworks/portal/database/entities"> Set LF line endings @@ -73,42 +72,15 @@ - - javax.transaction - jta - 1.1 - - - - mysql - mysql-connector-java - ${mysql.version} - - - com.google.protobuf - protobuf-java - - - - - - org.hibernate - hibernate-core - ${hibernate.version} - - - org.hibernate - hibernate-entitymanager - ${hibernate.version} - - - - - org.springframework - spring-orm - ${spring.version} - - + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.mysql + mysql-connector-j + runtime + - \ No newline at end of file + diff --git a/portal_database/src/main/java/net/locusworks/portal/database/config/PortalBeanConfiguration.java b/portal_database/src/main/java/net/locusworks/portal/database/config/PortalBeanConfiguration.java index fbc24f0..6c49001 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/config/PortalBeanConfiguration.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/config/PortalBeanConfiguration.java @@ -11,14 +11,13 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.Primary; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; -import org.springframework.orm.hibernate5.LocalSessionFactoryBean; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.JpaVendorAdapter; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; -import org.springframework.orm.jpa.vendor.Database; -import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import org.springframework.transaction.PlatformTransactionManager; -import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.transaction.annotation.EnableTransactionManagement; + /*** * Spring bean configuration for the database. @@ -56,9 +55,9 @@ public class PortalBeanConfiguration { hibernateProperties.setProperty("hibernate.connection.useUnicode", "true"); } - @Autowired - private DataSource dataSource; - + @Autowired + private DataSource dataSource; + /** * Create the entity manager factory bean used in the database connection * @return entityManagerFactoryBean @@ -76,19 +75,6 @@ public class PortalBeanConfiguration { return lef; } - /** - * Create the session factory bean - * @return sessionFactoryBean - */ - @Bean - public LocalSessionFactoryBean portalSessionFactory() { - LocalSessionFactoryBean sessionBean = new LocalSessionFactoryBean(); - sessionBean.setDataSource(dataSource); - sessionBean.setPackagesToScan(PACKAGES_TO_SCAN); - sessionBean.setHibernateProperties(hibernateProperties); - return sessionBean; - } - /** * Create the JPA Vendor adaptor bean that is used in the entity manager factory * @return jpaVendorAdaptor @@ -99,8 +85,7 @@ public class PortalBeanConfiguration { HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter(); hibernateJpaVendorAdapter.setShowSql(false); hibernateJpaVendorAdapter.setGenerateDdl(false); - hibernateJpaVendorAdapter.setDatabase(Database.MYSQL); - return hibernateJpaVendorAdapter; + return hibernateJpaVendorAdapter; } /** @@ -112,6 +97,6 @@ public class PortalBeanConfiguration { public PlatformTransactionManager portalTransactionManager() { JpaTransactionManager manager = new JpaTransactionManager(); manager.setEntityManagerFactory(portalEntityManagerFactory().getObject()); - return new JpaTransactionManager(); + return manager; } } diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/ApplicationLog.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/ApplicationLog.java index 599a970..2202211 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/ApplicationLog.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/ApplicationLog.java @@ -7,21 +7,21 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "application_log", catalog = "portal", schema = "") @@ -52,7 +52,7 @@ public class ApplicationLog implements Serializable { private String ipAddress; @Basic(optional = false) @Column(name = "timestamp") - @Temporal(TemporalType.TIMESTAMP) + @JdbcTypeCode(SqlTypes.TIMESTAMP) private Date timestamp; public ApplicationLog() { diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/ApplicationUser.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/ApplicationUser.java index 6434d09..340ee50 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/ApplicationUser.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/ApplicationUser.java @@ -8,24 +8,24 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; import java.util.List; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.OneToOne; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "application_user", catalog = "portal", schema = "") @@ -44,11 +44,11 @@ public class ApplicationUser implements Serializable { private String emailAddressTxt; @Basic(optional = false) @Column(name = "effective_date") - @Temporal(TemporalType.DATE) + @JdbcTypeCode(SqlTypes.DATE) private Date effectiveDate; @Basic(optional = false) @Column(name = "expiration_date") - @Temporal(TemporalType.DATE) + @JdbcTypeCode(SqlTypes.DATE) private Date expirationDate; @OneToMany(cascade = CascadeType.ALL, mappedBy = "createdBy") private List scriptEnvironmentVariableList; diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/CredentialType.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/CredentialType.java index 7edb284..96afcd3 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/CredentialType.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/CredentialType.java @@ -7,21 +7,21 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.List; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "credential_type", catalog = "portal", schema = "") diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/Credentials.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/Credentials.java index 59cc87d..f389bc2 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/Credentials.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/Credentials.java @@ -8,25 +8,25 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; import java.util.List; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "credentials", catalog = "portal", schema = "") @@ -48,7 +48,7 @@ public class Credentials implements Serializable { private int referenceId; @Basic(optional = false) @Column(name = "date_added") - @Temporal(TemporalType.TIMESTAMP) + @JdbcTypeCode(SqlTypes.TIMESTAMP) private Date dateAdded; @OneToMany(cascade = CascadeType.ALL, mappedBy = "credentials") private List scriptRemoteList; diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/EmailTemplate.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/EmailTemplate.java index 505b5e6..41a5870 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/EmailTemplate.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/EmailTemplate.java @@ -8,26 +8,26 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; import java.util.List; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.Lob; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "email_template", catalog = "portal", schema = "") @@ -53,7 +53,7 @@ public class EmailTemplate implements Serializable { private byte[] emailMessage; @Basic(optional = false) @Column(name = "date_created") - @Temporal(TemporalType.DATE) + @JdbcTypeCode(SqlTypes.DATE) private Date dateCreated; @OneToMany(cascade = CascadeType.ALL, mappedBy = "emailTemplate") private List scriptEmailList; diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/EnvironmentVariable.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/EnvironmentVariable.java index abcf052..f0104e4 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/EnvironmentVariable.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/EnvironmentVariable.java @@ -7,23 +7,23 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "environment_variable", catalog = "portal", schema = "") @@ -45,11 +45,11 @@ public class EnvironmentVariable implements Serializable { private String value; @Basic(optional = false) @Column(name = "last_updated") - @Temporal(TemporalType.TIMESTAMP) + @JdbcTypeCode(SqlTypes.TIMESTAMP) private Date lastUpdated; @Basic(optional = false) @Column(name = "date_created") - @Temporal(TemporalType.TIMESTAMP) + @JdbcTypeCode(SqlTypes.TIMESTAMP) private Date dateCreated; @JoinColumn(name = "created_by", referencedColumnName = "id") @ManyToOne(optional = false) diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/GitRepo.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/GitRepo.java index 8f18fec..d69c97c 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/GitRepo.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/GitRepo.java @@ -7,23 +7,23 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "git_repo", catalog = "portal", schema = "") @@ -51,11 +51,11 @@ public class GitRepo implements Serializable { private String branch; @Basic(optional = false) @Column(name = "last_updated") - @Temporal(TemporalType.TIMESTAMP) + @JdbcTypeCode(SqlTypes.TIMESTAMP) private Date lastUpdated; @Basic(optional = false) @Column(name = "dated_created") - @Temporal(TemporalType.DATE) + @JdbcTypeCode(SqlTypes.DATE) private Date datedCreated; @JoinColumn(name = "credentials", referencedColumnName = "id") @ManyToOne(optional = false) diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/HashType.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/HashType.java index 2daae22..4efb042 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/HashType.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/HashType.java @@ -7,21 +7,21 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "hash_type", catalog = "portal", schema = "") @@ -46,11 +46,11 @@ public class HashType implements Serializable { private short valid; @Basic(optional = false) @Column(name = "last_modified") - @Temporal(TemporalType.DATE) + @JdbcTypeCode(SqlTypes.DATE) private Date lastModified; @Basic(optional = false) @Column(name = "date_created") - @Temporal(TemporalType.DATE) + @JdbcTypeCode(SqlTypes.DATE) private Date dateCreated; public HashType() { diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/KeyValue.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/KeyValue.java index 487d98f..c91c34a 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/KeyValue.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/KeyValue.java @@ -7,24 +7,24 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.Lob; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "key_value", catalog = "portal", schema = "") @@ -47,7 +47,7 @@ public class KeyValue implements Serializable { private byte[] referenceValue; @Basic(optional = false) @Column(name = "date_created") - @Temporal(TemporalType.TIMESTAMP) + @JdbcTypeCode(SqlTypes.TIMESTAMP) private Date dateCreated; @JoinColumn(name = "created_by", referencedColumnName = "id") @ManyToOne(optional = false) diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/Keyword.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/Keyword.java index 198551a..3b140ae 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/Keyword.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/Keyword.java @@ -7,23 +7,23 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "keyword", catalog = "portal", schema = "") @@ -42,7 +42,7 @@ public class Keyword implements Serializable { private String keyword; @Basic(optional = false) @Column(name = "date_created") - @Temporal(TemporalType.DATE) + @JdbcTypeCode(SqlTypes.DATE) private Date dateCreated; @JoinColumn(name = "created_by", referencedColumnName = "id") @ManyToOne(optional = false) diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/Password.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/Password.java index 5d6ee0e..b3c0f87 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/Password.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/Password.java @@ -7,23 +7,23 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "password", catalog = "portal", schema = "") @@ -51,7 +51,7 @@ public class Password implements Serializable { private String password; @Basic(optional = false) @Column(name = "date_created") - @Temporal(TemporalType.DATE) + @JdbcTypeCode(SqlTypes.DATE) private Date dateCreated; @JoinColumn(name = "created_by", referencedColumnName = "id") @ManyToOne(optional = false) diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/Permission.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/Permission.java index 69c498f..50a0ee4 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/Permission.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/Permission.java @@ -8,25 +8,25 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; import java.util.List; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "permission", catalog = "portal", schema = "") @@ -48,11 +48,11 @@ public class Permission implements Serializable { private String displayName; @Basic(optional = false) @Column(name = "date_created") - @Temporal(TemporalType.DATE) + @JdbcTypeCode(SqlTypes.DATE) private Date dateCreated; @Basic(optional = false) @Column(name = "last_updated") - @Temporal(TemporalType.DATE) + @JdbcTypeCode(SqlTypes.DATE) private Date lastUpdated; @OneToMany(cascade = CascadeType.ALL, mappedBy = "permission") private List permissionGroupPermissionList; diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/PermissionCategory.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/PermissionCategory.java index 258e709..4f8878f 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/PermissionCategory.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/PermissionCategory.java @@ -8,23 +8,23 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; import java.util.List; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "permission_category", catalog = "portal", schema = "") @@ -46,7 +46,7 @@ public class PermissionCategory implements Serializable { private String displayName; @Basic(optional = false) @Column(name = "date_created") - @Temporal(TemporalType.DATE) + @JdbcTypeCode(SqlTypes.DATE) private Date dateCreated; @Basic(optional = false) @Column(name = "last_updated") diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/PermissionGroup.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/PermissionGroup.java index 1ad619f..85d3b09 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/PermissionGroup.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/PermissionGroup.java @@ -8,23 +8,23 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; import java.util.List; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "permission_group", catalog = "portal", schema = "") @@ -49,11 +49,11 @@ public class PermissionGroup implements Serializable { private short enabled; @Basic(optional = false) @Column(name = "date_created") - @Temporal(TemporalType.DATE) + @JdbcTypeCode(SqlTypes.DATE) private Date dateCreated; @Basic(optional = false) @Column(name = "last_modified") - @Temporal(TemporalType.DATE) + @JdbcTypeCode(SqlTypes.DATE) private Date lastModified; @OneToMany(cascade = CascadeType.ALL, mappedBy = "permissionGroup") private List userAttributeList; diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/PermissionGroupPermission.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/PermissionGroupPermission.java index 218d8b6..61e6055 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/PermissionGroupPermission.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/PermissionGroupPermission.java @@ -7,23 +7,23 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "permission_group_permission", catalog = "portal", schema = "") @@ -42,11 +42,11 @@ public class PermissionGroupPermission implements Serializable { private short allowed; @Basic(optional = false) @Column(name = "date_created") - @Temporal(TemporalType.DATE) + @JdbcTypeCode(SqlTypes.DATE) private Date dateCreated; @Basic(optional = false) @Column(name = "last_modified") - @Temporal(TemporalType.DATE) + @JdbcTypeCode(SqlTypes.DATE) private Date lastModified; @JoinColumn(name = "permission", referencedColumnName = "id") @ManyToOne(optional = false) diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/ResourceFile.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/ResourceFile.java index b2f56ae..1679a1d 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/ResourceFile.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/ResourceFile.java @@ -7,23 +7,23 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "resource_file", catalog = "portal", schema = "") @@ -51,7 +51,7 @@ public class ResourceFile implements Serializable { private short valid; @Basic(optional = false) @Column(name = "date_created") - @Temporal(TemporalType.DATE) + @JdbcTypeCode(SqlTypes.DATE) private Date dateCreated; @JoinColumn(name = "script_result", referencedColumnName = "id") @ManyToOne diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/ScheduleFrequency.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/ScheduleFrequency.java index d952941..3b005cd 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/ScheduleFrequency.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/ScheduleFrequency.java @@ -7,21 +7,21 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.List; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "schedule_frequency", catalog = "portal", schema = "") diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/Script.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/Script.java index 2857840..d230116 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/Script.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/Script.java @@ -8,25 +8,25 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; import java.util.List; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "script", catalog = "portal", schema = "") @@ -52,7 +52,7 @@ public class Script implements Serializable { private String outputDirectory; @Basic(optional = false) @Column(name = "date_created") - @Temporal(TemporalType.DATE) + @JdbcTypeCode(SqlTypes.DATE) private Date dateCreated; @OneToMany(cascade = CascadeType.ALL, mappedBy = "script") private List scriptEnvironmentVariableList; diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptChain.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptChain.java index ad2314d..8c464fa 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptChain.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptChain.java @@ -6,21 +6,21 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "script_chain", catalog = "portal", schema = "") diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptEmail.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptEmail.java index 9ce29ce..40c3467 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptEmail.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptEmail.java @@ -8,25 +8,25 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; import java.util.List; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "script_email", catalog = "portal", schema = "") @@ -42,7 +42,7 @@ public class ScriptEmail implements Serializable { private Integer id; @Basic(optional = false) @Column(name = "date_created") - @Temporal(TemporalType.DATE) + @JdbcTypeCode(SqlTypes.DATE) private Date dateCreated; @JoinColumn(name = "email_template", referencedColumnName = "id") @ManyToOne(optional = false) diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptEmailRecipient.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptEmailRecipient.java index a1744f8..6cbf4ec 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptEmailRecipient.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptEmailRecipient.java @@ -7,23 +7,23 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "script_email_recipient", catalog = "portal", schema = "") @@ -39,7 +39,7 @@ public class ScriptEmailRecipient implements Serializable { private Integer id; @Basic(optional = false) @Column(name = "date_created") - @Temporal(TemporalType.DATE) + @JdbcTypeCode(SqlTypes.DATE) private Date dateCreated; @JoinColumn(name = "recipient", referencedColumnName = "id") @ManyToOne(optional = false) diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptEnvironmentVariable.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptEnvironmentVariable.java index 0afc84c..7ec5da6 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptEnvironmentVariable.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptEnvironmentVariable.java @@ -7,23 +7,23 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "script_environment_variable", catalog = "portal", schema = "") @@ -45,11 +45,11 @@ public class ScriptEnvironmentVariable implements Serializable { private String value; @Basic(optional = false) @Column(name = "last_updated") - @Temporal(TemporalType.TIMESTAMP) + @JdbcTypeCode(SqlTypes.TIMESTAMP) private Date lastUpdated; @Basic(optional = false) @Column(name = "date_created") - @Temporal(TemporalType.TIMESTAMP) + @JdbcTypeCode(SqlTypes.TIMESTAMP) private Date dateCreated; @JoinColumn(name = "created_by", referencedColumnName = "id") @ManyToOne(optional = false) diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptParameter.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptParameter.java index a77fee7..9432170 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptParameter.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptParameter.java @@ -6,21 +6,21 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "script_parameter", catalog = "portal", schema = "") diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptRemote.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptRemote.java index db8cf85..973348a 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptRemote.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptRemote.java @@ -6,21 +6,21 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "script_remote", catalog = "portal", schema = "") diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptSchedule.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptSchedule.java index 63d2df1..c07ed9d 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptSchedule.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptSchedule.java @@ -8,25 +8,25 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; import java.util.List; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "script_schedule", catalog = "portal", schema = "") @@ -45,17 +45,17 @@ public class ScriptSchedule implements Serializable { private String jobId; @Basic(optional = false) @Column(name = "start_datetime") - @Temporal(TemporalType.TIMESTAMP) + @JdbcTypeCode(SqlTypes.TIMESTAMP) private Date startDatetime; @Column(name = "end_datetime") - @Temporal(TemporalType.TIMESTAMP) + @JdbcTypeCode(SqlTypes.TIMESTAMP) private Date endDatetime; @Column(name = "max_executions") private Integer maxExecutions; @Column(name = "current_execution_count") private Integer currentExecutionCount; @Column(name = "last_run") - @Temporal(TemporalType.TIMESTAMP) + @JdbcTypeCode(SqlTypes.TIMESTAMP) private Date lastRun; @Column(name = "execution_status") private Integer executionStatus; diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptScheduleResults.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptScheduleResults.java index c5879d8..99989c9 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptScheduleResults.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptScheduleResults.java @@ -8,25 +8,25 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; import java.util.List; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.Lob; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "script_schedule_results", catalog = "portal", schema = "") @@ -49,11 +49,11 @@ public class ScriptScheduleResults implements Serializable { private byte[] results; @Basic(optional = false) @Column(name = "start_time") - @Temporal(TemporalType.TIMESTAMP) + @JdbcTypeCode(SqlTypes.TIMESTAMP) private Date startTime; @Basic(optional = false) @Column(name = "end_time") - @Temporal(TemporalType.TIMESTAMP) + @JdbcTypeCode(SqlTypes.TIMESTAMP) private Date endTime; @OneToMany(mappedBy = "scriptResult") private List resourceFileList; diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptScp.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptScp.java index 3b79ea2..2d8dcb2 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptScp.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptScp.java @@ -7,23 +7,23 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "script_scp", catalog = "portal", schema = "") @@ -53,11 +53,11 @@ public class ScriptScp implements Serializable { private String dataRegex; @Basic(optional = false) @Column(name = "last_updated") - @Temporal(TemporalType.TIMESTAMP) + @JdbcTypeCode(SqlTypes.TIMESTAMP) private Date lastUpdated; @Basic(optional = false) @Column(name = "date_created") - @Temporal(TemporalType.TIMESTAMP) + @JdbcTypeCode(SqlTypes.TIMESTAMP) private Date dateCreated; @JoinColumn(name = "script", referencedColumnName = "id") @ManyToOne(optional = false) diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptType.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptType.java index 2d4151c..ad2297a 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptType.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/ScriptType.java @@ -7,21 +7,21 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.List; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "script_type", catalog = "portal", schema = "") diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/SshKey.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/SshKey.java index ab02e9f..0eb7246 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/SshKey.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/SshKey.java @@ -7,24 +7,24 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.Lob; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "ssh_key", catalog = "portal", schema = "") @@ -55,7 +55,7 @@ public class SshKey implements Serializable { private String passphrase; @Basic(optional = false) @Column(name = "date_created") - @Temporal(TemporalType.DATE) + @JdbcTypeCode(SqlTypes.DATE) private Date dateCreated; @JoinColumn(name = "created_by", referencedColumnName = "id") @ManyToOne(optional = false) diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/UserAttribute.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/UserAttribute.java index 4eac7e9..a024f6f 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/UserAttribute.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/UserAttribute.java @@ -6,22 +6,22 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToOne; -import javax.persistence.Table; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "user_attribute", catalog = "portal", schema = "") diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/UserPasswordTracking.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/UserPasswordTracking.java index 9a8d049..0f8a8f5 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/UserPasswordTracking.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/UserPasswordTracking.java @@ -7,23 +7,23 @@ package net.locusworks.portal.database.entities; import java.io.Serializable; import java.util.Date; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * - * @author NGAS + * @author Locusworks */ @Entity @Table(name = "user_password_tracking", catalog = "portal", schema = "") @@ -42,11 +42,11 @@ public class UserPasswordTracking implements Serializable { private String passwordTxt; @Basic(optional = false) @Column(name = "effective_date") - @Temporal(TemporalType.DATE) + @JdbcTypeCode(SqlTypes.DATE) private Date effectiveDate; @Basic(optional = false) @Column(name = "expiration_date") - @Temporal(TemporalType.DATE) + @JdbcTypeCode(SqlTypes.DATE) private Date expirationDate; @JoinColumn(name = "application_user", referencedColumnName = "id") @ManyToOne(optional = false) diff --git a/portal_database/src/main/java/net/locusworks/portal/database/entities/package-info.java b/portal_database/src/main/java/net/locusworks/portal/database/entities/package-info.java index 255280e..eed656d 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/entities/package-info.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/entities/package-info.java @@ -1,6 +1,6 @@ /** * Package contains all the JPO Entities that map to the database - * @author NGAS + * @author Locusworks * @since 1.0.0-RELEASE * @version 1.0 */ diff --git a/portal_database/src/main/java/net/locusworks/portal/database/migration/PortalMigration.java b/portal_database/src/main/java/net/locusworks/portal/database/migration/PortalMigration.java index 1301a46..9b83f62 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/migration/PortalMigration.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/migration/PortalMigration.java @@ -17,14 +17,24 @@ public class PortalMigration { * @param dataSource the Datasource to use for the migration * @return Flyway migration item */ - public static Flyway getFlyway(DataSource dataSource) { - Flyway flyway = new Flyway(); - flyway.setTable("_flyway_migration"); - flyway.setSchemas("portal"); - flyway.setLocations("database/migration"); - flyway.setOutOfOrder(false); - flyway.setDataSource(dataSource); - return flyway; - } + public static Flyway getFlyway(DataSource dataSource) { + var configuration = Flyway.configure() + .table("_flyway_migration") + .schemas("portal") + .outOfOrder(false) + .dataSource(dataSource); + try (var connection = dataSource.getConnection()) { + if (connection.getMetaData().getDatabaseProductName().startsWith("H2")) { + configuration.locations( + "classpath:database/migration/MySQL/Tables", + "classpath:database/migration/MySQL/Data"); + } else { + configuration.locations("classpath:database/migration"); + } + } catch (Exception ex) { + throw new IllegalStateException("Unable to identify database for migrations", ex); + } + return configuration.load(); + } } diff --git a/portal_database/src/main/java/net/locusworks/portal/database/repos/CredentialsRepository.java b/portal_database/src/main/java/net/locusworks/portal/database/repos/CredentialsRepository.java index c04a28a..54fbda9 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/repos/CredentialsRepository.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/repos/CredentialsRepository.java @@ -1,26 +1,18 @@ package net.locusworks.portal.database.repos; -import java.math.BigInteger; -import java.util.List; -import java.util.Set; +import java.util.List; +import java.util.Set; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; -import org.springframework.data.jpa.repository.query.Procedure; -import org.springframework.data.repository.CrudRepository; -import org.springframework.data.repository.query.Param; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; import org.springframework.transaction.annotation.Transactional; import net.locusworks.portal.database.entities.Credentials; public interface CredentialsRepository extends CrudRepository { - public static final String CRED_IN_USE_PROC = "credentials_in_use"; - public static final String CRED_COUNT_PROC = "credential_count"; - public static final String CRED_UUID_IN_PARAM = "cred_uuid"; - public static final String CRED_USE_OUT_PARA = "cred_use"; - public static final String CRED_COUNT_OUT_PARAM = "cred_count"; - @Query("SELECT sc FROM Credentials sc WHERE sc.id = ?1") Credentials findOne(Integer id); @@ -29,11 +21,15 @@ public interface CredentialsRepository extends CrudRepository findAll(); - @Procedure(procedureName=CRED_IN_USE_PROC, outputParameterName=CRED_USE_OUT_PARA) - boolean inUse(@Param(CRED_UUID_IN_PARAM) String uuid); - - @Procedure(procedureName=CRED_COUNT_PROC, outputParameterName=CRED_COUNT_OUT_PARAM) - BigInteger credentialCount(@Param(CRED_UUID_IN_PARAM) String uuid); + @Query(value = """ + SELECT + (SELECT COUNT(*) FROM git_repo WHERE credentials = c.id) + + (SELECT COUNT(*) FROM script_remote WHERE credentials = c.id) + + (SELECT COUNT(*) FROM script_scp WHERE from_credentials = c.id OR to_credentials = c.id) + FROM credentials c + WHERE c.uuid = :uuid + """, nativeQuery = true) + long credentialCount(@Param("uuid") String uuid); @Modifying @Transactional diff --git a/portal_database/src/main/java/net/locusworks/portal/database/repos/EmailTemplateRepository.java b/portal_database/src/main/java/net/locusworks/portal/database/repos/EmailTemplateRepository.java index d6f0115..787618e 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/repos/EmailTemplateRepository.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/repos/EmailTemplateRepository.java @@ -3,7 +3,7 @@ package net.locusworks.portal.database.repos; import java.util.List; import java.util.Set; -import javax.transaction.Transactional; +import jakarta.transaction.Transactional; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; diff --git a/portal_database/src/main/java/net/locusworks/portal/database/repos/KeyValueRepository.java b/portal_database/src/main/java/net/locusworks/portal/database/repos/KeyValueRepository.java index c6de209..6c8667f 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/repos/KeyValueRepository.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/repos/KeyValueRepository.java @@ -3,7 +3,7 @@ package net.locusworks.portal.database.repos; import java.util.List; import java.util.Set; -import javax.transaction.Transactional; +import jakarta.transaction.Transactional; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; diff --git a/portal_database/src/main/java/net/locusworks/portal/database/repos/ScriptRemoteRepository.java b/portal_database/src/main/java/net/locusworks/portal/database/repos/ScriptRemoteRepository.java index f493360..7e402f2 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/repos/ScriptRemoteRepository.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/repos/ScriptRemoteRepository.java @@ -2,7 +2,7 @@ package net.locusworks.portal.database.repos; import java.util.Set; -import javax.transaction.Transactional; +import jakarta.transaction.Transactional; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; diff --git a/portal_database/src/main/java/net/locusworks/portal/database/repos/ScriptRepository.java b/portal_database/src/main/java/net/locusworks/portal/database/repos/ScriptRepository.java index 5d5a715..8eccb26 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/repos/ScriptRepository.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/repos/ScriptRepository.java @@ -7,7 +7,7 @@ import java.util.Set; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; import org.springframework.transaction.annotation.Transactional; import net.locusworks.portal.database.entities.Script; diff --git a/portal_database/src/main/java/net/locusworks/portal/database/repos/ScriptScpRepository.java b/portal_database/src/main/java/net/locusworks/portal/database/repos/ScriptScpRepository.java index 613d1b4..44cda8e 100644 --- a/portal_database/src/main/java/net/locusworks/portal/database/repos/ScriptScpRepository.java +++ b/portal_database/src/main/java/net/locusworks/portal/database/repos/ScriptScpRepository.java @@ -2,7 +2,7 @@ package net.locusworks.portal.database.repos; import java.util.Set; -import javax.transaction.Transactional; +import jakarta.transaction.Transactional; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; diff --git a/portal_database/src/main/resources/META-INF/persistence.xml b/portal_database/src/main/resources/META-INF/persistence.xml deleted file mode 100644 index 035bc98..0000000 --- a/portal_database/src/main/resources/META-INF/persistence.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - org.hibernate.ejb.HibernatePersistence - net.locusworks.portal.database.entities.ApplicationLog - net.locusworks.portal.database.entities.ApplicationUser - net.locusworks.portal.database.entities.Credentials - net.locusworks.portal.database.entities.EnvironmentVariable - net.locusworks.portal.database.entities.GitRepo - net.locusworks.portal.database.entities.HashType - net.locusworks.portal.database.entities.Keyword - net.locusworks.portal.database.entities.Password - net.locusworks.portal.database.entities.Permission - net.locusworks.portal.database.entities.PermissionCategory - net.locusworks.portal.database.entities.PermissionGroup - net.locusworks.portal.database.entities.PermissionGroupPermission - net.locusworks.portal.database.entities.ResourceFile - net.locusworks.portal.database.entities.ScheduleFrequency - net.locusworks.portal.database.entities.Script - net.locusworks.portal.database.entities.ScriptChain - net.locusworks.portal.database.entities.ScriptEnvironmentVariable - net.locusworks.portal.database.entities.ScriptParameter - net.locusworks.portal.database.entities.ScriptRemote - net.locusworks.portal.database.entities.ScriptSchedule - net.locusworks.portal.database.entities.ScriptScheduleResults - net.locusworks.portal.database.entities.ScriptScp - net.locusworks.portal.database.entities.ScriptType - net.locusworks.portal.database.entities.SshKey - net.locusworks.portal.database.entities.UserAttribute - net.locusworks.portal.database.entities.UserPasswordTracking - net.locusworks.portal.database.entities.CredentialType - net.locusworks.portal.database.entities.KeyValue - net.locusworks.portal.database.entities.EmailTemplate - net.locusworks.portal.database.entities.ScriptEmail - net.locusworks.portal.database.entities.ScriptEmailRecipient - - - - - - - - diff --git a/portal_database/src/main/resources/database/migration/MySQL/Data/V01_000_002__admin_user_create.sql b/portal_database/src/main/resources/database/migration/MySQL/Data/V01_000_002__admin_user_create.sql index 8fa2a8c..1a106be 100644 --- a/portal_database/src/main/resources/database/migration/MySQL/Data/V01_000_002__admin_user_create.sql +++ b/portal_database/src/main/resources/database/migration/MySQL/Data/V01_000_002__admin_user_create.sql @@ -1,6 +1,6 @@ INSERT ignore INTO portal.application_user (id, email_address_txt, effective_date, expiration_date) values -(null, 'portalAdmin@locusworks.net', CURDATE(), '9999/12/31'); +(null, 'portalAdmin@locusworks.net', CURDATE(), '9999-12-31'); commit; @@ -17,6 +17,6 @@ INSERT ignore INTO portal.user_password_tracking (id, application_user, password values (null, (select id from portal.application_user where email_address_txt = 'portalAdmin@locusworks.net'), -'1000:9284df482920e9660aacca58f3a2ca7713d1e369e81e5d13:bf409cc87063667241984e044a1f8f798f18511b4242013d', curdate(), '9999/12/31'); +'1000:9284df482920e9660aacca58f3a2ca7713d1e369e81e5d13:bf409cc87063667241984e044a1f8f798f18511b4242013d', curdate(), '9999-12-31'); -commit; \ No newline at end of file +commit; diff --git a/portal_database/src/main/resources/database/migration/MySQL/Tables/V01_000_000__portal_tables.sql b/portal_database/src/main/resources/database/migration/MySQL/Tables/V01_000_000__portal_tables.sql index 9a12d19..3789575 100644 --- a/portal_database/src/main/resources/database/migration/MySQL/Tables/V01_000_000__portal_tables.sql +++ b/portal_database/src/main/resources/database/migration/MySQL/Tables/V01_000_000__portal_tables.sql @@ -7,7 +7,7 @@ CREATE TABLE portal.application_log ( ip_address varchar(45) NOT NULL COMMENT 'IP address of where the event came from', timestamp datetime NOT NULL, PRIMARY KEY (id), - UNIQUE KEY id_UNIQUE (id) + UNIQUE KEY application_log_id_UNIQUE (id) ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4 COMMENT='Application logs'; CREATE TABLE portal.permission_category ( @@ -17,7 +17,7 @@ CREATE TABLE portal.permission_category ( date_created date NOT NULL COMMENT 'Date the permission category was created', last_updated varchar(45) NOT NULL COMMENT 'Last update time of the category', PRIMARY KEY (id), - UNIQUE KEY name (name) + UNIQUE KEY permission_category_name_UNIQUE (name) ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4 COMMENT='Category the permission belongs to'; CREATE TABLE portal.permission ( @@ -28,7 +28,7 @@ CREATE TABLE portal.permission ( date_created date NOT NULL, last_updated date NOT NULL, PRIMARY KEY (id), - UNIQUE KEY name (name), + UNIQUE KEY permission_name_UNIQUE (name), KEY p_pc_fk_idx (permission_category), CONSTRAINT p_pc_fk FOREIGN KEY (permission_category) REFERENCES permission_category (id) ON DELETE NO ACTION ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4 COMMENT='available permissions'; @@ -41,7 +41,7 @@ CREATE TABLE portal.permission_group ( date_created date NOT NULL, last_modified date NOT NULL, PRIMARY KEY (id), - UNIQUE KEY name_UNIQUE (name) + UNIQUE KEY permission_group_name_UNIQUE (name) ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4 COMMENT='permission group definitions'; CREATE TABLE portal.permission_group_permission ( @@ -121,7 +121,7 @@ CREATE TABLE portal.password ( date_created date NOT NULL COMMENT 'Date the credentials were added', PRIMARY KEY (id), UNIQUE KEY credential_name_UNIQUE (name), - UNIQUE KEY uuid_UNIQUE (uuid), + UNIQUE KEY password_uuid_UNIQUE (uuid), KEY pgc_au_fk_idx (created_by), CONSTRAINT pgc_au_fk FOREIGN KEY (created_by) REFERENCES application_user (id) ON UPDATE CASCADE ON DELETE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4 COMMENT='username and password for git repo'; @@ -137,7 +137,7 @@ CREATE TABLE portal.ssh_key ( date_created date NOT NULL COMMENT 'Date the credentials were added', PRIMARY KEY (id), UNIQUE KEY ssh_key_name_UNIQUE (name), - UNIQUE KEY uuid_UNIQUE (uuid), + UNIQUE KEY ssh_key_uuid_UNIQUE (uuid), KEY pgsk_au_fk_idx (created_by), CONSTRAINT pgsk_au_fk FOREIGN KEY (created_by) REFERENCES application_user (id) ON UPDATE CASCADE ON DELETE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4 COMMENT='ssh key and passphrase for the git repo'; @@ -153,7 +153,7 @@ CREATE TABLE portal.git_repo ( last_updated datetime NOT NULL COMMENT 'last time directory was updated', dated_created date NOT NULL COMMENT 'date the git repo was created', PRIMARY KEY (id), - UNIQUE KEY name_UNIQUE (name), + UNIQUE KEY git_repo_name_UNIQUE (name), KEY pg_au_fk_idx (created_by), KEY gr_c_fk_idx (credentials), CONSTRAINT gr_c_fk FOREIGN KEY (credentials) REFERENCES credentials (id) ON UPDATE CASCADE ON DELETE RESTRICT, @@ -235,7 +235,7 @@ CREATE TABLE portal.script_schedule ( execution_status int(11) DEFAULT NULL COMMENT 'status of the last execution', finished tinyint(4) NOT NULL DEFAULT '0' COMMENT 'Indiciated if the script has finished its execution run', PRIMARY KEY (id), - UNIQUE KEY uuid_UNIQUE (job_id), + UNIQUE KEY script_schedule_uuid_UNIQUE (job_id), KEY s_ss_fk_idx (script), KEY s_sf_fk_idx (frequency), CONSTRAINT s_sf_fk FOREIGN KEY (frequency) REFERENCES schedule_frequency (id) ON DELETE NO ACTION ON UPDATE NO ACTION, @@ -297,7 +297,7 @@ CREATE TABLE portal.script_chain ( execute_after_min int(11) DEFAULT NULL COMMENT 'number of minutes after parent finishes the child should execute', PRIMARY KEY (id), UNIQUE KEY unique_sp_sc_es (parent_script,child_script,exit_status), - KEY s_sp_fk_idx (parent_script), + KEY script_chain_parent_fk_idx (parent_script), KEY sc_s_fk_idx (child_script), CONSTRAINT sc_s_fk FOREIGN KEY (child_script) REFERENCES script (id) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT sp_s_fk FOREIGN KEY (parent_script) REFERENCES script (id) ON DELETE CASCADE ON UPDATE CASCADE @@ -312,7 +312,7 @@ CREATE TABLE portal.script_environment_variable ( last_updated datetime NOT NULL COMMENT 'last time environment variable was updated', date_created datetime NOT NULL COMMENT 'date the environment variable was created', PRIMARY KEY (id), - UNIQUE KEY id_UNIQUE (id), + UNIQUE KEY script_environment_variable_id_UNIQUE (id), UNIQUE KEY name_script_UNIQUE (name,script), KEY sev_au_fk_idx (created_by), KEY sev_s_fk_idx (script), @@ -329,7 +329,7 @@ CREATE TABLE portal.resource_file ( script_result int(11) DEFAULT NULL COMMENT 'the script that retrived and stored the file', date_created date NOT NULL, PRIMARY KEY (id), - UNIQUE KEY id_UNIQUE (id), + UNIQUE KEY resource_file_id_UNIQUE (id), KEY s_sr_ak_idx (script_result), CONSTRAINT s_sr_ak FOREIGN KEY (script_result) REFERENCES script_schedule_results (id) ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4; @@ -342,8 +342,8 @@ CREATE TABLE portal.environment_variable ( last_updated datetime NOT NULL COMMENT 'last time environment variable was updated', date_created datetime NOT NULL COMMENT 'date the environment variable was created', PRIMARY KEY (id), - UNIQUE KEY id_UNIQUE (id), - UNIQUE KEY name_UNIQUE (name), + UNIQUE KEY environment_variable_id_UNIQUE (id), + UNIQUE KEY environment_variable_name_UNIQUE (name), KEY ev_au_fk_idx (created_by), CONSTRAINT ev_au_fk FOREIGN KEY (created_by) REFERENCES application_user (id) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4 COMMENT='Global System Environment variables for scripts to use outside what is already establed by the server.'; diff --git a/portal_json/src/main/java/net/locusworks/portal/json/ApplicationLogRequest.java b/portal_json/src/main/java/net/locusworks/portal/json/ApplicationLogRequest.java index ab4de0d..9eb31ff 100644 --- a/portal_json/src/main/java/net/locusworks/portal/json/ApplicationLogRequest.java +++ b/portal_json/src/main/java/net/locusworks/portal/json/ApplicationLogRequest.java @@ -6,8 +6,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import net.locusworks.common.annotations.MapValue; @JsonIgnoreProperties(ignoreUnknown=true) -@MapValue -public class ApplicationLogRequest { +public class ApplicationLogRequest { @MapValue(ignore=true) private Integer id; diff --git a/portal_json/src/main/java/net/locusworks/portal/json/ConfigurationRequest.java b/portal_json/src/main/java/net/locusworks/portal/json/ConfigurationRequest.java index c0df650..aa0a153 100644 --- a/portal_json/src/main/java/net/locusworks/portal/json/ConfigurationRequest.java +++ b/portal_json/src/main/java/net/locusworks/portal/json/ConfigurationRequest.java @@ -1,8 +1,12 @@ package net.locusworks.portal.json; -public class ConfigurationRequest { - - private String filepath; +public class ConfigurationRequest { + + private String filepath; + private String dbType; + private String h2Url; + private String h2Username; + private String h2Password; private String dbUsername; private String dbPassword; private String dbRootUser; @@ -13,7 +17,32 @@ public class ConfigurationRequest { private String caCertFile; private String caCertPassword; private String aesSeedFile; - private String logLevel; + private String logLevel; + + public String getDbType() { + return dbType; + } + public void setDbType(String dbType) { + this.dbType = dbType; + } + public String getH2Url() { + return h2Url; + } + public void setH2Url(String h2Url) { + this.h2Url = h2Url; + } + public String getH2Username() { + return h2Username; + } + public void setH2Username(String h2Username) { + this.h2Username = h2Username; + } + public String getH2Password() { + return h2Password; + } + public void setH2Password(String h2Password) { + this.h2Password = h2Password; + } /** * @return the file path diff --git a/portal_migration/src/main/java/net/locusworks/portal/migration/util/MigrationItem.java b/portal_migration/src/main/java/net/locusworks/portal/migration/util/MigrationItem.java index 170ff45..25f9dd9 100644 --- a/portal_migration/src/main/java/net/locusworks/portal/migration/util/MigrationItem.java +++ b/portal_migration/src/main/java/net/locusworks/portal/migration/util/MigrationItem.java @@ -6,8 +6,8 @@ import org.flywaydb.core.Flyway; import org.flywaydb.core.api.MigrationInfo; import org.flywaydb.core.internal.info.MigrationInfoDumper; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; /** * Migration item class to help with flyway migrations @@ -39,7 +39,7 @@ public class MigrationItem { * @return array of schemas */ public String[] getSchemas() { - return flyway.getSchemas(); + return flyway.getConfiguration().getSchemas(); } /** diff --git a/portal_migration/src/main/java/net/locusworks/portal/migration/util/MigrationManager.java b/portal_migration/src/main/java/net/locusworks/portal/migration/util/MigrationManager.java index 2e16785..abb7e2b 100644 --- a/portal_migration/src/main/java/net/locusworks/portal/migration/util/MigrationManager.java +++ b/portal_migration/src/main/java/net/locusworks/portal/migration/util/MigrationManager.java @@ -1,15 +1,17 @@ package net.locusworks.portal.migration.util; -import java.util.List; - -import javax.sql.DataSource; +import java.util.List; + +import javax.sql.DataSource; + +import jakarta.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.common.utils.Utils; import net.locusworks.portal.common.PortalDataSource; import net.locusworks.portal.database.migration.PortalMigration; @@ -20,8 +22,8 @@ import net.locusworks.portal.database.migration.PortalMigration; * @since 1.0.0-RELEASE * @version 1.0 */ -@Component -public class MigrationManager { +@Component("migration") +public class MigrationManager { @Autowired private PortalDataSource portalDatasource; @@ -32,10 +34,11 @@ public class MigrationManager { public MigrationManager() { } - /** - * Perform the migrations - */ - public void migrate() { + /** + * Perform the migrations + */ + @PostConstruct + public void migrate() { logger.info("Performing database migrations"); DataSource ds = portalDatasource.getPortalRootDataSource(); diff --git a/portal_webapp/pom.xml b/portal_webapp/pom.xml index bb98453..b02ec42 100644 --- a/portal_webapp/pom.xml +++ b/portal_webapp/pom.xml @@ -1,284 +1,35 @@ - - - 4.0.0 - - - net.locusworks - portal - 1.0.0-RELEASE - - - portal_webapp - Portal Web Server - war - The web server code that handles all transactions between the client and the server as well as server startup initialization. All other libraries (besides client) are utilized in this library. - - - - - ${project.parent.basedir} - - - false - - - 1 - 1 - - - - - - - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.version} - - true - target/site/${project.artifactId} - findbugs-exclude.xml - - - - - - - - - - maven-war-plugin - 2.3 - - portal - - false - - true - WEB-INF/lib/ - - - ${project.version} - ${maven.build.timestamp} - testsuite - ${project.version} - ${build.revision} - - - false - - - ../portal_client/dist/ - client - - - - - - maven-compiler-plugin - 3.1 - - - - -Xlint - - - - - maven-antrun-plugin - 1.6 - - - none - warcopy - - - - - - - - - run - - - - - - - - - - - commons-logging - commons-logging - 1.2 - - - - - - - junit - junit - ${junit.version} - test - - - - - org.apache.tomcat - tomcat-catalina - ${tomcat-version} - test - - - org.apache.tomcat - tomcat-servlet-api - ${tomcat-version} - provided - - - org.apache.tomcat - tomcat-jsp-api - ${tomcat-version} - provided - - - org.apache.tomcat - tomcat-annotations-api - ${tomcat-version} - provided - - - - - org.springframework - spring-webmvc - ${spring.version} - - - org.springframework - spring-web - ${spring.version} - - - org.springframework - spring-websocket - ${spring.version} - - - org.springframework - spring-messaging - ${spring.version} - jar - - - org.springframework - spring-context-support - ${spring.version} - - - org.springframework.security - spring-security-config - ${spring.security.version} - jar - - - org.springframework.security - spring-security-web - ${spring.security.version} - jar - - - org.springframework.security - spring-security-core - ${spring.security.version} - jar - - - org.springframework.security - spring-security-messaging - ${spring.security.version} - jar - - - - - javax.websocket - javax.websocket-api - 1.1 - provided - - - - - org.eclipse.jgit - org.eclipse.jgit - 5.0.1.201806211838-r - - - org.slf4j - slf4j-api - - - - - - - com.jcraft - jsch - 0.1.54 - - - - - org.quartz-scheduler - quartz - 2.3.0 - - - org.slf4j - slf4j-api - - - - - org.quartz-scheduler - quartz-jobs - 2.3.0 - - - - - javax.mail - javax.mail-api - 1.6.1 - - - - - com.sun.mail - javax.mail - 1.6.1 - - - - net.locusworks - portal_database - ${current.version} - - - net.locusworks - portal_common - ${current.version} - - - net.locusworks - portal_migration - ${current.version} - - - - + + + 4.0.0 + net.locusworksportal1.0.0-RELEASE + portal_webapp + Portal Web Server + Executable Spring Boot portal web server. + ${project.parent.basedir}false11 + + + src/main/resources + src/main/webappstaticWEB-INF/** + ../portal_client/diststatic/client + + + org.springframework.bootspring-boot-maven-plugin${spring-boot.version}repackage + maven-compiler-plugin-Xlint + + + + org.springframework.bootspring-boot-starter-web + org.springframework.bootspring-boot-starter-security + org.springframework.bootspring-boot-starter-websocket + org.springframework.bootspring-boot-starter-mail + org.springframework.bootspring-boot-starter-quartz + org.springframework.securityspring-security-messaging + org.eclipse.jgitorg.eclipse.jgit7.7.1.202607240634-r + org.eclipse.jgitorg.eclipse.jgit.ssh.jsch7.7.1.202607240634-r + com.github.mwiedejsch2.28.7 + com.mysqlmysql-connector-j + net.locusworksportal_database${current.version} + net.locusworksportal_common${current.version} + net.locusworksportal_migration${current.version} + + diff --git a/portal_webapp/src/main/java/net/locusworks/portal/PortalApplication.java b/portal_webapp/src/main/java/net/locusworks/portal/PortalApplication.java new file mode 100644 index 0000000..792bc89 --- /dev/null +++ b/portal_webapp/src/main/java/net/locusworks/portal/PortalApplication.java @@ -0,0 +1,36 @@ +package net.locusworks.portal; + +import java.io.IOException; +import java.nio.file.Files; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.security.web.session.HttpSessionEventPublisher; + +import net.locusworks.portal.common.utils.Constants; + +@SpringBootApplication +public class PortalApplication { + public static void main(String[] args) { + initializePortalHome(); + SpringApplication.run(PortalApplication.class, args); + } + + private static void initializePortalHome() { + var portalHome = Constants.getPortalHome(); + System.setProperty(Constants.PORTAL_HOME_PROPERTY, portalHome.toString()); + try { + Files.createDirectories(portalHome); + Files.createDirectories(portalHome.resolve("logs")); + Files.createDirectories(portalHome.resolve("keys")); + } catch (IOException ex) { + throw new IllegalStateException("Unable to initialize portal home: " + portalHome, ex); + } + } + + @Bean + HttpSessionEventPublisher httpSessionEventPublisher() { + return new HttpSessionEventPublisher(); + } +} diff --git a/portal_webapp/src/main/java/net/locusworks/portal/config/PortalQuartzSchedulerConfig.java b/portal_webapp/src/main/java/net/locusworks/portal/config/PortalQuartzSchedulerConfig.java index 569e58b..8f3faed 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/config/PortalQuartzSchedulerConfig.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/config/PortalQuartzSchedulerConfig.java @@ -42,7 +42,7 @@ public class PortalQuartzSchedulerConfig { public SchedulerFactoryBean schedulerFactory() { SchedulerFactoryBean factory = new SchedulerFactoryBean(); factory.setAutoStartup(true); - factory.setSchedulerName("NGAS Portal scheduler"); + factory.setSchedulerName("Locusworks Portal scheduler"); factory.setOverwriteExistingJobs(true); factory.setJobFactory(jobFactory()); return factory; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/config/WebSecurityConfig.java b/portal_webapp/src/main/java/net/locusworks/portal/config/WebSecurityConfig.java index 4ac6b1d..6013b71 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/config/WebSecurityConfig.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/config/WebSecurityConfig.java @@ -1,11 +1,10 @@ package net.locusworks.portal.config; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter; +import org.springframework.security.web.SecurityFilterChain; import net.locusworks.portal.handlers.PortalAuthenticationFailureHandler; import net.locusworks.portal.handlers.PortalAuthenticationSuccessHandler; @@ -20,44 +19,34 @@ import net.locusworks.portal.providers.CustomAuthenticationProvider; */ @Configuration @EnableWebSecurity -public class WebSecurityConfig extends WebSecurityConfigurerAdapter { - - @Autowired - CustomAuthenticationProvider provider; +public class WebSecurityConfig { /*** * Sets up the allowed pages and how to handle successful and failed login attempts */ - @Override - protected void configure(HttpSecurity http) throws Exception { - http - .csrf().disable() - // See https://jira.springsource.org/browse/SPR-11496 - .headers().addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsHeaderWriter.XFrameOptionsMode.SAMEORIGIN)) - .and() - .formLogin() + @Bean + SecurityFilterChain securityFilterChain(HttpSecurity http, CustomAuthenticationProvider provider) throws Exception { + http + .csrf(csrf -> csrf.disable()) + // AccountController authenticates programmatically. Retain the resulting + // SecurityContext in the HTTP session for subsequent API requests. + .securityContext(context -> context.requireExplicitSave(false)) + .headers(headers -> headers.frameOptions(frame -> frame.sameOrigin())) + .formLogin(form -> form .successHandler(new PortalAuthenticationSuccessHandler()) // handle successful login .failureHandler(new PortalAuthenticationFailureHandler()) // handle failure login // specify our own login page rather than the default, this is what spring will forward to if an un-authenticated request come in .loginPage("/client/index.html") .loginProcessingUrl("/springLogin") // this is the magic spring page that we post our login request (there is no real page hint hint) - .permitAll() // all users can access the login form - .and() - .logout() + .permitAll()) + .logout(logout -> logout .logoutSuccessHandler(new PortalLogoutSuccessHandler()) // calls this on logout success .logoutUrl("/logout") // where the client should be redirected for logout, no file exists - .permitAll() - .and() - .authorizeRequests() - .antMatchers("/").permitAll() - .antMatchers("/ws/**").permitAll()//allow to subscribe to stomp topics - .antMatchers("/index.html").permitAll() - .antMatchers("/assets/**").permitAll() - .antMatchers("/account/isLoggedIn.do").permitAll() - .antMatchers("/account/login.do").permitAll() - .antMatchers("/client/**").permitAll() - .anyRequest().authenticated()// all other URLs require just authenticated access - .and() - .authenticationProvider(provider); // our custom authenticator - } -} + .permitAll()) + .authorizeHttpRequests(auth -> auth + .requestMatchers("/", "/ws/**", "/index.html", "/assets/**", "/account/isLoggedIn.do", "/account/login.do", "/client/**").permitAll() + .anyRequest().authenticated()) + .authenticationProvider(provider); // our custom authenticator + return http.build(); + } +} diff --git a/portal_webapp/src/main/java/net/locusworks/portal/config/WebSocketConfig.java b/portal_webapp/src/main/java/net/locusworks/portal/config/WebSocketConfig.java index 13adea1..8689040 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/config/WebSocketConfig.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/config/WebSocketConfig.java @@ -1,16 +1,20 @@ package net.locusworks.portal.config; -import org.springframework.context.annotation.Configuration; -import org.springframework.messaging.simp.config.ChannelRegistration; -import org.springframework.messaging.simp.config.MessageBrokerRegistry; -import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry; -import org.springframework.security.config.annotation.web.socket.AbstractSecurityWebSocketMessageBrokerConfigurer; -import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; -import org.springframework.web.socket.config.annotation.StompEndpointRegistry; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.messaging.Message; +import org.springframework.messaging.simp.config.ChannelRegistration; +import org.springframework.messaging.simp.config.MessageBrokerRegistry; +import org.springframework.security.authorization.AuthorizationManager; +import org.springframework.security.config.annotation.web.socket.EnableWebSocketSecurity; +import org.springframework.security.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager; +import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; +import org.springframework.web.socket.config.annotation.StompEndpointRegistry; +import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.portal.common.enums.PermissionType; import net.locusworks.portal.services.CommService; import net.locusworks.portal.websocket.WebsocketOutboundChannelInterceptor; @@ -21,16 +25,16 @@ import net.locusworks.portal.websocket.WebsocketOutboundChannelInterceptor; * @since 1.0.0-RELEASE * @version 1.0 */ -@Configuration -@EnableWebSocketMessageBroker -public class WebSocketConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer { +@Configuration +@EnableWebSocketMessageBroker +@EnableWebSocketSecurity +public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { private static final Integer BUFFER_LIMIT = 512 * 1024; private static ApplicationLogger logger = ApplicationLoggerFactory.getLogger(WebSocketConfig.class); - //Socks library uses version 1.1.4. The current library included with spring websockets is 1.0.0. need to override it with our current one - public static final String SOCKS_1_1_4_LOCATION = "../../client/yarn_components/sockjs-client/dist/sockjs.min.js"; + private static final String SOCKJS_CLIENT_LOCATION = "/portal/client/vendor/sockjs.min.js"; //Define our allowed authorties private static String[] authorities = new String[] { @@ -47,28 +51,24 @@ public class WebSocketConfig extends AbstractSecurityWebSocketMessageBrokerConfi @Override public void registerStompEndpoints(StompEndpointRegistry registry) { - logger.info("Registering STOMP!"); - registry.addEndpoint(CommService.STOMP_ENDPOINT) - .setAllowedOrigins("*") - .withSockJS() - .setClientLibraryUrl(SOCKS_1_1_4_LOCATION); + logger.info("Registering STOMP!"); + registry.addEndpoint(CommService.STOMP_ENDPOINT) + .withSockJS() + .setClientLibraryUrl(SOCKJS_CLIENT_LOCATION); } - @Override - protected void configureInbound(MessageSecurityMetadataSourceRegistry message) { - message - .nullDestMatcher().permitAll() + @Bean + AuthorizationManager> messageAuthorizationManager( + MessageMatcherDelegatingAuthorizationManager.Builder messages) { + messages + .nullDestMatcher().permitAll() .simpSubscribeDestMatchers("/user/queue/pong").permitAll() .simpDestMatchers("/start/ping").permitAll() .simpDestMatchers("/app/**").hasAnyAuthority(authorities) - .simpSubscribeDestMatchers(CommService.STOMP_TOPIC_PREFIX + "**").permitAll() - .anyMessage().denyAll(); - } - - @Override - protected boolean sameOriginDisabled() { - return true; - } + .simpSubscribeDestMatchers(CommService.STOMP_TOPIC_PREFIX + "**").permitAll() + .anyMessage().denyAll(); + return messages.build(); + } @Override public void configureClientOutboundChannel(ChannelRegistration registration) { diff --git a/portal_webapp/src/main/java/net/locusworks/portal/controllers/AccountController.java b/portal_webapp/src/main/java/net/locusworks/portal/controllers/AccountController.java index 76dc682..b2569da 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/controllers/AccountController.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/controllers/AccountController.java @@ -4,8 +4,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Controller; @@ -13,8 +13,8 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.common.utils.Success; import net.locusworks.portal.common.enums.PermissionType; import net.locusworks.portal.common.enums.TriggerType; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/controllers/ApplicationLogController.java b/portal_webapp/src/main/java/net/locusworks/portal/controllers/ApplicationLogController.java index 378c58f..c72d0c1 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/controllers/ApplicationLogController.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/controllers/ApplicationLogController.java @@ -7,8 +7,8 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.common.utils.Success; import net.locusworks.portal.common.enums.PermissionType; import net.locusworks.portal.common.exceptions.PortalException; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/controllers/BaseController.java b/portal_webapp/src/main/java/net/locusworks/portal/controllers/BaseController.java index 5e7baea..4759709 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/controllers/BaseController.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/controllers/BaseController.java @@ -4,7 +4,7 @@ import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/controllers/ConfigurationController.java b/portal_webapp/src/main/java/net/locusworks/portal/controllers/ConfigurationController.java index 9b1397d..ec851e9 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/controllers/ConfigurationController.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/controllers/ConfigurationController.java @@ -13,8 +13,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import net.locusworks.common.configuration.PropertiesManager; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.common.utils.Success; import net.locusworks.portal.common.enums.PermissionType; import net.locusworks.portal.common.exceptions.PortalException; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/controllers/CredentialsController.java b/portal_webapp/src/main/java/net/locusworks/portal/controllers/CredentialsController.java index 78d6d22..d50f2c9 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/controllers/CredentialsController.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/controllers/CredentialsController.java @@ -8,8 +8,8 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.common.utils.Success; import net.locusworks.portal.common.enums.CredentialType; import net.locusworks.portal.common.enums.PermissionType; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/controllers/ExceptionController.java b/portal_webapp/src/main/java/net/locusworks/portal/controllers/ExceptionController.java index 58384b6..46de0e1 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/controllers/ExceptionController.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/controllers/ExceptionController.java @@ -10,8 +10,8 @@ import org.springframework.web.context.request.WebRequest; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; import net.locusworks.common.exceptions.ApplicationException; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.common.objectmapper.ObjectMapperError; import net.locusworks.common.objectmapper.ObjectMapperHelper; import net.locusworks.portal.services.ApplicationLogService; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/controllers/FileController.java b/portal_webapp/src/main/java/net/locusworks/portal/controllers/FileController.java index 0c40af1..3f41477 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/controllers/FileController.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/controllers/FileController.java @@ -2,7 +2,7 @@ package net.locusworks.portal.controllers; import java.io.File; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import org.apache.commons.io.FileUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -13,8 +13,8 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.common.utils.Success; import net.locusworks.portal.common.enums.PermissionType; import net.locusworks.portal.common.enums.TriggerType; @@ -61,9 +61,7 @@ public class FileController extends BaseController { try(FileDownloadServletResponse fdsr = new FileDownloadServletResponse(response, rfr.getFileName())) { fdsr.sendFile(fileToDownload); - } catch (InterruptedException ex) { - logger.warn("File download was interrupted: %s", ex.getMessage()); - } + } } /** @@ -104,4 +102,4 @@ public class FileController extends BaseController { throw (PortalException)ex; } } -} \ No newline at end of file +} diff --git a/portal_webapp/src/main/java/net/locusworks/portal/controllers/GitController.java b/portal_webapp/src/main/java/net/locusworks/portal/controllers/GitController.java index ee44ce5..af190b8 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/controllers/GitController.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/controllers/GitController.java @@ -8,8 +8,8 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.common.utils.Success; import net.locusworks.portal.common.enums.PermissionType; import net.locusworks.portal.common.exceptions.PortalException; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/controllers/LogController.java b/portal_webapp/src/main/java/net/locusworks/portal/controllers/LogController.java index f74fc3b..2ff8799 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/controllers/LogController.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/controllers/LogController.java @@ -7,9 +7,9 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; -import net.locusworks.common.logger.ApplicationLoggerFactory.LoggerInfo; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLoggerFactory.LoggerInfo; import net.locusworks.common.utils.Success; import net.locusworks.portal.common.enums.PermissionType; import net.locusworks.portal.common.exceptions.PortalException; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/controllers/PermissionsController.java b/portal_webapp/src/main/java/net/locusworks/portal/controllers/PermissionsController.java index f3ff201..d4a6e26 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/controllers/PermissionsController.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/controllers/PermissionsController.java @@ -7,8 +7,8 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.common.utils.Success; import net.locusworks.common.utils.Utils; import net.locusworks.portal.common.enums.PermissionType; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/controllers/ScriptController.java b/portal_webapp/src/main/java/net/locusworks/portal/controllers/ScriptController.java index f2ac941..2e9fef9 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/controllers/ScriptController.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/controllers/ScriptController.java @@ -6,8 +6,8 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.common.utils.Success; import net.locusworks.portal.common.enums.PermissionType; import net.locusworks.portal.common.enums.TriggerType; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/controllers/SystemController.java b/portal_webapp/src/main/java/net/locusworks/portal/controllers/SystemController.java index 374c0cb..5c9cd79 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/controllers/SystemController.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/controllers/SystemController.java @@ -8,8 +8,8 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.common.utils.Success; import net.locusworks.portal.common.enums.PermissionType; import net.locusworks.portal.common.enums.TriggerType; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/extendedlogger/ExtendedLogger.java b/portal_webapp/src/main/java/net/locusworks/portal/extendedlogger/ExtendedLogger.java index cf2707e..02efdb8 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/extendedlogger/ExtendedLogger.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/extendedlogger/ExtendedLogger.java @@ -1,7 +1,7 @@ package net.locusworks.portal.extendedlogger; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.LogLevel; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.LogLevel; /** * Extended the portal logger class to for specialized loggers such as the leak prevent and jsch diff --git a/portal_webapp/src/main/java/net/locusworks/portal/extendedlogger/ExtendedLoggerFactory.java b/portal_webapp/src/main/java/net/locusworks/portal/extendedlogger/ExtendedLoggerFactory.java index 4e43771..4f65596 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/extendedlogger/ExtendedLoggerFactory.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/extendedlogger/ExtendedLoggerFactory.java @@ -1,8 +1,8 @@ package net.locusworks.portal.extendedlogger; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; -import net.locusworks.common.logger.LogLevel; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; +import net.locusworks.logger.LogLevel; /** * Extended portal logger factory to create ExtendedApplicationLoggers to be used diff --git a/portal_webapp/src/main/java/net/locusworks/portal/handlers/AbstractObjectMessageHandler.java b/portal_webapp/src/main/java/net/locusworks/portal/handlers/AbstractObjectMessageHandler.java index 57d646a..af67763 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/handlers/AbstractObjectMessageHandler.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/handlers/AbstractObjectMessageHandler.java @@ -3,8 +3,8 @@ package net.locusworks.portal.handlers; import org.springframework.messaging.Message; import org.springframework.messaging.simp.stomp.StompHeaderAccessor; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import static net.locusworks.common.Charsets.UTF_8; @@ -16,7 +16,14 @@ import static net.locusworks.common.Charsets.UTF_8; */ public abstract class AbstractObjectMessageHandler implements StompMessageHandler { - private String destination; + private String destination; + + protected AbstractObjectMessageHandler() { + } + + protected AbstractObjectMessageHandler(String destination) { + this.destination = destination; + } private static ApplicationLogger logger = ApplicationLoggerFactory.getLogger(AbstractObjectMessageHandler.class); diff --git a/portal_webapp/src/main/java/net/locusworks/portal/handlers/BrokerAvailabilityHandler.java b/portal_webapp/src/main/java/net/locusworks/portal/handlers/BrokerAvailabilityHandler.java index a5fca5a..c4ad891 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/handlers/BrokerAvailabilityHandler.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/handlers/BrokerAvailabilityHandler.java @@ -5,8 +5,8 @@ import org.springframework.context.ApplicationListener; import org.springframework.messaging.simp.broker.BrokerAvailabilityEvent; import org.springframework.stereotype.Component; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.portal.common.http.HttpClientHelper; import net.locusworks.portal.services.SchedulerService; import net.locusworks.portal.services.WebCommService; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/handlers/LoggerInitializer.java b/portal_webapp/src/main/java/net/locusworks/portal/handlers/LoggerInitializer.java index 33cd74f..b20941b 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/handlers/LoggerInitializer.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/handlers/LoggerInitializer.java @@ -1,10 +1,12 @@ package net.locusworks.portal.handlers; -import static net.locusworks.portal.common.utils.Constants.PROPERTIES_FILE; +import static net.locusworks.portal.common.utils.Constants.PROPERTIES_FILE; +import static net.locusworks.portal.common.utils.Constants.getPortalHome; import java.io.File; import java.io.FileOutputStream; -import java.io.IOException; +import java.io.IOException; +import java.nio.file.Files; import java.util.List; import java.util.Map; import java.util.Properties; @@ -13,11 +15,11 @@ import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import net.locusworks.common.configuration.PropertiesManager; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; -import net.locusworks.common.logger.ApplicationLoggerFactory.LoggerInfo; -import net.locusworks.common.logger.ApplicationLoggerInitializer; -import net.locusworks.common.logger.LogLevel; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLoggerFactory.LoggerInfo; +import net.locusworks.logger.ApplicationLoggerInitializer; +import net.locusworks.logger.LogLevel; import net.locusworks.common.properties.OrderedProperties; import net.locusworks.portal.common.enums.Configuration; @@ -37,13 +39,13 @@ public class LoggerInitializer implements ApplicationLoggerInitializer { @Override public void loadLoggers() { - File loggerFile = new File(String.format("%s/conf/%s", System.getProperty("catalina.base"), LOGGER_FILE)); + File loggerFile = new File(getPortalHome().toFile(), LOGGER_FILE); if (!loggerFile.exists()) { return; } try { - Properties conf = PropertiesManager.loadConfiguration(loggerFile); + Properties conf = PropertiesManager.loadConfiguration(loggerFile.toPath()); List loggerInfo = conf.entrySet() .stream() .map(item -> new LoggerInfo(String.valueOf(item.getKey()), String.valueOf(item.getValue()))) @@ -58,7 +60,7 @@ public class LoggerInitializer implements ApplicationLoggerInitializer { @Override public void saveLogLevels(Map loggers) { OrderedProperties conf = new OrderedProperties(); - File loggerFile = new File(String.format("%s/conf/%s", System.getProperty("catalina.base"), LOGGER_FILE)); + File loggerFile = new File(getPortalHome().toFile(), LOGGER_FILE); loggers.entrySet() .stream() @@ -68,7 +70,12 @@ public class LoggerInitializer implements ApplicationLoggerInitializer { .sorted((item1, item2) -> item1.getName().compareTo(item2.getName())) .forEach(item -> conf.setProperty(item.getName(), item.getLogLevel().toName())); - try(FileOutputStream fos = new FileOutputStream(loggerFile)) { + try { + Files.createDirectories(loggerFile.toPath().getParent()); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + try(FileOutputStream fos = new FileOutputStream(loggerFile)) { conf.store(fos, "Portal Logger Levels"); } catch (IOException ex) { throw new RuntimeException(ex); @@ -79,8 +86,8 @@ public class LoggerInitializer implements ApplicationLoggerInitializer { public LogLevel initialize() { try { Properties defaults = PropertiesManager.loadConfiguration(this.getClass(), PROPERTIES_FILE); - File patchRepoConfFile = new File(String.format("%s/conf/%s", System.getProperty("catalina.base"), PROPERTIES_FILE)); - Properties conf = PropertiesManager.loadConfiguration(patchRepoConfFile); + File patchRepoConfFile = new File(getPortalHome().toFile(), PROPERTIES_FILE); + Properties conf = PropertiesManager.loadConfiguration(patchRepoConfFile.toPath()); String logLevel = conf.getProperty(Configuration.LOG_LEVEL.getValue()); if (StringUtils.isBlank(logLevel)) { @@ -94,4 +101,4 @@ public class LoggerInitializer implements ApplicationLoggerInitializer { throw new RuntimeException("Unable to get properites: ", ex); } } -} \ No newline at end of file +} diff --git a/portal_webapp/src/main/java/net/locusworks/portal/handlers/PortalAuthenticationFailureHandler.java b/portal_webapp/src/main/java/net/locusworks/portal/handlers/PortalAuthenticationFailureHandler.java index 9814261..db4c306 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/handlers/PortalAuthenticationFailureHandler.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/handlers/PortalAuthenticationFailureHandler.java @@ -1,8 +1,8 @@ package net.locusworks.portal.handlers; import java.io.IOException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.stereotype.Component; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/handlers/PortalAuthenticationSuccessHandler.java b/portal_webapp/src/main/java/net/locusworks/portal/handlers/PortalAuthenticationSuccessHandler.java index 54af22c..eb9f073 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/handlers/PortalAuthenticationSuccessHandler.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/handlers/PortalAuthenticationSuccessHandler.java @@ -2,8 +2,8 @@ package net.locusworks.portal.handlers; import java.io.IOException; import java.util.HashMap; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/handlers/PortalLogoutSuccessHandler.java b/portal_webapp/src/main/java/net/locusworks/portal/handlers/PortalLogoutSuccessHandler.java index 55a2a0e..c50904e 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/handlers/PortalLogoutSuccessHandler.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/handlers/PortalLogoutSuccessHandler.java @@ -1,18 +1,18 @@ package net.locusworks.portal.handlers; import java.io.IOException; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; /** * Component to handle logout attempts diff --git a/portal_webapp/src/main/java/net/locusworks/portal/handlers/SeedUpdatedHandler.java b/portal_webapp/src/main/java/net/locusworks/portal/handlers/SeedUpdatedHandler.java index 3d4952b..ba9bc3f 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/handlers/SeedUpdatedHandler.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/handlers/SeedUpdatedHandler.java @@ -6,8 +6,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.portal.common.enums.TriggerType; import net.locusworks.portal.common.services.AESService; import net.locusworks.portal.common.services.ConfigurationService; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/handlers/SystemTriggerMessageHandler.java b/portal_webapp/src/main/java/net/locusworks/portal/handlers/SystemTriggerMessageHandler.java index 773a0ca..d182c53 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/handlers/SystemTriggerMessageHandler.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/handlers/SystemTriggerMessageHandler.java @@ -1,7 +1,7 @@ package net.locusworks.portal.handlers; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.portal.handlers.AbstractObjectMessageHandler; import net.locusworks.portal.services.CommService; @@ -20,7 +20,7 @@ public class SystemTriggerMessageHandler extends AbstractObjectMessageHandler { * Sets the destination to be the global system topic */ public SystemTriggerMessageHandler() { - setDestination(CommService.getStompAccountTopic(CommService.STOMP_SYSTEM_TOPIC_SUFFIX)); + super(CommService.getStompAccountTopic(CommService.STOMP_SYSTEM_TOPIC_SUFFIX)); } @Override diff --git a/portal_webapp/src/main/java/net/locusworks/portal/handlers/SystemWebSocketHandler.java b/portal_webapp/src/main/java/net/locusworks/portal/handlers/SystemWebSocketHandler.java index 2eb9f60..ebd1f60 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/handlers/SystemWebSocketHandler.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/handlers/SystemWebSocketHandler.java @@ -25,8 +25,8 @@ import org.springframework.web.socket.sockjs.client.SockJsClient; import org.springframework.web.socket.sockjs.client.Transport; import org.springframework.web.socket.sockjs.client.WebSocketTransport; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.portal.common.http.HttpClientHelper.HttpSchema; import net.locusworks.portal.common.services.ConfigurationService; import net.locusworks.portal.handlers.StompMessageHandler; @@ -141,7 +141,7 @@ public class SystemWebSocketHandler extends AbstractWebSocketHandler { String endpoint = String.format("%s://%s:%s/%s", schema == HttpSchema.HTTPS ? "wss" : "ws", endPoint.host, endPoint.port, "portal/ws/stomp"); SockJsClient sockJsClient = new SockJsClient(transports); - sockJsClient.doHandshake(this, endpoint); + sockJsClient.execute(this, endpoint); } catch (Exception ex) { logger.error("Unable to connect to stomp socket " + ex.getMessage(), ex); diff --git a/portal_webapp/src/main/java/net/locusworks/portal/services/ApplicationLogService.java b/portal_webapp/src/main/java/net/locusworks/portal/services/ApplicationLogService.java index 7c0c347..2f3054c 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/services/ApplicationLogService.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/services/ApplicationLogService.java @@ -6,8 +6,8 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpSession; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -17,7 +17,7 @@ import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; -import net.locusworks.common.logger.LogLevel; +import net.locusworks.logger.LogLevel; import net.locusworks.common.utils.Utils; import net.locusworks.portal.common.enums.EventType; import net.locusworks.portal.common.enums.TriggerType; @@ -27,8 +27,8 @@ import net.locusworks.portal.database.repos.ApplicationLogRepository; import net.locusworks.portal.json.ApplicationLogRequest; import net.locusworks.portal.json.ApplicationUserRequest; import net.locusworks.portal.json.PurgeLogRequest; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; /** * Service that adds certain logs to the log database for viewing diff --git a/portal_webapp/src/main/java/net/locusworks/portal/services/CommService.java b/portal_webapp/src/main/java/net/locusworks/portal/services/CommService.java index 46f53d0..a55b8c1 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/services/CommService.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/services/CommService.java @@ -6,8 +6,8 @@ import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.messaging.support.MessageBuilder; import org.springframework.stereotype.Service; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.common.objectmapper.ObjectMapperError; import net.locusworks.common.objectmapper.ObjectMapperHelper; import net.locusworks.common.utils.Utils; @@ -39,7 +39,7 @@ import javax.management.Query; public class CommService { public static final String STOMP_TOPIC_PREFIX = "/topic/"; public static final String STOMP_QUEUE_PREFIX = "/queue/"; - public static final String STOMP_ENDPOINT = "/stomp"; + public static final String STOMP_ENDPOINT = "/ws/stomp"; public static final String STOMP_ACCOUNT = "account|"; public static final String STOMP_SYSTEM_TOPIC_SUFFIX = "system"; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/services/CredentialService.java b/portal_webapp/src/main/java/net/locusworks/portal/services/CredentialService.java index 3f7cb44..9282021 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/services/CredentialService.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/services/CredentialService.java @@ -219,7 +219,7 @@ public class CredentialService { throw PortalException.constraintViolation("Unable to find credentials uid of %s", request.getUid()); } - boolean inUse = credRepo.inUse(creds.getUuid()); + boolean inUse = credRepo.credentialCount(creds.getUuid()) > 0; if (inUse) { throw PortalException.constraintViolation("Credential is in use. Please delete records that use this credentials then try again."); } diff --git a/portal_webapp/src/main/java/net/locusworks/portal/services/GitService.java b/portal_webapp/src/main/java/net/locusworks/portal/services/GitService.java index 3d919d6..9a08e27 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/services/GitService.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/services/GitService.java @@ -5,7 +5,7 @@ import java.util.Date; import java.util.List; import java.util.stream.Collectors; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import org.apache.commons.io.FileUtils; import org.quartz.Job; @@ -13,8 +13,8 @@ import org.quartz.JobExecutionContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.portal.common.enums.FrequencyType; import net.locusworks.portal.common.exceptions.PortalException; import net.locusworks.portal.common.services.ConfigurationService; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/services/PortalContextService.java b/portal_webapp/src/main/java/net/locusworks/portal/services/PortalContextService.java index 88b08a4..3fb0a46 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/services/PortalContextService.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/services/PortalContextService.java @@ -4,18 +4,18 @@ import java.sql.Driver; import java.sql.DriverManager; import java.util.Enumeration; -import javax.servlet.ServletContextEvent; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.stereotype.Component; -import org.springframework.web.context.ContextLoaderListener; import com.mysql.cj.jdbc.AbandonedConnectionCleanupThread; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.portal.common.PortalDataSource; import net.locusworks.portal.extendedlogger.ExtendedLoggerFactory; import net.locusworks.portal.handlers.LoggerInitializer; @@ -30,7 +30,7 @@ import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventorFactory; * @version 1.0 */ @Component -public class PortalContextService extends ContextLoaderListener implements ApplicationListener { +public class PortalContextService implements ApplicationListener { private ClassLoaderLeakPreventor leakPreventor; @@ -48,8 +48,8 @@ public class PortalContextService extends ContextLoaderListener implements Appli } } - @Override - public void contextInitialized(ServletContextEvent sce) { + @PostConstruct + public void contextInitialized() { // Initialize the logger; ApplicationLoggerFactory.init(new LoggerInitializer()); try { @@ -58,18 +58,16 @@ public class PortalContextService extends ContextLoaderListener implements Appli leakPreventor = lpf.newLeakPreventor(); } catch (Exception e) {} - super.contextInitialized(sce); } - @Override - public void contextDestroyed(ServletContextEvent sce) { + @PreDestroy + public void contextDestroyed() { ApplicationLoggerFactory.saveLogLevels(); cleanUpJDBCDrivers(); cleanUpDatasources(); cleanUpSchedulerService(); cleanUpThreads(); resetSystemOut(); - super.contextDestroyed(sce); } private void resetSystemOut() { diff --git a/portal_webapp/src/main/java/net/locusworks/portal/services/ResourceFileService.java b/portal_webapp/src/main/java/net/locusworks/portal/services/ResourceFileService.java index 9de75e8..d515028 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/services/ResourceFileService.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/services/ResourceFileService.java @@ -11,8 +11,8 @@ import org.apache.commons.io.FileUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.portal.database.entities.ResourceFile; import net.locusworks.portal.database.repos.ResourceFileRepository; import net.locusworks.portal.json.ResourceFileRequest; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/services/SchedulerService.java b/portal_webapp/src/main/java/net/locusworks/portal/services/SchedulerService.java index 0bdc6ec..8deeddd 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/services/SchedulerService.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/services/SchedulerService.java @@ -10,7 +10,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import org.quartz.CalendarIntervalScheduleBuilder; import org.quartz.Job; @@ -27,8 +27,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.quartz.SchedulerFactoryBean; import org.springframework.stereotype.Service; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.portal.common.enums.FrequencyType; import net.locusworks.portal.common.utils.DateService; import net.locusworks.portal.util.TaskScheduler; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/services/ScriptService.java b/portal_webapp/src/main/java/net/locusworks/portal/services/ScriptService.java index 2539d45..2bc7985 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/services/ScriptService.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/services/ScriptService.java @@ -13,12 +13,13 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; @@ -28,7 +29,7 @@ import org.springframework.stereotype.Service; import com.jcraft.jsch.JSch; -import net.locusworks.common.logger.LogLevel; +import net.locusworks.logger.LogLevel; import net.locusworks.common.utils.Utils; import net.locusworks.portal.common.enums.FrequencyType; import net.locusworks.portal.common.enums.ScriptType; @@ -80,8 +81,8 @@ import net.locusworks.portal.services.SendMailService.EmailMessageFormatter; import net.locusworks.portal.util.JSchHelper; import net.locusworks.portal.util.JSchResults; import net.locusworks.portal.util.JSchHelper.SCP_DIRECTION; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import static net.locusworks.common.utils.Constants.TRUE; import static net.locusworks.common.utils.Constants.EXIT_FAIL; @@ -652,8 +653,8 @@ public class ScriptService implements Job { String fromHost = scp.getFromHost(); String toHost = scp.getToHost(); - boolean fromLocal = StringUtils.startsWithIgnoreCase(fromHost, LOCAL_LOCATION); - boolean toLocal = StringUtils.startsWithIgnoreCase(toHost, LOCAL_LOCATION); + boolean fromLocal = Strings.CI.startsWith(fromHost, LOCAL_LOCATION); + boolean toLocal = Strings.CI.startsWith(toHost, LOCAL_LOCATION); JSchResults exitStatus = null; if (!fromLocal && toLocal) { diff --git a/portal_webapp/src/main/java/net/locusworks/portal/services/SecureRandomService.java b/portal_webapp/src/main/java/net/locusworks/portal/services/SecureRandomService.java index 6f8191f..4c8b6ef 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/services/SecureRandomService.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/services/SecureRandomService.java @@ -3,7 +3,7 @@ package net.locusworks.portal.services; import java.security.SecureRandom; import java.util.Date; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import org.springframework.stereotype.Service; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/services/SendMailService.java b/portal_webapp/src/main/java/net/locusworks/portal/services/SendMailService.java index 63a4c17..5073336 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/services/SendMailService.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/services/SendMailService.java @@ -7,20 +7,20 @@ import java.util.Set; import java.util.TreeMap; import java.util.stream.Collectors; -import javax.mail.Message; -import javax.mail.Session; -import javax.mail.Transport; -import javax.mail.internet.AddressException; -import javax.mail.internet.InternetAddress; -import javax.mail.internet.MimeMessage; +import jakarta.mail.Message; +import jakarta.mail.Session; +import jakarta.mail.Transport; +import jakarta.mail.internet.AddressException; +import jakarta.mail.internet.InternetAddress; +import jakarta.mail.internet.MimeMessage; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.mail.MailSendException; import org.springframework.stereotype.Service; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; -import net.locusworks.common.logger.SystemDebugLogger; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; +import net.locusworks.logger.SystemDebugLogger; import net.locusworks.common.utils.Utils; import net.locusworks.portal.common.exceptions.PortalException; import net.locusworks.portal.common.services.AESService; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/services/SystemService.java b/portal_webapp/src/main/java/net/locusworks/portal/services/SystemService.java index be98135..71a7607 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/services/SystemService.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/services/SystemService.java @@ -9,8 +9,8 @@ import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.portal.common.exceptions.PortalException; import net.locusworks.portal.common.services.AESService; import net.locusworks.portal.database.entities.EmailTemplate; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/services/UserSecurityService.java b/portal_webapp/src/main/java/net/locusworks/portal/services/UserSecurityService.java index 2353902..2b4873c 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/services/UserSecurityService.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/services/UserSecurityService.java @@ -10,18 +10,19 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.stereotype.Service; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; -import net.locusworks.common.crypto.HashSalt; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.crypto.HashSalt; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.common.utils.StreamUtils; import net.locusworks.common.utils.Utils; import net.locusworks.portal.common.exceptions.PortalException; @@ -75,8 +76,9 @@ public class UserSecurityService { @Autowired private UserPasswordTrackingRepository usrPwdTrkRepo; - @Autowired - private CustomAuthenticationProvider provider; + @Autowired + @Lazy + private CustomAuthenticationProvider provider; /** * Initialize the user security service upon server startup @@ -500,4 +502,4 @@ public class UserSecurityService { return aur; } -} \ No newline at end of file +} diff --git a/portal_webapp/src/main/java/net/locusworks/portal/services/WebCommService.java b/portal_webapp/src/main/java/net/locusworks/portal/services/WebCommService.java index 41e9370..670d48d 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/services/WebCommService.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/services/WebCommService.java @@ -4,8 +4,8 @@ import org.springframework.context.ApplicationEvent; import org.springframework.stereotype.Service; import org.springframework.web.context.WebApplicationContext; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.portal.handlers.StompMessageHandler; import net.locusworks.portal.handlers.SystemWebSocketHandler; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/util/FileDownloadServletResponse.java b/portal_webapp/src/main/java/net/locusworks/portal/util/FileDownloadServletResponse.java index 775f762..af5439b 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/util/FileDownloadServletResponse.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/util/FileDownloadServletResponse.java @@ -1,15 +1,16 @@ package net.locusworks.portal.util; -import java.io.File; +import java.io.File; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponseWrapper; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; /** * Class to help download files * @author Isaac Parenteau @@ -69,7 +70,7 @@ public class FileDownloadServletResponse extends HttpServletResponseWrapper impl } @Override - public void close() throws Exception { + public void close() throws IOException { super.getResponse().getOutputStream().close(); } -} \ No newline at end of file +} diff --git a/portal_webapp/src/main/java/net/locusworks/portal/util/GitConfigSession.java b/portal_webapp/src/main/java/net/locusworks/portal/util/GitConfigSession.java index 81da53d..397d35b 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/util/GitConfigSession.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/util/GitConfigSession.java @@ -8,10 +8,10 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.eclipse.jgit.api.TransportConfigCallback; import org.eclipse.jgit.transport.CredentialsProvider; -import org.eclipse.jgit.transport.JschConfigSessionFactory; +import org.eclipse.jgit.transport.ssh.jsch.JschConfigSessionFactory; import org.eclipse.jgit.transport.SshTransport; import org.eclipse.jgit.transport.Transport; -import org.eclipse.jgit.transport.OpenSshConfig.Host; +import org.eclipse.jgit.transport.ssh.jsch.OpenSshConfig.Host; import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; import org.eclipse.jgit.util.FS; diff --git a/portal_webapp/src/main/java/net/locusworks/portal/util/JSchHelper.java b/portal_webapp/src/main/java/net/locusworks/portal/util/JSchHelper.java index fe7fbe6..b3a3559 100644 --- a/portal_webapp/src/main/java/net/locusworks/portal/util/JSchHelper.java +++ b/portal_webapp/src/main/java/net/locusworks/portal/util/JSchHelper.java @@ -19,8 +19,8 @@ import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.JSch; import com.jcraft.jsch.Session; -import net.locusworks.common.logger.ApplicationLogger; -import net.locusworks.common.logger.ApplicationLoggerFactory; +import net.locusworks.logger.ApplicationLogger; +import net.locusworks.logger.ApplicationLoggerFactory; import net.locusworks.common.utils.Utils; import net.locusworks.portal.common.enums.CredentialType; import net.locusworks.portal.common.services.AESService; @@ -247,7 +247,7 @@ public class JSchHelper implements AutoCloseable { } @Override - public void close() throws Exception { + public void close() { if(session != null && session.isConnected()) { session.disconnect(); } @@ -466,4 +466,4 @@ public class JSchHelper implements AutoCloseable { } return b; } -} \ No newline at end of file +} diff --git a/portal_webapp/src/main/resources/application.properties b/portal_webapp/src/main/resources/application.properties new file mode 100644 index 0000000..5a30af2 --- /dev/null +++ b/portal_webapp/src/main/resources/application.properties @@ -0,0 +1,7 @@ +spring.application.name=portal +server.servlet.context-path=/portal +server.servlet.session.timeout=540m +spring.jpa.open-in-view=false +spring.jpa.hibernate.ddl-auto=none +spring.servlet.multipart.max-file-size=10MB +spring.servlet.multipart.max-request-size=10MB diff --git a/portal_webapp/src/main/resources/log4j2.xml b/portal_webapp/src/main/resources/log4j2.xml index fcd56cf..de4c6b9 100644 --- a/portal_webapp/src/main/resources/log4j2.xml +++ b/portal_webapp/src/main/resources/log4j2.xml @@ -8,8 +8,8 @@ - + diff --git a/portal_webapp/src/main/resources/portal.properties b/portal_webapp/src/main/resources/portal.properties index 6915c21..841c260 100644 --- a/portal_webapp/src/main/resources/portal.properties +++ b/portal_webapp/src/main/resources/portal.properties @@ -1,6 +1,10 @@ userExpirationDays=3650 logLevel=INFO -dbHost=localhost +dbType=h2 +h2Url=jdbc:h2:file:${portal.home}/data/portal;MODE=MySQL;DATABASE_TO_LOWER=TRUE;DEFAULT_NULL_ORDERING=HIGH;NON_KEYWORDS=VALUE;DB_CLOSE_ON_EXIT=FALSE;INIT=CREATE SCHEMA IF NOT EXISTS portal +h2Username=sa +h2Password= +dbHost=localhost dbPort=3306 dbUsername=portalAdmin dbPassword=VWUPJBKSje2S8J/YMdx15QhhRMRsy39URVR6c6ksrtE\= @@ -8,4 +12,4 @@ dbRootUser=root dbRootPassword=VvzxDy5E1o1Q8rL7XMO2mQ\=\= caCertFile=${user.home}/cacerts.jks caCertPassword=N/OQnJ9uQh1oYxadwGC3vA== -aesSeedFile=${catalina.base}/conf/portal.tomcat \ No newline at end of file +aesSeedFile=${portal.home}/portal.tomcat diff --git a/portal_webapp/src/main/webapp/META-INF/context.xml b/portal_webapp/src/main/webapp/META-INF/context.xml deleted file mode 100644 index 6c564eb..0000000 --- a/portal_webapp/src/main/webapp/META-INF/context.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - WEB-INF/web.xml - - - - - diff --git a/portal_webapp/src/main/webapp/WEB-INF/portal-config.xml b/portal_webapp/src/main/webapp/WEB-INF/portal-config.xml deleted file mode 100644 index c9883af..0000000 --- a/portal_webapp/src/main/webapp/WEB-INF/portal-config.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - /view/ - - - .jsp - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/portal_webapp/src/main/webapp/WEB-INF/portal-servlet.xml b/portal_webapp/src/main/webapp/WEB-INF/portal-servlet.xml deleted file mode 100644 index 93f64ed..0000000 --- a/portal_webapp/src/main/webapp/WEB-INF/portal-servlet.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - \ No newline at end of file diff --git a/portal_webapp/src/main/webapp/WEB-INF/web.xml b/portal_webapp/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index c7abba5..0000000 --- a/portal_webapp/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - NG Portal - - portal - org.springframework.web.servlet.DispatcherServlet - 1 - true - - - net.locusworks.portal.services.PortalContextService - - - - - - org.springframework.security.web.session.HttpSessionEventPublisher - - - - springSecurityFilterChain - org.springframework.web.filter.DelegatingFilterProxy - true - - - springSecurityFilterChain - /* - - - index.html - - - portal - /ws/* - - - portal - *.do - - - portal - *.view - - - portal - *.resf - - - portal - *.pdf - - - 540 - - - contextConfigLocation - /WEB-INF/portal-config.xml - - diff --git a/scripts/deploy-server.sh b/scripts/deploy-server.sh index e9466ae..2bf6956 100644 --- a/scripts/deploy-server.sh +++ b/scripts/deploy-server.sh @@ -1,7 +1,25 @@ -#! /bin/bash +#!/usr/bin/env bash -. portal-env.sh -. portal-catalina.sh env -cd ${PORTAL_HOME} -set -x -cp "portal_webapp/target/patchrepo.war" "${CATALINA_HOME}/webapps/" \ No newline at end of file +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PORTAL_HOME="${PORTAL_HOME:-$(cd "${SCRIPT_DIR}/.." && pwd)}" +PORTAL_DEPLOY_DIR="${PORTAL_DEPLOY_DIR:-${PORTAL_HOME}/deploy}" + +shopt -s nullglob +artifacts=("${PORTAL_HOME}"/portal_webapp/target/portal_webapp-*.jar) +shopt -u nullglob + +if (( ${#artifacts[@]} != 1 )); then + echo "Expected one executable portal_webapp JAR, found ${#artifacts[@]}. Run 'mvn clean package' first." >&2 + exit 1 +fi + +install -d "${PORTAL_DEPLOY_DIR}" +install -m 0644 "${artifacts[0]}" "${PORTAL_DEPLOY_DIR}/portal.jar" +echo "Installed ${artifacts[0]} as ${PORTAL_DEPLOY_DIR}/portal.jar" + +if [[ -n "${PORTAL_SERVICE:-}" ]]; then + systemctl restart "${PORTAL_SERVICE}" + echo "Restarted ${PORTAL_SERVICE}" +fi diff --git a/test.properties b/test.properties index c8f7462..61dc36b 100644 --- a/test.properties +++ b/test.properties @@ -1,3 +1,3 @@ ssh.private.key=C:\\Users\\J65594\\.ssh\\id_rsa ssh.public.key=C:\\Users\\J65594\\.ssh\\id_rsa.pub -git.scm=ssh://git@bigmac.northgrum.com:8010/saipt/stig-apply.git \ No newline at end of file +git.scm=ssh://git@bigmac.locusworks.net:8010/saipt/stig-apply.git \ No newline at end of file