diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index a914fd258..98a7ee768 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,7 +1,7 @@ # See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.209.6/containers/java/.devcontainer/base.Dockerfile -# [Choice] Java version (use -bullseye variants on local arm64/Apple Silicon): 17, 17-bullseye, 17-buster -ARG VARIANT="17" +# [Choice] Java version (use -bullseye variants on local arm64/Apple Silicon): 11, 17, 11-bullseye, 17-bullseye, 11-buster, 17-buster +ARG VARIANT="11" FROM mcr.microsoft.com/vscode/devcontainers/java:0-${VARIANT} # [Option] Install Maven diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index c4c949372..8a6c221d7 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -5,41 +5,35 @@ "build": { "dockerfile": "Dockerfile", "args": { - // Update the VARIANT arg to pick a Java version: 17, 19 + // Update the VARIANT arg to pick a Java version: 11, 17 // Append -bullseye or -buster to pin to an OS version. // Use the -bullseye variants on local arm64/Apple Silicon. - "VARIANT": "17-bullseye", + "VARIANT": "11", // Options - // maven and gradle wrappers are used by default, we don't need them installed globally - // "INSTALL_MAVEN": "true", - // "INSTALL_GRADLE": "false", - "NODE_VERSION": "18.16.1" + "INSTALL_MAVEN": "true", + "INSTALL_GRADLE": "false", + "NODE_VERSION": "lts/*" } }, - "customizations": { - "vscode": { - // Set *default* container specific settings.json values on container create. - "settings": { - "java.jdt.ls.java.home": "/docker-java-home" - }, - - // Add the IDs of extensions you want installed when the container is created. - "extensions": [ - "angular.ng-template", - "christian-kohler.npm-intellisense", - "firsttris.vscode-jest-runner", - "ms-vscode.vscode-typescript-tslint-plugin", - "dbaeumer.vscode-eslint", - "vscjava.vscode-java-pack", - "pivotal.vscode-boot-dev-pack", - "esbenp.prettier-vscode" - ] - } + // Set *default* container specific settings.json values on container create. + "settings": { + "java.home": "/docker-java-home" }, + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "christian-kohler.npm-intellisense", + "firsttris.vscode-jest-runner", + "ms-vscode.vscode-typescript-tslint-plugin", + "dbaeumer.vscode-eslint", + "vscjava.vscode-java-pack", + "pivotal.vscode-boot-dev-pack", + "esbenp.prettier-vscode" + ], + // Use 'forwardPorts' to make a list of ports inside the container available locally. - "forwardPorts": [4200, 3001, 9000, 8080], + "forwardPorts": [3001, 9000, 8080], // Use 'postCreateCommand' to run commands after the container is created. // "postCreateCommand": "java -version", diff --git a/.eslintignore b/.eslintignore index d2162abac..0f4bda1ad 100644 --- a/.eslintignore +++ b/.eslintignore @@ -5,5 +5,4 @@ webpack/ target/ build/ node/ -coverage/ postcss.config.js diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index d58133087..000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "parser": "@typescript-eslint/parser", - "plugins": ["@angular-eslint/eslint-plugin", "@typescript-eslint"], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:@typescript-eslint/recommended-requiring-type-checking", - "plugin:@angular-eslint/recommended", - "prettier", - "eslint-config-prettier" - ], - "env": { - "browser": true, - "es6": true, - "commonjs": true - }, - "parserOptions": { - "ecmaVersion": 2018, - "sourceType": "module", - "project": ["./tsconfig.app.json", "./src/test/javascript/cypress/tsconfig.json", "./tsconfig.spec.json"] - }, - "rules": { - "@angular-eslint/component-selector": [ - "error", - { - "type": "element", - "prefix": "jhi", - "style": "kebab-case" - } - ], - "@angular-eslint/directive-selector": [ - "error", - { - "type": "attribute", - "prefix": "jhi", - "style": "camelCase" - } - ], - "@angular-eslint/relative-url-prefix": "error", - "@typescript-eslint/ban-types": [ - "error", - { - "extendDefaults": true, - "types": { - "{}": false - } - } - ], - "@typescript-eslint/explicit-function-return-type": ["error", { "allowExpressions": true }], - "@typescript-eslint/explicit-module-boundary-types": "off", - "@typescript-eslint/member-ordering": [ - "error", - { - "default": [ - "public-static-field", - "protected-static-field", - "private-static-field", - "public-instance-field", - "protected-instance-field", - "private-instance-field", - "constructor", - "public-static-method", - "protected-static-method", - "private-static-method", - "public-instance-method", - "protected-instance-method", - "private-instance-method" - ] - } - ], - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-floating-promises": "off", - "@typescript-eslint/no-non-null-assertion": "off", - "@typescript-eslint/no-parameter-properties": ["warn", { "allows": ["public", "private", "protected"] }], - "@typescript-eslint/no-shadow": ["error"], - "@typescript-eslint/no-unnecessary-condition": "error", - "@typescript-eslint/no-unsafe-argument": "off", - "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/no-unsafe-call": "off", - "@typescript-eslint/no-unsafe-member-access": "off", - "@typescript-eslint/prefer-nullish-coalescing": "error", - "@typescript-eslint/prefer-optional-chain": "error", - "@typescript-eslint/unbound-method": "off", - "arrow-body-style": "error", - "curly": "error", - "eqeqeq": ["error", "always", { "null": "ignore" }], - "guard-for-in": "error", - "no-bitwise": "error", - "no-caller": "error", - "no-console": ["error", { "allow": ["warn", "error"] }], - "no-eval": "error", - "no-labels": "error", - "no-new": "error", - "no-new-wrappers": "error", - "object-shorthand": ["error", "always", { "avoidExplicitReturnArrows": true }], - "radix": "error", - "spaced-comment": ["warn", "always"] - } -} diff --git a/.gitignore b/.gitignore index d543a07cf..50f7684bb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,10 @@ +###################### +# Project Specific +###################### +/src/main/webapp/content/css/main.css +/target/classes/static/** +/src/test/javascript/coverage/ + ###################### # Node ###################### @@ -30,6 +37,7 @@ local.properties .settings/ .loadpath .factorypath +/src/main/resources/rebel.xml # External tool builders .externalToolBuilders/** diff --git a/.husky/pre-commit b/.husky/pre-commit old mode 100644 new mode 100755 diff --git a/.jhipster/BankAccount.json b/.jhipster/BankAccount.json index 104f5a62d..7526e5d64 100644 --- a/.jhipster/BankAccount.json +++ b/.jhipster/BankAccount.json @@ -36,5 +36,5 @@ "relationshipType": "one-to-many" } ], - "searchEngine": "no" + "searchEngine": false } diff --git a/.jhipster/Label.json b/.jhipster/Label.json index b87f70b38..9d886990b 100644 --- a/.jhipster/Label.json +++ b/.jhipster/Label.json @@ -24,5 +24,5 @@ "relationshipType": "many-to-many" } ], - "searchEngine": "no" + "searchEngine": false } diff --git a/.jhipster/Operation.json b/.jhipster/Operation.json index 0c3a562a5..750770814 100644 --- a/.jhipster/Operation.json +++ b/.jhipster/Operation.json @@ -42,5 +42,5 @@ "relationshipType": "many-to-many" } ], - "searchEngine": "no" + "searchEngine": false } diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar index cb28b0e37..bf82ff01c 100644 Binary files a/.mvn/wrapper/maven-wrapper.jar and b/.mvn/wrapper/maven-wrapper.jar differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 3c6fda8c6..dc3affce3 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -6,7 +6,7 @@ # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an @@ -14,5 +14,5 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.2/apache-maven-3.9.2-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar diff --git a/.yo-rc.json b/.yo-rc.json index 97e4fa876..1e5e64831 100644 --- a/.yo-rc.json +++ b/.yo-rc.json @@ -14,7 +14,7 @@ "creationTimestamp": 1577000812973, "databaseType": "sql", "devDatabaseType": "h2Memory", - "devServerPort": 4200, + "devServerPort": 9060, "dtoSuffix": "DTO", "embeddableLaunchScript": false, "enableGradleEnterprise": false, @@ -26,7 +26,7 @@ "entitySuffix": "", "hibernateCache": "ehcache", "jhiPrefix": "jhi", - "jhipsterVersion": "7.9.3", + "jhipsterVersion": "7.9.4", "jwtSecretKey": "bXktc2VjcmV0LWtleS13aGljaC1zaG91bGQtYmUtY2hhbmdlZC1pbi1wcm9kdWN0aW9uLWFuZC1iZS1iYXNlNjQtZW5jb2RlZAo=", "languages": ["en"], "messageBroker": false, diff --git a/README.md b/README.md index f4bc2359b..1143552fc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # jhipsterSampleApplication -This application was generated using JHipster 7.9.3, you can find documentation and help at [https://www.jhipster.tech/documentation-archive/v7.9.3](https://www.jhipster.tech/documentation-archive/v7.9.3). +This application was generated using JHipster 7.9.4, you can find documentation and help at [https://www.jhipster.tech/documentation-archive/v7.9.4](https://www.jhipster.tech/documentation-archive/v7.9.4). ## Project Structure @@ -34,7 +34,7 @@ You will only need to run this command when dependencies change in [package.json npm install ``` -We use npm scripts and [Angular CLI][] with [Webpack][] as our build system. +We use npm scripts and [Webpack][] as our build system. Run the following commands in two separate terminals to create a blissful development experience where your browser auto-refreshes when files change on your hard drive. @@ -54,12 +54,20 @@ The `npm run` command will list all of the scripts available to run for this pro JHipster ships with PWA (Progressive Web App) support, and it's turned off by default. One of the main components of a PWA is a service worker. -The service worker initialization code is disabled by default. To enable it, uncomment the following code in `src/main/webapp/app/app.module.ts`: +The service worker initialization code is commented out by default. To enable it, uncomment the following code in `src/main/webapp/index.html`: -```typescript -ServiceWorkerModule.register('ngsw-worker.js', { enabled: false }), +```html + ``` +Note: [Workbox](https://developers.google.com/web/tools/workbox/) powers JHipster's service worker. It dynamically generates the `service-worker.js` file. + ### Managing dependencies For example, to add [Leaflet][] library as a runtime dependency of your application, you would run following command: @@ -75,46 +83,16 @@ npm install --save-dev --save-exact @types/leaflet ``` Then you would import the JS and CSS files specified in library's installation instructions so that [Webpack][] knows about them: -Edit [src/main/webapp/app/app.module.ts](src/main/webapp/app/app.module.ts) file: - -``` -import 'leaflet/dist/leaflet.js'; -``` - -Edit [src/main/webapp/content/scss/vendor.scss](src/main/webapp/content/scss/vendor.scss) file: - -``` -@import 'leaflet/dist/leaflet.css'; -``` - Note: There are still a few other things remaining to do for Leaflet that we won't detail here. For further instructions on how to develop with JHipster, have a look at [Using JHipster in development][]. -### Using Angular CLI - -You can also use [Angular CLI][] to generate some custom client code. - -For example, the following command: - -``` -ng generate component my-component -``` - -will generate few files: - -``` -create src/main/webapp/app/my-component/my-component.component.html -create src/main/webapp/app/my-component/my-component.component.ts -update src/main/webapp/app/app.module.ts -``` - ### JHipster Control Center JHipster Control Center can help you manage and control your application(s). You can start a local control center server (accessible on http://localhost:7419) with: ``` -docker compose -f src/main/docker/jhipster-control-center.yml up +docker-compose -f src/main/docker/jhipster-control-center.yml up ``` ## Building for production @@ -173,13 +151,9 @@ The lighthouse report is created in `target/cypress/lhreport.html` ### Other tests -Performance tests are run by [Gatling][] and written in Scala. They're located in [src/test/java/gatling/simulations](src/test/java/gatling/simulations). +Performance tests are run by [Gatling][] and written in Scala. They're located in [src/test/gatling](src/test/gatling). -You can execute all Gatling tests with - -``` -./mvnw gatling:test -``` +To use those tests, you must install Gatling from [https://gatling.io/](https://gatling.io/). For more information, refer to the [Running tests page][]. @@ -188,30 +162,23 @@ For more information, refer to the [Running tests page][]. Sonar is used to analyse code quality. You can start a local Sonar server (accessible on http://localhost:9001) with: ``` -docker compose -f src/main/docker/sonar.yml up -d +docker-compose -f src/main/docker/sonar.yml up -d ``` -Note: we have turned off forced authentication redirect for UI in [src/main/docker/sonar.yml](src/main/docker/sonar.yml) for out of the box experience while trying out SonarQube, for real use cases turn it back on. +Note: we have turned off authentication in [src/main/docker/sonar.yml](src/main/docker/sonar.yml) for out of the box experience while trying out SonarQube, for real use cases turn it back on. You can run a Sonar analysis with using the [sonar-scanner](https://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner) or by using the maven plugin. Then, run a Sonar analysis: ``` -./mvnw -Pprod clean verify sonar:sonar -Dsonar.login=admin -Dsonar.password=admin +./mvnw -Pprod clean verify sonar:sonar ``` If you need to re-run the Sonar phase, please be sure to specify at least the `initialize` phase since Sonar properties are loaded from the sonar-project.properties file. ``` -./mvnw initialize sonar:sonar -Dsonar.login=admin -Dsonar.password=admin -``` - -Additionally, Instead of passing `sonar.password` and `sonar.login` as CLI arguments, these parameters can be configured from [sonar-project.properties](sonar-project.properties) as shown below: - -``` -sonar.login=admin -sonar.password=admin +./mvnw initialize sonar:sonar ``` For more information, refer to the [Code quality page][]. @@ -223,13 +190,13 @@ You can use Docker to improve your JHipster development experience. A number of For example, to start a postgresql database in a docker container, run: ``` -docker compose -f src/main/docker/postgresql.yml up -d +docker-compose -f src/main/docker/postgresql.yml up -d ``` To stop it and remove the container, run: ``` -docker compose -f src/main/docker/postgresql.yml down +docker-compose -f src/main/docker/postgresql.yml down ``` You can also fully dockerize your application and all the services that it depends on. @@ -248,7 +215,7 @@ npm run java:docker:arm64 Then run: ``` -docker compose -f src/main/docker/app.yml up -d +docker-compose -f src/main/docker/app.yml up -d ``` When running Docker Desktop on MacOS Big Sur or later, consider enabling experimental `Use the new Virtualization framework` for better processing performance ([disk access performance is worse](https://github.com/docker/roadmap/issues/7)). @@ -259,21 +226,20 @@ For more information refer to [Using Docker and Docker-Compose][], this page als To configure CI for your project, run the ci-cd sub-generator (`jhipster ci-cd`), this will let you generate configuration files for a number of Continuous Integration systems. Consult the [Setting up Continuous Integration][] page for more information. -[JHipster Homepage and latest documentation]: https://www.jhipster.tech -[JHipster 7.9.3 archive]: https://www.jhipster.tech/documentation-archive/v7.9.3 -[Using JHipster in development]: https://www.jhipster.tech/documentation-archive/v7.9.3/development/ -[Using Docker and Docker-Compose]: https://www.jhipster.tech/documentation-archive/v7.9.3/docker-compose -[Using JHipster in production]: https://www.jhipster.tech/documentation-archive/v7.9.3/production/ -[Running tests page]: https://www.jhipster.tech/documentation-archive/v7.9.3/running-tests/ -[Code quality page]: https://www.jhipster.tech/documentation-archive/v7.9.3/code-quality/ -[Setting up Continuous Integration]: https://www.jhipster.tech/documentation-archive/v7.9.3/setting-up-ci/ -[Node.js]: https://nodejs.org/ -[NPM]: https://www.npmjs.com/ -[Webpack]: https://webpack.github.io/ -[BrowserSync]: https://www.browsersync.io/ -[Jest]: https://facebook.github.io/jest/ -[Cypress]: https://www.cypress.io/ -[Leaflet]: https://leafletjs.com/ -[DefinitelyTyped]: https://definitelytyped.org/ -[Angular CLI]: https://cli.angular.io/ -[Gatling]: https://gatling.io/ +[jhipster homepage and latest documentation]: https://www.jhipster.tech +[jhipster 7.9.4 archive]: https://www.jhipster.tech/documentation-archive/v7.9.4 +[using jhipster in development]: https://www.jhipster.tech/documentation-archive/v7.9.4/development/ +[using docker and docker-compose]: https://www.jhipster.tech/documentation-archive/v7.9.4/docker-compose +[using jhipster in production]: https://www.jhipster.tech/documentation-archive/v7.9.4/production/ +[running tests page]: https://www.jhipster.tech/documentation-archive/v7.9.4/running-tests/ +[code quality page]: https://www.jhipster.tech/documentation-archive/v7.9.4/code-quality/ +[setting up continuous integration]: https://www.jhipster.tech/documentation-archive/v7.9.4/setting-up-ci/ +[node.js]: https://nodejs.org/ +[npm]: https://www.npmjs.com/ +[webpack]: https://webpack.github.io/ +[browsersync]: https://www.browsersync.io/ +[jest]: https://facebook.github.io/jest/ +[cypress]: https://www.cypress.io/ +[leaflet]: https://leafletjs.com/ +[definitelytyped]: https://definitelytyped.org/ +[gatling]: https://gatling.io/ diff --git a/angular.json b/angular.json deleted file mode 100644 index 05fdc8af9..000000000 --- a/angular.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "jhipster-sample-application": { - "projectType": "application", - "schematics": { - "@schematics/angular:component": { - "style": "scss" - }, - "@schematics/angular:application": { - "strict": true - } - }, - "root": "", - "sourceRoot": "src/main/webapp", - "prefix": "jhi", - "architect": { - "build": { - "builder": "@angular-builders/custom-webpack:browser", - "options": { - "customWebpackConfig": { - "path": "./webpack/webpack.custom.js" - }, - "outputPath": "target/classes/static/", - "index": "src/main/webapp/index.html", - "main": "src/main/webapp/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "src/main/webapp/content", - "src/main/webapp/favicon.ico", - "src/main/webapp/manifest.webapp", - "src/main/webapp/robots.txt" - ], - "styles": ["src/main/webapp/content/scss/vendor.scss", "src/main/webapp/content/scss/global.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "optimization": true, - "outputHashing": "all", - "sourceMap": false, - "namedChunks": false, - "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, - "serviceWorker": true, - "ngswConfigPath": "ngsw-config.json", - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ] - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "builder": "@angular-builders/custom-webpack:dev-server", - "options": { - "browserTarget": "jhipster-sample-application:build:development", - "port": 4200 - }, - "configurations": { - "production": { - "browserTarget": "jhipster-sample-application:build:production" - }, - "development": { - "browserTarget": "jhipster-sample-application:build:development" - } - }, - "defaultConfiguration": "development" - }, - "test": { - "builder": "@angular-builders/jest:run", - "options": { - "configPath": "jest.conf.js" - } - } - } - } - }, - "cli": { - "cache": { - "enabled": true, - "path": "./target/angular/", - "environment": "all" - }, - "packageManager": "npm" - } -} diff --git a/cypress-audits.config.ts b/cypress-audits.config.ts index c84b1785b..2664df2a6 100644 --- a/cypress-audits.config.ts +++ b/cypress-audits.config.ts @@ -1,5 +1,5 @@ import { defineConfig } from 'cypress'; -import defaultConfig from './cypress.config'; +import { defaultConfig } from './cypress.config'; export default defineConfig({ ...defaultConfig, diff --git a/cypress.config.ts b/cypress.config.ts index 46b2d43b6..a521c1eaf 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -1,6 +1,6 @@ import { defineConfig } from 'cypress'; -export default defineConfig({ +export const defaultConfig = { video: false, fixturesFolder: 'src/test/javascript/cypress/fixtures', screenshotsFolder: 'target/cypress/screenshots', @@ -23,6 +23,8 @@ export default defineConfig({ baseUrl: 'http://localhost:8080/', specPattern: 'src/test/javascript/cypress/e2e/**/*.cy.ts', supportFile: 'src/test/javascript/cypress/support/index.ts', - experimentalRunAllSpecs: true, + experimentalSessionAndOrigin: true, }, -}); +}; + +export default defineConfig(defaultConfig); diff --git a/jest.conf.js b/jest.conf.js deleted file mode 100644 index 969b41fb8..000000000 --- a/jest.conf.js +++ /dev/null @@ -1,29 +0,0 @@ -const { pathsToModuleNameMapper } = require('ts-jest'); - -const { - compilerOptions: { paths = {}, baseUrl = './' }, -} = require('./tsconfig.json'); -const environment = require('./webpack/environment'); - -module.exports = { - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$|dayjs/esm)'], - resolver: 'jest-preset-angular/build/resolvers/ng-jest-resolver.js', - globals: { - ...environment, - }, - roots: ['', `/${baseUrl}`], - modulePaths: [`/${baseUrl}`], - setupFiles: ['jest-date-mock'], - cacheDirectory: '/target/jest-cache', - coverageDirectory: '/target/test-results/', - moduleNameMapper: pathsToModuleNameMapper(paths, { prefix: `/${baseUrl}/` }), - reporters: [ - 'default', - ['jest-junit', { outputDirectory: '/target/test-results/', outputName: 'TESTS-results-jest.xml' }], - ['jest-sonar', { outputDirectory: './target/test-results/jest', outputName: 'TESTS-results-sonar.xml' }], - ], - testMatch: ['/src/main/webapp/app/**/@(*.)@(spec.ts)'], - testEnvironmentOptions: { - url: 'https://jhipster.tech', - }, -}; diff --git a/mvnw b/mvnw old mode 100644 new mode 100755 index 8d937f4c1..5643201c7 --- a/mvnw +++ b/mvnw @@ -19,7 +19,7 @@ # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.2.0 +# Maven Start Up Batch script # # Required ENV vars: # ------------------ @@ -27,6 +27,7 @@ # # Optional ENV vars # ----------------- +# M2_HOME - location of maven2's installed home dir # MAVEN_OPTS - parameters passed to the Java VM when running Maven # e.g. to debug Maven itself, use # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 @@ -53,7 +54,7 @@ fi cygwin=false; darwin=false; mingw=false -case "$(uname)" in +case "`uname`" in CYGWIN*) cygwin=true ;; MINGW*) mingw=true;; Darwin*) darwin=true @@ -61,9 +62,9 @@ case "$(uname)" in # See https://developer.apple.com/library/mac/qa/qa1170/_index.html if [ -z "$JAVA_HOME" ]; then if [ -x "/usr/libexec/java_home" ]; then - JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME + export JAVA_HOME="`/usr/libexec/java_home`" else - JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + export JAVA_HOME="/Library/Java/Home" fi fi ;; @@ -71,38 +72,68 @@ esac if [ -z "$JAVA_HOME" ] ; then if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=$(java-config --jre-home) + JAVA_HOME=`java-config --jre-home` fi fi +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + # For Cygwin, ensure paths are in UNIX format before anything is touched if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` [ -n "$JAVA_HOME" ] && - JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` [ -n "$CLASSPATH" ] && - CLASSPATH=$(cygpath --path --unix "$CLASSPATH") + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` fi # For Mingw, ensure paths are in UNIX format before anything is touched if $mingw ; then - [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && - JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" fi if [ -z "$JAVA_HOME" ]; then - javaExecutable="$(which javac)" - if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then # readlink(1) is not available as standard on Solaris 10. - readLink=$(which readlink) - if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then if $darwin ; then - javaHome="$(dirname "\"$javaExecutable\"")" - javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" else - javaExecutable="$(readlink -f "\"$javaExecutable\"")" + javaExecutable="`readlink -f \"$javaExecutable\"`" fi - javaHome="$(dirname "\"$javaExecutable\"")" - javaHome=$(expr "$javaHome" : '\(.*\)/bin') + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` JAVA_HOME="$javaHome" export JAVA_HOME fi @@ -118,7 +149,7 @@ if [ -z "$JAVACMD" ] ; then JAVACMD="$JAVA_HOME/bin/java" fi else - JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" + JAVACMD="`\\unset -f command; \\command -v java`" fi fi @@ -132,9 +163,12 @@ if [ -z "$JAVA_HOME" ] ; then echo "Warning: JAVA_HOME environment variable is not set." fi +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + # traverses directory structure from process work directory to filesystem root # first directory with .mvn subdirectory is considered project base directory find_maven_basedir() { + if [ -z "$1" ] then echo "Path not specified to find_maven_basedir" @@ -150,99 +184,96 @@ find_maven_basedir() { fi # workaround for JBEAP-8937 (on Solaris 10/Sparc) if [ -d "${wdir}" ]; then - wdir=$(cd "$wdir/.." || exit 1; pwd) + wdir=`cd "$wdir/.."; pwd` fi # end of workaround done - printf '%s' "$(cd "$basedir" || exit 1; pwd)" + echo "${basedir}" } # concatenates all lines of a file concat_lines() { if [ -f "$1" ]; then - # Remove \r in case we run on Windows within Git Bash - # and check out the repository with auto CRLF management - # enabled. Otherwise, we may read lines that are delimited with - # \r\n and produce $'-Xarg\r' rather than -Xarg due to word - # splitting rules. - tr -s '\r\n' ' ' < "$1" - fi -} - -log() { - if [ "$MVNW_VERBOSE" = true ]; then - printf '%s\n' "$1" + echo "$(tr -s '\n' ' ' < "$1")" fi } -BASE_DIR=$(find_maven_basedir "$(dirname "$0")") +BASE_DIR=`find_maven_basedir "$(pwd)"` if [ -z "$BASE_DIR" ]; then exit 1; fi -MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR -log "$MAVEN_PROJECTBASEDIR" - ########################################################################################## # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central # This allows using the maven wrapper in projects that prohibit checking in binary data. ########################################################################################## -wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" -if [ -r "$wrapperJarPath" ]; then - log "Found $wrapperJarPath" +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi else - log "Couldn't find $wrapperJarPath, downloading it ..." - + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi if [ -n "$MVNW_REPOURL" ]; then - wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" else - wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" fi - while IFS="=" read -r key value; do - # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) - safeValue=$(echo "$value" | tr -d '\r') - case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; esac - done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" - log "Downloading from: $wrapperUrl" - + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" if $cygwin; then - wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` fi if command -v wget > /dev/null; then - log "Found wget ... using wget" - [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" else - wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" fi elif command -v curl > /dev/null; then - log "Found curl ... using curl" - [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + curl -o "$wrapperJarPath" "$jarUrl" -f else - curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f fi + else - log "Falling back to using Java to download" - javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" - javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" # For Cygwin, switch paths to Windows format before running javac if $cygwin; then - javaSource=$(cygpath --path --windows "$javaSource") - javaClass=$(cygpath --path --windows "$javaClass") + javaClass=`cygpath --path --windows "$javaClass"` fi - if [ -e "$javaSource" ]; then - if [ ! -e "$javaClass" ]; then - log " - Compiling MavenWrapperDownloader.java ..." - ("$JAVA_HOME/bin/javac" "$javaSource") + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") fi - if [ -e "$javaClass" ]; then - log " - Running MavenWrapperDownloader.java ..." - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") fi fi fi @@ -251,58 +282,35 @@ fi # End of extension ########################################################################################## -# If specified, validate the SHA-256 sum of the Maven wrapper jar file -wrapperSha256Sum="" -while IFS="=" read -r key value; do - case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; - esac -done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" -if [ -n "$wrapperSha256Sum" ]; then - wrapperSha256Result=false - if command -v sha256sum > /dev/null; then - if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then - wrapperSha256Result=true - fi - elif command -v shasum > /dev/null; then - if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then - wrapperSha256Result=true - fi - else - echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." - echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." - exit 1 - fi - if [ $wrapperSha256Result = false ]; then - echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 - echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 - echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 - exit 1 - fi +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR fi - MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" # For Cygwin, switch paths to Windows format before running java if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` [ -n "$JAVA_HOME" ] && - JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` [ -n "$CLASSPATH" ] && - CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` fi # Provide a "standardized" way to retrieve the CLI args that will # work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" export MAVEN_CMD_LINE_ARGS WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain -# shellcheck disable=SC2086 # safe args exec "$JAVACMD" \ $MAVEN_OPTS \ $MAVEN_DEBUG_OPTS \ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" \ "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd index c4586b564..8a15b7f31 100644 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -18,12 +18,13 @@ @REM ---------------------------------------------------------------------------- @REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM Maven Start Up Batch script @REM @REM Required ENV vars: @REM JAVA_HOME - location of a JDK home dir @REM @REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven @@ -119,10 +120,10 @@ SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain -set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B ) @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central @@ -133,11 +134,11 @@ if exist %WRAPPER_JAR% ( ) ) else ( if not "%MVNW_REPOURL%" == "" ( - SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" ) if "%MVNW_VERBOSE%" == "true" ( echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %WRAPPER_URL% + echo Downloading from: %DOWNLOAD_URL% ) powershell -Command "&{"^ @@ -145,7 +146,7 @@ if exist %WRAPPER_JAR% ( "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ "}" if "%MVNW_VERBOSE%" == "true" ( echo Finished downloading %WRAPPER_JAR% @@ -153,24 +154,6 @@ if exist %WRAPPER_JAR% ( ) @REM End of extension -@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file -SET WRAPPER_SHA_256_SUM="" -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B -) -IF NOT %WRAPPER_SHA_256_SUM%=="" ( - powershell -Command "&{"^ - "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ - "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ - " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ - " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ - " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ - " exit 1;"^ - "}"^ - "}" - if ERRORLEVEL 1 goto error -) - @REM Provide a "standardized" way to retrieve the CLI args that will @REM work with both Windows and non-Windows executions. set MAVEN_CMD_LINE_ARGS=%* diff --git a/ngsw-config.json b/ngsw-config.json deleted file mode 100644 index 8d5760288..000000000 --- a/ngsw-config.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "$schema": "./node_modules/@angular/service-worker/config/schema.json", - "index": "/index.html", - "assetGroups": [ - { - "name": "app", - "installMode": "prefetch", - "resources": { - "files": ["/favicon.ico", "/index.html", "/manifest.webapp", "/*.css", "/*.js"] - } - }, - { - "name": "assets", - "installMode": "lazy", - "updateMode": "prefetch", - "resources": { - "files": ["/content/**", "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)"] - } - } - ] -} diff --git a/npmw b/npmw old mode 100644 new mode 100755 diff --git a/npmw.cmd b/npmw.cmd index b6e798095..e45f868db 100644 --- a/npmw.cmd +++ b/npmw.cmd @@ -17,7 +17,7 @@ if exist "%NPMW_DIR%mvnw.cmd" ( ) if not exist %NPM_EXE% ( - call %INSTALL_NPM_COMMAND% + call %INSTALL_NPM_COMMAND% ) if exist %NODE_EXE% ( diff --git a/package.json b/package.json index d570225be..a159f610e 100644 --- a/package.json +++ b/package.json @@ -1,49 +1,33 @@ { - "name": "jhipster-sample-application", - "version": "0.0.1-SNAPSHOT", - "private": true, - "description": "Description for Jhipster Sample Application", - "license": "UNLICENSED", "scripts": { "app:start": "./mvnw", - "app:up": "docker compose -f src/main/docker/app.yml up --wait", "backend:build-cache": "./mvnw dependency:go-offline", "backend:debug": "./mvnw -Dspring-boot.run.jvmArguments=\"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000\"", "backend:doc:test": "./mvnw -ntp javadoc:javadoc --batch-mode", "backend:info": "./mvnw -ntp enforcer:display-info --batch-mode", "backend:nohttp:test": "./mvnw -ntp checkstyle:check --batch-mode", "backend:start": "./mvnw -Dskip.installnodenpm -Dskip.npm", - "backend:unit:test": "./mvnw -ntp -Dskip.installnodenpm -Dskip.npm verify --batch-mode -Dlogging.level.ROOT=OFF -Dlogging.level.tech.jhipster=OFF -Dlogging.level.io.github.jhipster.sample=OFF -Dlogging.level.org.springframework=OFF -Dlogging.level.org.springframework.web=OFF -Dlogging.level.org.springframework.security=OFF", - "build": "npm run webapp:prod --", - "build-watch": "concurrently 'npm run webapp:build:dev -- --watch' npm:backend:start", + "backend:unit:test": "./mvnw -ntp -Dskip.installnodenpm -Dskip.npm verify --batch-mode -Dlogging.level.ROOT=OFF -Dlogging.level.org.zalando=OFF -Dlogging.level.tech.jhipster=OFF -Dlogging.level.io.github.jhipster.sample=OFF -Dlogging.level.org.springframework=OFF -Dlogging.level.org.springframework.web=OFF -Dlogging.level.org.springframework.security=OFF", "ci:backend:test": "npm run backend:info && npm run backend:doc:test && npm run backend:nohttp:test && npm run backend:unit:test -- -P$npm_package_config_default_environment", "ci:e2e:package": "npm run java:$npm_package_config_packaging:$npm_package_config_default_environment -- -Pe2e -Denforcer.skip=true", "ci:e2e:prepare": "npm run ci:e2e:prepare:docker", - "ci:e2e:prepare:docker": "npm run services:up --if-present && docker ps -a", - "ci:e2e:run": "concurrently -k -s first \"npm run ci:e2e:server:start\" \"npm run e2e:headless\"", - "preci:e2e:server:start": "npm run services:db:await --if-present && npm run services:others:await --if-present", - "ci:e2e:server:start": "java -jar target/e2e.$npm_package_config_packaging --spring.profiles.active=e2e,$npm_package_config_default_environment -Dlogging.level.ROOT=OFF -Dlogging.level.tech.jhipster=OFF -Dlogging.level.io.github.jhipster.sample=OFF -Dlogging.level.org.springframework=OFF -Dlogging.level.org.springframework.web=OFF -Dlogging.level.org.springframework.security=OFF --logging.level.org.springframework.web=ERROR", - "ci:e2e:teardown": "npm run ci:e2e:teardown:docker --if-present", - "ci:e2e:teardown:docker": "docker compose -f src/main/docker/services.yml down -v && docker ps -a", + "ci:e2e:prepare:docker": "npm run docker:db:up && npm run docker:others:up && docker ps -a", + "preci:e2e:server:start": "npm run docker:db:await --if-present && npm run docker:others:await --if-present", + "ci:e2e:server:start": "java -jar target/e2e.$npm_package_config_packaging --spring.profiles.active=e2e,$npm_package_config_default_environment -Dlogging.level.ROOT=OFF -Dlogging.level.org.zalando=OFF -Dlogging.level.tech.jhipster=OFF -Dlogging.level.io.github.jhipster.sample=OFF -Dlogging.level.org.springframework=OFF -Dlogging.level.org.springframework.web=OFF -Dlogging.level.org.springframework.security=OFF --logging.level.org.springframework.web=ERROR", + "ci:e2e:teardown": "npm run ci:e2e:teardown:docker", + "ci:e2e:teardown:docker": "npm run docker:db:down --if-present && npm run docker:others:down && docker ps -a", "ci:frontend:build": "npm run webapp:build:$npm_package_config_default_environment", "ci:frontend:test": "npm run ci:frontend:build && npm test", - "ci:server:await": "echo \"Waiting for server at port $npm_package_config_backend_port to start\" && wait-on -t 180000 http-get://localhost:$npm_package_config_backend_port/management/health && echo \"Server at port $npm_package_config_backend_port started\"", - "clean-www": "rimraf target/classes/static/app/{src,target/}", - "cleanup": "rimraf target/classes/static/", - "cypress": "cypress open --e2e", "cypress:audits": "cypress open --e2e --config-file cypress-audits.config.js", - "docker:db:down": "docker compose -f src/main/docker/postgresql.yml down -v", - "docker:db:up": "docker compose -f src/main/docker/postgresql.yml up --wait", - "e2e": "npm run e2e:cypress:headed --", - "e2e:cypress": "cypress run --e2e --browser chrome", - "e2e:cypress:audits": "cypress run --e2e --browser chrome --config-file cypress-audits.config.js", + "docker:app:up": "docker-compose -f src/main/docker/app.yml up -d", + "docker:db:down": "docker-compose -f src/main/docker/postgresql.yml down -v", + "docker:db:up": "docker-compose -f src/main/docker/postgresql.yml up -d", + "docker:others:await": "", + "docker:others:down": "", + "predocker:others:up": "", + "docker:others:up": "", + "e2e:cypress:audits": "cypress run --e2e --browser chrome --record ${CYPRESS_ENABLE_RECORD:-false} --config-file cypress-audits.config.js", "e2e:cypress:audits:headless": "npm run e2e:cypress -- --config-file cypress-audits.config.js", - "e2e:cypress:headed": "npm run e2e:cypress -- --headed", - "e2e:cypress:record": "npm run e2e:cypress -- --record", - "e2e:dev": "concurrently -k -s first \"./mvnw\" \"npm run e2e\"", - "e2e:devserver": "concurrently -k -s first \"npm run backend:start\" \"npm start\" \"wait-on -t 180000 http-get://localhost:9000 && npm run e2e:headless -- -c baseUrl=http://localhost:9000\"", - "pree2e:headless": "npm run ci:server:await", - "e2e:headless": "npm run e2e:cypress --", "java:docker": "./mvnw -ntp verify -DskipTests -Pprod jib:dockerBuild", "java:docker:arm64": "npm run java:docker -- -Djib-maven-plugin.architecture=arm64", "java:docker:dev": "npm run java:docker -- -Pdev,webapp", @@ -54,110 +38,20 @@ "java:war": "./mvnw -ntp verify -DskipTests --batch-mode -Pwar", "java:war:dev": "npm run java:war -- -Pdev,webapp", "java:war:prod": "npm run java:war -- -Pprod", - "jest": "jest --coverage --logHeapUsage --maxWorkers=2 --config jest.conf.js", - "lint": "eslint . --ext .js,.ts", - "lint:fix": "npm run lint -- --fix", - "prepare": "husky install", - "prettier:check": "prettier --check \"{,src/**/,webpack/,.blueprint/**/}*.{md,json,yml,html,cjs,mjs,js,ts,tsx,css,scss,java}\"", - "prettier:format": "prettier --write \"{,src/**/,webpack/,.blueprint/**/}*.{md,json,yml,html,cjs,mjs,js,ts,tsx,css,scss,java}\"", - "serve": "npm run start --", - "services:up": "docker compose -f src/main/docker/services.yml up --wait", - "start": "ng serve --hmr", - "start-tls": "npm run webapp:dev-ssl", - "pretest": "npm run lint", - "test": "ng test --coverage --log-heap-usage -w=2", - "test:watch": "npm run test -- --watch", - "watch": "concurrently npm:start npm:backend:start", - "webapp:build": "npm run clean-www && npm run webapp:build:dev", - "webapp:build:dev": "ng build --configuration development", - "webapp:build:prod": "ng build --configuration production", - "webapp:dev": "ng serve", - "webapp:dev-ssl": "ng serve --ssl", - "webapp:dev-verbose": "ng serve --verbose", - "webapp:prod": "npm run clean-www && npm run webapp:build:prod", - "webapp:test": "npm run test --" + "prepare": "husky install" }, "config": { "backend_port": 8080, "default_environment": "prod", "packaging": "jar" }, - "dependencies": { - "@angular/common": "16.1.4", - "@angular/compiler": "16.1.4", - "@angular/core": "16.1.4", - "@angular/forms": "16.1.4", - "@angular/localize": "16.1.4", - "@angular/platform-browser": "16.1.4", - "@angular/platform-browser-dynamic": "16.1.4", - "@angular/router": "16.1.4", - "@fortawesome/angular-fontawesome": "0.13.0", - "@fortawesome/fontawesome-svg-core": "6.4.0", - "@fortawesome/free-solid-svg-icons": "6.4.0", - "@ng-bootstrap/ng-bootstrap": "15.1.0", - "@ngx-translate/core": "15.0.0", - "@ngx-translate/http-loader": "8.0.0", - "@popperjs/core": "2.11.8", - "bootstrap": "5.3.0", - "dayjs": "1.11.9", - "ngx-infinite-scroll": "16.0.0", - "rxjs": "7.8.1", - "tslib": "2.6.0", - "zone.js": "0.13.1" - }, "devDependencies": { - "@angular-builders/custom-webpack": "16.0.0", - "@angular-builders/jest": "16.0.0", - "@angular-devkit/build-angular": "16.1.4", - "@angular-eslint/eslint-plugin": "16.0.2", - "@angular/cli": "16.1.4", - "@angular/compiler-cli": "16.1.4", - "@angular/service-worker": "16.1.4", - "@types/jest": "29.5.3", - "@types/node": "18.16.19", - "@typescript-eslint/eslint-plugin": "5.61.0", - "@typescript-eslint/parser": "5.61.0", - "browser-sync": "2.29.3", - "browser-sync-webpack-plugin": "2.3.0", - "concurrently": "8.2.0", - "copy-webpack-plugin": "11.0.0", - "cypress": "12.17.1", + "concurrently": "7.3.0", "cypress-audit": "1.1.0", - "eslint": "8.44.0", - "eslint-config-prettier": "8.8.0", - "eslint-plugin-cypress": "2.13.3", - "eslint-webpack-plugin": "4.0.1", - "folder-hash": "4.0.4", - "generator-jhipster": "7.9.3", - "husky": "8.0.3", - "jest": "29.6.1", - "jest-date-mock": "1.0.8", - "jest-environment-jsdom": "29.6.1", - "jest-junit": "16.0.0", - "jest-preset-angular": "13.1.1", - "jest-sonar": "0.2.16", - "lighthouse": "10.4.0", - "lint-staged": "13.2.3", - "merge-jsons-webpack-plugin": "2.0.1", - "prettier": "2.8.8", - "prettier-plugin-java": "2.2.0", - "prettier-plugin-packagejson": "2.4.5", - "rimraf": "5.0.1", - "swagger-ui-dist": "5.1.0", - "ts-jest": "29.1.1", - "typescript": "5.1.6", - "wait-on": "7.0.1", - "webpack-bundle-analyzer": "4.9.0", - "webpack-merge": "5.9.0", - "webpack-notifier": "1.15.0" - }, - "engines": { - "node": ">=18.16.1" - }, - "cacheDirectories": [ - "node_modules" - ], - "overrides": { - "webpack": "5.88.1" + "eslint-plugin-cypress": "2.12.1", + "husky": "7.0.4", + "lighthouse": "9.6.6", + "lint-staged": "13.0.3", + "wait-on": "6.0.1" } } diff --git a/pom.xml b/pom.xml index 8b5acdaba..40ccfc18b 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,7 @@ - 4.0.0 @@ -8,17 +10,25 @@ 0.0.1-SNAPSHOT jar Jhipster Sample Application - Description for Jhipster Sample Application + Description for jhipsterSampleApplication + + + + + + + + + + - + 3.2.5 - 17 - v18.16.1 - 9.8.0 + 11 + v16.17.0 + 8.19.1 + UTF-8 UTF-8 yyyyMMddHHmmss @@ -28,55 +38,58 @@ -Djava.security.egd=file:/dev/./urandom -Xmx1G jdt_apt false - 8.0.0-beta.2 - 3.1.1 - 1.0.1 - 10.12.1 + + + + + + + + 7.9.3 + + 2.7.3 + + 5.6.10.Final + + 4.15.0 + 4.15.0 + 2.0.1.Final + 4.0.0 + 0.22.0 + 1.5.2.Final + + 3.2.0 + 3.12.1 + 3.10.1 + 3.4.1 + 2.10 + 3.1.0 + 3.0.0-M7 + 3.2.2 + 2.2.1 + 3.3.0 + 3.0.0-M7 + 3.3.2 + 3.1.2 + 10.3.2 + 0.0.10 + 1.12.1 1.11 - 1.13.4 - 4.3.7 - 3.9.5 - 6.0.0 - 2.2.220 - 6.1.7.Final - 0.8.10 - 4.0.3 + 3.1.0 + 5.0.0 + 2.4.0 + 0.8.8 + 3.2.1 + eclipse-temurin:11-jre-focal amd64 - eclipse-temurin:17-jre-focal - 3.3.2 1.0.0 - - - - - - 4.20.0 - 1.5.5.Final - 3.1.0 - 3.3.0 - 3.3.1 - 3.11.0 - 2.1 - 3.3.0 - 3.1.2 - 2.2.1 - 3.3.0 - 3.5.0 - 3.3.1 - 3.12.1 - 3.1.2 - 3.4.0 - 2.6.0 - 0.0.11 - - - - - 1.1.0 3.9.1.2184 - 2.37.0 - 3.0.2 + + @@ -88,6 +101,7 @@ pom import + @@ -97,207 +111,198 @@ jhipster-framework - org.springframework.boot - spring-boot-configuration-processor - provided + javax.annotation + javax.annotation-api org.springframework.boot - spring-boot-loader-tools + spring-boot-starter-cache - org.springframework.boot - spring-boot-starter-actuator + com.fasterxml.jackson.module + jackson-module-jaxb-annotations - org.springframework.boot - spring-boot-starter-cache + com.fasterxml.jackson.datatype + jackson-datatype-hibernate5 - org.springframework.boot - spring-boot-starter-data-jpa + com.fasterxml.jackson.datatype + jackson-datatype-hppc - org.springframework.boot - spring-boot-starter-logging + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 - org.springframework.boot - spring-boot-starter-mail + org.springdoc + springdoc-openapi-webmvc-core - org.springframework.boot - spring-boot-starter-oauth2-resource-server + com.zaxxer + HikariCP - org.springframework.boot - spring-boot-starter-security + org.apache.commons + commons-lang3 - org.springframework.boot - spring-boot-starter-test - test + javax.cache + cache-api - org.springframework.boot - spring-boot-starter-thymeleaf + org.ehcache + ehcache - org.springframework.boot - spring-boot-starter-undertow + org.hibernate + hibernate-jcache - org.springframework.boot - spring-boot-starter-web + org.hibernate + hibernate-jpamodelgen + provided - org.springframework.boot - spring-boot-test - test + org.hibernate + hibernate-core - org.springframework.security - spring-security-data + org.hibernate.validator + hibernate-validator - org.springframework.security - spring-security-test - test + org.liquibase + liquibase-core + + ${liquibase.version} - org.springdoc - springdoc-openapi-starter-webmvc-api + org.mapstruct + mapstruct + ${mapstruct.version} - com.fasterxml.jackson.datatype - jackson-datatype-hibernate6 + org.mapstruct + mapstruct-processor + ${mapstruct.version} + provided - com.fasterxml.jackson.datatype - jackson-datatype-hppc + org.springframework.boot + spring-boot-configuration-processor + provided - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 + org.springframework.boot + spring-boot-loader-tools - com.fasterxml.jackson.module - jackson-module-jaxb-annotations + org.springframework.boot + spring-boot-starter-actuator - com.tngtech.archunit - archunit-junit5-api - ${archunit-junit5.version} - test + org.springframework.boot + spring-boot-starter-data-jpa - - - com.tngtech.archunit - archunit-junit5-engine - ${archunit-junit5.version} + org.testcontainers + jdbc test - com.zaxxer - HikariCP + org.springframework.boot + spring-boot-starter-logging - io.dropwizard.metrics - metrics-core + org.springframework.boot + spring-boot-starter-mail - io.gatling.highcharts - gatling-charts-highcharts - ${gatling.version} - test + org.springframework.boot + spring-boot-starter-security - io.micrometer - micrometer-registry-prometheus + org.springframework.boot + spring-boot-starter-thymeleaf - jakarta.annotation - jakarta.annotation-api + org.springframework.boot + spring-boot-starter-web - javax.cache - cache-api + org.springframework.boot + spring-boot-starter-test + test - org.apache.commons - commons-lang3 + org.springframework.boot + spring-boot-test + test - org.ehcache - ehcache - jakarta + org.springframework.security + spring-security-test + test - org.hibernate.orm - hibernate-core - ${hibernate.version} + com.tngtech.archunit + archunit-junit5-api + ${archunit-junit5.version} + test + + - org.hibernate.orm - hibernate-jcache - ${hibernate.version} + com.tngtech.archunit + archunit-junit5-engine + ${archunit-junit5.version} + test - org.hibernate.orm - hibernate-jpamodelgen - provided + org.zalando + problem-spring-web - org.hibernate.validator - hibernate-validator + org.springframework.boot + spring-boot-starter-undertow - org.liquibase - liquibase-core - ${liquibase.version} + io.jsonwebtoken + jjwt-api - org.mapstruct - mapstruct - ${mapstruct.version} + io.jsonwebtoken + jjwt-impl + runtime - org.mapstruct - mapstruct-processor - ${mapstruct.version} - provided + io.jsonwebtoken + jjwt-jackson + runtime + - org.testcontainers - jdbc - test + org.springframework.security + spring-security-data - org.testcontainers - postgresql - test + io.micrometer + micrometer-registry-prometheus + + + io.dropwizard.metrics + metrics-core + spring-boot:run - org.springframework.boot - spring-boot-maven-plugin - - - com.diffplug.spotless - spotless-maven-plugin - - - com.google.cloud.tools - jib-maven-plugin - - - io.gatling - gatling-maven-plugin + org.apache.maven.plugins + maven-compiler-plugin org.apache.maven.plugins @@ -305,7 +310,7 @@ org.apache.maven.plugins - maven-compiler-plugin + maven-javadoc-plugin org.apache.maven.plugins @@ -323,10 +328,6 @@ org.apache.maven.plugins maven-idea-plugin - - org.apache.maven.plugins - maven-javadoc-plugin - org.apache.maven.plugins maven-resources-plugin @@ -335,14 +336,6 @@ org.apache.maven.plugins maven-surefire-plugin - - org.codehaus.mojo - properties-maven-plugin - - - org.gaul - modernizer-maven-plugin - org.jacoco jacoco-maven-plugin @@ -351,46 +344,123 @@ org.sonarsource.scanner.maven sonar-maven-plugin + + org.springframework.boot + spring-boot-maven-plugin + + + com.google.cloud.tools + jib-maven-plugin + + + org.codehaus.mojo + properties-maven-plugin + + + org.gaul + modernizer-maven-plugin + + - org.springframework.boot - spring-boot-maven-plugin - ${spring-boot.version} + org.apache.maven.plugins + maven-checkstyle-plugin + ${maven-checkstyle-plugin.version} + + + com.puppycrawl.tools + checkstyle + ${checkstyle.version} + + + io.spring.nohttp + nohttp-checkstyle + ${nohttp-checkstyle.version} + + + + checkstyle.xml + pom.xml,README.md + .git/**/*,target/**/*,node_modules/**/*,node/**/* + ./ + - repackage + check - - ${start-class} - - - com.diffplug.spotless - spotless-maven-plugin - ${spotless-maven-plugin.version} + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} - - - - - + ${java.version} + ${java.version} + + + org.springframework.boot + spring-boot-configuration-processor + ${spring-boot.version} + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + + org.hibernate + hibernate-jpamodelgen + ${hibernate.version} + + + org.glassfish.jaxb + jaxb-runtime + ${jaxb-runtime.version} + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven-javadoc-plugin.version} + + ${maven.compiler.source} + + + + org.apache.maven.plugins + maven-war-plugin + ${maven-war-plugin.version} + - spotless - process-sources + default-war - apply + war + package + + WEB-INF/**,META-INF/** + false + target/classes/static/ + + + src/main/webapp + + WEB-INF/** + + + + com.github.eirslett @@ -398,10 +468,100 @@ ${frontend-maven-plugin.version} target - ${node.version} - ${npm.version} + + org.codehaus.mojo + properties-maven-plugin + ${properties-maven-plugin.version} + + + initialize + + read-project-properties + + + + sonar-project.properties + + + + + + + io.github.git-commit-id + git-commit-id-maven-plugin + ${git-commit-id-plugin.version} + + + + revision + + + + + false + false + true + + ^git.commit.id.abbrev$ + ^git.commit.id.describe$ + ^git.branch$ + + + + + org.gaul + modernizer-maven-plugin + ${modernizer-maven-plugin.version} + + + modernizer + package + + modernizer + + + + + ${java.version} + + + + org.jacoco + jacoco-maven-plugin + ${jacoco-maven-plugin.version} + + + pre-unit-tests + + prepare-agent + + + + + post-unit-test + test + + report + + + + pre-integration-tests + + prepare-agent-integration + + + + + post-integration-tests + post-integration-test + + report-integration + + + + com.google.cloud.tools jib-maven-plugin @@ -447,101 +607,12 @@ - io.gatling - gatling-maven-plugin - ${gatling-maven-plugin.version} - - true - ${project.basedir}/src/test/gatling/conf - - - - io.github.git-commit-id - git-commit-id-maven-plugin - ${git-commit-id-maven-plugin.version} - - - - revision - - - - - false - false - true - - ^git.commit.id.abbrev$ - ^git.commit.id.describe$ - ^git.branch$ - - - - - org.apache.maven.plugins - maven-checkstyle-plugin - ${maven-checkstyle-plugin.version} - - - com.puppycrawl.tools - checkstyle - ${checkstyle.version} - - - io.spring.nohttp - nohttp-checkstyle - ${nohttp-checkstyle.version} - - - - checkstyle.xml - pom.xml,README.md - .git/**/*,target/**/*,node_modules/**/*,node/**/* - ./ - - - - - check - - - - - - org.apache.maven.plugins maven-clean-plugin ${maven-clean-plugin.version} - org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler-plugin.version} - - ${java.version} - ${java.version} - - - org.springframework.boot - spring-boot-configuration-processor - ${spring-boot.version} - - - org.mapstruct - mapstruct-processor - ${mapstruct.version} - - - org.glassfish.jaxb - jaxb-runtime - ${jaxb-runtime.version} - - - org.hibernate.orm - hibernate-jpamodelgen - ${hibernate.version} - - - + maven-site-plugin + ${maven-site-plugin.version} org.apache.maven.plugins @@ -567,7 +638,7 @@ enforce-dependencyConvergence - + false @@ -583,43 +654,12 @@ [${maven.version},) - You are running an incompatible version of Java. JHipster supports JDK 17 to 19. - [17,18),[18,19),[19,20) + You are running an incompatible version of Java. JHipster supports JDK 11 to 18. + [11,12),[12,13),[13,14),[14,15),[15,16),[16,17),[17,18),[18,19) - - org.apache.maven.plugins - maven-failsafe-plugin - ${maven-failsafe-plugin.version} - - - - ${project.build.outputDirectory} - alphabetical - - **/*IT* - **/*IntTest* - - @{argLine} -Dspring.profiles.active=${profile.test} - - - - integration-test - - integration-test - - - - verify - - verify - - - - org.apache.maven.plugins maven-idea-plugin @@ -628,19 +668,6 @@ node_modules - - org.apache.maven.plugins - maven-jar-plugin - ${maven-jar-plugin.version} - - - org.apache.maven.plugins - maven-javadoc-plugin - ${maven-javadoc-plugin.version} - - ${maven.compiler.source} - - org.apache.maven.plugins maven-resources-plugin @@ -678,11 +705,6 @@ - - org.apache.maven.plugins - maven-site-plugin - ${maven-site-plugin.version} - org.apache.maven.plugins maven-surefire-plugin @@ -698,156 +720,46 @@ org.apache.maven.plugins - maven-war-plugin - ${maven-war-plugin.version} - - - default-war - - war - - package - - - - WEB-INF/**,META-INF/** - false - target/classes/static/ - - - src/main/webapp - - WEB-INF/** - - - - - - - org.codehaus.mojo - properties-maven-plugin - ${properties-maven-plugin.version} - - - initialize - - read-project-properties - - - - sonar-project.properties - - - - - + maven-jar-plugin + ${maven-jar-plugin.version} + - org.gaul - modernizer-maven-plugin - ${modernizer-maven-plugin.version} - - - modernizer - package - - modernizer - - - - - ${java.version} - + org.sonarsource.scanner.maven + sonar-maven-plugin + ${sonar-maven-plugin.version} - org.jacoco - jacoco-maven-plugin - ${jacoco-maven-plugin.version} + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} - pre-unit-tests - - prepare-agent - - - - - post-unit-test - test - - report - - - - pre-integration-tests - - prepare-agent-integration - - - - - post-integration-tests - post-integration-test - report-integration + repackage - - - org.liquibase - liquibase-maven-plugin - ${liquibase.version} - config/liquibase/master.xml - ${project.basedir}/src/main/resources/config/liquibase/changelog/${maven.build.timestamp}_changelog.xml - ${liquibase-plugin.driver} - ${liquibase-plugin.url} - - ${liquibase-plugin.username} - ${liquibase-plugin.password} - hibernate:spring:io.github.jhipster.sample.domain?dialect=${liquibase-plugin.hibernate-dialect}&hibernate.physical_naming_strategy=org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy&hibernate.implicit_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy - true - debug - !test + ${start-class} + true + - - - org.liquibase - liquibase-core - ${liquibase.version} - - - org.liquibase.ext - liquibase-hibernate6 - ${liquibase.version} - - - org.springframework.boot - spring-boot-starter-data-jpa - ${spring-boot.version} - - - jakarta.validation - jakarta.validation-api - ${validation-api.version} - - - com.h2database - h2 - ${h2.version} - - - - - org.sonarsource.scanner.maven - sonar-maven-plugin - ${sonar-maven-plugin.version} + + - + + no-liquibase + + ,no-liquibase + + api-docs @@ -855,20 +767,143 @@ - dev + tls + + ,tls + + + + webapp true + + + + net.nicoulaj.maven.plugins + checksum-maven-plugin + ${checksum-maven-plugin.version} + + + create-pre-compiled-webapp-checksum + + files + + generate-resources + + + create-compiled-webapp-checksum + + files + + compile + + checksums.csv.old + + + + + + + ${project.basedir} + + src/main/webapp/**/*.* + target/classes/static/**/*.* + package-lock.json + package.json + webpack/*.* + tsconfig.json + + + **/app/**/service-worker.js + **/app/**/vendor.css + + + + false + false + false + + SHA-1 + + true + true + + + + org.apache.maven.plugins + maven-antrun-plugin + ${maven-antrun-plugin.version} + + + eval-frontend-checksum + generate-resources + + run + + + + + + + + + + + + true + + + + + + com.github.eirslett + frontend-maven-plugin + + + install-node-and-npm + + install-node-and-npm + + + ${node.version} + ${npm.version} + + + + npm install + + npm + + + + webapp build dev + + npm + + generate-resources + + run webapp:build + + ${project.version} + + false + + + + + + - dev${profile.tls}${profile.no-liquibase} - testdev - org.hibernate.dialect.H2Dialect - org.h2.Driver - jdbc:h2:tcp://localhost:18080/mem:jhipstersampleapplication - jhipsterSampleApplication - + dev${profile.no-liquibase} + + + dev + + true + org.springframework.boot @@ -891,140 +926,185 @@ + - - - - e2e - - ,e2e - - - e2e - org.springframework.boot - spring-boot-maven-plugin + org.apache.maven.plugins + maven-failsafe-plugin + ${maven-failsafe-plugin.version} + + + ${project.build.outputDirectory} + + alphabetical + + **/*IT* + **/*IntTest* + + @{argLine} -Dspring.profiles.active=testdev + - repackage + integration-test - repackage + integration-test + + + + verify + + verify + + org.liquibase + liquibase-maven-plugin + ${liquibase.version} + + ${project.basedir}/src/main/resources/config/liquibase/master.xml + ${project.basedir}/src/main/resources/config/liquibase/changelog/${maven.build.timestamp}_changelog.xml + + + + jhipsterSampleApplication + + hibernate:spring:io.github.jhipster.sample.domain?dialect=&hibernate.physical_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy&hibernate.implicit_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy + true + debug + !test + + + + org.liquibase + liquibase-core + ${liquibase.version} + + + org.liquibase.ext + liquibase-hibernate5 + ${liquibase-hibernate5.version} + + + org.springframework.boot + spring-boot-starter-data-jpa + ${spring-boot.version} + + + javax.validation + validation-api + ${validation-api.version} + + + + + + dev${profile.tls}${profile.no-liquibase} + - - eclipse - - - m2e.version - - + prod - - org.springframework.boot - spring-boot-starter-undertow + org.testcontainers + postgresql + test + + + org.postgresql + postgresql - - org.eclipse.m2e - lifecycle-mapping - ${lifecycle-mapping.version} + org.apache.maven.plugins + maven-failsafe-plugin + ${maven-failsafe-plugin.version} - - - - - org.jacoco - jacoco-maven-plugin - ${jacoco-maven-plugin.version} - - prepare-agent - - - - - - - - - com.github.eirslett - frontend-maven-plugin - ${frontend-maven-plugin.version} - - install-node-and-npm - npm - - - - - - - - + + ${project.build.outputDirectory} + + alphabetical + + **/*IT* + **/*IntTest* + + @{argLine} -Dspring.profiles.active=testprod + + + + integration-test + + integration-test + + + + verify + + verify + + + + + + org.liquibase + liquibase-maven-plugin + ${liquibase.version} + + ${project.basedir}/src/main/resources/config/liquibase/master.xml + ${project.basedir}/src/main/resources/config/liquibase/changelog/${maven.build.timestamp}_changelog.xml + org.postgresql.Driver + jdbc:postgresql://localhost:5432/jhipsterSampleApplication + + jhipsterSampleApplication + + hibernate:spring:io.github.jhipster.sample.domain?dialect=tech.jhipster.domain.util.FixedPostgreSQL10Dialect&hibernate.physical_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy&hibernate.implicit_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy + true + debug + !test + + + org.liquibase + liquibase-core + ${liquibase.version} + + + org.liquibase.ext + liquibase-hibernate5 + ${liquibase-hibernate5.version} + + + org.springframework.boot + spring-boot-starter-data-jpa + ${spring-boot.version} + + + javax.validation + validation-api + ${validation-api.version} + + + tech.jhipster + jhipster-framework + ${jhipster-dependencies.version} + + - - - - - IDE - - - org.mapstruct - mapstruct-processor - ${mapstruct.version} - - - org.hibernate.orm - hibernate-jpamodelgen - - - - - no-liquibase - - ,no-liquibase - - - - prod - - - prod${profile.api-docs}${profile.tls}${profile.e2e}${profile.no-liquibase} - testprod - org.hibernate.dialect.PostgreSQLDialect - org.postgresql.Driver - jdbc:postgresql://localhost:5432/jhipsterSampleApplication - jhipsterSampleApplication - - - - org.apache.maven.plugins maven-clean-plugin @@ -1054,6 +1134,10 @@ install-node-and-npm + + ${node.version} + ${npm.version} + npm install @@ -1094,17 +1178,9 @@ - - - org.postgresql - postgresql - - - - - tls - ,tls + + prod${profile.api-docs}${profile.tls}${profile.e2e}${profile.no-liquibase} @@ -1119,128 +1195,118 @@ - webapp + + IDE + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + org.hibernate + hibernate-jpamodelgen + + + + + + eclipse - true + + m2e.version + + + + + org.springframework.boot + spring-boot-starter-undertow + + - - - net.nicoulaj.maven.plugins - checksum-maven-plugin - ${checksum-maven-plugin.version} - - - create-pre-compiled-webapp-checksum - - files - - generate-resources - - - create-compiled-webapp-checksum - - files - - compile - - checksums.csv.old - - - - - - - ${project.basedir} - - src/main/webapp/**/*.* - target/classes/static/**/*.* - package-lock.json - package.json - webpack/*.* - tsconfig.json - tsconfig.app.json - - - **/app/**/service-worker.js - **/app/**/vendor.css - - - - false - false - false - - SHA-1 - - true - true - - - - org.apache.maven.plugins - maven-antrun-plugin - ${maven-antrun-plugin.version} - - - eval-frontend-checksum - generate-resources - - run - - - - - - - - - - - - true - - - - - - com.github.eirslett - frontend-maven-plugin - - - install-node-and-npm - - install-node-and-npm - - - - npm install - - npm - - - - webapp build dev - - npm - - generate-resources - - run webapp:build - - ${project.version} - - false - - - - - + + + + + org.eclipse.m2e + lifecycle-mapping + ${lifecycle-mapping.version} + + + + + + org.jacoco + + jacoco-maven-plugin + + + ${jacoco-maven-plugin.version} + + + prepare-agent + + + + + + + + + com.github.eirslett + frontend-maven-plugin + ${frontend-maven-plugin.version} + + install-node-and-npm + npm + + + + + + + + + + + + + + + e2e - - dev${profile.no-liquibase} + ,e2e + + e2e + + + + org.springframework.boot + spring-boot-maven-plugin + + + repackage + + repackage + + + + + + + + diff --git a/sonar-project.properties b/sonar-project.properties index 6c7e8f869..148d4a173 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -6,7 +6,7 @@ sonar.sources=src sonar.tests=src sonar.host.url=http://localhost:9001 -sonar.test.inclusions=src/test/**/*.*, src/main/webapp/app/**/*.spec.ts +sonar.test.inclusions=src/test/**/*.* sonar.coverage.jacoco.xmlReportPaths=target/site/**/jacoco*.xml sonar.java.codeCoveragePlugin=jacoco sonar.junit.reportPaths=target/surefire-reports,target/failsafe-reports diff --git a/src/main/docker/app.yml b/src/main/docker/app.yml index 95e5e1c8b..4e10698cb 100644 --- a/src/main/docker/app.yml +++ b/src/main/docker/app.yml @@ -1,29 +1,28 @@ # This configuration is intended for development purpose, it's **your** responsibility to harden it for production -name: jhipstersampleapplication +version: '3.8' services: - app: + jhipstersampleapplication-app: image: jhipstersampleapplication environment: - _JAVA_OPTIONS=-Xmx512m -Xms256m - SPRING_PROFILES_ACTIVE=prod,api-docs - - MANAGEMENT_PROMETHEUS_METRICS_EXPORT_ENABLED=true - - SPRING_DATASOURCE_URL=jdbc:postgresql://postgresql:5432/jhipsterSampleApplication - - SPRING_LIQUIBASE_URL=jdbc:postgresql://postgresql:5432/jhipsterSampleApplication + - MANAGEMENT_METRICS_EXPORT_PROMETHEUS_ENABLED=true + - SPRING_DATASOURCE_URL=jdbc:postgresql://jhipstersampleapplication-postgresql:5432/jhipsterSampleApplication + - SPRING_LIQUIBASE_URL=jdbc:postgresql://jhipstersampleapplication-postgresql:5432/jhipsterSampleApplication + - JHIPSTER_SLEEP=30 # gives time for other services to boot before the application + # If you want to expose these ports outside your dev PC, + # remove the "127.0.0.1:" prefix ports: - 127.0.0.1:8080:8080 - healthcheck: - test: - - CMD - - curl - - -f - - http://localhost:8080/management/health - interval: 5s - timeout: 5s - retries: 40 - depends_on: - postgresql: - condition: service_healthy - postgresql: - extends: - file: ./postgresql.yml - service: postgresql + jhipstersampleapplication-postgresql: + image: postgres:14.5 + # volumes: + # - ~/volumes/jhipster/jhipsterSampleApplication/postgresql/:/var/lib/postgresql/data/ + environment: + - POSTGRES_USER=jhipsterSampleApplication + - POSTGRES_PASSWORD= + - POSTGRES_HOST_AUTH_METHOD=trust + # If you want to expose these ports outside your dev PC, + # remove the "127.0.0.1:" prefix + ports: + - 127.0.0.1:5432:5432 diff --git a/src/main/docker/jhipster-control-center.yml b/src/main/docker/jhipster-control-center.yml index e5aaacb0c..6e966e558 100644 --- a/src/main/docker/jhipster-control-center.yml +++ b/src/main/docker/jhipster-control-center.yml @@ -28,7 +28,7 @@ # - In Consul mode, the ports are in the consul.yml file. # - In Eureka mode, the ports are in the jhipster-registry.yml file. -name: jhipstersampleapplication +version: '3.8' services: jhipster-control-center: image: 'jhipster/jhipster-control-center:v0.5.0' @@ -40,6 +40,7 @@ services: environment: - _JAVA_OPTIONS=-Xmx512m -Xms256m - SPRING_PROFILES_ACTIVE=prod,api-docs,static + - JHIPSTER_SLEEP=30 # gives time for other services to boot before the application - SPRING_SECURITY_USER_PASSWORD=admin # The token should have the same value than the one declared in you Spring configuration under the jhipster.security.authentication.jwt.base64-secret configuration's entry - JHIPSTER_SECURITY_AUTHENTICATION_JWT_BASE64_SECRET=bXktc2VjcmV0LWtleS13aGljaC1zaG91bGQtYmUtY2hhbmdlZC1pbi1wcm9kdWN0aW9uLWFuZC1iZS1iYXNlNjQtZW5jb2RlZAo= diff --git a/src/main/docker/monitoring.yml b/src/main/docker/monitoring.yml index 7c1802d95..7bec8d866 100644 --- a/src/main/docker/monitoring.yml +++ b/src/main/docker/monitoring.yml @@ -1,8 +1,8 @@ # This configuration is intended for development purpose, it's **your** responsibility to harden it for production -name: jhipstersampleapplication +version: '3.8' services: - prometheus: - image: prom/prometheus:v2.45.0 + jhipstersampleapplication-prometheus: + image: prom/prometheus:v2.38.0 volumes: - ./prometheus/:/etc/prometheus/ command: @@ -14,8 +14,8 @@ services: # On MacOS, remove next line and replace localhost by host.docker.internal in prometheus/prometheus.yml and # grafana/provisioning/datasources/datasource.yml network_mode: 'host' # to test locally running service - grafana: - image: grafana/grafana:10.0.2 + jhipstersampleapplication-grafana: + image: grafana/grafana:9.1.0 volumes: - ./grafana/provisioning/:/etc/grafana/provisioning/ environment: diff --git a/src/main/docker/postgresql.yml b/src/main/docker/postgresql.yml index ebe8af9f2..bd209c23d 100644 --- a/src/main/docker/postgresql.yml +++ b/src/main/docker/postgresql.yml @@ -1,19 +1,14 @@ # This configuration is intended for development purpose, it's **your** responsibility to harden it for production -name: jhipstersampleapplication +version: '3.8' services: - postgresql: - image: postgres:15.3 + jhipstersampleapplication-postgresql: + image: postgres:14.5 # volumes: # - ~/volumes/jhipster/jhipsterSampleApplication/postgresql/:/var/lib/postgresql/data/ environment: - POSTGRES_USER=jhipsterSampleApplication - POSTGRES_PASSWORD= - POSTGRES_HOST_AUTH_METHOD=trust - healthcheck: - test: ['CMD-SHELL', 'pg_isready -U $${POSTGRES_USER}'] - interval: 5s - timeout: 5s - retries: 10 # If you want to expose these ports outside your dev PC, # remove the "127.0.0.1:" prefix ports: diff --git a/src/main/docker/services.yml b/src/main/docker/services.yml deleted file mode 100644 index a1c65b45e..000000000 --- a/src/main/docker/services.yml +++ /dev/null @@ -1,7 +0,0 @@ -# This configuration is intended for development purpose, it's **your** responsibility to harden it for production -name: jhipstersampleapplication -services: - postgresql: - extends: - file: ./postgresql.yml - service: postgresql diff --git a/src/main/docker/sonar.yml b/src/main/docker/sonar.yml index 506984756..14d80429b 100644 --- a/src/main/docker/sonar.yml +++ b/src/main/docker/sonar.yml @@ -1,15 +1,13 @@ # This configuration is intended for development purpose, it's **your** responsibility to harden it for production -name: jhipstersampleapplication +version: '3.8' services: - sonar: - container_name: sonarqube - image: sonarqube:10.1.0-community - # Forced authentication redirect for UI is turned off for out of the box experience while trying out SonarQube - # For real use cases delete SONAR_FORCEAUTHENTICATION variable or set SONAR_FORCEAUTHENTICATION=true + jhipstersampleapplication-sonar: + image: sonarqube:9.6.0-community + # Authentication is turned off for out of the box experience while trying out SonarQube + # For real use cases delete sonar.forceAuthentication variable or set sonar.forceAuthentication=true environment: - - SONAR_FORCEAUTHENTICATION=false + - sonar.forceAuthentication=false # If you want to expose these ports outside your dev PC, # remove the "127.0.0.1:" prefix ports: - 127.0.0.1:9001:9000 - - 127.0.0.1:9000:9000 diff --git a/src/main/java/io/github/jhipster/sample/GeneratedByJHipster.java b/src/main/java/io/github/jhipster/sample/GeneratedByJHipster.java index 2ba0226a3..37db78956 100644 --- a/src/main/java/io/github/jhipster/sample/GeneratedByJHipster.java +++ b/src/main/java/io/github/jhipster/sample/GeneratedByJHipster.java @@ -1,12 +1,12 @@ package io.github.jhipster.sample; -import jakarta.annotation.Generated; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import javax.annotation.Generated; -@Generated(value = "JHipster", comments = "Generated by JHipster 7.9.3") +@Generated(value = "JHipster", comments = "Generated by JHipster 7.9.4") @Retention(RetentionPolicy.SOURCE) @Target({ ElementType.TYPE }) public @interface GeneratedByJHipster { diff --git a/src/main/java/io/github/jhipster/sample/JhipsterSampleApplicationApp.java b/src/main/java/io/github/jhipster/sample/JhipsterSampleApplicationApp.java index 3e7334f3a..6e283669c 100644 --- a/src/main/java/io/github/jhipster/sample/JhipsterSampleApplicationApp.java +++ b/src/main/java/io/github/jhipster/sample/JhipsterSampleApplicationApp.java @@ -2,12 +2,12 @@ import io.github.jhipster.sample.config.ApplicationProperties; import io.github.jhipster.sample.config.CRLFLogConverter; -import jakarta.annotation.PostConstruct; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; import java.util.Collection; import java.util.Optional; +import javax.annotation.PostConstruct; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -86,14 +86,11 @@ private static void logApplicationStartup(Environment env) { } log.info( CRLFLogConverter.CRLF_SAFE_MARKER, - """ - - ---------------------------------------------------------- - \tApplication '{}' is running! Access URLs: - \tLocal: \t\t{}://localhost:{}{} - \tExternal: \t{}://{}:{}{} - \tProfile(s): \t{} - ----------------------------------------------------------""", + "\n----------------------------------------------------------\n\t" + + "Application '{}' is running! Access URLs:\n\t" + + "Local: \t\t{}://localhost:{}{}\n\t" + + "External: \t{}://{}:{}{}\n\t" + + "Profile(s): \t{}\n----------------------------------------------------------", env.getProperty("spring.application.name"), protocol, serverPort, diff --git a/src/main/java/io/github/jhipster/sample/aop/logging/package-info.java b/src/main/java/io/github/jhipster/sample/aop/logging/package-info.java deleted file mode 100644 index 84f774c6c..000000000 --- a/src/main/java/io/github/jhipster/sample/aop/logging/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Logging aspect. - */ -package io.github.jhipster.sample.aop.logging; diff --git a/src/main/java/io/github/jhipster/sample/config/CRLFLogConverter.java b/src/main/java/io/github/jhipster/sample/config/CRLFLogConverter.java index 8a75b6d5b..89e5be71e 100644 --- a/src/main/java/io/github/jhipster/sample/config/CRLFLogConverter.java +++ b/src/main/java/io/github/jhipster/sample/config/CRLFLogConverter.java @@ -12,22 +12,11 @@ import org.springframework.boot.ansi.AnsiOutput; import org.springframework.boot.ansi.AnsiStyle; -/** - * Log filter to prevent attackers from forging log entries by submitting input containing CRLF characters. - * CRLF characters are replaced with a red colored _ character. - * - * @see Log Forging Description - * @see JHipster issue - */ public class CRLFLogConverter extends CompositeConverter { public static final Marker CRLF_SAFE_MARKER = MarkerFactory.getMarker("CRLF_SAFE"); - private static final String[] SAFE_LOGGERS = { - "org.hibernate", - "org.springframework.boot.autoconfigure", - "org.springframework.boot.diagnostics", - }; + private static final String[] SAFE_LOGGERS = { "org.hibernate" }; private static final Map ELEMENTS; static { diff --git a/src/main/java/io/github/jhipster/sample/config/JacksonConfiguration.java b/src/main/java/io/github/jhipster/sample/config/JacksonConfiguration.java index 1941d23f1..0c5eeda24 100644 --- a/src/main/java/io/github/jhipster/sample/config/JacksonConfiguration.java +++ b/src/main/java/io/github/jhipster/sample/config/JacksonConfiguration.java @@ -1,10 +1,12 @@ package io.github.jhipster.sample.config; -import com.fasterxml.jackson.datatype.hibernate6.Hibernate6Module; +import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.zalando.problem.jackson.ProblemModule; +import org.zalando.problem.violations.ConstraintViolationProblemModule; @Configuration public class JacksonConfiguration { @@ -27,7 +29,23 @@ public Jdk8Module jdk8TimeModule() { * Support for Hibernate types in Jackson. */ @Bean - public Hibernate6Module hibernate6Module() { - return new Hibernate6Module(); + public Hibernate5Module hibernate5Module() { + return new Hibernate5Module(); + } + + /* + * Module for serialization/deserialization of RFC7807 Problem. + */ + @Bean + public ProblemModule problemModule() { + return new ProblemModule(); + } + + /* + * Module for serialization/deserialization of ConstraintViolationProblem. + */ + @Bean + public ConstraintViolationProblemModule constraintViolationProblemModule() { + return new ConstraintViolationProblemModule(); } } diff --git a/src/main/java/io/github/jhipster/sample/config/LiquibaseConfiguration.java b/src/main/java/io/github/jhipster/sample/config/LiquibaseConfiguration.java index 98873154f..bbf72f6a2 100644 --- a/src/main/java/io/github/jhipster/sample/config/LiquibaseConfiguration.java +++ b/src/main/java/io/github/jhipster/sample/config/LiquibaseConfiguration.java @@ -31,8 +31,8 @@ public LiquibaseConfiguration(Environment env) { @Bean public SpringLiquibase liquibase( @Qualifier("taskExecutor") Executor executor, - LiquibaseProperties liquibaseProperties, @LiquibaseDataSource ObjectProvider liquibaseDataSource, + LiquibaseProperties liquibaseProperties, ObjectProvider dataSource, DataSourceProperties dataSourceProperties ) { @@ -54,7 +54,7 @@ public SpringLiquibase liquibase( liquibase.setDatabaseChangeLogLockTable(liquibaseProperties.getDatabaseChangeLogLockTable()); liquibase.setDatabaseChangeLogTable(liquibaseProperties.getDatabaseChangeLogTable()); liquibase.setDropFirst(liquibaseProperties.isDropFirst()); - liquibase.setLabelFilter(liquibaseProperties.getLabelFilter()); + liquibase.setLabels(liquibaseProperties.getLabels()); liquibase.setChangeLogParameters(liquibaseProperties.getParameters()); liquibase.setRollbackFile(liquibaseProperties.getRollbackFile()); liquibase.setTestRollbackOnUpdate(liquibaseProperties.isTestRollbackOnUpdate()); diff --git a/src/main/java/io/github/jhipster/sample/config/SecurityConfiguration.java b/src/main/java/io/github/jhipster/sample/config/SecurityConfiguration.java index 2d932076b..09b36fa1a 100644 --- a/src/main/java/io/github/jhipster/sample/config/SecurityConfiguration.java +++ b/src/main/java/io/github/jhipster/sample/config/SecurityConfiguration.java @@ -1,32 +1,44 @@ package io.github.jhipster.sample.config; -import static org.springframework.security.config.Customizer.withDefaults; - import io.github.jhipster.sample.security.*; -import io.github.jhipster.sample.web.filter.SpaWebFilter; +import io.github.jhipster.sample.security.jwt.*; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.http.HttpMethod; -import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer.FrameOptionsConfig; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint; -import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler; import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter; +import org.springframework.web.filter.CorsFilter; +import org.zalando.problem.spring.web.advice.security.SecurityProblemSupport; import tech.jhipster.config.JHipsterProperties; -@Configuration -@EnableMethodSecurity(securedEnabled = true) +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) +@Import(SecurityProblemSupport.class) public class SecurityConfiguration { private final JHipsterProperties jHipsterProperties; - public SecurityConfiguration(JHipsterProperties jHipsterProperties) { + private final TokenProvider tokenProvider; + + private final CorsFilter corsFilter; + private final SecurityProblemSupport problemSupport; + + public SecurityConfiguration( + TokenProvider tokenProvider, + CorsFilter corsFilter, + JHipsterProperties jHipsterProperties, + SecurityProblemSupport problemSupport + ) { + this.tokenProvider = tokenProvider; + this.corsFilter = corsFilter; + this.problemSupport = problemSupport; this.jHipsterProperties = jHipsterProperties; } @@ -37,53 +49,57 @@ public PasswordEncoder passwordEncoder() { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + // @formatter:off http - .cors(withDefaults()) - .csrf(csrf -> csrf.ignoringRequestMatchers("/h2-console/**").disable()) - .addFilterAfter(new SpaWebFilter(), BasicAuthenticationFilter.class) - .headers(headers -> - headers - .contentSecurityPolicy(csp -> csp.policyDirectives(jHipsterProperties.getSecurity().getContentSecurityPolicy())) - .frameOptions(FrameOptionsConfig::sameOrigin) - .referrerPolicy(referrer -> referrer.policy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)) - .permissionsPolicy(permissions -> - permissions.policy( - "camera=(), fullscreen=(self), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), sync-xhr=()" - ) - ) - ) - .authorizeHttpRequests(authz -> - // prettier-ignore - authz - .requestMatchers("/", "/index.html", "/*.js", "/*.map", "/*.css").permitAll() - .requestMatchers("/*.ico", "/*.png", "/*.svg", "/*.webapp").permitAll() - .requestMatchers("/app/**").permitAll() - .requestMatchers("/i18n/**").permitAll() - .requestMatchers("/content/**").permitAll() - .requestMatchers("/swagger-ui/**").permitAll() - .requestMatchers("/h2-console/**").permitAll() - .requestMatchers(HttpMethod.POST, "/api/authenticate").permitAll() - .requestMatchers(HttpMethod.GET, "/api/authenticate").permitAll() - .requestMatchers("/api/register").permitAll() - .requestMatchers("/api/activate").permitAll() - .requestMatchers("/api/account/reset-password/init").permitAll() - .requestMatchers("/api/account/reset-password/finish").permitAll() - .requestMatchers("/api/admin/**").hasAuthority(AuthoritiesConstants.ADMIN) - .requestMatchers("/api/**").authenticated() - .requestMatchers("/v3/api-docs/**").hasAuthority(AuthoritiesConstants.ADMIN) - .requestMatchers("/management/health").permitAll() - .requestMatchers("/management/health/**").permitAll() - .requestMatchers("/management/info").permitAll() - .requestMatchers("/management/prometheus").permitAll() - .requestMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN) - ) - .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) - .exceptionHandling(exceptions -> - exceptions - .authenticationEntryPoint(new BearerTokenAuthenticationEntryPoint()) - .accessDeniedHandler(new BearerTokenAccessDeniedHandler()) - ) - .oauth2ResourceServer(oauth2 -> oauth2.jwt()); + .csrf() + .ignoringAntMatchers("/h2-console/**") + .disable() + .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class) + .exceptionHandling() + .authenticationEntryPoint(problemSupport) + .accessDeniedHandler(problemSupport) + .and() + .headers() + .contentSecurityPolicy(jHipsterProperties.getSecurity().getContentSecurityPolicy()) + .and() + .referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN) + .and() + .permissionsPolicy().policy("camera=(), fullscreen=(self), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), sync-xhr=()") + .and() + .frameOptions().sameOrigin() + .and() + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() + .antMatchers("/app/**/*.{js,html}").permitAll() + .antMatchers("/i18n/**").permitAll() + .antMatchers("/content/**").permitAll() + .antMatchers("/swagger-ui/**").permitAll() + .antMatchers("/test/**").permitAll() + .antMatchers("/h2-console/**").permitAll() + .antMatchers("/api/authenticate").permitAll() + .antMatchers("/api/register").permitAll() + .antMatchers("/api/activate").permitAll() + .antMatchers("/api/account/reset-password/init").permitAll() + .antMatchers("/api/account/reset-password/finish").permitAll() + .antMatchers("/api/admin/**").hasAuthority(AuthoritiesConstants.ADMIN) + .antMatchers("/api/**").authenticated() + .antMatchers("/management/health").permitAll() + .antMatchers("/management/health/**").permitAll() + .antMatchers("/management/info").permitAll() + .antMatchers("/management/prometheus").permitAll() + .antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN) + .and() + .httpBasic() + .and() + .apply(securityConfigurerAdapter()); return http.build(); + // @formatter:on + } + + private JWTConfigurer securityConfigurerAdapter() { + return new JWTConfigurer(tokenProvider); } } diff --git a/src/main/java/io/github/jhipster/sample/config/SecurityJwtConfiguration.java b/src/main/java/io/github/jhipster/sample/config/SecurityJwtConfiguration.java deleted file mode 100644 index 9e36acf0a..000000000 --- a/src/main/java/io/github/jhipster/sample/config/SecurityJwtConfiguration.java +++ /dev/null @@ -1,68 +0,0 @@ -package io.github.jhipster.sample.config; - -import static io.github.jhipster.sample.security.SecurityUtils.AUTHORITIES_KEY; -import static io.github.jhipster.sample.security.SecurityUtils.JWT_ALGORITHM; - -import com.nimbusds.jose.jwk.source.ImmutableSecret; -import com.nimbusds.jose.util.Base64; -import io.github.jhipster.sample.management.SecurityMetersService; -import javax.crypto.SecretKey; -import javax.crypto.spec.SecretKeySpec; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.oauth2.jwt.JwtDecoder; -import org.springframework.security.oauth2.jwt.JwtEncoder; -import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; -import org.springframework.security.oauth2.jwt.NimbusJwtEncoder; -import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter; -import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter; - -@Configuration -public class SecurityJwtConfiguration { - - @Value("${jhipster.security.authentication.jwt.base64-secret}") - private String jwtKey; - - @Bean - public JwtDecoder jwtDecoder(SecurityMetersService metersService) { - NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withSecretKey(getSecretKey()).macAlgorithm(JWT_ALGORITHM).build(); - return token -> { - try { - return jwtDecoder.decode(token); - } catch (Exception e) { - if (e.getMessage().contains("Invalid signature")) { - metersService.trackTokenInvalidSignature(); - } else if (e.getMessage().contains("Jwt expired at")) { - metersService.trackTokenExpired(); - } else if (e.getMessage().contains("Invalid JWT serialization")) { - metersService.trackTokenMalformed(); - } else if (e.getMessage().contains("Invalid unsecured/JWS/JWE")) { - metersService.trackTokenMalformed(); - } - throw e; - } - }; - } - - @Bean - public JwtEncoder jwtEncoder() { - return new NimbusJwtEncoder(new ImmutableSecret<>(getSecretKey())); - } - - @Bean - public JwtAuthenticationConverter jwtAuthenticationConverter() { - JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); - grantedAuthoritiesConverter.setAuthorityPrefix(""); - grantedAuthoritiesConverter.setAuthoritiesClaimName(AUTHORITIES_KEY); - - JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter(); - jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter); - return jwtAuthenticationConverter; - } - - private SecretKey getSecretKey() { - byte[] keyBytes = Base64.from(jwtKey).decode(); - return new SecretKeySpec(keyBytes, 0, keyBytes.length, JWT_ALGORITHM.getName()); - } -} diff --git a/src/main/java/io/github/jhipster/sample/config/WebConfigurer.java b/src/main/java/io/github/jhipster/sample/config/WebConfigurer.java index f15994e5b..75d7d6cd2 100644 --- a/src/main/java/io/github/jhipster/sample/config/WebConfigurer.java +++ b/src/main/java/io/github/jhipster/sample/config/WebConfigurer.java @@ -2,10 +2,10 @@ import static java.net.URLDecoder.decode; -import jakarta.servlet.*; import java.io.File; import java.nio.charset.StandardCharsets; import java.nio.file.Paths; +import javax.servlet.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.web.server.*; @@ -62,7 +62,8 @@ public void customize(WebServerFactory server) { } private void setLocationForStaticAssets(WebServerFactory server) { - if (server instanceof ConfigurableServletWebServerFactory servletWebServer) { + if (server instanceof ConfigurableServletWebServerFactory) { + ConfigurableServletWebServerFactory servletWebServer = (ConfigurableServletWebServerFactory) server; File root; String prefixPath = resolvePathPrefix(); root = new File(prefixPath + "target/classes/static/"); diff --git a/src/main/java/io/github/jhipster/sample/config/package-info.java b/src/main/java/io/github/jhipster/sample/config/package-info.java index ad869b14f..7a623f3fd 100644 --- a/src/main/java/io/github/jhipster/sample/config/package-info.java +++ b/src/main/java/io/github/jhipster/sample/config/package-info.java @@ -1,4 +1,4 @@ /** - * Application configuration. + * Spring Framework configuration files. */ package io.github.jhipster.sample.config; diff --git a/src/main/java/io/github/jhipster/sample/domain/AbstractAuditingEntity.java b/src/main/java/io/github/jhipster/sample/domain/AbstractAuditingEntity.java index 55f172427..ffef4f599 100644 --- a/src/main/java/io/github/jhipster/sample/domain/AbstractAuditingEntity.java +++ b/src/main/java/io/github/jhipster/sample/domain/AbstractAuditingEntity.java @@ -1,11 +1,11 @@ package io.github.jhipster.sample.domain; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import jakarta.persistence.Column; -import jakarta.persistence.EntityListeners; -import jakarta.persistence.MappedSuperclass; import java.io.Serializable; import java.time.Instant; +import javax.persistence.Column; +import javax.persistence.EntityListeners; +import javax.persistence.MappedSuperclass; import org.springframework.data.annotation.CreatedBy; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedBy; diff --git a/src/main/java/io/github/jhipster/sample/domain/Authority.java b/src/main/java/io/github/jhipster/sample/domain/Authority.java index bdaf7281f..ecc01e6ad 100644 --- a/src/main/java/io/github/jhipster/sample/domain/Authority.java +++ b/src/main/java/io/github/jhipster/sample/domain/Authority.java @@ -1,13 +1,13 @@ package io.github.jhipster.sample.domain; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.Table; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; import java.io.Serializable; import java.util.Objects; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; diff --git a/src/main/java/io/github/jhipster/sample/domain/BankAccount.java b/src/main/java/io/github/jhipster/sample/domain/BankAccount.java index da0a4be57..dde2660df 100644 --- a/src/main/java/io/github/jhipster/sample/domain/BankAccount.java +++ b/src/main/java/io/github/jhipster/sample/domain/BankAccount.java @@ -1,12 +1,12 @@ package io.github.jhipster.sample.domain; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import jakarta.persistence.*; -import jakarta.validation.constraints.*; import java.io.Serializable; import java.math.BigDecimal; import java.util.HashSet; import java.util.Set; +import javax.persistence.*; +import javax.validation.constraints.*; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; @@ -35,10 +35,10 @@ public class BankAccount implements Serializable { @Column(name = "balance", precision = 21, scale = 2, nullable = false) private BigDecimal balance; - @ManyToOne(fetch = FetchType.LAZY) + @ManyToOne private User user; - @OneToMany(fetch = FetchType.LAZY, mappedBy = "bankAccount") + @OneToMany(mappedBy = "bankAccount") @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) @JsonIgnoreProperties(value = { "bankAccount", "labels" }, allowSetters = true) private Set operations = new HashSet<>(); diff --git a/src/main/java/io/github/jhipster/sample/domain/Label.java b/src/main/java/io/github/jhipster/sample/domain/Label.java index 3d573d8c2..b613aabaf 100644 --- a/src/main/java/io/github/jhipster/sample/domain/Label.java +++ b/src/main/java/io/github/jhipster/sample/domain/Label.java @@ -1,11 +1,11 @@ package io.github.jhipster.sample.domain; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import jakarta.persistence.*; -import jakarta.validation.constraints.*; import java.io.Serializable; import java.util.HashSet; import java.util.Set; +import javax.persistence.*; +import javax.validation.constraints.*; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; @@ -31,7 +31,7 @@ public class Label implements Serializable { @Column(name = "label", nullable = false) private String label; - @ManyToMany(fetch = FetchType.LAZY, mappedBy = "labels") + @ManyToMany(mappedBy = "labels") @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) @JsonIgnoreProperties(value = { "bankAccount", "labels" }, allowSetters = true) private Set operations = new HashSet<>(); diff --git a/src/main/java/io/github/jhipster/sample/domain/Operation.java b/src/main/java/io/github/jhipster/sample/domain/Operation.java index 3a454d6e1..acf20cf04 100644 --- a/src/main/java/io/github/jhipster/sample/domain/Operation.java +++ b/src/main/java/io/github/jhipster/sample/domain/Operation.java @@ -1,13 +1,13 @@ package io.github.jhipster.sample.domain; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import jakarta.persistence.*; -import jakarta.validation.constraints.*; import java.io.Serializable; import java.math.BigDecimal; import java.time.Instant; import java.util.HashSet; import java.util.Set; +import javax.persistence.*; +import javax.validation.constraints.*; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; @@ -39,11 +39,11 @@ public class Operation implements Serializable { @Column(name = "amount", precision = 21, scale = 2, nullable = false) private BigDecimal amount; - @ManyToOne(fetch = FetchType.LAZY) + @ManyToOne @JsonIgnoreProperties(value = { "user", "operations" }, allowSetters = true) private BankAccount bankAccount; - @ManyToMany(fetch = FetchType.LAZY) + @ManyToMany @JoinTable( name = "rel_operation__label", joinColumns = @JoinColumn(name = "operation_id"), diff --git a/src/main/java/io/github/jhipster/sample/domain/User.java b/src/main/java/io/github/jhipster/sample/domain/User.java index 81460224e..4ce67bf5a 100644 --- a/src/main/java/io/github/jhipster/sample/domain/User.java +++ b/src/main/java/io/github/jhipster/sample/domain/User.java @@ -2,16 +2,16 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import io.github.jhipster.sample.config.Constants; -import jakarta.persistence.*; -import jakarta.validation.constraints.Email; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Pattern; -import jakarta.validation.constraints.Size; import java.io.Serializable; import java.time.Instant; import java.util.HashSet; import java.util.Locale; import java.util.Set; +import javax.persistence.*; +import javax.validation.constraints.Email; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; import org.apache.commons.lang3.StringUtils; import org.hibernate.annotations.BatchSize; import org.hibernate.annotations.Cache; diff --git a/src/main/java/io/github/jhipster/sample/domain/package-info.java b/src/main/java/io/github/jhipster/sample/domain/package-info.java index cab748aff..b5eb9b2eb 100644 --- a/src/main/java/io/github/jhipster/sample/domain/package-info.java +++ b/src/main/java/io/github/jhipster/sample/domain/package-info.java @@ -1,4 +1,4 @@ /** - * Domain objects. + * JPA domain objects. */ package io.github.jhipster.sample.domain; diff --git a/src/main/java/io/github/jhipster/sample/management/package-info.java b/src/main/java/io/github/jhipster/sample/management/package-info.java deleted file mode 100644 index a0a6fef96..000000000 --- a/src/main/java/io/github/jhipster/sample/management/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Application management. - */ -package io.github.jhipster.sample.management; diff --git a/src/main/java/io/github/jhipster/sample/package-info.java b/src/main/java/io/github/jhipster/sample/package-info.java deleted file mode 100644 index e3ed9e153..000000000 --- a/src/main/java/io/github/jhipster/sample/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Application root. - */ -package io.github.jhipster.sample; diff --git a/src/main/java/io/github/jhipster/sample/repository/BankAccountRepository.java b/src/main/java/io/github/jhipster/sample/repository/BankAccountRepository.java index 09a9a3da3..f7048995b 100644 --- a/src/main/java/io/github/jhipster/sample/repository/BankAccountRepository.java +++ b/src/main/java/io/github/jhipster/sample/repository/BankAccountRepository.java @@ -30,12 +30,12 @@ default Page findAllWithEagerRelationships(Pageable pageable) { } @Query( - value = "select bankAccount from BankAccount bankAccount left join fetch bankAccount.user", - countQuery = "select count(bankAccount) from BankAccount bankAccount" + value = "select distinct bankAccount from BankAccount bankAccount left join fetch bankAccount.user", + countQuery = "select count(distinct bankAccount) from BankAccount bankAccount" ) Page findAllWithToOneRelationships(Pageable pageable); - @Query("select bankAccount from BankAccount bankAccount left join fetch bankAccount.user") + @Query("select distinct bankAccount from BankAccount bankAccount left join fetch bankAccount.user") List findAllWithToOneRelationships(); @Query("select bankAccount from BankAccount bankAccount left join fetch bankAccount.user where bankAccount.id =:id") diff --git a/src/main/java/io/github/jhipster/sample/repository/OperationRepository.java b/src/main/java/io/github/jhipster/sample/repository/OperationRepository.java index 8be1aca3d..a81c14758 100644 --- a/src/main/java/io/github/jhipster/sample/repository/OperationRepository.java +++ b/src/main/java/io/github/jhipster/sample/repository/OperationRepository.java @@ -30,12 +30,12 @@ default Page findAllWithEagerRelationships(Pageable pageable) { } @Query( - value = "select operation from Operation operation left join fetch operation.bankAccount", - countQuery = "select count(operation) from Operation operation" + value = "select distinct operation from Operation operation left join fetch operation.bankAccount", + countQuery = "select count(distinct operation) from Operation operation" ) Page findAllWithToOneRelationships(Pageable pageable); - @Query("select operation from Operation operation left join fetch operation.bankAccount") + @Query("select distinct operation from Operation operation left join fetch operation.bankAccount") List findAllWithToOneRelationships(); @Query("select operation from Operation operation left join fetch operation.bankAccount where operation.id =:id") diff --git a/src/main/java/io/github/jhipster/sample/repository/OperationRepositoryWithBagRelationshipsImpl.java b/src/main/java/io/github/jhipster/sample/repository/OperationRepositoryWithBagRelationshipsImpl.java index b316f42aa..e88dbdcd6 100644 --- a/src/main/java/io/github/jhipster/sample/repository/OperationRepositoryWithBagRelationshipsImpl.java +++ b/src/main/java/io/github/jhipster/sample/repository/OperationRepositoryWithBagRelationshipsImpl.java @@ -1,13 +1,14 @@ package io.github.jhipster.sample.repository; import io.github.jhipster.sample.domain.Operation; -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Optional; import java.util.stream.IntStream; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import org.hibernate.annotations.QueryHints; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; @@ -37,10 +38,11 @@ public List fetchBagRelationships(List operations) { Operation fetchLabels(Operation result) { return entityManager .createQuery( - "select operation from Operation operation left join fetch operation.labels where operation.id = :id", + "select operation from Operation operation left join fetch operation.labels where operation is :operation", Operation.class ) - .setParameter("id", result.getId()) + .setParameter("operation", result) + .setHint(QueryHints.PASS_DISTINCT_THROUGH, false) .getSingleResult(); } @@ -49,10 +51,11 @@ List fetchLabels(List operations) { IntStream.range(0, operations.size()).forEach(index -> order.put(operations.get(index).getId(), index)); List result = entityManager .createQuery( - "select operation from Operation operation left join fetch operation.labels where operation in :operations", + "select distinct operation from Operation operation left join fetch operation.labels where operation in :operations", Operation.class ) .setParameter("operations", operations) + .setHint(QueryHints.PASS_DISTINCT_THROUGH, false) .getResultList(); Collections.sort(result, (o1, o2) -> Integer.compare(order.get(o1.getId()), order.get(o2.getId()))); return result; diff --git a/src/main/java/io/github/jhipster/sample/repository/package-info.java b/src/main/java/io/github/jhipster/sample/repository/package-info.java index 2bf83af74..d9ff8cf34 100644 --- a/src/main/java/io/github/jhipster/sample/repository/package-info.java +++ b/src/main/java/io/github/jhipster/sample/repository/package-info.java @@ -1,4 +1,4 @@ /** - * Repository layer. + * Spring Data JPA repositories. */ package io.github.jhipster.sample.repository; diff --git a/src/main/java/io/github/jhipster/sample/security/DomainUserDetailsService.java b/src/main/java/io/github/jhipster/sample/security/DomainUserDetailsService.java index d8345e484..a9d2f3168 100644 --- a/src/main/java/io/github/jhipster/sample/security/DomainUserDetailsService.java +++ b/src/main/java/io/github/jhipster/sample/security/DomainUserDetailsService.java @@ -4,9 +4,11 @@ import io.github.jhipster.sample.domain.User; import io.github.jhipster.sample.repository.UserRepository; import java.util.*; +import java.util.stream.Collectors; import org.hibernate.validator.internal.constraintvalidators.hv.EmailValidator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; @@ -51,12 +53,12 @@ private org.springframework.security.core.userdetails.User createSpringSecurityU if (!user.isActivated()) { throw new UserNotActivatedException("User " + lowercaseLogin + " was not activated"); } - List grantedAuthorities = user + List grantedAuthorities = user .getAuthorities() .stream() .map(Authority::getName) .map(SimpleGrantedAuthority::new) - .toList(); + .collect(Collectors.toList()); return new org.springframework.security.core.userdetails.User(user.getLogin(), user.getPassword(), grantedAuthorities); } } diff --git a/src/main/java/io/github/jhipster/sample/security/SecurityUtils.java b/src/main/java/io/github/jhipster/sample/security/SecurityUtils.java index 77259f7ff..7aabaa032 100644 --- a/src/main/java/io/github/jhipster/sample/security/SecurityUtils.java +++ b/src/main/java/io/github/jhipster/sample/security/SecurityUtils.java @@ -8,18 +8,12 @@ import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.oauth2.jose.jws.MacAlgorithm; -import org.springframework.security.oauth2.jwt.Jwt; /** * Utility class for Spring Security. */ public final class SecurityUtils { - public static final MacAlgorithm JWT_ALGORITHM = MacAlgorithm.HS512; - - public static final String AUTHORITIES_KEY = "auth"; - private SecurityUtils() {} /** @@ -35,12 +29,11 @@ public static Optional getCurrentUserLogin() { private static String extractPrincipal(Authentication authentication) { if (authentication == null) { return null; - } else if (authentication.getPrincipal() instanceof UserDetails springSecurityUser) { + } else if (authentication.getPrincipal() instanceof UserDetails) { + UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal(); return springSecurityUser.getUsername(); - } else if (authentication.getPrincipal() instanceof Jwt jwt) { - return jwt.getSubject(); - } else if (authentication.getPrincipal() instanceof String s) { - return s; + } else if (authentication.getPrincipal() instanceof String) { + return (String) authentication.getPrincipal(); } return null; } diff --git a/src/main/java/io/github/jhipster/sample/security/jwt/JWTConfigurer.java b/src/main/java/io/github/jhipster/sample/security/jwt/JWTConfigurer.java new file mode 100644 index 000000000..3b75bd1a7 --- /dev/null +++ b/src/main/java/io/github/jhipster/sample/security/jwt/JWTConfigurer.java @@ -0,0 +1,21 @@ +package io.github.jhipster.sample.security.jwt; + +import org.springframework.security.config.annotation.SecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.web.DefaultSecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +public class JWTConfigurer extends SecurityConfigurerAdapter { + + private final TokenProvider tokenProvider; + + public JWTConfigurer(TokenProvider tokenProvider) { + this.tokenProvider = tokenProvider; + } + + @Override + public void configure(HttpSecurity http) { + JWTFilter customFilter = new JWTFilter(tokenProvider); + http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class); + } +} diff --git a/src/main/java/io/github/jhipster/sample/security/jwt/JWTFilter.java b/src/main/java/io/github/jhipster/sample/security/jwt/JWTFilter.java new file mode 100644 index 000000000..27faea2be --- /dev/null +++ b/src/main/java/io/github/jhipster/sample/security/jwt/JWTFilter.java @@ -0,0 +1,47 @@ +package io.github.jhipster.sample.security.jwt; + +import java.io.IOException; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.GenericFilterBean; + +/** + * Filters incoming requests and installs a Spring Security principal if a header corresponding to a valid user is + * found. + */ +public class JWTFilter extends GenericFilterBean { + + public static final String AUTHORIZATION_HEADER = "Authorization"; + + private final TokenProvider tokenProvider; + + public JWTFilter(TokenProvider tokenProvider) { + this.tokenProvider = tokenProvider; + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException { + HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; + String jwt = resolveToken(httpServletRequest); + if (StringUtils.hasText(jwt) && this.tokenProvider.validateToken(jwt)) { + Authentication authentication = this.tokenProvider.getAuthentication(jwt); + SecurityContextHolder.getContext().setAuthentication(authentication); + } + filterChain.doFilter(servletRequest, servletResponse); + } + + private String resolveToken(HttpServletRequest request) { + String bearerToken = request.getHeader(AUTHORIZATION_HEADER); + if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { + return bearerToken.substring(7); + } + return null; + } +} diff --git a/src/main/java/io/github/jhipster/sample/security/jwt/TokenProvider.java b/src/main/java/io/github/jhipster/sample/security/jwt/TokenProvider.java new file mode 100644 index 000000000..203f94423 --- /dev/null +++ b/src/main/java/io/github/jhipster/sample/security/jwt/TokenProvider.java @@ -0,0 +1,126 @@ +package io.github.jhipster.sample.security.jwt; + +import io.github.jhipster.sample.management.SecurityMetersService; +import io.jsonwebtoken.*; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; +import io.jsonwebtoken.security.SignatureException; +import java.nio.charset.StandardCharsets; +import java.security.Key; +import java.util.*; +import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; +import tech.jhipster.config.JHipsterProperties; + +@Component +public class TokenProvider { + + private final Logger log = LoggerFactory.getLogger(TokenProvider.class); + + private static final String AUTHORITIES_KEY = "auth"; + + private static final String INVALID_JWT_TOKEN = "Invalid JWT token."; + + private final Key key; + + private final JwtParser jwtParser; + + private final long tokenValidityInMilliseconds; + + private final long tokenValidityInMillisecondsForRememberMe; + + private final SecurityMetersService securityMetersService; + + public TokenProvider(JHipsterProperties jHipsterProperties, SecurityMetersService securityMetersService) { + byte[] keyBytes; + String secret = jHipsterProperties.getSecurity().getAuthentication().getJwt().getBase64Secret(); + if (!ObjectUtils.isEmpty(secret)) { + log.debug("Using a Base64-encoded JWT secret key"); + keyBytes = Decoders.BASE64.decode(secret); + } else { + log.warn( + "Warning: the JWT key used is not Base64-encoded. " + + "We recommend using the `jhipster.security.authentication.jwt.base64-secret` key for optimum security." + ); + secret = jHipsterProperties.getSecurity().getAuthentication().getJwt().getSecret(); + keyBytes = secret.getBytes(StandardCharsets.UTF_8); + } + key = Keys.hmacShaKeyFor(keyBytes); + jwtParser = Jwts.parserBuilder().setSigningKey(key).build(); + this.tokenValidityInMilliseconds = 1000 * jHipsterProperties.getSecurity().getAuthentication().getJwt().getTokenValidityInSeconds(); + this.tokenValidityInMillisecondsForRememberMe = + 1000 * jHipsterProperties.getSecurity().getAuthentication().getJwt().getTokenValidityInSecondsForRememberMe(); + + this.securityMetersService = securityMetersService; + } + + public String createToken(Authentication authentication, boolean rememberMe) { + String authorities = authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.joining(",")); + + long now = (new Date()).getTime(); + Date validity; + if (rememberMe) { + validity = new Date(now + this.tokenValidityInMillisecondsForRememberMe); + } else { + validity = new Date(now + this.tokenValidityInMilliseconds); + } + + return Jwts + .builder() + .setSubject(authentication.getName()) + .claim(AUTHORITIES_KEY, authorities) + .signWith(key, SignatureAlgorithm.HS512) + .setExpiration(validity) + .compact(); + } + + public Authentication getAuthentication(String token) { + Claims claims = jwtParser.parseClaimsJws(token).getBody(); + + Collection authorities = Arrays + .stream(claims.get(AUTHORITIES_KEY).toString().split(",")) + .filter(auth -> !auth.trim().isEmpty()) + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + + User principal = new User(claims.getSubject(), "", authorities); + + return new UsernamePasswordAuthenticationToken(principal, token, authorities); + } + + public boolean validateToken(String authToken) { + try { + jwtParser.parseClaimsJws(authToken); + + return true; + } catch (ExpiredJwtException e) { + this.securityMetersService.trackTokenExpired(); + + log.trace(INVALID_JWT_TOKEN, e); + } catch (UnsupportedJwtException e) { + this.securityMetersService.trackTokenUnsupported(); + + log.trace(INVALID_JWT_TOKEN, e); + } catch (MalformedJwtException e) { + this.securityMetersService.trackTokenMalformed(); + + log.trace(INVALID_JWT_TOKEN, e); + } catch (SignatureException e) { + this.securityMetersService.trackTokenInvalidSignature(); + + log.trace(INVALID_JWT_TOKEN, e); + } catch (IllegalArgumentException e) { // TODO: should we let it bubble (no catch), to avoid defensive programming and follow the fail-fast principle? + log.error("Token validation error {}", e.getMessage()); + } + + return false; + } +} diff --git a/src/main/java/io/github/jhipster/sample/security/package-info.java b/src/main/java/io/github/jhipster/sample/security/package-info.java index 11718c951..6c3ea1460 100644 --- a/src/main/java/io/github/jhipster/sample/security/package-info.java +++ b/src/main/java/io/github/jhipster/sample/security/package-info.java @@ -1,4 +1,4 @@ /** - * Application security utilities. + * Spring Security configuration. */ package io.github.jhipster.sample.security; diff --git a/src/main/java/io/github/jhipster/sample/service/MailService.java b/src/main/java/io/github/jhipster/sample/service/MailService.java index 4c90cecf3..73cfe1835 100644 --- a/src/main/java/io/github/jhipster/sample/service/MailService.java +++ b/src/main/java/io/github/jhipster/sample/service/MailService.java @@ -1,10 +1,10 @@ package io.github.jhipster.sample.service; import io.github.jhipster.sample.domain.User; -import jakarta.mail.MessagingException; -import jakarta.mail.internet.MimeMessage; import java.nio.charset.StandardCharsets; import java.util.Locale; +import javax.mail.MessagingException; +import javax.mail.internet.MimeMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.MessageSource; @@ -14,7 +14,7 @@ import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.thymeleaf.context.Context; -import org.thymeleaf.spring6.SpringTemplateEngine; +import org.thymeleaf.spring5.SpringTemplateEngine; import tech.jhipster.config.JHipsterProperties; /** diff --git a/src/main/java/io/github/jhipster/sample/service/UserService.java b/src/main/java/io/github/jhipster/sample/service/UserService.java index 6da6914fc..fc7647b4f 100644 --- a/src/main/java/io/github/jhipster/sample/service/UserService.java +++ b/src/main/java/io/github/jhipster/sample/service/UserService.java @@ -211,7 +211,6 @@ public Optional updateUser(AdminUserDTO userDTO) { .filter(Optional::isPresent) .map(Optional::get) .forEach(managedAuthorities::add); - userRepository.save(user); this.clearUserCaches(user); log.debug("Changed Information for User: {}", user); return user; @@ -250,7 +249,6 @@ public void updateUser(String firstName, String lastName, String email, String l } user.setLangKey(langKey); user.setImageUrl(imageUrl); - userRepository.save(user); this.clearUserCaches(user); log.debug("Changed Information for User: {}", user); }); @@ -315,7 +313,7 @@ public void removeNotActivatedUsers() { */ @Transactional(readOnly = true) public List getAuthorities() { - return authorityRepository.findAll().stream().map(Authority::getName).toList(); + return authorityRepository.findAll().stream().map(Authority::getName).collect(Collectors.toList()); } private void clearUserCaches(User user) { diff --git a/src/main/java/io/github/jhipster/sample/service/dto/AdminUserDTO.java b/src/main/java/io/github/jhipster/sample/service/dto/AdminUserDTO.java index 07a686a3e..89f7a0ad4 100644 --- a/src/main/java/io/github/jhipster/sample/service/dto/AdminUserDTO.java +++ b/src/main/java/io/github/jhipster/sample/service/dto/AdminUserDTO.java @@ -3,11 +3,11 @@ import io.github.jhipster.sample.config.Constants; import io.github.jhipster.sample.domain.Authority; import io.github.jhipster.sample.domain.User; -import jakarta.validation.constraints.*; import java.io.Serializable; import java.time.Instant; import java.util.Set; import java.util.stream.Collectors; +import javax.validation.constraints.*; /** * A DTO representing a user, with his authorities. diff --git a/src/main/java/io/github/jhipster/sample/service/dto/package-info.java b/src/main/java/io/github/jhipster/sample/service/dto/package-info.java index 66d446a2d..5df624026 100644 --- a/src/main/java/io/github/jhipster/sample/service/dto/package-info.java +++ b/src/main/java/io/github/jhipster/sample/service/dto/package-info.java @@ -1,4 +1,4 @@ /** - * Data transfer objects for rest mapping. + * Data Transfer Objects. */ package io.github.jhipster.sample.service.dto; diff --git a/src/main/java/io/github/jhipster/sample/service/mapper/UserMapper.java b/src/main/java/io/github/jhipster/sample/service/mapper/UserMapper.java index e35a348a1..1684667e3 100644 --- a/src/main/java/io/github/jhipster/sample/service/mapper/UserMapper.java +++ b/src/main/java/io/github/jhipster/sample/service/mapper/UserMapper.java @@ -21,7 +21,7 @@ public class UserMapper { public List usersToUserDTOs(List users) { - return users.stream().filter(Objects::nonNull).map(this::userToUserDTO).toList(); + return users.stream().filter(Objects::nonNull).map(this::userToUserDTO).collect(Collectors.toList()); } public UserDTO userToUserDTO(User user) { @@ -29,7 +29,7 @@ public UserDTO userToUserDTO(User user) { } public List usersToAdminUserDTOs(List users) { - return users.stream().filter(Objects::nonNull).map(this::userToAdminUserDTO).toList(); + return users.stream().filter(Objects::nonNull).map(this::userToAdminUserDTO).collect(Collectors.toList()); } public AdminUserDTO userToAdminUserDTO(User user) { @@ -37,7 +37,7 @@ public AdminUserDTO userToAdminUserDTO(User user) { } public List userDTOsToUsers(List userDTOs) { - return userDTOs.stream().filter(Objects::nonNull).map(this::userDTOToUser).toList(); + return userDTOs.stream().filter(Objects::nonNull).map(this::userDTOToUser).collect(Collectors.toList()); } public User userDTOToUser(AdminUserDTO userDTO) { diff --git a/src/main/java/io/github/jhipster/sample/service/mapper/package-info.java b/src/main/java/io/github/jhipster/sample/service/mapper/package-info.java index f302380f7..fd3db9331 100644 --- a/src/main/java/io/github/jhipster/sample/service/mapper/package-info.java +++ b/src/main/java/io/github/jhipster/sample/service/mapper/package-info.java @@ -1,4 +1,4 @@ /** - * Data transfer objects mappers. + * MapStruct mappers for mapping domain objects and Data Transfer Objects. */ package io.github.jhipster.sample.service.mapper; diff --git a/src/main/java/io/github/jhipster/sample/service/package-info.java b/src/main/java/io/github/jhipster/sample/service/package-info.java index a4ea907f0..39ae575ae 100644 --- a/src/main/java/io/github/jhipster/sample/service/package-info.java +++ b/src/main/java/io/github/jhipster/sample/service/package-info.java @@ -1,4 +1,4 @@ /** - * Service layer. + * Service layer beans. */ package io.github.jhipster.sample.service; diff --git a/src/main/java/io/github/jhipster/sample/web/filter/SpaWebFilter.java b/src/main/java/io/github/jhipster/sample/web/filter/SpaWebFilter.java deleted file mode 100644 index 1f6f52d37..000000000 --- a/src/main/java/io/github/jhipster/sample/web/filter/SpaWebFilter.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.github.jhipster.sample.web.filter; - -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import java.io.IOException; -import org.springframework.web.filter.OncePerRequestFilter; - -public class SpaWebFilter extends OncePerRequestFilter { - - /** - * Forwards any unmapped paths (except those containing a period) to the client {@code index.html}. - */ - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) - throws ServletException, IOException { - String path = request.getRequestURI(); - if ( - !path.startsWith("/api") && - !path.startsWith("/management") && - !path.startsWith("/v3/api-docs") && - !path.contains(".") && - path.matches("/(.*)") - ) { - request.getRequestDispatcher("/index.html").forward(request, response); - return; - } - - filterChain.doFilter(request, response); - } -} diff --git a/src/main/java/io/github/jhipster/sample/web/filter/package-info.java b/src/main/java/io/github/jhipster/sample/web/filter/package-info.java deleted file mode 100644 index 2ff72f622..000000000 --- a/src/main/java/io/github/jhipster/sample/web/filter/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Request chain filters. - */ -package io.github.jhipster.sample.web.filter; diff --git a/src/main/java/io/github/jhipster/sample/web/rest/AccountResource.java b/src/main/java/io/github/jhipster/sample/web/rest/AccountResource.java index 34ea30586..9ee6857fa 100644 --- a/src/main/java/io/github/jhipster/sample/web/rest/AccountResource.java +++ b/src/main/java/io/github/jhipster/sample/web/rest/AccountResource.java @@ -10,8 +10,9 @@ import io.github.jhipster.sample.web.rest.errors.*; import io.github.jhipster.sample.web.rest.vm.KeyAndPasswordVM; import io.github.jhipster.sample.web.rest.vm.ManagedUserVM; -import jakarta.validation.Valid; import java.util.*; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -78,6 +79,18 @@ public void activateAccount(@RequestParam(value = "key") String key) { } } + /** + * {@code GET /authenticate} : check if the user is authenticated, and return its login. + * + * @param request the HTTP request. + * @return the login if the user is authenticated. + */ + @GetMapping("/authenticate") + public String isAuthenticated(HttpServletRequest request) { + log.debug("REST request to check if the current user is authenticated"); + return request.getRemoteUser(); + } + /** * {@code GET /account} : get the current user. * @@ -105,7 +118,7 @@ public void saveAccount(@Valid @RequestBody AdminUserDTO userDTO) { .getCurrentUserLogin() .orElseThrow(() -> new AccountResourceException("Current user login not found")); Optional existingUser = userRepository.findOneByEmailIgnoreCase(userDTO.getEmail()); - if (existingUser.isPresent() && (!existingUser.orElseThrow().getLogin().equalsIgnoreCase(userLogin))) { + if (existingUser.isPresent() && (!existingUser.get().getLogin().equalsIgnoreCase(userLogin))) { throw new EmailAlreadyUsedException(); } Optional user = userRepository.findOneByLogin(userLogin); @@ -144,7 +157,7 @@ public void changePassword(@RequestBody PasswordChangeDTO passwordChangeDto) { public void requestPasswordReset(@RequestBody String mail) { Optional user = userService.requestPasswordReset(mail); if (user.isPresent()) { - mailService.sendPasswordResetMail(user.orElseThrow()); + mailService.sendPasswordResetMail(user.get()); } else { // Pretend the request has been successful to prevent checking which emails really exist // but log that an invalid attempt has been made diff --git a/src/main/java/io/github/jhipster/sample/web/rest/AuthenticateController.java b/src/main/java/io/github/jhipster/sample/web/rest/AuthenticateController.java deleted file mode 100644 index 6a7d7480c..000000000 --- a/src/main/java/io/github/jhipster/sample/web/rest/AuthenticateController.java +++ /dev/null @@ -1,124 +0,0 @@ -package io.github.jhipster.sample.web.rest; - -import static io.github.jhipster.sample.security.SecurityUtils.AUTHORITIES_KEY; -import static io.github.jhipster.sample.security.SecurityUtils.JWT_ALGORITHM; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.github.jhipster.sample.web.rest.vm.LoginVM; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.validation.Valid; -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.util.stream.Collectors; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.oauth2.jwt.JwsHeader; -import org.springframework.security.oauth2.jwt.JwtClaimsSet; -import org.springframework.security.oauth2.jwt.JwtEncoder; -import org.springframework.security.oauth2.jwt.JwtEncoderParameters; -import org.springframework.web.bind.annotation.*; - -/** - * Controller to authenticate users. - */ -@RestController -@RequestMapping("/api") -public class AuthenticateController { - - private final Logger log = LoggerFactory.getLogger(AuthenticateController.class); - - private final JwtEncoder jwtEncoder; - - @Value("${jhipster.security.authentication.jwt.token-validity-in-seconds:0}") - private long tokenValidityInSeconds; - - @Value("${jhipster.security.authentication.jwt.token-validity-in-seconds-for-remember-me:0}") - private long tokenValidityInSecondsForRememberMe; - - private final AuthenticationManagerBuilder authenticationManagerBuilder; - - public AuthenticateController(JwtEncoder jwtEncoder, AuthenticationManagerBuilder authenticationManagerBuilder) { - this.jwtEncoder = jwtEncoder; - this.authenticationManagerBuilder = authenticationManagerBuilder; - } - - @PostMapping("/authenticate") - public ResponseEntity authorize(@Valid @RequestBody LoginVM loginVM) { - UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( - loginVM.getUsername(), - loginVM.getPassword() - ); - - Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); - SecurityContextHolder.getContext().setAuthentication(authentication); - String jwt = this.createToken(authentication, loginVM.isRememberMe()); - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.setBearerAuth(jwt); - return new ResponseEntity<>(new JWTToken(jwt), httpHeaders, HttpStatus.OK); - } - - /** - * {@code GET /authenticate} : check if the user is authenticated, and return its login. - * - * @param request the HTTP request. - * @return the login if the user is authenticated. - */ - @GetMapping("/authenticate") - public String isAuthenticated(HttpServletRequest request) { - log.debug("REST request to check if the current user is authenticated"); - return request.getRemoteUser(); - } - - public String createToken(Authentication authentication, boolean rememberMe) { - String authorities = authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.joining(" ")); - - Instant now = Instant.now(); - Instant validity; - if (rememberMe) { - validity = now.plus(this.tokenValidityInSecondsForRememberMe, ChronoUnit.SECONDS); - } else { - validity = now.plus(this.tokenValidityInSeconds, ChronoUnit.SECONDS); - } - - // @formatter:off - JwtClaimsSet claims = JwtClaimsSet.builder() - .issuedAt(now) - .expiresAt(validity) - .subject(authentication.getName()) - .claim(AUTHORITIES_KEY, authorities) - .build(); - - JwsHeader jwsHeader = JwsHeader.with(JWT_ALGORITHM).build(); - return this.jwtEncoder.encode(JwtEncoderParameters.from(jwsHeader, claims)).getTokenValue(); - } - - /** - * Object to return as body in JWT Authentication. - */ - static class JWTToken { - - private String idToken; - - JWTToken(String idToken) { - this.idToken = idToken; - } - - @JsonProperty("id_token") - String getIdToken() { - return idToken; - } - - void setIdToken(String idToken) { - this.idToken = idToken; - } - } -} diff --git a/src/main/java/io/github/jhipster/sample/web/rest/BankAccountResource.java b/src/main/java/io/github/jhipster/sample/web/rest/BankAccountResource.java index 2abebfe5b..a83565715 100644 --- a/src/main/java/io/github/jhipster/sample/web/rest/BankAccountResource.java +++ b/src/main/java/io/github/jhipster/sample/web/rest/BankAccountResource.java @@ -3,13 +3,13 @@ import io.github.jhipster.sample.domain.BankAccount; import io.github.jhipster.sample.repository.BankAccountRepository; import io.github.jhipster.sample.web.rest.errors.BadRequestAlertException; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; import java.net.URI; import java.net.URISyntaxException; import java.util.List; import java.util.Objects; import java.util.Optional; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; diff --git a/src/main/java/io/github/jhipster/sample/web/rest/ClientForwardController.java b/src/main/java/io/github/jhipster/sample/web/rest/ClientForwardController.java new file mode 100644 index 000000000..a8f83973d --- /dev/null +++ b/src/main/java/io/github/jhipster/sample/web/rest/ClientForwardController.java @@ -0,0 +1,17 @@ +package io.github.jhipster.sample.web.rest; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +public class ClientForwardController { + + /** + * Forwards any unmapped paths (except those containing a period) to the client {@code index.html}. + * @return forward to client {@code index.html}. + */ + @GetMapping(value = "/**/{path:[^\\.]*}") + public String forward() { + return "forward:/"; + } +} diff --git a/src/main/java/io/github/jhipster/sample/web/rest/LabelResource.java b/src/main/java/io/github/jhipster/sample/web/rest/LabelResource.java index fc761a0fb..f7b5518e3 100644 --- a/src/main/java/io/github/jhipster/sample/web/rest/LabelResource.java +++ b/src/main/java/io/github/jhipster/sample/web/rest/LabelResource.java @@ -3,13 +3,13 @@ import io.github.jhipster.sample.domain.Label; import io.github.jhipster.sample.repository.LabelRepository; import io.github.jhipster.sample.web.rest.errors.BadRequestAlertException; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; import java.net.URI; import java.net.URISyntaxException; import java.util.List; import java.util.Objects; import java.util.Optional; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; diff --git a/src/main/java/io/github/jhipster/sample/web/rest/OperationResource.java b/src/main/java/io/github/jhipster/sample/web/rest/OperationResource.java index 301d00af2..81d033a2a 100644 --- a/src/main/java/io/github/jhipster/sample/web/rest/OperationResource.java +++ b/src/main/java/io/github/jhipster/sample/web/rest/OperationResource.java @@ -3,13 +3,13 @@ import io.github.jhipster.sample.domain.Operation; import io.github.jhipster.sample.repository.OperationRepository; import io.github.jhipster.sample.web.rest.errors.BadRequestAlertException; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; import java.net.URI; import java.net.URISyntaxException; import java.util.List; import java.util.Objects; import java.util.Optional; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; @@ -160,7 +160,7 @@ public ResponseEntity partialUpdateOperation( */ @GetMapping("/operations") public ResponseEntity> getAllOperations( - @org.springdoc.core.annotations.ParameterObject Pageable pageable, + @org.springdoc.api.annotations.ParameterObject Pageable pageable, @RequestParam(required = false, defaultValue = "false") boolean eagerload ) { log.debug("REST request to get a page of Operations"); diff --git a/src/main/java/io/github/jhipster/sample/web/rest/PublicUserResource.java b/src/main/java/io/github/jhipster/sample/web/rest/PublicUserResource.java index 6db110b7f..1e9956f7b 100644 --- a/src/main/java/io/github/jhipster/sample/web/rest/PublicUserResource.java +++ b/src/main/java/io/github/jhipster/sample/web/rest/PublicUserResource.java @@ -39,7 +39,7 @@ public PublicUserResource(UserService userService) { * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body all users. */ @GetMapping("/users") - public ResponseEntity> getAllPublicUsers(@org.springdoc.core.annotations.ParameterObject Pageable pageable) { + public ResponseEntity> getAllPublicUsers(@org.springdoc.api.annotations.ParameterObject Pageable pageable) { log.debug("REST request to get all public User names"); if (!onlyContainsAllowedProperties(pageable)) { return ResponseEntity.badRequest().build(); diff --git a/src/main/java/io/github/jhipster/sample/web/rest/UserJWTController.java b/src/main/java/io/github/jhipster/sample/web/rest/UserJWTController.java new file mode 100644 index 000000000..cdc088c2b --- /dev/null +++ b/src/main/java/io/github/jhipster/sample/web/rest/UserJWTController.java @@ -0,0 +1,68 @@ +package io.github.jhipster.sample.web.rest; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.github.jhipster.sample.security.jwt.JWTFilter; +import io.github.jhipster.sample.security.jwt.TokenProvider; +import io.github.jhipster.sample.web.rest.vm.LoginVM; +import javax.validation.Valid; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.*; + +/** + * Controller to authenticate users. + */ +@RestController +@RequestMapping("/api") +public class UserJWTController { + + private final TokenProvider tokenProvider; + + private final AuthenticationManagerBuilder authenticationManagerBuilder; + + public UserJWTController(TokenProvider tokenProvider, AuthenticationManagerBuilder authenticationManagerBuilder) { + this.tokenProvider = tokenProvider; + this.authenticationManagerBuilder = authenticationManagerBuilder; + } + + @PostMapping("/authenticate") + public ResponseEntity authorize(@Valid @RequestBody LoginVM loginVM) { + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( + loginVM.getUsername(), + loginVM.getPassword() + ); + + Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); + SecurityContextHolder.getContext().setAuthentication(authentication); + String jwt = tokenProvider.createToken(authentication, loginVM.isRememberMe()); + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.add(JWTFilter.AUTHORIZATION_HEADER, "Bearer " + jwt); + return new ResponseEntity<>(new JWTToken(jwt), httpHeaders, HttpStatus.OK); + } + + /** + * Object to return as body in JWT Authentication. + */ + static class JWTToken { + + private String idToken; + + JWTToken(String idToken) { + this.idToken = idToken; + } + + @JsonProperty("id_token") + String getIdToken() { + return idToken; + } + + void setIdToken(String idToken) { + this.idToken = idToken; + } + } +} diff --git a/src/main/java/io/github/jhipster/sample/web/rest/UserResource.java b/src/main/java/io/github/jhipster/sample/web/rest/UserResource.java index c0d3b8187..a6f822d12 100644 --- a/src/main/java/io/github/jhipster/sample/web/rest/UserResource.java +++ b/src/main/java/io/github/jhipster/sample/web/rest/UserResource.java @@ -10,12 +10,12 @@ import io.github.jhipster.sample.web.rest.errors.BadRequestAlertException; import io.github.jhipster.sample.web.rest.errors.EmailAlreadyUsedException; import io.github.jhipster.sample.web.rest.errors.LoginAlreadyUsedException; -import jakarta.validation.Valid; -import jakarta.validation.constraints.Pattern; import java.net.URI; import java.net.URISyntaxException; import java.util.*; import java.util.Collections; +import javax.validation.Valid; +import javax.validation.constraints.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; @@ -140,11 +140,11 @@ public ResponseEntity createUser(@Valid @RequestBody AdminUserDTO userDTO) public ResponseEntity updateUser(@Valid @RequestBody AdminUserDTO userDTO) { log.debug("REST request to update User : {}", userDTO); Optional existingUser = userRepository.findOneByEmailIgnoreCase(userDTO.getEmail()); - if (existingUser.isPresent() && (!existingUser.orElseThrow().getId().equals(userDTO.getId()))) { + if (existingUser.isPresent() && (!existingUser.get().getId().equals(userDTO.getId()))) { throw new EmailAlreadyUsedException(); } existingUser = userRepository.findOneByLogin(userDTO.getLogin().toLowerCase()); - if (existingUser.isPresent() && (!existingUser.orElseThrow().getId().equals(userDTO.getId()))) { + if (existingUser.isPresent() && (!existingUser.get().getId().equals(userDTO.getId()))) { throw new LoginAlreadyUsedException(); } Optional updatedUser = userService.updateUser(userDTO); @@ -163,7 +163,7 @@ public ResponseEntity updateUser(@Valid @RequestBody AdminUserDTO */ @GetMapping("/users") @PreAuthorize("hasAuthority(\"" + AuthoritiesConstants.ADMIN + "\")") - public ResponseEntity> getAllUsers(@org.springdoc.core.annotations.ParameterObject Pageable pageable) { + public ResponseEntity> getAllUsers(@org.springdoc.api.annotations.ParameterObject Pageable pageable) { log.debug("REST request to get all User for an admin"); if (!onlyContainsAllowedProperties(pageable)) { return ResponseEntity.badRequest().build(); diff --git a/src/main/java/io/github/jhipster/sample/web/rest/errors/BadRequestAlertException.java b/src/main/java/io/github/jhipster/sample/web/rest/errors/BadRequestAlertException.java index 1ea059995..6a4cc7ec3 100644 --- a/src/main/java/io/github/jhipster/sample/web/rest/errors/BadRequestAlertException.java +++ b/src/main/java/io/github/jhipster/sample/web/rest/errors/BadRequestAlertException.java @@ -1,13 +1,13 @@ package io.github.jhipster.sample.web.rest.errors; import java.net.URI; -import org.springframework.http.HttpStatus; -import org.springframework.web.ErrorResponseException; -import tech.jhipster.web.rest.errors.ProblemDetailWithCause; -import tech.jhipster.web.rest.errors.ProblemDetailWithCause.ProblemDetailWithCauseBuilder; +import java.util.HashMap; +import java.util.Map; +import org.zalando.problem.AbstractThrowableProblem; +import org.zalando.problem.Status; @SuppressWarnings("java:S110") // Inheritance tree of classes should not be too deep -public class BadRequestAlertException extends ErrorResponseException { +public class BadRequestAlertException extends AbstractThrowableProblem { private static final long serialVersionUID = 1L; @@ -20,18 +20,7 @@ public BadRequestAlertException(String defaultMessage, String entityName, String } public BadRequestAlertException(URI type, String defaultMessage, String entityName, String errorKey) { - super( - HttpStatus.BAD_REQUEST, - ProblemDetailWithCauseBuilder - .instance() - .withStatus(HttpStatus.BAD_REQUEST.value()) - .withType(type) - .withTitle(defaultMessage) - .withProperty("message", "error." + errorKey) - .withProperty("params", entityName) - .build(), - null - ); + super(type, defaultMessage, Status.BAD_REQUEST, null, null, null, getAlertParameters(entityName, errorKey)); this.entityName = entityName; this.errorKey = errorKey; } @@ -44,7 +33,10 @@ public String getErrorKey() { return errorKey; } - public ProblemDetailWithCause getProblemDetailWithCause() { - return (ProblemDetailWithCause) this.getBody(); + private static Map getAlertParameters(String entityName, String errorKey) { + Map parameters = new HashMap<>(); + parameters.put("message", "error." + errorKey); + parameters.put("params", entityName); + return parameters; } } diff --git a/src/main/java/io/github/jhipster/sample/web/rest/errors/ExceptionTranslator.java b/src/main/java/io/github/jhipster/sample/web/rest/errors/ExceptionTranslator.java index c785e4f55..4762f03db 100644 --- a/src/main/java/io/github/jhipster/sample/web/rest/errors/ExceptionTranslator.java +++ b/src/main/java/io/github/jhipster/sample/web/rest/errors/ExceptionTranslator.java @@ -1,39 +1,35 @@ package io.github.jhipster.sample.web.rest.errors; -import static org.springframework.core.annotation.AnnotatedElementUtils.findMergedAnnotation; - -import jakarta.servlet.http.HttpServletRequest; import java.net.URI; import java.util.Arrays; import java.util.Collection; import java.util.List; -import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.env.Environment; import org.springframework.dao.ConcurrencyFailureException; import org.springframework.dao.DataAccessException; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageConversionException; -import org.springframework.lang.Nullable; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.authentication.BadCredentialsException; -import org.springframework.web.ErrorResponse; -import org.springframework.web.ErrorResponseException; +import org.springframework.validation.BindingResult; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.context.request.WebRequest; -import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; +import org.zalando.problem.DefaultProblem; +import org.zalando.problem.Problem; +import org.zalando.problem.ProblemBuilder; +import org.zalando.problem.Status; +import org.zalando.problem.StatusType; +import org.zalando.problem.spring.web.advice.ProblemHandling; +import org.zalando.problem.spring.web.advice.security.SecurityAdviceTrait; +import org.zalando.problem.violations.ConstraintViolationProblem; import tech.jhipster.config.JHipsterConstants; -import tech.jhipster.web.rest.errors.ProblemDetailWithCause; -import tech.jhipster.web.rest.errors.ProblemDetailWithCause.ProblemDetailWithCauseBuilder; import tech.jhipster.web.util.HeaderUtil; /** @@ -41,12 +37,12 @@ * The error response follows RFC7807 - Problem Details for HTTP APIs (https://tools.ietf.org/html/rfc7807). */ @ControllerAdvice -public class ExceptionTranslator extends ResponseEntityExceptionHandler { +public class ExceptionTranslator implements ProblemHandling, SecurityAdviceTrait { private static final String FIELD_ERRORS_KEY = "fieldErrors"; private static final String MESSAGE_KEY = "message"; private static final String PATH_KEY = "path"; - private static final boolean CASUAL_CHAIN_ENABLED = false; + private static final String VIOLATIONS_KEY = "violations"; @Value("${jhipster.clientApp.name}") private String applicationName; @@ -57,96 +53,46 @@ public ExceptionTranslator(Environment env) { this.env = env; } - @ExceptionHandler - public ResponseEntity handleAnyException(Throwable ex, NativeWebRequest request) { - ProblemDetailWithCause pdCause = wrapAndCustomizeProblem(ex, request); - return handleExceptionInternal( - (Exception) ex, - pdCause, - buildHeaders(ex, request), - HttpStatusCode.valueOf(pdCause.getStatus()), - request - ); - } - - @Nullable + /** + * Post-process the Problem payload to add the message key for the front-end if needed. + */ @Override - protected ResponseEntity handleExceptionInternal( - Exception ex, - @Nullable Object body, - HttpHeaders headers, - HttpStatusCode statusCode, - WebRequest request - ) { - body = body == null ? wrapAndCustomizeProblem((Throwable) ex, (NativeWebRequest) request) : body; - return super.handleExceptionInternal(ex, body, headers, statusCode, request); - } - - protected ProblemDetailWithCause wrapAndCustomizeProblem(Throwable ex, NativeWebRequest request) { - return customizeProblem(getProblemDetailWithCause(ex), ex, request); - } - - private ProblemDetailWithCause getProblemDetailWithCause(Throwable ex) { - if ( - ex instanceof io.github.jhipster.sample.service.EmailAlreadyUsedException || - ex instanceof io.github.jhipster.sample.service.UsernameAlreadyUsedException - ) { - // return 201 - CREATED on purpose to not reveal information to potential attackers - // see https://github.com/jhipster/generator-jhipster/issues/21731 - return ProblemDetailWithCauseBuilder.instance().withStatus(201).build(); + public ResponseEntity process(@Nullable ResponseEntity entity, NativeWebRequest request) { + if (entity == null) { + return null; } - if ( - ex instanceof io.github.jhipster.sample.service.InvalidPasswordException - ) return (ProblemDetailWithCause) new InvalidPasswordException().getBody(); - - if ( - ex instanceof ErrorResponseException exp && exp.getBody() instanceof ProblemDetailWithCause - ) return (ProblemDetailWithCause) exp.getBody(); - return ProblemDetailWithCauseBuilder.instance().withStatus(toStatus(ex).value()).build(); - } - - protected ProblemDetailWithCause customizeProblem(ProblemDetailWithCause problem, Throwable err, NativeWebRequest request) { - if (problem.getStatus() <= 0) problem.setStatus(toStatus(err)); - - if (problem.getType() == null || problem.getType().equals(URI.create("about:blank"))) problem.setType(getMappedType(err)); - - // higher precedence to Custom/ResponseStatus types - String title = extractTitle(err, problem.getStatus()); - String problemTitle = problem.getTitle(); - if (problemTitle == null || !problemTitle.equals(title)) { - problem.setTitle(title); + Problem problem = entity.getBody(); + if (!(problem instanceof ConstraintViolationProblem || problem instanceof DefaultProblem)) { + return entity; } - if (problem.getDetail() == null) { - // higher precedence to cause - problem.setDetail(getCustomizedErrorDetails(err)); + HttpServletRequest nativeRequest = request.getNativeRequest(HttpServletRequest.class); + String requestUri = nativeRequest != null ? nativeRequest.getRequestURI() : StringUtils.EMPTY; + ProblemBuilder builder = Problem + .builder() + .withType(Problem.DEFAULT_TYPE.equals(problem.getType()) ? ErrorConstants.DEFAULT_TYPE : problem.getType()) + .withStatus(problem.getStatus()) + .withTitle(problem.getTitle()) + .with(PATH_KEY, requestUri); + + if (problem instanceof ConstraintViolationProblem) { + builder + .with(VIOLATIONS_KEY, ((ConstraintViolationProblem) problem).getViolations()) + .with(MESSAGE_KEY, ErrorConstants.ERR_VALIDATION); + } else { + builder.withCause(((DefaultProblem) problem).getCause()).withDetail(problem.getDetail()).withInstance(problem.getInstance()); + problem.getParameters().forEach(builder::with); + if (!problem.getParameters().containsKey(MESSAGE_KEY) && problem.getStatus() != null) { + builder.with(MESSAGE_KEY, "error.http." + problem.getStatus().getStatusCode()); + } } - - Map problemProperties = problem.getProperties(); - if (problemProperties == null || !problemProperties.containsKey(MESSAGE_KEY)) problem.setProperty( - MESSAGE_KEY, - getMappedMessageKey(err) != null ? getMappedMessageKey(err) : "error.http." + problem.getStatus() - ); - - if (problemProperties == null || !problemProperties.containsKey(PATH_KEY)) problem.setProperty(PATH_KEY, getPathValue(request)); - - if ( - (err instanceof MethodArgumentNotValidException) && - (problemProperties == null || !problemProperties.containsKey(FIELD_ERRORS_KEY)) - ) problem.setProperty(FIELD_ERRORS_KEY, getFieldErrors((MethodArgumentNotValidException) err)); - - problem.setCause(buildCause(err.getCause(), request).orElse(null)); - - return problem; + return new ResponseEntity<>(builder.build(), entity.getHeaders(), entity.getStatusCode()); } - private String extractTitle(Throwable err, int statusCode) { - return getCustomizedTitle(err) != null ? getCustomizedTitle(err) : extractTitleForResponseStatus(err, statusCode); - } - - private List getFieldErrors(MethodArgumentNotValidException ex) { - return ex - .getBindingResult() + @Override + public ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException ex, @Nonnull NativeWebRequest request) { + BindingResult result = ex.getBindingResult(); + List fieldErrors = result .getFieldErrors() .stream() .map(f -> @@ -156,116 +102,121 @@ private List getFieldErrors(MethodArgumentNotValidException ex) { StringUtils.isNotBlank(f.getDefaultMessage()) ? f.getDefaultMessage() : f.getCode() ) ) - .toList(); - } + .collect(Collectors.toList()); - private String extractTitleForResponseStatus(Throwable err, int statusCode) { - ResponseStatus specialStatus = extractResponseStatus(err); - return specialStatus == null ? HttpStatus.valueOf(statusCode).getReasonPhrase() : specialStatus.reason(); + Problem problem = Problem + .builder() + .withType(ErrorConstants.CONSTRAINT_VIOLATION_TYPE) + .withTitle("Method argument not valid") + .withStatus(defaultConstraintViolationStatus()) + .with(MESSAGE_KEY, ErrorConstants.ERR_VALIDATION) + .with(FIELD_ERRORS_KEY, fieldErrors) + .build(); + return create(ex, problem, request); } - private String extractURI(NativeWebRequest request) { - HttpServletRequest nativeRequest = request.getNativeRequest(HttpServletRequest.class); - return nativeRequest != null ? nativeRequest.getRequestURI() : StringUtils.EMPTY; - } - - private HttpStatus toStatus(final Throwable throwable) { - // Let the ErrorResponse take this responsibility - if (throwable instanceof ErrorResponse err) return HttpStatus.valueOf(err.getBody().getStatus()); - - return Optional - .ofNullable(getMappedStatus(throwable)) - .orElse( - Optional.ofNullable(resolveResponseStatus(throwable)).map(ResponseStatus::value).orElse(HttpStatus.INTERNAL_SERVER_ERROR) - ); - } - - private ResponseStatus extractResponseStatus(final Throwable throwable) { - return Optional.ofNullable(resolveResponseStatus(throwable)).orElse(null); + @ExceptionHandler + public ResponseEntity handleEmailAlreadyUsedException( + io.github.jhipster.sample.service.EmailAlreadyUsedException ex, + NativeWebRequest request + ) { + EmailAlreadyUsedException problem = new EmailAlreadyUsedException(); + return create( + problem, + request, + HeaderUtil.createFailureAlert(applicationName, true, problem.getEntityName(), problem.getErrorKey(), problem.getMessage()) + ); } - private ResponseStatus resolveResponseStatus(final Throwable type) { - final ResponseStatus candidate = findMergedAnnotation(type.getClass(), ResponseStatus.class); - return candidate == null && type.getCause() != null ? resolveResponseStatus(type.getCause()) : candidate; + @ExceptionHandler + public ResponseEntity handleUsernameAlreadyUsedException( + io.github.jhipster.sample.service.UsernameAlreadyUsedException ex, + NativeWebRequest request + ) { + LoginAlreadyUsedException problem = new LoginAlreadyUsedException(); + return create( + problem, + request, + HeaderUtil.createFailureAlert(applicationName, true, problem.getEntityName(), problem.getErrorKey(), problem.getMessage()) + ); } - private URI getMappedType(Throwable err) { - if (err instanceof MethodArgumentNotValidException exp) return ErrorConstants.CONSTRAINT_VIOLATION_TYPE; - return ErrorConstants.DEFAULT_TYPE; + @ExceptionHandler + public ResponseEntity handleInvalidPasswordException( + io.github.jhipster.sample.service.InvalidPasswordException ex, + NativeWebRequest request + ) { + return create(new InvalidPasswordException(), request); } - private String getMappedMessageKey(Throwable err) { - if (err instanceof MethodArgumentNotValidException) return ErrorConstants.ERR_VALIDATION; else if ( - err instanceof ConcurrencyFailureException || err.getCause() != null && err.getCause() instanceof ConcurrencyFailureException - ) return ErrorConstants.ERR_CONCURRENCY_FAILURE; - return null; + @ExceptionHandler + public ResponseEntity handleBadRequestAlertException(BadRequestAlertException ex, NativeWebRequest request) { + return create( + ex, + request, + HeaderUtil.createFailureAlert(applicationName, true, ex.getEntityName(), ex.getErrorKey(), ex.getMessage()) + ); } - private String getCustomizedTitle(Throwable err) { - if (err instanceof MethodArgumentNotValidException exp) return "Method argument not valid"; - return null; + @ExceptionHandler + public ResponseEntity handleConcurrencyFailure(ConcurrencyFailureException ex, NativeWebRequest request) { + Problem problem = Problem.builder().withStatus(Status.CONFLICT).with(MESSAGE_KEY, ErrorConstants.ERR_CONCURRENCY_FAILURE).build(); + return create(ex, problem, request); } - private String getCustomizedErrorDetails(Throwable err) { + @Override + public ProblemBuilder prepare(final Throwable throwable, final StatusType status, final URI type) { Collection activeProfiles = Arrays.asList(env.getActiveProfiles()); - if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_PRODUCTION)) { - if (err instanceof HttpMessageConversionException) return "Unable to convert http message"; - if (err instanceof DataAccessException) return "Failure during data access"; - if (containsPackageName(err.getMessage())) return "Unexpected runtime exception"; - } - return err.getCause() != null ? err.getCause().getMessage() : err.getMessage(); - } - - private HttpStatus getMappedStatus(Throwable err) { - // Where we disagree with Spring defaults - if (err instanceof AccessDeniedException) return HttpStatus.FORBIDDEN; - if (err instanceof ConcurrencyFailureException) return HttpStatus.CONFLICT; - if (err instanceof BadCredentialsException) return HttpStatus.UNAUTHORIZED; - return null; - } - - private URI getPathValue(NativeWebRequest request) { - if (request == null) return URI.create("about:blank"); - return URI.create(extractURI(request)); - } - private HttpHeaders buildHeaders(Throwable err, NativeWebRequest request) { - return err instanceof BadRequestAlertException - ? HeaderUtil.createFailureAlert( - applicationName, - true, - ((BadRequestAlertException) err).getEntityName(), - ((BadRequestAlertException) err).getErrorKey(), - ((BadRequestAlertException) err).getMessage() - ) - : null; - } - - public Optional buildCause(final Throwable throwable, NativeWebRequest request) { - if (throwable != null && isCasualChainEnabled()) { - return Optional.of(customizeProblem(getProblemDetailWithCause(throwable), throwable, request)); + if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_PRODUCTION)) { + if (throwable instanceof HttpMessageConversionException) { + return Problem + .builder() + .withType(type) + .withTitle(status.getReasonPhrase()) + .withStatus(status) + .withDetail("Unable to convert http message") + .withCause( + Optional.ofNullable(throwable.getCause()).filter(cause -> isCausalChainsEnabled()).map(this::toProblem).orElse(null) + ); + } + if (throwable instanceof DataAccessException) { + return Problem + .builder() + .withType(type) + .withTitle(status.getReasonPhrase()) + .withStatus(status) + .withDetail("Failure during data access") + .withCause( + Optional.ofNullable(throwable.getCause()).filter(cause -> isCausalChainsEnabled()).map(this::toProblem).orElse(null) + ); + } + if (containsPackageName(throwable.getMessage())) { + return Problem + .builder() + .withType(type) + .withTitle(status.getReasonPhrase()) + .withStatus(status) + .withDetail("Unexpected runtime exception") + .withCause( + Optional.ofNullable(throwable.getCause()).filter(cause -> isCausalChainsEnabled()).map(this::toProblem).orElse(null) + ); + } } - return Optional.ofNullable(null); - } - private boolean isCasualChainEnabled() { - // Customize as per the needs - return CASUAL_CHAIN_ENABLED; + return Problem + .builder() + .withType(type) + .withTitle(status.getReasonPhrase()) + .withStatus(status) + .withDetail(throwable.getMessage()) + .withCause( + Optional.ofNullable(throwable.getCause()).filter(cause -> isCausalChainsEnabled()).map(this::toProblem).orElse(null) + ); } private boolean containsPackageName(String message) { // This list is for sure not complete - return StringUtils.containsAny( - message, - "org.", - "java.", - "net.", - "jakarta.", - "javax.", - "com.", - "io.", - "de.", - "io.github.jhipster.sample" - ); + return StringUtils.containsAny(message, "org.", "java.", "net.", "javax.", "com.", "io.", "de.", "io.github.jhipster.sample"); } } diff --git a/src/main/java/io/github/jhipster/sample/web/rest/errors/InvalidPasswordException.java b/src/main/java/io/github/jhipster/sample/web/rest/errors/InvalidPasswordException.java index ee14dcb5e..f1b35e4f6 100644 --- a/src/main/java/io/github/jhipster/sample/web/rest/errors/InvalidPasswordException.java +++ b/src/main/java/io/github/jhipster/sample/web/rest/errors/InvalidPasswordException.java @@ -1,24 +1,14 @@ package io.github.jhipster.sample.web.rest.errors; -import org.springframework.http.HttpStatus; -import org.springframework.web.ErrorResponseException; -import tech.jhipster.web.rest.errors.ProblemDetailWithCause.ProblemDetailWithCauseBuilder; +import org.zalando.problem.AbstractThrowableProblem; +import org.zalando.problem.Status; @SuppressWarnings("java:S110") // Inheritance tree of classes should not be too deep -public class InvalidPasswordException extends ErrorResponseException { +public class InvalidPasswordException extends AbstractThrowableProblem { private static final long serialVersionUID = 1L; public InvalidPasswordException() { - super( - HttpStatus.BAD_REQUEST, - ProblemDetailWithCauseBuilder - .instance() - .withStatus(HttpStatus.BAD_REQUEST.value()) - .withType(ErrorConstants.INVALID_PASSWORD_TYPE) - .withTitle("Incorrect password") - .build(), - null - ); + super(ErrorConstants.INVALID_PASSWORD_TYPE, "Incorrect password", Status.BAD_REQUEST); } } diff --git a/src/main/java/io/github/jhipster/sample/web/rest/errors/package-info.java b/src/main/java/io/github/jhipster/sample/web/rest/errors/package-info.java index bd857ca1e..14d01d335 100644 --- a/src/main/java/io/github/jhipster/sample/web/rest/errors/package-info.java +++ b/src/main/java/io/github/jhipster/sample/web/rest/errors/package-info.java @@ -1,4 +1,6 @@ /** - * Rest layer error handling. + * Specific errors used with Zalando's "problem-spring-web" library. + * + * More information on https://github.com/zalando/problem-spring-web */ package io.github.jhipster.sample.web.rest.errors; diff --git a/src/main/java/io/github/jhipster/sample/web/rest/package-info.java b/src/main/java/io/github/jhipster/sample/web/rest/package-info.java index 2183fd0c5..6921f39cc 100644 --- a/src/main/java/io/github/jhipster/sample/web/rest/package-info.java +++ b/src/main/java/io/github/jhipster/sample/web/rest/package-info.java @@ -1,4 +1,4 @@ /** - * Rest layer. + * Spring MVC REST controllers. */ package io.github.jhipster.sample.web.rest; diff --git a/src/main/java/io/github/jhipster/sample/web/rest/vm/LoginVM.java b/src/main/java/io/github/jhipster/sample/web/rest/vm/LoginVM.java index 5aa190ca2..e92f17339 100644 --- a/src/main/java/io/github/jhipster/sample/web/rest/vm/LoginVM.java +++ b/src/main/java/io/github/jhipster/sample/web/rest/vm/LoginVM.java @@ -1,7 +1,7 @@ package io.github.jhipster.sample.web.rest.vm; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; /** * View Model object for storing a user's credentials. diff --git a/src/main/java/io/github/jhipster/sample/web/rest/vm/ManagedUserVM.java b/src/main/java/io/github/jhipster/sample/web/rest/vm/ManagedUserVM.java index 94b361358..fb2170ced 100644 --- a/src/main/java/io/github/jhipster/sample/web/rest/vm/ManagedUserVM.java +++ b/src/main/java/io/github/jhipster/sample/web/rest/vm/ManagedUserVM.java @@ -1,7 +1,7 @@ package io.github.jhipster.sample.web.rest.vm; import io.github.jhipster.sample.service.dto.AdminUserDTO; -import jakarta.validation.constraints.Size; +import javax.validation.constraints.Size; /** * View Model extending the AdminUserDTO, which is meant to be used in the user management UI. diff --git a/src/main/java/io/github/jhipster/sample/web/rest/vm/package-info.java b/src/main/java/io/github/jhipster/sample/web/rest/vm/package-info.java index ef70cbc04..258542907 100644 --- a/src/main/java/io/github/jhipster/sample/web/rest/vm/package-info.java +++ b/src/main/java/io/github/jhipster/sample/web/rest/vm/package-info.java @@ -1,4 +1,4 @@ /** - * Rest layer visual models. + * View Models used by Spring MVC REST controllers. */ package io.github.jhipster.sample.web.rest.vm; diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt index 5be7dbe6f..e0bc55aaf 100644 --- a/src/main/resources/banner.txt +++ b/src/main/resources/banner.txt @@ -6,5 +6,5 @@ ${AnsiColor.GREEN}╚██████╔╝${AnsiColor.RED} ██║ ██║ ████████╗ ██║ ██████╔╝ ██║ ████████╗ ██║ ╚██╗ ${AnsiColor.GREEN} ╚═════╝ ${AnsiColor.RED} ╚═╝ ╚═╝ ╚═══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══════╝ ╚═╝ ╚═╝ -${AnsiColor.BRIGHT_BLUE}:: JHipster 🤓 :: Running Spring Boot ${spring-boot.version} :: Startup profile(s) ${spring.profiles.active} :: +${AnsiColor.BRIGHT_BLUE}:: JHipster 🤓 :: Running Spring Boot ${spring-boot.version} :: :: https://www.jhipster.tech ::${AnsiColor.DEFAULT} diff --git a/src/main/resources/config/application-dev.yml b/src/main/resources/config/application-dev.yml index c8fc2c2db..b36f29562 100644 --- a/src/main/resources/config/application-dev.yml +++ b/src/main/resources/config/application-dev.yml @@ -32,7 +32,7 @@ spring: indent-output: true datasource: type: com.zaxxer.hikari.HikariDataSource - url: jdbc:h2:mem:jhipstersampleapplication;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE + url: jdbc:h2:mem:jhipstersampleapplication;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;MODE=LEGACY username: jhipsterSampleApplication password: hikari: @@ -42,6 +42,7 @@ spring: console: # disable spring boot built-in h2-console since we start it manually with correct configuration enabled: false + jpa: liquibase: # Remove 'faker' if you do not want the sample data to be loaded automatically contexts: dev, faker @@ -72,7 +73,7 @@ jhipster: # CORS is only enabled by default with the "dev" profile cors: # Allow Ionic for JHipster by default (* no longer allowed in Spring Boot 2.4+) - allowed-origins: 'http://localhost:8100,https://localhost:8100,http://localhost:9000,https://localhost:9000,http://localhost:4200,https://localhost:4200' + allowed-origins: 'http://localhost:8100,https://localhost:8100,http://localhost:9000,https://localhost:9000,http://localhost:9060,https://localhost:9060' # Enable CORS when running in GitHub Codespaces allowed-origin-patterns: 'https://*.githubpreview.dev' allowed-methods: '*' @@ -96,7 +97,7 @@ jhipster: enabled: false host: localhost port: 5000 - ring-buffer-size: 512 + queue-size: 512 # =================================================================== # Application specific properties # Add your own application properties here, see the ApplicationProperties class diff --git a/src/main/resources/config/application-prod.yml b/src/main/resources/config/application-prod.yml index d61ba8790..e074eae65 100644 --- a/src/main/resources/config/application-prod.yml +++ b/src/main/resources/config/application-prod.yml @@ -20,9 +20,9 @@ logging: io.github.jhipster.sample: INFO management: - prometheus: - metrics: - export: + metrics: + export: + prometheus: enabled: false spring: @@ -39,6 +39,8 @@ spring: hikari: poolName: Hikari auto-commit: false + jpa: + database-platform: tech.jhipster.domain.util.FixedPostgreSQL10Dialect # Replace by 'prod, faker' to add the faker context and have sample data loaded in production liquibase: contexts: prod @@ -96,7 +98,7 @@ jhipster: jwt: # This token must be encoded using Base64 and be at least 256 bits long (you can type `openssl rand -base64 64` on your command line to generate a 512 bits one) # As this is the PRODUCTION configuration, you MUST change the default key, and store it securely: - # - In the Consul configserver + # - In the JHipster Registry (which includes a Spring Cloud Config server) # - In a separate `application-prod.yml` file, in the same folder as your executable JAR file # - In the `JHIPSTER_SECURITY_AUTHENTICATION_JWT_BASE64_SECRET` environment variable base64-secret: bXktc2VjcmV0LWtleS13aGljaC1zaG91bGQtYmUtY2hhbmdlZC1pbi1wcm9kdWN0aW9uLWFuZC1iZS1iYXNlNjQtZW5jb2RlZAo= @@ -111,7 +113,7 @@ jhipster: enabled: false host: localhost port: 5000 - ring-buffer-size: 512 + queue-size: 512 # =================================================================== # Application specific properties # Add your own application properties here, see the ApplicationProperties class diff --git a/src/main/resources/config/application.yml b/src/main/resources/config/application.yml index af5f628de..f5b3593f7 100644 --- a/src/main/resources/config/application.yml +++ b/src/main/resources/config/application.yml @@ -30,18 +30,20 @@ management: base-path: /management exposure: include: - - configprops - - env - - health - - info - - jhimetrics - - jhiopenapigroups - - logfile - - loggers - - prometheus - - threaddump - - caches - - liquibase + [ + 'configprops', + 'env', + 'health', + 'info', + 'jhimetrics', + 'jhiopenapigroups', + 'logfile', + 'loggers', + 'prometheus', + 'threaddump', + 'caches', + 'liquibase', + ] endpoint: health: show-details: when_authorized @@ -63,9 +65,10 @@ management: health: mail: enabled: false # When using the MailService, configure an SMTP server and set this to true - prometheus: - metrics: - export: + metrics: + export: + # Prometheus is the default metrics backend + prometheus: enabled: true step: 60 enable: @@ -111,7 +114,6 @@ spring: open-in-view: false properties: hibernate.jdbc.time_zone: UTC - hibernate.type.preferred_instant_jdbc_type: TIMESTAMP hibernate.id.new_generator_mappings: true hibernate.connection.provider_disables_autocommit: true hibernate.cache.use_second_level_cache: true @@ -126,15 +128,15 @@ spring: hibernate: ddl-auto: none naming: - physical-strategy: org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy + physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy messages: basename: i18n/messages main: allow-bean-definition-overriding: true mvc: - problemdetails: - enabled: true + pathmatch: + matching-strategy: ant_path_matcher task: execution: thread-name-prefix: jhipster-sample-application-task- diff --git a/src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml b/src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml index 5f42c305c..eaac648ea 100644 --- a/src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml +++ b/src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml @@ -78,13 +78,6 @@ - - - + + + + - diff --git a/src/main/resources/config/liquibase/changelog/20150805124838_added_entity_constraints_BankAccount.xml b/src/main/resources/config/liquibase/changelog/20150805124838_added_entity_constraints_BankAccount.xml index e056305c7..65d974331 100644 --- a/src/main/resources/config/liquibase/changelog/20150805124838_added_entity_constraints_BankAccount.xml +++ b/src/main/resources/config/liquibase/changelog/20150805124838_added_entity_constraints_BankAccount.xml @@ -12,7 +12,6 @@ baseTableName="bank_account" constraintName="fk_bank_account__user_id" referencedColumnNames="id" - referencedTableName="jhi_user" - /> + referencedTableName="jhi_user"/> diff --git a/src/main/resources/config/liquibase/changelog/20150805125054_added_entity_constraints_Operation.xml b/src/main/resources/config/liquibase/changelog/20150805125054_added_entity_constraints_Operation.xml index 10b30f87d..118071f7d 100644 --- a/src/main/resources/config/liquibase/changelog/20150805125054_added_entity_constraints_Operation.xml +++ b/src/main/resources/config/liquibase/changelog/20150805125054_added_entity_constraints_Operation.xml @@ -12,21 +12,18 @@ baseTableName="operation" constraintName="fk_operation__bank_account_id" referencedColumnNames="id" - referencedTableName="bank_account" - /> + referencedTableName="bank_account"/> + referencedTableName="operation"/> + referencedTableName="label"/> diff --git a/src/main/resources/config/liquibase/fake-data/bank_account.csv b/src/main/resources/config/liquibase/fake-data/bank_account.csv index def791ca0..8999823f1 100644 --- a/src/main/resources/config/liquibase/fake-data/bank_account.csv +++ b/src/main/resources/config/liquibase/fake-data/bank_account.csv @@ -1,11 +1,11 @@ id;name;balance -1;weber Crew Outdoors;21578 -2;why Cotton Chips;2519 -3;empower Zambia;20374 -4;white male and;27549 -5;Technician salmon;10093 -6;purple;132 -7;quantify;1838 -8;Generic Club sensor;19099 -9;deposit Modern Rock;28312 -10;services Cadmium support;20848 +1;monitor;17676 +2;TCP;39826 +3;Digitized multi-byte;1602 +4;Fantastic Loan Towels;56737 +5;Movies;98235 +6;Savings Implemented;58341 +7;Gorgeous cross-platform non-volatile;34885 +8;Franc Spurs;16567 +9;Borders Uzbekistan;31332 +10;Montana withdrawal HTTP;3173 diff --git a/src/main/resources/config/liquibase/fake-data/label.csv b/src/main/resources/config/liquibase/fake-data/label.csv index 45ecf5365..d21b7313d 100644 --- a/src/main/resources/config/liquibase/fake-data/label.csv +++ b/src/main/resources/config/liquibase/fake-data/label.csv @@ -1,11 +1,11 @@ id;label -1;benchmark mesh -2;virtual feign Liaison -3;digital beard female -4;utilisation -5;Lorenzo yippee cohesive -6;South -7;Baby Sports -8;Oregon Rustic -9;Executive carol -10;East playfully likewise +1;deposit +2;repurpose Secured +3;seize invoice +4;Kip +5;encompassing disintermediate CSS +6;XSS +7;Bedfordshire Small +8;connecting User +9;Michigan +10;Loan Strategist diff --git a/src/main/resources/config/liquibase/fake-data/operation.csv b/src/main/resources/config/liquibase/fake-data/operation.csv index 765c0f2bd..194bd648a 100644 --- a/src/main/resources/config/liquibase/fake-data/operation.csv +++ b/src/main/resources/config/liquibase/fake-data/operation.csv @@ -1,11 +1,11 @@ id;date;description;amount -1;2015-08-04T18:15:20;reprove index Home;12453 -2;2015-08-05T07:09:22;Southwest generate Trafficway;21276 -3;2015-08-04T17:28:20;Diesel;4985 -4;2015-08-04T20:57:35;zowie Account reinvent;30447 -5;2015-08-05T04:28:32;even Flerovium entail;17846 -6;2015-08-05T11:15:56;Applications owlishly East;17911 -7;2015-08-04T15:01:17;Bacon;24187 -8;2015-08-04T16:26:15;Gorgeous;6465 -9;2015-08-05T07:39:33;migration;20416 -10;2015-08-04T17:04:53;atque boohoo indeed;31047 +1;2015-08-05T08:48:38;Mississippi Account Associate;13968 +2;2015-08-05T04:22:04;port innovate Persevering;9517 +3;2015-08-04T15:35:56;Hawaii Sausages connecting;52157 +4;2015-08-04T23:59:53;Optimization Rustic Synergistic;14208 +5;2015-08-04T22:10:39;Card Iowa;77596 +6;2015-08-05T03:47:20;mesh Rhode Automotive;8019 +7;2015-08-05T07:24:14;infrastructures Cambridgeshire GB;67835 +8;2015-08-04T19:16:50;Implemented synthesizing program;18655 +9;2015-08-04T21:34:28;Generic RAM;43990 +10;2015-08-05T07:36:05;Bedfordshire partnerships;13274 diff --git a/src/main/resources/config/liquibase/master.xml b/src/main/resources/config/liquibase/master.xml index f3cf9e743..ac3595a55 100644 --- a/src/main/resources/config/liquibase/master.xml +++ b/src/main/resources/config/liquibase/master.xml @@ -11,8 +11,8 @@ - - + + diff --git a/src/main/resources/config/tls/keystore.p12 b/src/main/resources/config/tls/keystore.p12 index 477f1e76c..abfbe4c35 100644 Binary files a/src/main/resources/config/tls/keystore.p12 and b/src/main/resources/config/tls/keystore.p12 differ diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml index 2bcc7aeec..e81506284 100644 --- a/src/main/resources/logback-spring.xml +++ b/src/main/resources/logback-spring.xml @@ -2,20 +2,25 @@ - + - - + - - + - - + +--> - - - - - - + + + + + @@ -49,25 +53,22 @@ - + + - - - - - - + + true diff --git a/src/main/resources/templates/error.html b/src/main/resources/templates/error.html old mode 100644 new mode 100755 diff --git a/src/main/webapp/app/account/account.route.ts b/src/main/webapp/app/account/account.route.ts deleted file mode 100644 index a1a8b4624..000000000 --- a/src/main/webapp/app/account/account.route.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Routes } from '@angular/router'; - -import activateRoute from './activate/activate.route'; -import passwordRoute from './password/password.route'; -import passwordResetFinishRoute from './password-reset/finish/password-reset-finish.route'; -import passwordResetInitRoute from './password-reset/init/password-reset-init.route'; -import registerRoute from './register/register.route'; -import settingsRoute from './settings/settings.route'; - -const accountRoutes: Routes = [ - activateRoute, - passwordRoute, - passwordResetFinishRoute, - passwordResetInitRoute, - registerRoute, - settingsRoute, -]; - -export default accountRoutes; diff --git a/src/main/webapp/app/account/activate/activate.component.html b/src/main/webapp/app/account/activate/activate.component.html deleted file mode 100644 index 4cd58373b..000000000 --- a/src/main/webapp/app/account/activate/activate.component.html +++ /dev/null @@ -1,16 +0,0 @@ -
-
-
-

Activation

- -
- Your user account has been activated. Please - sign in. -
- -
- Your user could not be activated. Please use the registration form to sign up. -
-
-
-
diff --git a/src/main/webapp/app/account/activate/activate.component.spec.ts b/src/main/webapp/app/account/activate/activate.component.spec.ts deleted file mode 100644 index af9af8890..000000000 --- a/src/main/webapp/app/account/activate/activate.component.spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { TestBed, waitForAsync, tick, fakeAsync, inject } from '@angular/core/testing'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { ActivatedRoute } from '@angular/router'; -import { of, throwError } from 'rxjs'; - -import { ActivateService } from './activate.service'; -import ActivateComponent from './activate.component'; - -describe('ActivateComponent', () => { - let comp: ActivateComponent; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, ActivateComponent], - providers: [ - { - provide: ActivatedRoute, - useValue: { queryParams: of({ key: 'ABC123' }) }, - }, - ], - }) - .overrideTemplate(ActivateComponent, '') - .compileComponents(); - })); - - beforeEach(() => { - const fixture = TestBed.createComponent(ActivateComponent); - comp = fixture.componentInstance; - }); - - it('calls activate.get with the key from params', inject( - [ActivateService], - fakeAsync((service: ActivateService) => { - jest.spyOn(service, 'get').mockReturnValue(of()); - - comp.ngOnInit(); - tick(); - - expect(service.get).toHaveBeenCalledWith('ABC123'); - }) - )); - - it('should set set success to true upon successful activation', inject( - [ActivateService], - fakeAsync((service: ActivateService) => { - jest.spyOn(service, 'get').mockReturnValue(of({})); - - comp.ngOnInit(); - tick(); - - expect(comp.error).toBe(false); - expect(comp.success).toBe(true); - }) - )); - - it('should set set error to true upon activation failure', inject( - [ActivateService], - fakeAsync((service: ActivateService) => { - jest.spyOn(service, 'get').mockReturnValue(throwError('ERROR')); - - comp.ngOnInit(); - tick(); - - expect(comp.error).toBe(true); - expect(comp.success).toBe(false); - }) - )); -}); diff --git a/src/main/webapp/app/account/activate/activate.component.ts b/src/main/webapp/app/account/activate/activate.component.ts deleted file mode 100644 index 933948077..000000000 --- a/src/main/webapp/app/account/activate/activate.component.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute, RouterModule } from '@angular/router'; -import { mergeMap } from 'rxjs/operators'; - -import SharedModule from 'app/shared/shared.module'; -import { ActivateService } from './activate.service'; - -@Component({ - selector: 'jhi-activate', - standalone: true, - imports: [SharedModule, RouterModule], - templateUrl: './activate.component.html', -}) -export default class ActivateComponent implements OnInit { - error = false; - success = false; - - constructor(private activateService: ActivateService, private route: ActivatedRoute) {} - - ngOnInit(): void { - this.route.queryParams.pipe(mergeMap(params => this.activateService.get(params.key))).subscribe({ - next: () => (this.success = true), - error: () => (this.error = true), - }); - } -} diff --git a/src/main/webapp/app/account/activate/activate.route.ts b/src/main/webapp/app/account/activate/activate.route.ts deleted file mode 100644 index 5f602552d..000000000 --- a/src/main/webapp/app/account/activate/activate.route.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Route } from '@angular/router'; - -import ActivateComponent from './activate.component'; - -const activateRoute: Route = { - path: 'activate', - component: ActivateComponent, - title: 'activate.title', -}; - -export default activateRoute; diff --git a/src/main/webapp/app/account/activate/activate.service.spec.ts b/src/main/webapp/app/account/activate/activate.service.spec.ts deleted file mode 100644 index 9acfc7727..000000000 --- a/src/main/webapp/app/account/activate/activate.service.spec.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; - -import { ActivateService } from './activate.service'; -import { ApplicationConfigService } from 'app/core/config/application-config.service'; - -describe('ActivateService Service', () => { - let service: ActivateService; - let httpMock: HttpTestingController; - let applicationConfigService: ApplicationConfigService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - }); - - service = TestBed.inject(ActivateService); - applicationConfigService = TestBed.inject(ApplicationConfigService); - httpMock = TestBed.inject(HttpTestingController); - }); - - afterEach(() => { - httpMock.verify(); - }); - - describe('Service methods', () => { - it('should call api/activate endpoint with correct values', () => { - // GIVEN - let expectedResult; - const key = 'key'; - const value = true; - - // WHEN - service.get(key).subscribe(received => { - expectedResult = received; - }); - const testRequest = httpMock.expectOne({ - method: 'GET', - url: applicationConfigService.getEndpointFor(`api/activate?key=${key}`), - }); - testRequest.flush(value); - - // THEN - expect(expectedResult).toEqual(value); - }); - }); -}); diff --git a/src/main/webapp/app/account/activate/activate.service.ts b/src/main/webapp/app/account/activate/activate.service.ts deleted file mode 100644 index d6969d577..000000000 --- a/src/main/webapp/app/account/activate/activate.service.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient, HttpParams } from '@angular/common/http'; -import { Observable } from 'rxjs'; - -import { ApplicationConfigService } from 'app/core/config/application-config.service'; - -@Injectable({ providedIn: 'root' }) -export class ActivateService { - constructor(private http: HttpClient, private applicationConfigService: ApplicationConfigService) {} - - get(key: string): Observable<{}> { - return this.http.get(this.applicationConfigService.getEndpointFor('api/activate'), { - params: new HttpParams().set('key', key), - }); - } -} diff --git a/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.html b/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.html deleted file mode 100644 index 493ef8f9f..000000000 --- a/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.html +++ /dev/null @@ -1,137 +0,0 @@ -
-
-
-

Reset password

- -
- The reset key is missing. -
- -
- Choose a new password -
- -
- Your password couldn't be reset. Remember a password request is only valid for 24 hours. -
- -
- Your password has been reset. Please - sign in. -
- -
- The password and its confirmation do not match! -
- -
-
-
- - - -
- - Your password is required. - - - - Your password is required to be at least 4 characters. - - - - Your password cannot be longer than 50 characters. - -
- - -
- -
- - - -
- - Your confirmation password is required. - - - - Your confirmation password is required to be at least 4 characters. - - - - Your confirmation password cannot be longer than 50 characters. - -
-
- - -
-
-
-
-
diff --git a/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.spec.ts b/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.spec.ts deleted file mode 100644 index bbef2da80..000000000 --- a/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.spec.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { ElementRef } from '@angular/core'; -import { ComponentFixture, TestBed, inject, tick, fakeAsync } from '@angular/core/testing'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { FormBuilder } from '@angular/forms'; -import { ActivatedRoute } from '@angular/router'; -import { of, throwError } from 'rxjs'; - -import PasswordResetFinishComponent from './password-reset-finish.component'; -import { PasswordResetFinishService } from './password-reset-finish.service'; - -describe('PasswordResetFinishComponent', () => { - let fixture: ComponentFixture; - let comp: PasswordResetFinishComponent; - - beforeEach(() => { - fixture = TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, PasswordResetFinishComponent], - providers: [ - FormBuilder, - { - provide: ActivatedRoute, - useValue: { queryParams: of({ key: 'XYZPDQ' }) }, - }, - ], - }) - .overrideTemplate(PasswordResetFinishComponent, '') - .createComponent(PasswordResetFinishComponent); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PasswordResetFinishComponent); - comp = fixture.componentInstance; - comp.ngOnInit(); - }); - - it('should define its initial state', () => { - expect(comp.initialized).toBe(true); - expect(comp.key).toEqual('XYZPDQ'); - }); - - it('sets focus after the view has been initialized', () => { - const node = { - focus: jest.fn(), - }; - comp.newPassword = new ElementRef(node); - - comp.ngAfterViewInit(); - - expect(node.focus).toHaveBeenCalled(); - }); - - it('should ensure the two passwords entered match', () => { - comp.passwordForm.patchValue({ - newPassword: 'password', - confirmPassword: 'non-matching', - }); - - comp.finishReset(); - - expect(comp.doNotMatch).toBe(true); - }); - - it('should update success to true after resetting password', inject( - [PasswordResetFinishService], - fakeAsync((service: PasswordResetFinishService) => { - jest.spyOn(service, 'save').mockReturnValue(of({})); - comp.passwordForm.patchValue({ - newPassword: 'password', - confirmPassword: 'password', - }); - - comp.finishReset(); - tick(); - - expect(service.save).toHaveBeenCalledWith('XYZPDQ', 'password'); - expect(comp.success).toBe(true); - }) - )); - - it('should notify of generic error', inject( - [PasswordResetFinishService], - fakeAsync((service: PasswordResetFinishService) => { - jest.spyOn(service, 'save').mockReturnValue(throwError('ERROR')); - comp.passwordForm.patchValue({ - newPassword: 'password', - confirmPassword: 'password', - }); - - comp.finishReset(); - tick(); - - expect(service.save).toHaveBeenCalledWith('XYZPDQ', 'password'); - expect(comp.success).toBe(false); - expect(comp.error).toBe(true); - }) - )); -}); diff --git a/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.ts b/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.ts deleted file mode 100644 index 8a2c7eabc..000000000 --- a/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { Component, OnInit, AfterViewInit, ElementRef, ViewChild } from '@angular/core'; -import { FormGroup, FormControl, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { ActivatedRoute, RouterModule } from '@angular/router'; -import PasswordStrengthBarComponent from 'app/account/password/password-strength-bar/password-strength-bar.component'; -import SharedModule from 'app/shared/shared.module'; - -import { PasswordResetFinishService } from './password-reset-finish.service'; - -@Component({ - selector: 'jhi-password-reset-finish', - standalone: true, - imports: [SharedModule, RouterModule, FormsModule, ReactiveFormsModule, PasswordStrengthBarComponent], - templateUrl: './password-reset-finish.component.html', -}) -export default class PasswordResetFinishComponent implements OnInit, AfterViewInit { - @ViewChild('newPassword', { static: false }) - newPassword?: ElementRef; - - initialized = false; - doNotMatch = false; - error = false; - success = false; - key = ''; - - passwordForm = new FormGroup({ - newPassword: new FormControl('', { - nonNullable: true, - validators: [Validators.required, Validators.minLength(4), Validators.maxLength(50)], - }), - confirmPassword: new FormControl('', { - nonNullable: true, - validators: [Validators.required, Validators.minLength(4), Validators.maxLength(50)], - }), - }); - - constructor(private passwordResetFinishService: PasswordResetFinishService, private route: ActivatedRoute) {} - - ngOnInit(): void { - this.route.queryParams.subscribe(params => { - if (params['key']) { - this.key = params['key']; - } - this.initialized = true; - }); - } - - ngAfterViewInit(): void { - if (this.newPassword) { - this.newPassword.nativeElement.focus(); - } - } - - finishReset(): void { - this.doNotMatch = false; - this.error = false; - - const { newPassword, confirmPassword } = this.passwordForm.getRawValue(); - - if (newPassword !== confirmPassword) { - this.doNotMatch = true; - } else { - this.passwordResetFinishService.save(this.key, newPassword).subscribe({ - next: () => (this.success = true), - error: () => (this.error = true), - }); - } - } -} diff --git a/src/main/webapp/app/account/password-reset/finish/password-reset-finish.route.ts b/src/main/webapp/app/account/password-reset/finish/password-reset-finish.route.ts deleted file mode 100644 index 2963d150d..000000000 --- a/src/main/webapp/app/account/password-reset/finish/password-reset-finish.route.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Route } from '@angular/router'; - -import PasswordResetFinishComponent from './password-reset-finish.component'; - -const passwordResetFinishRoute: Route = { - path: 'reset/finish', - component: PasswordResetFinishComponent, - title: 'global.menu.account.password', -}; - -export default passwordResetFinishRoute; diff --git a/src/main/webapp/app/account/password-reset/finish/password-reset-finish.service.spec.ts b/src/main/webapp/app/account/password-reset/finish/password-reset-finish.service.spec.ts deleted file mode 100644 index fbc815700..000000000 --- a/src/main/webapp/app/account/password-reset/finish/password-reset-finish.service.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; - -import { PasswordResetFinishService } from './password-reset-finish.service'; -import { ApplicationConfigService } from 'app/core/config/application-config.service'; - -describe('PasswordResetFinish Service', () => { - let service: PasswordResetFinishService; - let httpMock: HttpTestingController; - let applicationConfigService: ApplicationConfigService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - }); - - service = TestBed.inject(PasswordResetFinishService); - applicationConfigService = TestBed.inject(ApplicationConfigService); - httpMock = TestBed.inject(HttpTestingController); - }); - - afterEach(() => { - httpMock.verify(); - }); - - describe('Service methods', () => { - it('should call reset-password/finish endpoint with correct values', () => { - // GIVEN - const key = 'abc'; - const newPassword = 'password'; - - // WHEN - service.save(key, newPassword).subscribe(); - - const testRequest = httpMock.expectOne({ - method: 'POST', - url: applicationConfigService.getEndpointFor('api/account/reset-password/finish'), - }); - - // THEN - expect(testRequest.request.body).toEqual({ key, newPassword }); - }); - }); -}); diff --git a/src/main/webapp/app/account/password-reset/finish/password-reset-finish.service.ts b/src/main/webapp/app/account/password-reset/finish/password-reset-finish.service.ts deleted file mode 100644 index 1dff3243e..000000000 --- a/src/main/webapp/app/account/password-reset/finish/password-reset-finish.service.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { Observable } from 'rxjs'; - -import { ApplicationConfigService } from 'app/core/config/application-config.service'; - -@Injectable({ providedIn: 'root' }) -export class PasswordResetFinishService { - constructor(private http: HttpClient, private applicationConfigService: ApplicationConfigService) {} - - save(key: string, newPassword: string): Observable<{}> { - return this.http.post(this.applicationConfigService.getEndpointFor('api/account/reset-password/finish'), { key, newPassword }); - } -} diff --git a/src/main/webapp/app/account/password-reset/init/password-reset-init.component.html b/src/main/webapp/app/account/password-reset/init/password-reset-init.component.html deleted file mode 100644 index 301a96e96..000000000 --- a/src/main/webapp/app/account/password-reset/init/password-reset-init.component.html +++ /dev/null @@ -1,81 +0,0 @@ -
-
-
-

Reset your password

- - - -
- Enter the email address you used to register -
- -
- Check your emails for details on how to reset your password. -
- -
-
- - - -
- - Your email is required. - - - - Your email is invalid. - - - - Your email is required to be at least 5 characters. - - - - Your email cannot be longer than 50 characters. - -
-
- - -
-
-
-
diff --git a/src/main/webapp/app/account/password-reset/init/password-reset-init.component.spec.ts b/src/main/webapp/app/account/password-reset/init/password-reset-init.component.spec.ts deleted file mode 100644 index 3d3e90ef4..000000000 --- a/src/main/webapp/app/account/password-reset/init/password-reset-init.component.spec.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { ElementRef } from '@angular/core'; -import { ComponentFixture, TestBed, inject } from '@angular/core/testing'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { FormBuilder } from '@angular/forms'; -import { of, throwError } from 'rxjs'; - -import PasswordResetInitComponent from './password-reset-init.component'; -import { PasswordResetInitService } from './password-reset-init.service'; - -describe('PasswordResetInitComponent', () => { - let fixture: ComponentFixture; - let comp: PasswordResetInitComponent; - - beforeEach(() => { - fixture = TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, PasswordResetInitComponent], - providers: [FormBuilder], - }) - .overrideTemplate(PasswordResetInitComponent, '') - .createComponent(PasswordResetInitComponent); - comp = fixture.componentInstance; - }); - - it('sets focus after the view has been initialized', () => { - const node = { - focus: jest.fn(), - }; - comp.email = new ElementRef(node); - - comp.ngAfterViewInit(); - - expect(node.focus).toHaveBeenCalled(); - }); - - it('notifies of success upon successful requestReset', inject([PasswordResetInitService], (service: PasswordResetInitService) => { - jest.spyOn(service, 'save').mockReturnValue(of({})); - comp.resetRequestForm.patchValue({ - email: 'user@domain.com', - }); - - comp.requestReset(); - - expect(service.save).toHaveBeenCalledWith('user@domain.com'); - expect(comp.success).toBe(true); - })); - - it('no notification of success upon error response', inject([PasswordResetInitService], (service: PasswordResetInitService) => { - jest.spyOn(service, 'save').mockReturnValue( - throwError({ - status: 503, - data: 'something else', - }) - ); - comp.resetRequestForm.patchValue({ - email: 'user@domain.com', - }); - comp.requestReset(); - - expect(service.save).toHaveBeenCalledWith('user@domain.com'); - expect(comp.success).toBe(false); - })); -}); diff --git a/src/main/webapp/app/account/password-reset/init/password-reset-init.component.ts b/src/main/webapp/app/account/password-reset/init/password-reset-init.component.ts deleted file mode 100644 index b68b90125..000000000 --- a/src/main/webapp/app/account/password-reset/init/password-reset-init.component.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Component, AfterViewInit, ElementRef, ViewChild } from '@angular/core'; -import { FormBuilder, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'; -import SharedModule from 'app/shared/shared.module'; - -import { PasswordResetInitService } from './password-reset-init.service'; - -@Component({ - selector: 'jhi-password-reset-init', - standalone: true, - imports: [SharedModule, FormsModule, ReactiveFormsModule], - templateUrl: './password-reset-init.component.html', -}) -export default class PasswordResetInitComponent implements AfterViewInit { - @ViewChild('email', { static: false }) - email?: ElementRef; - - success = false; - resetRequestForm = this.fb.group({ - email: ['', [Validators.required, Validators.minLength(5), Validators.maxLength(254), Validators.email]], - }); - - constructor(private passwordResetInitService: PasswordResetInitService, private fb: FormBuilder) {} - - ngAfterViewInit(): void { - if (this.email) { - this.email.nativeElement.focus(); - } - } - - requestReset(): void { - this.passwordResetInitService.save(this.resetRequestForm.get(['email'])!.value).subscribe(() => (this.success = true)); - } -} diff --git a/src/main/webapp/app/account/password-reset/init/password-reset-init.route.ts b/src/main/webapp/app/account/password-reset/init/password-reset-init.route.ts deleted file mode 100644 index 654634bec..000000000 --- a/src/main/webapp/app/account/password-reset/init/password-reset-init.route.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Route } from '@angular/router'; - -import PasswordResetInitComponent from './password-reset-init.component'; - -const passwordResetInitRoute: Route = { - path: 'reset/request', - component: PasswordResetInitComponent, - title: 'global.menu.account.password', -}; - -export default passwordResetInitRoute; diff --git a/src/main/webapp/app/account/password-reset/init/password-reset-init.service.spec.ts b/src/main/webapp/app/account/password-reset/init/password-reset-init.service.spec.ts deleted file mode 100644 index bb0995e63..000000000 --- a/src/main/webapp/app/account/password-reset/init/password-reset-init.service.spec.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; - -import { PasswordResetInitService } from './password-reset-init.service'; -import { ApplicationConfigService } from 'app/core/config/application-config.service'; - -describe('PasswordResetInit Service', () => { - let service: PasswordResetInitService; - let httpMock: HttpTestingController; - let applicationConfigService: ApplicationConfigService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - }); - - service = TestBed.inject(PasswordResetInitService); - applicationConfigService = TestBed.inject(ApplicationConfigService); - httpMock = TestBed.inject(HttpTestingController); - }); - - afterEach(() => { - httpMock.verify(); - }); - - describe('Service methods', () => { - it('should call reset-password/init endpoint with correct values', () => { - // GIVEN - const mail = 'test@test.com'; - - // WHEN - service.save(mail).subscribe(); - - const testRequest = httpMock.expectOne({ - method: 'POST', - url: applicationConfigService.getEndpointFor('api/account/reset-password/init'), - }); - - // THEN - expect(testRequest.request.body).toEqual(mail); - }); - }); -}); diff --git a/src/main/webapp/app/account/password-reset/init/password-reset-init.service.ts b/src/main/webapp/app/account/password-reset/init/password-reset-init.service.ts deleted file mode 100644 index 8ff05e078..000000000 --- a/src/main/webapp/app/account/password-reset/init/password-reset-init.service.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { Observable } from 'rxjs'; - -import { ApplicationConfigService } from 'app/core/config/application-config.service'; - -@Injectable({ providedIn: 'root' }) -export class PasswordResetInitService { - constructor(private http: HttpClient, private applicationConfigService: ApplicationConfigService) {} - - save(mail: string): Observable<{}> { - return this.http.post(this.applicationConfigService.getEndpointFor('api/account/reset-password/init'), mail); - } -} diff --git a/src/main/webapp/app/account/password/password-strength-bar/password-strength-bar.component.html b/src/main/webapp/app/account/password/password-strength-bar/password-strength-bar.component.html deleted file mode 100644 index 244da088f..000000000 --- a/src/main/webapp/app/account/password/password-strength-bar/password-strength-bar.component.html +++ /dev/null @@ -1,10 +0,0 @@ -
- Password strength: -
    -
  • -
  • -
  • -
  • -
  • -
-
diff --git a/src/main/webapp/app/account/password/password-strength-bar/password-strength-bar.component.scss b/src/main/webapp/app/account/password/password-strength-bar/password-strength-bar.component.scss deleted file mode 100644 index 67ce4687a..000000000 --- a/src/main/webapp/app/account/password/password-strength-bar/password-strength-bar.component.scss +++ /dev/null @@ -1,23 +0,0 @@ -/* ========================================================================== -start Password strength bar style -========================================================================== */ -ul#strength { - display: inline; - list-style: none; - margin: 0; - margin-left: 15px; - padding: 0; - vertical-align: 2px; -} - -.point { - background: #ddd; - border-radius: 2px; - display: inline-block; - height: 5px; - margin-right: 1px; - width: 20px; - &:last-child { - margin: 0 !important; - } -} diff --git a/src/main/webapp/app/account/password/password-strength-bar/password-strength-bar.component.spec.ts b/src/main/webapp/app/account/password/password-strength-bar/password-strength-bar.component.spec.ts deleted file mode 100644 index 9fd533a7f..000000000 --- a/src/main/webapp/app/account/password/password-strength-bar/password-strength-bar.component.spec.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; - -import PasswordStrengthBarComponent from './password-strength-bar.component'; - -describe('PasswordStrengthBarComponent', () => { - let comp: PasswordStrengthBarComponent; - let fixture: ComponentFixture; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [PasswordStrengthBarComponent], - }) - .overrideTemplate(PasswordStrengthBarComponent, '') - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(PasswordStrengthBarComponent); - comp = fixture.componentInstance; - }); - - describe('PasswordStrengthBarComponents', () => { - it('should initialize with default values', () => { - expect(comp.measureStrength('')).toBe(0); - expect(comp.colors).toEqual(['#F00', '#F90', '#FF0', '#9F0', '#0F0']); - expect(comp.getColor(0).idx).toBe(1); - expect(comp.getColor(0).color).toBe(comp.colors[0]); - }); - - it('should increase strength upon password value change', () => { - expect(comp.measureStrength('')).toBe(0); - expect(comp.measureStrength('aa')).toBeGreaterThanOrEqual(comp.measureStrength('')); - expect(comp.measureStrength('aa^6')).toBeGreaterThanOrEqual(comp.measureStrength('aa')); - expect(comp.measureStrength('Aa090(**)')).toBeGreaterThanOrEqual(comp.measureStrength('aa^6')); - expect(comp.measureStrength('Aa090(**)+-07365')).toBeGreaterThanOrEqual(comp.measureStrength('Aa090(**)')); - }); - - it('should change the color based on strength', () => { - expect(comp.getColor(0).color).toBe(comp.colors[0]); - expect(comp.getColor(11).color).toBe(comp.colors[1]); - expect(comp.getColor(22).color).toBe(comp.colors[2]); - expect(comp.getColor(33).color).toBe(comp.colors[3]); - expect(comp.getColor(44).color).toBe(comp.colors[4]); - }); - }); -}); diff --git a/src/main/webapp/app/account/password/password-strength-bar/password-strength-bar.component.ts b/src/main/webapp/app/account/password/password-strength-bar/password-strength-bar.component.ts deleted file mode 100644 index d15d9d3fc..000000000 --- a/src/main/webapp/app/account/password/password-strength-bar/password-strength-bar.component.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { Component, ElementRef, Input, Renderer2 } from '@angular/core'; - -import SharedModule from 'app/shared/shared.module'; - -@Component({ - selector: 'jhi-password-strength-bar', - standalone: true, - imports: [SharedModule], - templateUrl: './password-strength-bar.component.html', - styleUrls: ['./password-strength-bar.component.scss'], -}) -export default class PasswordStrengthBarComponent { - colors = ['#F00', '#F90', '#FF0', '#9F0', '#0F0']; - - constructor(private renderer: Renderer2, private elementRef: ElementRef) {} - - measureStrength(p: string): number { - let force = 0; - const regex = /[$-/:-?{-~!"^_`[\]]/g; // " - const lowerLetters = /[a-z]+/.test(p); - const upperLetters = /[A-Z]+/.test(p); - const numbers = /\d+/.test(p); - const symbols = regex.test(p); - - const flags = [lowerLetters, upperLetters, numbers, symbols]; - const passedMatches = flags.filter((isMatchedFlag: boolean) => isMatchedFlag === true).length; - - force += 2 * p.length + (p.length >= 10 ? 1 : 0); - force += passedMatches * 10; - - // penalty (short password) - force = p.length <= 6 ? Math.min(force, 10) : force; - - // penalty (poor variety of characters) - force = passedMatches === 1 ? Math.min(force, 10) : force; - force = passedMatches === 2 ? Math.min(force, 20) : force; - force = passedMatches === 3 ? Math.min(force, 40) : force; - - return force; - } - - getColor(s: number): { idx: number; color: string } { - let idx = 0; - if (s > 10) { - if (s <= 20) { - idx = 1; - } else if (s <= 30) { - idx = 2; - } else if (s <= 40) { - idx = 3; - } else { - idx = 4; - } - } - return { idx: idx + 1, color: this.colors[idx] }; - } - - @Input() - set passwordToCheck(password: string) { - if (password) { - const c = this.getColor(this.measureStrength(password)); - const element = this.elementRef.nativeElement; - if (element.className) { - this.renderer.removeClass(element, element.className); - } - const lis = element.getElementsByTagName('li'); - for (let i = 0; i < lis.length; i++) { - if (i < c.idx) { - this.renderer.setStyle(lis[i], 'backgroundColor', c.color); - } else { - this.renderer.setStyle(lis[i], 'backgroundColor', '#DDD'); - } - } - } - } -} diff --git a/src/main/webapp/app/account/password/password.component.html b/src/main/webapp/app/account/password/password.component.html deleted file mode 100644 index 6584df72b..000000000 --- a/src/main/webapp/app/account/password/password.component.html +++ /dev/null @@ -1,152 +0,0 @@ -
-
-
-

- Password for [{{ account.login }}] -

- -
- Password changed! -
- -
- An error has occurred! The password could not be changed. -
- -
- The password and its confirmation do not match! -
- -
-
- - - -
- - Your password is required. - -
-
- -
- - - -
- - Your password is required. - - - - Your password is required to be at least 4 characters. - - - - Your password cannot be longer than 50 characters. - -
- - -
- -
- - - -
- - Your confirmation password is required. - - - - Your confirmation password is required to be at least 4 characters. - - - - Your confirmation password cannot be longer than 50 characters. - -
-
- - -
-
-
-
diff --git a/src/main/webapp/app/account/password/password.component.spec.ts b/src/main/webapp/app/account/password/password.component.spec.ts deleted file mode 100644 index 50cd6c056..000000000 --- a/src/main/webapp/app/account/password/password.component.spec.ts +++ /dev/null @@ -1,103 +0,0 @@ -jest.mock('app/core/auth/account.service'); - -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { HttpResponse } from '@angular/common/http'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { FormBuilder } from '@angular/forms'; -import { of, throwError } from 'rxjs'; - -import { AccountService } from 'app/core/auth/account.service'; - -import PasswordComponent from './password.component'; -import { PasswordService } from './password.service'; - -describe('PasswordComponent', () => { - let comp: PasswordComponent; - let fixture: ComponentFixture; - let service: PasswordService; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, PasswordComponent], - providers: [FormBuilder, AccountService], - }) - .overrideTemplate(PasswordComponent, '') - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(PasswordComponent); - comp = fixture.componentInstance; - service = TestBed.inject(PasswordService); - }); - - it('should show error if passwords do not match', () => { - // GIVEN - comp.passwordForm.patchValue({ - newPassword: 'password1', - confirmPassword: 'password2', - }); - // WHEN - comp.changePassword(); - // THEN - expect(comp.doNotMatch).toBe(true); - expect(comp.error).toBe(false); - expect(comp.success).toBe(false); - }); - - it('should call Auth.changePassword when passwords match', () => { - // GIVEN - const passwordValues = { - currentPassword: 'oldPassword', - newPassword: 'myPassword', - }; - - jest.spyOn(service, 'save').mockReturnValue(of(new HttpResponse({ body: true }))); - - comp.passwordForm.patchValue({ - currentPassword: passwordValues.currentPassword, - newPassword: passwordValues.newPassword, - confirmPassword: passwordValues.newPassword, - }); - - // WHEN - comp.changePassword(); - - // THEN - expect(service.save).toHaveBeenCalledWith(passwordValues.newPassword, passwordValues.currentPassword); - }); - - it('should set success to true upon success', () => { - // GIVEN - jest.spyOn(service, 'save').mockReturnValue(of(new HttpResponse({ body: true }))); - comp.passwordForm.patchValue({ - newPassword: 'myPassword', - confirmPassword: 'myPassword', - }); - - // WHEN - comp.changePassword(); - - // THEN - expect(comp.doNotMatch).toBe(false); - expect(comp.error).toBe(false); - expect(comp.success).toBe(true); - }); - - it('should notify of error if change password fails', () => { - // GIVEN - jest.spyOn(service, 'save').mockReturnValue(throwError('ERROR')); - comp.passwordForm.patchValue({ - newPassword: 'myPassword', - confirmPassword: 'myPassword', - }); - - // WHEN - comp.changePassword(); - - // THEN - expect(comp.doNotMatch).toBe(false); - expect(comp.success).toBe(false); - expect(comp.error).toBe(true); - }); -}); diff --git a/src/main/webapp/app/account/password/password.component.ts b/src/main/webapp/app/account/password/password.component.ts deleted file mode 100644 index ef21a9546..000000000 --- a/src/main/webapp/app/account/password/password.component.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { FormGroup, FormControl, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { Observable } from 'rxjs'; - -import SharedModule from 'app/shared/shared.module'; -import { AccountService } from 'app/core/auth/account.service'; -import { Account } from 'app/core/auth/account.model'; -import { PasswordService } from './password.service'; -import PasswordStrengthBarComponent from './password-strength-bar/password-strength-bar.component'; - -@Component({ - selector: 'jhi-password', - standalone: true, - imports: [SharedModule, FormsModule, ReactiveFormsModule, PasswordStrengthBarComponent], - templateUrl: './password.component.html', -}) -export default class PasswordComponent implements OnInit { - doNotMatch = false; - error = false; - success = false; - account$?: Observable; - passwordForm = new FormGroup({ - currentPassword: new FormControl('', { nonNullable: true, validators: Validators.required }), - newPassword: new FormControl('', { - nonNullable: true, - validators: [Validators.required, Validators.minLength(4), Validators.maxLength(50)], - }), - confirmPassword: new FormControl('', { - nonNullable: true, - validators: [Validators.required, Validators.minLength(4), Validators.maxLength(50)], - }), - }); - - constructor(private passwordService: PasswordService, private accountService: AccountService) {} - - ngOnInit(): void { - this.account$ = this.accountService.identity(); - } - - changePassword(): void { - this.error = false; - this.success = false; - this.doNotMatch = false; - - const { newPassword, confirmPassword, currentPassword } = this.passwordForm.getRawValue(); - if (newPassword !== confirmPassword) { - this.doNotMatch = true; - } else { - this.passwordService.save(newPassword, currentPassword).subscribe({ - next: () => (this.success = true), - error: () => (this.error = true), - }); - } - } -} diff --git a/src/main/webapp/app/account/password/password.route.ts b/src/main/webapp/app/account/password/password.route.ts deleted file mode 100644 index 96faba98e..000000000 --- a/src/main/webapp/app/account/password/password.route.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Route } from '@angular/router'; - -import { UserRouteAccessService } from 'app/core/auth/user-route-access.service'; -import PasswordComponent from './password.component'; - -const passwordRoute: Route = { - path: 'password', - component: PasswordComponent, - title: 'global.menu.account.password', - canActivate: [UserRouteAccessService], -}; - -export default passwordRoute; diff --git a/src/main/webapp/app/account/password/password.service.spec.ts b/src/main/webapp/app/account/password/password.service.spec.ts deleted file mode 100644 index e0d1536f5..000000000 --- a/src/main/webapp/app/account/password/password.service.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; - -import { PasswordService } from './password.service'; -import { ApplicationConfigService } from 'app/core/config/application-config.service'; - -describe('Password Service', () => { - let service: PasswordService; - let httpMock: HttpTestingController; - let applicationConfigService: ApplicationConfigService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - }); - - service = TestBed.inject(PasswordService); - applicationConfigService = TestBed.inject(ApplicationConfigService); - httpMock = TestBed.inject(HttpTestingController); - }); - - afterEach(() => { - httpMock.verify(); - }); - - describe('Service methods', () => { - it('should call change-password endpoint with correct values', () => { - // GIVEN - const password1 = 'password1'; - const password2 = 'password2'; - - // WHEN - service.save(password2, password1).subscribe(); - - const testRequest = httpMock.expectOne({ - method: 'POST', - url: applicationConfigService.getEndpointFor('api/account/change-password'), - }); - - // THEN - expect(testRequest.request.body).toEqual({ currentPassword: password1, newPassword: password2 }); - }); - }); -}); diff --git a/src/main/webapp/app/account/password/password.service.ts b/src/main/webapp/app/account/password/password.service.ts deleted file mode 100644 index 337a64fbc..000000000 --- a/src/main/webapp/app/account/password/password.service.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { Observable } from 'rxjs'; - -import { ApplicationConfigService } from 'app/core/config/application-config.service'; - -@Injectable({ providedIn: 'root' }) -export class PasswordService { - constructor(private http: HttpClient, private applicationConfigService: ApplicationConfigService) {} - - save(newPassword: string, currentPassword: string): Observable<{}> { - return this.http.post(this.applicationConfigService.getEndpointFor('api/account/change-password'), { currentPassword, newPassword }); - } -} diff --git a/src/main/webapp/app/account/register/register.component.html b/src/main/webapp/app/account/register/register.component.html deleted file mode 100644 index c9eb2af9f..000000000 --- a/src/main/webapp/app/account/register/register.component.html +++ /dev/null @@ -1,234 +0,0 @@ -
-
-
-

Registration

- -
- Registration saved! Please check your email for confirmation. -
- -
- Registration failed! Please try again later. -
- -
- Login name already registered! Please choose another one. -
- -
- Email is already in use! Please choose another one. -
- -
- The password and its confirmation do not match! -
-
-
- -
-
-
-
- - - -
- - Your username is required. - - - - Your username is required to be at least 1 character. - - - - Your username cannot be longer than 50 characters. - - - - Your username is invalid. - -
-
- -
- - - -
- - Your email is required. - - - - Your email is invalid. - - - - Your email is required to be at least 5 characters. - - - - Your email cannot be longer than 50 characters. - -
-
- -
- - - -
- - Your password is required. - - - - Your password is required to be at least 4 characters. - - - - Your password cannot be longer than 50 characters. - -
- - -
- -
- - - -
- - Your confirmation password is required. - - - - Your confirmation password is required to be at least 4 characters. - - - - Your confirmation password cannot be longer than 50 characters. - -
-
- - -
- -
- If you want to - sign in, you can try the default accounts:
- Administrator (login="admin" and password="admin")
- User (login="user" and - password="user").
-
-
-
-
diff --git a/src/main/webapp/app/account/register/register.component.spec.ts b/src/main/webapp/app/account/register/register.component.spec.ts deleted file mode 100644 index b9f8dadc9..000000000 --- a/src/main/webapp/app/account/register/register.component.spec.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync, inject, tick, fakeAsync } from '@angular/core/testing'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { FormBuilder } from '@angular/forms'; -import { of, throwError } from 'rxjs'; -import { TranslateModule, TranslateService } from '@ngx-translate/core'; - -import { EMAIL_ALREADY_USED_TYPE, LOGIN_ALREADY_USED_TYPE } from 'app/config/error.constants'; - -import { RegisterService } from './register.service'; -import RegisterComponent from './register.component'; - -describe('RegisterComponent', () => { - let fixture: ComponentFixture; - let comp: RegisterComponent; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot(), HttpClientTestingModule, RegisterComponent], - providers: [FormBuilder], - }) - .overrideTemplate(RegisterComponent, '') - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(RegisterComponent); - comp = fixture.componentInstance; - }); - - it('should ensure the two passwords entered match', () => { - comp.registerForm.patchValue({ - password: 'password', - confirmPassword: 'non-matching', - }); - - comp.register(); - - expect(comp.doNotMatch).toBe(true); - }); - - it('should update success to true after creating an account', inject( - [RegisterService, TranslateService], - fakeAsync((service: RegisterService, mockTranslateService: TranslateService) => { - jest.spyOn(service, 'save').mockReturnValue(of({})); - mockTranslateService.currentLang = 'en'; - comp.registerForm.patchValue({ - password: 'password', - confirmPassword: 'password', - }); - - comp.register(); - tick(); - - expect(service.save).toHaveBeenCalledWith({ - email: '', - password: 'password', - login: '', - langKey: 'en', - }); - expect(comp.success).toBe(true); - expect(comp.errorUserExists).toBe(false); - expect(comp.errorEmailExists).toBe(false); - expect(comp.error).toBe(false); - }) - )); - - it('should notify of user existence upon 400/login already in use', inject( - [RegisterService], - fakeAsync((service: RegisterService) => { - jest.spyOn(service, 'save').mockReturnValue( - throwError({ - status: 400, - error: { type: LOGIN_ALREADY_USED_TYPE }, - }) - ); - comp.registerForm.patchValue({ - password: 'password', - confirmPassword: 'password', - }); - - comp.register(); - tick(); - - expect(comp.errorUserExists).toBe(true); - expect(comp.errorEmailExists).toBe(false); - expect(comp.error).toBe(false); - }) - )); - - it('should notify of email existence upon 400/email address already in use', inject( - [RegisterService], - fakeAsync((service: RegisterService) => { - jest.spyOn(service, 'save').mockReturnValue( - throwError({ - status: 400, - error: { type: EMAIL_ALREADY_USED_TYPE }, - }) - ); - comp.registerForm.patchValue({ - password: 'password', - confirmPassword: 'password', - }); - - comp.register(); - tick(); - - expect(comp.errorEmailExists).toBe(true); - expect(comp.errorUserExists).toBe(false); - expect(comp.error).toBe(false); - }) - )); - - it('should notify of generic error', inject( - [RegisterService], - fakeAsync((service: RegisterService) => { - jest.spyOn(service, 'save').mockReturnValue( - throwError({ - status: 503, - }) - ); - comp.registerForm.patchValue({ - password: 'password', - confirmPassword: 'password', - }); - - comp.register(); - tick(); - - expect(comp.errorUserExists).toBe(false); - expect(comp.errorEmailExists).toBe(false); - expect(comp.error).toBe(true); - }) - )); -}); diff --git a/src/main/webapp/app/account/register/register.component.ts b/src/main/webapp/app/account/register/register.component.ts deleted file mode 100644 index 1ad9d25d6..000000000 --- a/src/main/webapp/app/account/register/register.component.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { Component, AfterViewInit, ElementRef, ViewChild } from '@angular/core'; -import { HttpErrorResponse } from '@angular/common/http'; -import { RouterModule } from '@angular/router'; -import { FormGroup, FormControl, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { TranslateService } from '@ngx-translate/core'; - -import { EMAIL_ALREADY_USED_TYPE, LOGIN_ALREADY_USED_TYPE } from 'app/config/error.constants'; -import { RegisterService } from './register.service'; -import SharedModule from 'app/shared/shared.module'; -import PasswordStrengthBarComponent from '../password/password-strength-bar/password-strength-bar.component'; - -@Component({ - selector: 'jhi-register', - standalone: true, - imports: [SharedModule, RouterModule, FormsModule, ReactiveFormsModule, PasswordStrengthBarComponent], - templateUrl: './register.component.html', -}) -export default class RegisterComponent implements AfterViewInit { - @ViewChild('login', { static: false }) - login?: ElementRef; - - doNotMatch = false; - error = false; - errorEmailExists = false; - errorUserExists = false; - success = false; - - registerForm = new FormGroup({ - login: new FormControl('', { - nonNullable: true, - validators: [ - Validators.required, - Validators.minLength(1), - Validators.maxLength(50), - Validators.pattern('^[a-zA-Z0-9!$&*+=?^_`{|}~.-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*$|^[_.@A-Za-z0-9-]+$'), - ], - }), - email: new FormControl('', { - nonNullable: true, - validators: [Validators.required, Validators.minLength(5), Validators.maxLength(254), Validators.email], - }), - password: new FormControl('', { - nonNullable: true, - validators: [Validators.required, Validators.minLength(4), Validators.maxLength(50)], - }), - confirmPassword: new FormControl('', { - nonNullable: true, - validators: [Validators.required, Validators.minLength(4), Validators.maxLength(50)], - }), - }); - - constructor(private translateService: TranslateService, private registerService: RegisterService) {} - - ngAfterViewInit(): void { - if (this.login) { - this.login.nativeElement.focus(); - } - } - - register(): void { - this.doNotMatch = false; - this.error = false; - this.errorEmailExists = false; - this.errorUserExists = false; - - const { password, confirmPassword } = this.registerForm.getRawValue(); - if (password !== confirmPassword) { - this.doNotMatch = true; - } else { - const { login, email } = this.registerForm.getRawValue(); - this.registerService - .save({ login, email, password, langKey: this.translateService.currentLang }) - .subscribe({ next: () => (this.success = true), error: response => this.processError(response) }); - } - } - - private processError(response: HttpErrorResponse): void { - if (response.status === 400 && response.error.type === LOGIN_ALREADY_USED_TYPE) { - this.errorUserExists = true; - } else if (response.status === 400 && response.error.type === EMAIL_ALREADY_USED_TYPE) { - this.errorEmailExists = true; - } else { - this.error = true; - } - } -} diff --git a/src/main/webapp/app/account/register/register.model.ts b/src/main/webapp/app/account/register/register.model.ts deleted file mode 100644 index 17508b0de..000000000 --- a/src/main/webapp/app/account/register/register.model.ts +++ /dev/null @@ -1,3 +0,0 @@ -export class Registration { - constructor(public login: string, public email: string, public password: string, public langKey: string) {} -} diff --git a/src/main/webapp/app/account/register/register.route.ts b/src/main/webapp/app/account/register/register.route.ts deleted file mode 100644 index 81323c3cb..000000000 --- a/src/main/webapp/app/account/register/register.route.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Route } from '@angular/router'; - -import RegisterComponent from './register.component'; - -const registerRoute: Route = { - path: 'register', - component: RegisterComponent, - title: 'register.title', -}; - -export default registerRoute; diff --git a/src/main/webapp/app/account/register/register.service.spec.ts b/src/main/webapp/app/account/register/register.service.spec.ts deleted file mode 100644 index e0d83baf0..000000000 --- a/src/main/webapp/app/account/register/register.service.spec.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; - -import { RegisterService } from './register.service'; -import { ApplicationConfigService } from 'app/core/config/application-config.service'; -import { Registration } from './register.model'; - -describe('RegisterService Service', () => { - let service: RegisterService; - let httpMock: HttpTestingController; - let applicationConfigService: ApplicationConfigService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - }); - - service = TestBed.inject(RegisterService); - applicationConfigService = TestBed.inject(ApplicationConfigService); - httpMock = TestBed.inject(HttpTestingController); - }); - - afterEach(() => { - httpMock.verify(); - }); - - describe('Service methods', () => { - it('should call register endpoint with correct values', () => { - // GIVEN - const login = 'abc'; - const email = 'test@test.com'; - const password = 'pass'; - const langKey = 'FR'; - const registration = new Registration(login, email, password, langKey); - - // WHEN - service.save(registration).subscribe(); - - const testRequest = httpMock.expectOne({ - method: 'POST', - url: applicationConfigService.getEndpointFor('api/register'), - }); - - // THEN - expect(testRequest.request.body).toEqual({ email, langKey, login, password }); - }); - }); -}); diff --git a/src/main/webapp/app/account/register/register.service.ts b/src/main/webapp/app/account/register/register.service.ts deleted file mode 100644 index 8696564ef..000000000 --- a/src/main/webapp/app/account/register/register.service.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { Observable } from 'rxjs'; - -import { ApplicationConfigService } from 'app/core/config/application-config.service'; -import { Registration } from './register.model'; - -@Injectable({ providedIn: 'root' }) -export class RegisterService { - constructor(private http: HttpClient, private applicationConfigService: ApplicationConfigService) {} - - save(registration: Registration): Observable<{}> { - return this.http.post(this.applicationConfigService.getEndpointFor('api/register'), registration); - } -} diff --git a/src/main/webapp/app/account/settings/settings.component.html b/src/main/webapp/app/account/settings/settings.component.html deleted file mode 100644 index 4fb7967e7..000000000 --- a/src/main/webapp/app/account/settings/settings.component.html +++ /dev/null @@ -1,166 +0,0 @@ -
-
-
-

- User settings for [{{ settingsForm.value.login }}] -

- -
- Settings saved! -
- - - -
-
- - - -
- - Your first name is required. - - - - Your first name is required to be at least 1 character - - - - Your first name cannot be longer than 50 characters - -
-
- -
- - - -
- - Your last name is required. - - - - Your last name is required to be at least 1 character - - - - Your last name cannot be longer than 50 characters - -
-
- -
- - - -
- - Your email is required. - - - - Your email is invalid. - - - - Your email is required to be at least 5 characters. - - - - Your email cannot be longer than 50 characters. - -
-
- -
- - -
- - -
-
-
-
diff --git a/src/main/webapp/app/account/settings/settings.component.spec.ts b/src/main/webapp/app/account/settings/settings.component.spec.ts deleted file mode 100644 index cad67277e..000000000 --- a/src/main/webapp/app/account/settings/settings.component.spec.ts +++ /dev/null @@ -1,90 +0,0 @@ -jest.mock('app/core/auth/account.service'); - -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { FormBuilder } from '@angular/forms'; -import { throwError, of } from 'rxjs'; -import { TranslateModule } from '@ngx-translate/core'; - -import { AccountService } from 'app/core/auth/account.service'; -import { Account } from 'app/core/auth/account.model'; - -import SettingsComponent from './settings.component'; - -describe('SettingsComponent', () => { - let comp: SettingsComponent; - let fixture: ComponentFixture; - let mockAccountService: AccountService; - const account: Account = { - firstName: 'John', - lastName: 'Doe', - activated: true, - email: 'john.doe@mail.com', - langKey: 'en', - login: 'john', - authorities: [], - imageUrl: '', - }; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot(), HttpClientTestingModule, SettingsComponent], - providers: [FormBuilder, AccountService], - }) - .overrideTemplate(SettingsComponent, '') - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(SettingsComponent); - comp = fixture.componentInstance; - mockAccountService = TestBed.inject(AccountService); - mockAccountService.identity = jest.fn(() => of(account)); - mockAccountService.getAuthenticationState = jest.fn(() => of(account)); - }); - - it('should send the current identity upon save', () => { - // GIVEN - mockAccountService.save = jest.fn(() => of({})); - const settingsFormValues = { - firstName: 'John', - lastName: 'Doe', - email: 'john.doe@mail.com', - langKey: 'en', - }; - - // WHEN - comp.ngOnInit(); - comp.save(); - - // THEN - expect(mockAccountService.identity).toHaveBeenCalled(); - expect(mockAccountService.save).toHaveBeenCalledWith(account); - expect(mockAccountService.authenticate).toHaveBeenCalledWith(account); - expect(comp.settingsForm.value).toMatchObject(expect.objectContaining(settingsFormValues)); - }); - - it('should notify of success upon successful save', () => { - // GIVEN - mockAccountService.save = jest.fn(() => of({})); - - // WHEN - comp.ngOnInit(); - comp.save(); - - // THEN - expect(comp.success).toBe(true); - }); - - it('should notify of error upon failed save', () => { - // GIVEN - mockAccountService.save = jest.fn(() => throwError('ERROR')); - - // WHEN - comp.ngOnInit(); - comp.save(); - - // THEN - expect(comp.success).toBe(false); - }); -}); diff --git a/src/main/webapp/app/account/settings/settings.component.ts b/src/main/webapp/app/account/settings/settings.component.ts deleted file mode 100644 index 7c631ede7..000000000 --- a/src/main/webapp/app/account/settings/settings.component.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { FormGroup, FormControl, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { TranslateService } from '@ngx-translate/core'; - -import SharedModule from 'app/shared/shared.module'; -import { AccountService } from 'app/core/auth/account.service'; -import { Account } from 'app/core/auth/account.model'; -import { LANGUAGES } from 'app/config/language.constants'; - -const initialAccount: Account = {} as Account; - -@Component({ - selector: 'jhi-settings', - standalone: true, - imports: [SharedModule, FormsModule, ReactiveFormsModule], - templateUrl: './settings.component.html', -}) -export default class SettingsComponent implements OnInit { - success = false; - languages = LANGUAGES; - - settingsForm = new FormGroup({ - firstName: new FormControl(initialAccount.firstName, { - nonNullable: true, - validators: [Validators.required, Validators.minLength(1), Validators.maxLength(50)], - }), - lastName: new FormControl(initialAccount.lastName, { - nonNullable: true, - validators: [Validators.required, Validators.minLength(1), Validators.maxLength(50)], - }), - email: new FormControl(initialAccount.email, { - nonNullable: true, - validators: [Validators.required, Validators.minLength(5), Validators.maxLength(254), Validators.email], - }), - langKey: new FormControl(initialAccount.langKey, { nonNullable: true }), - - activated: new FormControl(initialAccount.activated, { nonNullable: true }), - authorities: new FormControl(initialAccount.authorities, { nonNullable: true }), - imageUrl: new FormControl(initialAccount.imageUrl, { nonNullable: true }), - login: new FormControl(initialAccount.login, { nonNullable: true }), - }); - - constructor(private accountService: AccountService, private translateService: TranslateService) {} - - ngOnInit(): void { - this.accountService.identity().subscribe(account => { - if (account) { - this.settingsForm.patchValue(account); - } - }); - } - - save(): void { - this.success = false; - - const account = this.settingsForm.getRawValue(); - this.accountService.save(account).subscribe(() => { - this.success = true; - - this.accountService.authenticate(account); - - if (account.langKey !== this.translateService.currentLang) { - this.translateService.use(account.langKey); - } - }); - } -} diff --git a/src/main/webapp/app/account/settings/settings.route.ts b/src/main/webapp/app/account/settings/settings.route.ts deleted file mode 100644 index 3c9306611..000000000 --- a/src/main/webapp/app/account/settings/settings.route.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Route } from '@angular/router'; - -import { UserRouteAccessService } from 'app/core/auth/user-route-access.service'; -import SettingsComponent from './settings.component'; - -const settingsRoute: Route = { - path: 'settings', - component: SettingsComponent, - title: 'global.menu.account.settings', - canActivate: [UserRouteAccessService], -}; - -export default settingsRoute; diff --git a/src/main/webapp/app/admin/admin-routing.module.ts b/src/main/webapp/app/admin/admin-routing.module.ts deleted file mode 100644 index 34450cfe6..000000000 --- a/src/main/webapp/app/admin/admin-routing.module.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; -/* jhipster-needle-add-admin-module-import - JHipster will add admin modules imports here */ - -@NgModule({ - imports: [ - /* jhipster-needle-add-admin-module - JHipster will add admin modules here */ - RouterModule.forChild([ - { - path: 'user-management', - loadChildren: () => import('./user-management/user-management.route'), - title: 'userManagement.home.title', - }, - { - path: 'docs', - loadComponent: () => import('./docs/docs.component'), - title: 'global.menu.admin.apidocs', - }, - { - path: 'configuration', - loadComponent: () => import('./configuration/configuration.component'), - title: 'configuration.title', - }, - { - path: 'health', - loadComponent: () => import('./health/health.component'), - title: 'health.title', - }, - { - path: 'logs', - loadComponent: () => import('./logs/logs.component'), - title: 'logs.title', - }, - { - path: 'metrics', - loadComponent: () => import('./metrics/metrics.component'), - title: 'metrics.title', - }, - /* jhipster-needle-add-admin-route - JHipster will add admin routes here */ - ]), - ], -}) -export default class AdminRoutingModule {} diff --git a/src/main/webapp/app/admin/configuration/configuration.component.html b/src/main/webapp/app/admin/configuration/configuration.component.html deleted file mode 100644 index e76d02c30..000000000 --- a/src/main/webapp/app/admin/configuration/configuration.component.html +++ /dev/null @@ -1,57 +0,0 @@ -
-

Configuration

- - Filter (by prefix) - - -

Spring configuration

- - - - - - - - - - - - - - -
- Prefix - Properties
- {{ bean.prefix }} - -
-
{{ property.key }}
-
- {{ property.value | json }} -
-
-
- -
-

- {{ propertySource.name }} -

- - - - - - - - - - - - - - -
PropertyValue
{{ property.key }} - {{ property.value.value }} -
-
-
diff --git a/src/main/webapp/app/admin/configuration/configuration.component.spec.ts b/src/main/webapp/app/admin/configuration/configuration.component.spec.ts deleted file mode 100644 index cebc27935..000000000 --- a/src/main/webapp/app/admin/configuration/configuration.component.spec.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { of } from 'rxjs'; - -import ConfigurationComponent from './configuration.component'; -import { ConfigurationService } from './configuration.service'; -import { Bean, PropertySource } from './configuration.model'; - -describe('ConfigurationComponent', () => { - let comp: ConfigurationComponent; - let fixture: ComponentFixture; - let service: ConfigurationService; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, ConfigurationComponent], - providers: [ConfigurationService], - }) - .overrideTemplate(ConfigurationComponent, '') - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(ConfigurationComponent); - comp = fixture.componentInstance; - service = TestBed.inject(ConfigurationService); - }); - - describe('OnInit', () => { - it('Should call load all on init', () => { - // GIVEN - const beans: Bean[] = [ - { - prefix: 'jhipster', - properties: { - clientApp: { - name: 'jhipsterApp', - }, - }, - }, - ]; - const propertySources: PropertySource[] = [ - { - name: 'server.ports', - properties: { - 'local.server.port': { - value: '8080', - }, - }, - }, - ]; - jest.spyOn(service, 'getBeans').mockReturnValue(of(beans)); - jest.spyOn(service, 'getPropertySources').mockReturnValue(of(propertySources)); - - // WHEN - comp.ngOnInit(); - - // THEN - expect(service.getBeans).toHaveBeenCalled(); - expect(service.getPropertySources).toHaveBeenCalled(); - expect(comp.allBeans).toEqual(beans); - expect(comp.beans).toEqual(beans); - expect(comp.propertySources).toEqual(propertySources); - }); - }); -}); diff --git a/src/main/webapp/app/admin/configuration/configuration.component.ts b/src/main/webapp/app/admin/configuration/configuration.component.ts deleted file mode 100644 index ee97f6bc4..000000000 --- a/src/main/webapp/app/admin/configuration/configuration.component.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -import SharedModule from 'app/shared/shared.module'; -import { FormsModule } from '@angular/forms'; -import { SortDirective, SortByDirective } from 'app/shared/sort'; -import { ConfigurationService } from './configuration.service'; -import { Bean, PropertySource } from './configuration.model'; - -@Component({ - standalone: true, - selector: 'jhi-configuration', - templateUrl: './configuration.component.html', - imports: [SharedModule, FormsModule, SortDirective, SortByDirective], -}) -export default class ConfigurationComponent implements OnInit { - allBeans!: Bean[]; - beans: Bean[] = []; - beansFilter = ''; - beansAscending = true; - propertySources: PropertySource[] = []; - - constructor(private configurationService: ConfigurationService) {} - - ngOnInit(): void { - this.configurationService.getBeans().subscribe(beans => { - this.allBeans = beans; - this.filterAndSortBeans(); - }); - - this.configurationService.getPropertySources().subscribe(propertySources => (this.propertySources = propertySources)); - } - - filterAndSortBeans(): void { - const beansAscendingValue = this.beansAscending ? -1 : 1; - const beansAscendingValueReverse = this.beansAscending ? 1 : -1; - this.beans = this.allBeans - .filter(bean => !this.beansFilter || bean.prefix.toLowerCase().includes(this.beansFilter.toLowerCase())) - .sort((a, b) => (a.prefix < b.prefix ? beansAscendingValue : beansAscendingValueReverse)); - } -} diff --git a/src/main/webapp/app/admin/configuration/configuration.model.ts b/src/main/webapp/app/admin/configuration/configuration.model.ts deleted file mode 100644 index 6a671e0a9..000000000 --- a/src/main/webapp/app/admin/configuration/configuration.model.ts +++ /dev/null @@ -1,40 +0,0 @@ -export interface ConfigProps { - contexts: Contexts; -} - -export interface Contexts { - [key: string]: Context; -} - -export interface Context { - beans: Beans; - parentId?: any; -} - -export interface Beans { - [key: string]: Bean; -} - -export interface Bean { - prefix: string; - properties: any; -} - -export interface Env { - activeProfiles?: string[]; - propertySources: PropertySource[]; -} - -export interface PropertySource { - name: string; - properties: Properties; -} - -export interface Properties { - [key: string]: Property; -} - -export interface Property { - value: string; - origin?: string; -} diff --git a/src/main/webapp/app/admin/configuration/configuration.service.spec.ts b/src/main/webapp/app/admin/configuration/configuration.service.spec.ts deleted file mode 100644 index 6e6ff7f49..000000000 --- a/src/main/webapp/app/admin/configuration/configuration.service.spec.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; - -import { ConfigurationService } from './configuration.service'; -import { Bean, ConfigProps, Env, PropertySource } from './configuration.model'; - -describe('Logs Service', () => { - let service: ConfigurationService; - let httpMock: HttpTestingController; - let expectedResult: Bean[] | PropertySource[] | null; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - }); - - expectedResult = null; - service = TestBed.inject(ConfigurationService); - httpMock = TestBed.inject(HttpTestingController); - }); - - afterEach(() => { - httpMock.verify(); - }); - - describe('Service methods', () => { - it('should get the config', () => { - const bean: Bean = { - prefix: 'jhipster', - properties: { - clientApp: { - name: 'jhipsterApp', - }, - }, - }; - const configProps: ConfigProps = { - contexts: { - jhipster: { - beans: { - 'tech.jhipster.config.JHipsterProperties': bean, - }, - }, - }, - }; - service.getBeans().subscribe(received => (expectedResult = received)); - - const req = httpMock.expectOne({ method: 'GET' }); - req.flush(configProps); - expect(expectedResult).toEqual([bean]); - }); - - it('should get the env', () => { - const propertySources: PropertySource[] = [ - { - name: 'server.ports', - properties: { - 'local.server.port': { - value: '8080', - }, - }, - }, - ]; - const env: Env = { propertySources }; - service.getPropertySources().subscribe(received => (expectedResult = received)); - - const req = httpMock.expectOne({ method: 'GET' }); - req.flush(env); - expect(expectedResult).toEqual(propertySources); - }); - }); -}); diff --git a/src/main/webapp/app/admin/configuration/configuration.service.ts b/src/main/webapp/app/admin/configuration/configuration.service.ts deleted file mode 100644 index d8d30518d..000000000 --- a/src/main/webapp/app/admin/configuration/configuration.service.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; - -import { ApplicationConfigService } from 'app/core/config/application-config.service'; -import { Bean, Beans, ConfigProps, Env, PropertySource } from './configuration.model'; - -@Injectable({ providedIn: 'root' }) -export class ConfigurationService { - constructor(private http: HttpClient, private applicationConfigService: ApplicationConfigService) {} - - getBeans(): Observable { - return this.http.get(this.applicationConfigService.getEndpointFor('management/configprops')).pipe( - map(configProps => - Object.values( - Object.values(configProps.contexts) - .map(context => context.beans) - .reduce((allBeans: Beans, contextBeans: Beans) => ({ ...allBeans, ...contextBeans })) - ) - ) - ); - } - - getPropertySources(): Observable { - return this.http.get(this.applicationConfigService.getEndpointFor('management/env')).pipe(map(env => env.propertySources)); - } -} diff --git a/src/main/webapp/app/admin/docs/docs.component.html b/src/main/webapp/app/admin/docs/docs.component.html deleted file mode 100644 index 24025522f..000000000 --- a/src/main/webapp/app/admin/docs/docs.component.html +++ /dev/null @@ -1,10 +0,0 @@ - diff --git a/src/main/webapp/app/admin/docs/docs.component.scss b/src/main/webapp/app/admin/docs/docs.component.scss deleted file mode 100644 index bb9a6cc81..000000000 --- a/src/main/webapp/app/admin/docs/docs.component.scss +++ /dev/null @@ -1,6 +0,0 @@ -@import 'bootstrap/scss/functions'; -@import 'bootstrap/scss/variables'; - -iframe { - background: white; -} diff --git a/src/main/webapp/app/admin/docs/docs.component.ts b/src/main/webapp/app/admin/docs/docs.component.ts deleted file mode 100644 index ea4188354..000000000 --- a/src/main/webapp/app/admin/docs/docs.component.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - standalone: true, - selector: 'jhi-docs', - templateUrl: './docs.component.html', - styleUrls: ['./docs.component.scss'], -}) -export default class DocsComponent {} diff --git a/src/main/webapp/app/admin/health/health.component.html b/src/main/webapp/app/admin/health/health.component.html deleted file mode 100644 index 08e62ac31..000000000 --- a/src/main/webapp/app/admin/health/health.component.html +++ /dev/null @@ -1,48 +0,0 @@ -
-

- Health Checks - - -

- -
- - - - - - - - - - - - - - - -
Service nameStatusDetails
- {{ 'health.indicator.' + componentHealth.key | translate }} - - - {{ - { UNKNOWN: 'UNKNOWN', UP: 'UP', OUT_OF_SERVICE: 'OUT_OF_SERVICE', DOWN: 'DOWN' }[componentHealth.value!.status || 'UNKNOWN'] - }} - - - - - -
-
-
diff --git a/src/main/webapp/app/admin/health/health.component.spec.ts b/src/main/webapp/app/admin/health/health.component.spec.ts deleted file mode 100644 index 97ce8aba1..000000000 --- a/src/main/webapp/app/admin/health/health.component.spec.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { HttpErrorResponse } from '@angular/common/http'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { of, throwError } from 'rxjs'; - -import HealthComponent from './health.component'; -import { HealthService } from './health.service'; -import { Health } from './health.model'; - -describe('HealthComponent', () => { - let comp: HealthComponent; - let fixture: ComponentFixture; - let service: HealthService; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, HealthComponent], - }) - .overrideTemplate(HealthComponent, '') - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(HealthComponent); - comp = fixture.componentInstance; - service = TestBed.inject(HealthService); - }); - - describe('getBadgeClass', () => { - it('should get badge class', () => { - const upBadgeClass = comp.getBadgeClass('UP'); - const downBadgeClass = comp.getBadgeClass('DOWN'); - expect(upBadgeClass).toEqual('bg-success'); - expect(downBadgeClass).toEqual('bg-danger'); - }); - }); - - describe('refresh', () => { - it('should call refresh on init', () => { - // GIVEN - const health: Health = { status: 'UP', components: { mail: { status: 'UP', details: { mailDetail: 'mail' } } } }; - jest.spyOn(service, 'checkHealth').mockReturnValue(of(health)); - - // WHEN - comp.ngOnInit(); - - // THEN - expect(service.checkHealth).toHaveBeenCalled(); - expect(comp.health).toEqual(health); - }); - - it('should handle a 503 on refreshing health data', () => { - // GIVEN - const health: Health = { status: 'DOWN', components: { mail: { status: 'DOWN' } } }; - jest.spyOn(service, 'checkHealth').mockReturnValue(throwError(new HttpErrorResponse({ status: 503, error: health }))); - - // WHEN - comp.refresh(); - - // THEN - expect(service.checkHealth).toHaveBeenCalled(); - expect(comp.health).toEqual(health); - }); - }); -}); diff --git a/src/main/webapp/app/admin/health/health.component.ts b/src/main/webapp/app/admin/health/health.component.ts deleted file mode 100644 index 14bf698ad..000000000 --- a/src/main/webapp/app/admin/health/health.component.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { HttpErrorResponse } from '@angular/common/http'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; - -import SharedModule from 'app/shared/shared.module'; -import { HealthService } from './health.service'; -import { Health, HealthDetails, HealthStatus } from './health.model'; -import HealthModalComponent from './modal/health-modal.component'; - -@Component({ - standalone: true, - selector: 'jhi-health', - templateUrl: './health.component.html', - imports: [SharedModule, HealthModalComponent], -}) -export default class HealthComponent implements OnInit { - health?: Health; - - constructor(private modalService: NgbModal, private healthService: HealthService) {} - - ngOnInit(): void { - this.refresh(); - } - - getBadgeClass(statusState: HealthStatus): string { - if (statusState === 'UP') { - return 'bg-success'; - } - return 'bg-danger'; - } - - refresh(): void { - this.healthService.checkHealth().subscribe({ - next: health => (this.health = health), - error: (error: HttpErrorResponse) => { - if (error.status === 503) { - this.health = error.error; - } - }, - }); - } - - showHealth(health: { key: string; value: HealthDetails }): void { - const modalRef = this.modalService.open(HealthModalComponent); - modalRef.componentInstance.health = health; - } -} diff --git a/src/main/webapp/app/admin/health/health.model.ts b/src/main/webapp/app/admin/health/health.model.ts deleted file mode 100644 index 08112898e..000000000 --- a/src/main/webapp/app/admin/health/health.model.ts +++ /dev/null @@ -1,15 +0,0 @@ -export type HealthStatus = 'UP' | 'DOWN' | 'UNKNOWN' | 'OUT_OF_SERVICE'; - -export type HealthKey = 'diskSpace' | 'mail' | 'ping' | 'livenessState' | 'readinessState' | 'db'; - -export interface Health { - status: HealthStatus; - components: { - [key in HealthKey]?: HealthDetails; - }; -} - -export interface HealthDetails { - status: HealthStatus; - details?: { [key: string]: unknown }; -} diff --git a/src/main/webapp/app/admin/health/health.service.spec.ts b/src/main/webapp/app/admin/health/health.service.spec.ts deleted file mode 100644 index 850c531f7..000000000 --- a/src/main/webapp/app/admin/health/health.service.spec.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; - -import { HealthService } from './health.service'; -import { ApplicationConfigService } from 'app/core/config/application-config.service'; - -describe('HealthService Service', () => { - let service: HealthService; - let httpMock: HttpTestingController; - let applicationConfigService: ApplicationConfigService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - }); - - service = TestBed.inject(HealthService); - applicationConfigService = TestBed.inject(ApplicationConfigService); - httpMock = TestBed.inject(HttpTestingController); - }); - - afterEach(() => { - httpMock.verify(); - }); - - describe('Service methods', () => { - it('should call management/health endpoint with correct values', () => { - // GIVEN - let expectedResult; - const checkHealth = { - components: [], - }; - - // WHEN - service.checkHealth().subscribe(received => { - expectedResult = received; - }); - const testRequest = httpMock.expectOne({ - method: 'GET', - url: applicationConfigService.getEndpointFor('management/health'), - }); - testRequest.flush(checkHealth); - - // THEN - expect(expectedResult).toEqual(checkHealth); - }); - }); -}); diff --git a/src/main/webapp/app/admin/health/health.service.ts b/src/main/webapp/app/admin/health/health.service.ts deleted file mode 100644 index 4712a9787..000000000 --- a/src/main/webapp/app/admin/health/health.service.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { Observable } from 'rxjs'; - -import { ApplicationConfigService } from 'app/core/config/application-config.service'; -import { Health } from './health.model'; - -@Injectable({ providedIn: 'root' }) -export class HealthService { - constructor(private http: HttpClient, private applicationConfigService: ApplicationConfigService) {} - - checkHealth(): Observable { - return this.http.get(this.applicationConfigService.getEndpointFor('management/health')); - } -} diff --git a/src/main/webapp/app/admin/health/modal/health-modal.component.html b/src/main/webapp/app/admin/health/modal/health-modal.component.html deleted file mode 100644 index f55b8765f..000000000 --- a/src/main/webapp/app/admin/health/modal/health-modal.component.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - diff --git a/src/main/webapp/app/admin/health/modal/health-modal.component.spec.ts b/src/main/webapp/app/admin/health/modal/health-modal.component.spec.ts deleted file mode 100644 index b9aa047b9..000000000 --- a/src/main/webapp/app/admin/health/modal/health-modal.component.spec.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; - -import HealthModalComponent from './health-modal.component'; - -describe('HealthModalComponent', () => { - let comp: HealthModalComponent; - let fixture: ComponentFixture; - let mockActiveModal: NgbActiveModal; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, HealthModalComponent], - providers: [NgbActiveModal], - }) - .overrideTemplate(HealthModalComponent, '') - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(HealthModalComponent); - comp = fixture.componentInstance; - mockActiveModal = TestBed.inject(NgbActiveModal); - }); - - describe('readableValue', () => { - it('should return stringify value', () => { - // GIVEN - comp.health = undefined; - - // WHEN - const result = comp.readableValue({ name: 'jhipster' }); - - // THEN - expect(result).toEqual('{"name":"jhipster"}'); - }); - - it('should return string value', () => { - // GIVEN - comp.health = undefined; - - // WHEN - const result = comp.readableValue('jhipster'); - - // THEN - expect(result).toEqual('jhipster'); - }); - - it('should return storage space in an human readable unit (GB)', () => { - // GIVEN - comp.health = { - key: 'diskSpace', - value: { - status: 'UP', - }, - }; - - // WHEN - const result = comp.readableValue(1073741825); - - // THEN - expect(result).toEqual('1.00 GB'); - }); - - it('should return storage space in an human readable unit (MB)', () => { - // GIVEN - comp.health = { - key: 'diskSpace', - value: { - status: 'UP', - }, - }; - - // WHEN - const result = comp.readableValue(1073741824); - - // THEN - expect(result).toEqual('1024.00 MB'); - }); - - it('should return string value', () => { - // GIVEN - comp.health = { - key: 'mail', - value: { - status: 'UP', - }, - }; - - // WHEN - const result = comp.readableValue(1234); - - // THEN - expect(result).toEqual('1234'); - }); - }); - - describe('dismiss', () => { - it('should call dismiss when dismiss modal is called', () => { - // GIVEN - const spy = jest.spyOn(mockActiveModal, 'dismiss'); - - // WHEN - comp.dismiss(); - - // THEN - expect(spy).toHaveBeenCalled(); - }); - }); -}); diff --git a/src/main/webapp/app/admin/health/modal/health-modal.component.ts b/src/main/webapp/app/admin/health/modal/health-modal.component.ts deleted file mode 100644 index 9eefa8bb2..000000000 --- a/src/main/webapp/app/admin/health/modal/health-modal.component.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Component } from '@angular/core'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; - -import SharedModule from 'app/shared/shared.module'; -import { HealthKey, HealthDetails } from '../health.model'; - -@Component({ - standalone: true, - selector: 'jhi-health-modal', - templateUrl: './health-modal.component.html', - imports: [SharedModule], -}) -export default class HealthModalComponent { - health?: { key: HealthKey; value: HealthDetails }; - - constructor(private activeModal: NgbActiveModal) {} - - readableValue(value: any): string { - if (this.health?.key === 'diskSpace') { - // Should display storage space in an human readable unit - const val = value / 1073741824; - if (val > 1) { - return `${val.toFixed(2)} GB`; - } - return `${(value / 1048576).toFixed(2)} MB`; - } - - if (typeof value === 'object') { - return JSON.stringify(value); - } - return String(value); - } - - dismiss(): void { - this.activeModal.dismiss(); - } -} diff --git a/src/main/webapp/app/admin/logs/log.model.ts b/src/main/webapp/app/admin/logs/log.model.ts deleted file mode 100644 index 83f2e154a..000000000 --- a/src/main/webapp/app/admin/logs/log.model.ts +++ /dev/null @@ -1,15 +0,0 @@ -export type Level = 'TRACE' | 'DEBUG' | 'INFO' | 'WARN' | 'ERROR' | 'OFF'; - -export interface Logger { - configuredLevel: Level | null; - effectiveLevel: Level; -} - -export interface LoggersResponse { - levels: Level[]; - loggers: { [key: string]: Logger }; -} - -export class Log { - constructor(public name: string, public level: Level) {} -} diff --git a/src/main/webapp/app/admin/logs/logs.component.html b/src/main/webapp/app/admin/logs/logs.component.html deleted file mode 100644 index 85218480e..000000000 --- a/src/main/webapp/app/admin/logs/logs.component.html +++ /dev/null @@ -1,78 +0,0 @@ -
-

Logs

- -
-
-
- -

There are {{ loggers.length }} loggers.

- - Filter - - - - - - - - - - - - - - - - -
Name Level
- {{ logger.name | slice : 0 : 140 }} - - - - - - - - - - - - -
-
diff --git a/src/main/webapp/app/admin/logs/logs.component.spec.ts b/src/main/webapp/app/admin/logs/logs.component.spec.ts deleted file mode 100644 index 476fc1954..000000000 --- a/src/main/webapp/app/admin/logs/logs.component.spec.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { of } from 'rxjs'; - -import LogsComponent from './logs.component'; -import { LogsService } from './logs.service'; -import { Log, LoggersResponse } from './log.model'; - -describe('LogsComponent', () => { - let comp: LogsComponent; - let fixture: ComponentFixture; - let service: LogsService; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, LogsComponent], - providers: [LogsService], - }) - .overrideTemplate(LogsComponent, '') - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(LogsComponent); - comp = fixture.componentInstance; - service = TestBed.inject(LogsService); - }); - - describe('OnInit', () => { - it('should set all default values correctly', () => { - expect(comp.filter).toBe(''); - expect(comp.orderProp).toBe('name'); - expect(comp.ascending).toBe(true); - }); - - it('Should call load all on init', () => { - // GIVEN - const log = new Log('main', 'WARN'); - jest.spyOn(service, 'findAll').mockReturnValue( - of({ - loggers: { - main: { - effectiveLevel: 'WARN', - }, - }, - } as unknown as LoggersResponse) - ); - - // WHEN - comp.ngOnInit(); - - // THEN - expect(service.findAll).toHaveBeenCalled(); - expect(comp.loggers?.[0]).toEqual(expect.objectContaining(log)); - }); - }); - - describe('change log level', () => { - it('should change log level correctly', () => { - // GIVEN - const log = new Log('main', 'ERROR'); - jest.spyOn(service, 'changeLevel').mockReturnValue(of({})); - jest.spyOn(service, 'findAll').mockReturnValue( - of({ - loggers: { - main: { - effectiveLevel: 'ERROR', - }, - }, - } as unknown as LoggersResponse) - ); - - // WHEN - comp.changeLevel('main', 'ERROR'); - - // THEN - expect(service.changeLevel).toHaveBeenCalled(); - expect(service.findAll).toHaveBeenCalled(); - expect(comp.loggers?.[0]).toEqual(expect.objectContaining(log)); - }); - }); -}); diff --git a/src/main/webapp/app/admin/logs/logs.component.ts b/src/main/webapp/app/admin/logs/logs.component.ts deleted file mode 100644 index d1a001a5d..000000000 --- a/src/main/webapp/app/admin/logs/logs.component.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { finalize } from 'rxjs/operators'; - -import SharedModule from 'app/shared/shared.module'; -import { FormsModule } from '@angular/forms'; -import { SortDirective, SortByDirective } from 'app/shared/sort'; -import { Log, LoggersResponse, Level } from './log.model'; -import { LogsService } from './logs.service'; - -@Component({ - standalone: true, - selector: 'jhi-logs', - templateUrl: './logs.component.html', - imports: [SharedModule, FormsModule, SortDirective, SortByDirective], -}) -export default class LogsComponent implements OnInit { - loggers?: Log[]; - filteredAndOrderedLoggers?: Log[]; - isLoading = false; - filter = ''; - orderProp: keyof Log = 'name'; - ascending = true; - - constructor(private logsService: LogsService) {} - - ngOnInit(): void { - this.findAndExtractLoggers(); - } - - changeLevel(name: string, level: Level): void { - this.logsService.changeLevel(name, level).subscribe(() => this.findAndExtractLoggers()); - } - - filterAndSort(): void { - this.filteredAndOrderedLoggers = this.loggers!.filter( - logger => !this.filter || logger.name.toLowerCase().includes(this.filter.toLowerCase()) - ).sort((a, b) => { - if (a[this.orderProp] < b[this.orderProp]) { - return this.ascending ? -1 : 1; - } else if (a[this.orderProp] > b[this.orderProp]) { - return this.ascending ? 1 : -1; - } else if (this.orderProp === 'level') { - return a.name < b.name ? -1 : 1; - } - return 0; - }); - } - - private findAndExtractLoggers(): void { - this.isLoading = true; - this.logsService - .findAll() - .pipe( - finalize(() => { - this.filterAndSort(); - this.isLoading = false; - }) - ) - .subscribe({ - next: (response: LoggersResponse) => - (this.loggers = Object.entries(response.loggers).map(([key, logger]) => new Log(key, logger.effectiveLevel))), - error: () => (this.loggers = []), - }); - } -} diff --git a/src/main/webapp/app/admin/logs/logs.service.spec.ts b/src/main/webapp/app/admin/logs/logs.service.spec.ts deleted file mode 100644 index cebee2ccd..000000000 --- a/src/main/webapp/app/admin/logs/logs.service.spec.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; - -import { LogsService } from './logs.service'; - -describe('Logs Service', () => { - let service: LogsService; - let httpMock: HttpTestingController; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - }); - - service = TestBed.inject(LogsService); - httpMock = TestBed.inject(HttpTestingController); - }); - - afterEach(() => { - httpMock.verify(); - }); - - describe('Service methods', () => { - it('should change log level', () => { - service.changeLevel('main', 'ERROR').subscribe(); - - const req = httpMock.expectOne({ method: 'POST' }); - expect(req.request.body).toEqual({ configuredLevel: 'ERROR' }); - }); - }); -}); diff --git a/src/main/webapp/app/admin/logs/logs.service.ts b/src/main/webapp/app/admin/logs/logs.service.ts deleted file mode 100644 index 625868a8b..000000000 --- a/src/main/webapp/app/admin/logs/logs.service.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { Observable } from 'rxjs'; - -import { ApplicationConfigService } from 'app/core/config/application-config.service'; -import { LoggersResponse, Level } from './log.model'; - -@Injectable({ providedIn: 'root' }) -export class LogsService { - constructor(private http: HttpClient, private applicationConfigService: ApplicationConfigService) {} - - changeLevel(name: string, configuredLevel: Level): Observable<{}> { - return this.http.post(this.applicationConfigService.getEndpointFor(`management/loggers/${name}`), { configuredLevel }); - } - - findAll(): Observable { - return this.http.get(this.applicationConfigService.getEndpointFor('management/loggers')); - } -} diff --git a/src/main/webapp/app/admin/metrics/blocks/jvm-memory/jvm-memory.component.html b/src/main/webapp/app/admin/metrics/blocks/jvm-memory/jvm-memory.component.html deleted file mode 100644 index ca0def0dd..000000000 --- a/src/main/webapp/app/admin/metrics/blocks/jvm-memory/jvm-memory.component.html +++ /dev/null @@ -1,28 +0,0 @@ -

Memory

- -
-
- - {{ entry.key }} - ({{ entry.value.used / 1048576 | number : '1.0-0' }}M / {{ entry.value.max / 1048576 | number : '1.0-0' }}M) - - -
Committed : {{ entry.value.committed / 1048576 | number : '1.0-0' }}M
- - {{ entry.key }} {{ entry.value.used / 1048576 | number : '1.0-0' }}M - - - {{ (entry.value.used * 100) / entry.value.max | number : '1.0-0' }}% - -
-
diff --git a/src/main/webapp/app/admin/metrics/blocks/jvm-memory/jvm-memory.component.ts b/src/main/webapp/app/admin/metrics/blocks/jvm-memory/jvm-memory.component.ts deleted file mode 100644 index 8654a8b98..000000000 --- a/src/main/webapp/app/admin/metrics/blocks/jvm-memory/jvm-memory.component.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Component, Input } from '@angular/core'; - -import SharedModule from 'app/shared/shared.module'; -import { JvmMetrics } from 'app/admin/metrics/metrics.model'; - -@Component({ - standalone: true, - selector: 'jhi-jvm-memory', - templateUrl: './jvm-memory.component.html', - imports: [SharedModule], -}) -export class JvmMemoryComponent { - /** - * object containing all jvm memory metrics - */ - @Input() jvmMemoryMetrics?: { [key: string]: JvmMetrics }; - - /** - * boolean field saying if the metrics are in the process of being updated - */ - @Input() updating?: boolean; -} diff --git a/src/main/webapp/app/admin/metrics/blocks/jvm-threads/jvm-threads.component.html b/src/main/webapp/app/admin/metrics/blocks/jvm-threads/jvm-threads.component.html deleted file mode 100644 index 2951116a7..000000000 --- a/src/main/webapp/app/admin/metrics/blocks/jvm-threads/jvm-threads.component.html +++ /dev/null @@ -1,55 +0,0 @@ -

Threads

- -Runnable {{ threadStats.threadDumpRunnable }} - - - {{ (threadStats.threadDumpRunnable * 100) / threadStats.threadDumpAll | number : '1.0-0' }}% - - -Timed waiting ({{ threadStats.threadDumpTimedWaiting }}) - - - {{ (threadStats.threadDumpTimedWaiting * 100) / threadStats.threadDumpAll | number : '1.0-0' }}% - - -Waiting ({{ threadStats.threadDumpWaiting }}) - - - {{ (threadStats.threadDumpWaiting * 100) / threadStats.threadDumpAll | number : '1.0-0' }}% - - -Blocked ({{ threadStats.threadDumpBlocked }}) - - - {{ (threadStats.threadDumpBlocked * 100) / threadStats.threadDumpAll | number : '1.0-0' }}% - - -
Total: {{ threadStats.threadDumpAll }}
- - diff --git a/src/main/webapp/app/admin/metrics/blocks/jvm-threads/jvm-threads.component.ts b/src/main/webapp/app/admin/metrics/blocks/jvm-threads/jvm-threads.component.ts deleted file mode 100644 index dc726935b..000000000 --- a/src/main/webapp/app/admin/metrics/blocks/jvm-threads/jvm-threads.component.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; - -import SharedModule from 'app/shared/shared.module'; -import { Thread, ThreadState } from 'app/admin/metrics/metrics.model'; -import { MetricsModalThreadsComponent } from '../metrics-modal-threads/metrics-modal-threads.component'; - -@Component({ - standalone: true, - selector: 'jhi-jvm-threads', - templateUrl: './jvm-threads.component.html', - imports: [SharedModule], -}) -export class JvmThreadsComponent { - threadStats = { - threadDumpAll: 0, - threadDumpRunnable: 0, - threadDumpTimedWaiting: 0, - threadDumpWaiting: 0, - threadDumpBlocked: 0, - }; - - @Input() - set threads(threads: Thread[] | undefined) { - this._threads = threads; - - threads?.forEach(thread => { - if (thread.threadState === ThreadState.Runnable) { - this.threadStats.threadDumpRunnable += 1; - } else if (thread.threadState === ThreadState.Waiting) { - this.threadStats.threadDumpWaiting += 1; - } else if (thread.threadState === ThreadState.TimedWaiting) { - this.threadStats.threadDumpTimedWaiting += 1; - } else if (thread.threadState === ThreadState.Blocked) { - this.threadStats.threadDumpBlocked += 1; - } - }); - - this.threadStats.threadDumpAll = - this.threadStats.threadDumpRunnable + - this.threadStats.threadDumpWaiting + - this.threadStats.threadDumpTimedWaiting + - this.threadStats.threadDumpBlocked; - } - - get threads(): Thread[] | undefined { - return this._threads; - } - - private _threads: Thread[] | undefined; - - constructor(private modalService: NgbModal) {} - - open(): void { - const modalRef = this.modalService.open(MetricsModalThreadsComponent); - modalRef.componentInstance.threads = this.threads; - } -} diff --git a/src/main/webapp/app/admin/metrics/blocks/metrics-cache/metrics-cache.component.html b/src/main/webapp/app/admin/metrics/blocks/metrics-cache/metrics-cache.component.html deleted file mode 100644 index 0c37acf8b..000000000 --- a/src/main/webapp/app/admin/metrics/blocks/metrics-cache/metrics-cache.component.html +++ /dev/null @@ -1,42 +0,0 @@ -

Cache statistics

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cache nameCache HitsCache MissesCache GetsCache PutsCache RemovalsCache EvictionsCache Hit %Cache Miss %
{{ entry.key }}{{ entry.value['cache.gets.hit'] }}{{ entry.value['cache.gets.miss'] }}{{ entry.value['cache.gets.hit'] + entry.value['cache.gets.miss'] }}{{ entry.value['cache.puts'] }}{{ entry.value['cache.removals'] }}{{ entry.value['cache.evictions'] }} - {{ - filterNaN((100 * entry.value['cache.gets.hit']) / (entry.value['cache.gets.hit'] + entry.value['cache.gets.miss'])) - | number : '1.0-4' - }} - - {{ - filterNaN((100 * entry.value['cache.gets.miss']) / (entry.value['cache.gets.hit'] + entry.value['cache.gets.miss'])) - | number : '1.0-4' - }} -
-
diff --git a/src/main/webapp/app/admin/metrics/blocks/metrics-cache/metrics-cache.component.ts b/src/main/webapp/app/admin/metrics/blocks/metrics-cache/metrics-cache.component.ts deleted file mode 100644 index 5a174f7c5..000000000 --- a/src/main/webapp/app/admin/metrics/blocks/metrics-cache/metrics-cache.component.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; - -import SharedModule from 'app/shared/shared.module'; -import { CacheMetrics } from 'app/admin/metrics/metrics.model'; -import { filterNaN } from 'app/core/util/operators'; - -@Component({ - standalone: true, - selector: 'jhi-metrics-cache', - templateUrl: './metrics-cache.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, - imports: [SharedModule], -}) -export class MetricsCacheComponent { - /** - * object containing all cache related metrics - */ - @Input() cacheMetrics?: { [key: string]: CacheMetrics }; - - /** - * boolean field saying if the metrics are in the process of being updated - */ - @Input() updating?: boolean; - - filterNaN = (input: number): number => filterNaN(input); -} diff --git a/src/main/webapp/app/admin/metrics/blocks/metrics-datasource/metrics-datasource.component.html b/src/main/webapp/app/admin/metrics/blocks/metrics-datasource/metrics-datasource.component.html deleted file mode 100644 index 5517f1590..000000000 --- a/src/main/webapp/app/admin/metrics/blocks/metrics-datasource/metrics-datasource.component.html +++ /dev/null @@ -1,57 +0,0 @@ -

DataSource statistics (time in millisecond)

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Connection Pool Usage (active: {{ datasourceMetrics.active.value }}, min: - {{ datasourceMetrics.min.value }}, max: {{ datasourceMetrics.max.value }}, idle: {{ datasourceMetrics.idle.value }}) - CountMeanMinp50p75p95p99Max
Acquire{{ datasourceMetrics.acquire.count }}{{ filterNaN(datasourceMetrics.acquire.mean) | number : '1.0-2' }}{{ datasourceMetrics.acquire['0.0'] | number : '1.0-3' }}{{ datasourceMetrics.acquire['0.5'] | number : '1.0-3' }}{{ datasourceMetrics.acquire['0.75'] | number : '1.0-3' }}{{ datasourceMetrics.acquire['0.95'] | number : '1.0-3' }}{{ datasourceMetrics.acquire['0.99'] | number : '1.0-3' }}{{ filterNaN(datasourceMetrics.acquire.max) | number : '1.0-2' }}
Creation{{ datasourceMetrics.creation.count }}{{ filterNaN(datasourceMetrics.creation.mean) | number : '1.0-2' }}{{ datasourceMetrics.creation['0.0'] | number : '1.0-3' }}{{ datasourceMetrics.creation['0.5'] | number : '1.0-3' }}{{ datasourceMetrics.creation['0.75'] | number : '1.0-3' }}{{ datasourceMetrics.creation['0.95'] | number : '1.0-3' }}{{ datasourceMetrics.creation['0.99'] | number : '1.0-3' }}{{ filterNaN(datasourceMetrics.creation.max) | number : '1.0-2' }}
Usage{{ datasourceMetrics.usage.count }}{{ filterNaN(datasourceMetrics.usage.mean) | number : '1.0-2' }}{{ datasourceMetrics.usage['0.0'] | number : '1.0-3' }}{{ datasourceMetrics.usage['0.5'] | number : '1.0-3' }}{{ datasourceMetrics.usage['0.75'] | number : '1.0-3' }}{{ datasourceMetrics.usage['0.95'] | number : '1.0-3' }}{{ datasourceMetrics.usage['0.99'] | number : '1.0-3' }}{{ filterNaN(datasourceMetrics.usage.max) | number : '1.0-2' }}
-
diff --git a/src/main/webapp/app/admin/metrics/blocks/metrics-datasource/metrics-datasource.component.ts b/src/main/webapp/app/admin/metrics/blocks/metrics-datasource/metrics-datasource.component.ts deleted file mode 100644 index b666e1a34..000000000 --- a/src/main/webapp/app/admin/metrics/blocks/metrics-datasource/metrics-datasource.component.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; - -import SharedModule from 'app/shared/shared.module'; -import { Databases } from 'app/admin/metrics/metrics.model'; -import { filterNaN } from 'app/core/util/operators'; - -@Component({ - standalone: true, - selector: 'jhi-metrics-datasource', - templateUrl: './metrics-datasource.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, - imports: [SharedModule], -}) -export class MetricsDatasourceComponent { - /** - * object containing all datasource related metrics - */ - @Input() datasourceMetrics?: Databases; - - /** - * boolean field saying if the metrics are in the process of being updated - */ - @Input() updating?: boolean; - - filterNaN = (input: number): number => filterNaN(input); -} diff --git a/src/main/webapp/app/admin/metrics/blocks/metrics-endpoints-requests/metrics-endpoints-requests.component.html b/src/main/webapp/app/admin/metrics/blocks/metrics-endpoints-requests/metrics-endpoints-requests.component.html deleted file mode 100644 index 4d3123fa6..000000000 --- a/src/main/webapp/app/admin/metrics/blocks/metrics-endpoints-requests/metrics-endpoints-requests.component.html +++ /dev/null @@ -1,24 +0,0 @@ -

Endpoints requests (time in millisecond)

- -
- - - - - - - - - - - - - - - - - - - -
MethodEndpoint urlCountMean
{{ method.key }}{{ entry.key }}{{ method.value!.count }}{{ method.value!.mean | number : '1.0-3' }}
-
diff --git a/src/main/webapp/app/admin/metrics/blocks/metrics-endpoints-requests/metrics-endpoints-requests.component.ts b/src/main/webapp/app/admin/metrics/blocks/metrics-endpoints-requests/metrics-endpoints-requests.component.ts deleted file mode 100644 index f96e80ad4..000000000 --- a/src/main/webapp/app/admin/metrics/blocks/metrics-endpoints-requests/metrics-endpoints-requests.component.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Component, Input } from '@angular/core'; - -import SharedModule from 'app/shared/shared.module'; -import { Services } from 'app/admin/metrics/metrics.model'; - -@Component({ - standalone: true, - selector: 'jhi-metrics-endpoints-requests', - templateUrl: './metrics-endpoints-requests.component.html', - imports: [SharedModule], -}) -export class MetricsEndpointsRequestsComponent { - /** - * object containing service related metrics - */ - @Input() endpointsRequestsMetrics?: Services; - - /** - * boolean field saying if the metrics are in the process of being updated - */ - @Input() updating?: boolean; -} diff --git a/src/main/webapp/app/admin/metrics/blocks/metrics-garbagecollector/metrics-garbagecollector.component.html b/src/main/webapp/app/admin/metrics/blocks/metrics-garbagecollector/metrics-garbagecollector.component.html deleted file mode 100644 index 814055b77..000000000 --- a/src/main/webapp/app/admin/metrics/blocks/metrics-garbagecollector/metrics-garbagecollector.component.html +++ /dev/null @@ -1,92 +0,0 @@ -

Garbage collections

- -
-
-
- - GC Live Data Size/GC Max Data Size ({{ garbageCollectorMetrics['jvm.gc.live.data.size'] / 1048576 | number : '1.0-0' }}M / - {{ garbageCollectorMetrics['jvm.gc.max.data.size'] / 1048576 | number : '1.0-0' }}M) - - - - - {{ - (100 * garbageCollectorMetrics['jvm.gc.live.data.size']) / garbageCollectorMetrics['jvm.gc.max.data.size'] | number : '1.0-2' - }}% - - -
-
- -
-
- - GC Memory Promoted/GC Memory Allocated ({{ garbageCollectorMetrics['jvm.gc.memory.promoted'] / 1048576 | number : '1.0-0' }}M / - {{ garbageCollectorMetrics['jvm.gc.memory.allocated'] / 1048576 | number : '1.0-0' }}M) - - - - - {{ - (100 * garbageCollectorMetrics['jvm.gc.memory.promoted']) / garbageCollectorMetrics['jvm.gc.memory.allocated'] - | number : '1.0-2' - }}% - - -
-
- -
-
-
Classes loaded
-
{{ garbageCollectorMetrics.classesLoaded }}
-
-
-
Classes unloaded
-
{{ garbageCollectorMetrics.classesUnloaded }}
-
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
CountMeanMinp50p75p95p99Max
jvm.gc.pause{{ garbageCollectorMetrics['jvm.gc.pause'].count }}{{ garbageCollectorMetrics['jvm.gc.pause'].mean | number : '1.0-3' }}{{ garbageCollectorMetrics['jvm.gc.pause']['0.0'] | number : '1.0-3' }}{{ garbageCollectorMetrics['jvm.gc.pause']['0.5'] | number : '1.0-3' }}{{ garbageCollectorMetrics['jvm.gc.pause']['0.75'] | number : '1.0-3' }}{{ garbageCollectorMetrics['jvm.gc.pause']['0.95'] | number : '1.0-3' }}{{ garbageCollectorMetrics['jvm.gc.pause']['0.99'] | number : '1.0-3' }}{{ garbageCollectorMetrics['jvm.gc.pause'].max | number : '1.0-3' }}
-
-
diff --git a/src/main/webapp/app/admin/metrics/blocks/metrics-garbagecollector/metrics-garbagecollector.component.ts b/src/main/webapp/app/admin/metrics/blocks/metrics-garbagecollector/metrics-garbagecollector.component.ts deleted file mode 100644 index 49e397d6b..000000000 --- a/src/main/webapp/app/admin/metrics/blocks/metrics-garbagecollector/metrics-garbagecollector.component.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Component, Input } from '@angular/core'; - -import SharedModule from 'app/shared/shared.module'; -import { GarbageCollector } from 'app/admin/metrics/metrics.model'; - -@Component({ - standalone: true, - selector: 'jhi-metrics-garbagecollector', - templateUrl: './metrics-garbagecollector.component.html', - imports: [SharedModule], -}) -export class MetricsGarbageCollectorComponent { - /** - * object containing garbage collector related metrics - */ - @Input() garbageCollectorMetrics?: GarbageCollector; - - /** - * boolean field saying if the metrics are in the process of being updated - */ - @Input() updating?: boolean; -} diff --git a/src/main/webapp/app/admin/metrics/blocks/metrics-modal-threads/metrics-modal-threads.component.html b/src/main/webapp/app/admin/metrics/blocks/metrics-modal-threads/metrics-modal-threads.component.html deleted file mode 100644 index b53179bec..000000000 --- a/src/main/webapp/app/admin/metrics/blocks/metrics-modal-threads/metrics-modal-threads.component.html +++ /dev/null @@ -1,90 +0,0 @@ - - - - diff --git a/src/main/webapp/app/admin/metrics/blocks/metrics-modal-threads/metrics-modal-threads.component.ts b/src/main/webapp/app/admin/metrics/blocks/metrics-modal-threads/metrics-modal-threads.component.ts deleted file mode 100644 index 72c05cc77..000000000 --- a/src/main/webapp/app/admin/metrics/blocks/metrics-modal-threads/metrics-modal-threads.component.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; - -import SharedModule from 'app/shared/shared.module'; -import { Thread, ThreadState } from 'app/admin/metrics/metrics.model'; - -@Component({ - standalone: true, - selector: 'jhi-thread-modal', - templateUrl: './metrics-modal-threads.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, - imports: [SharedModule], -}) -export class MetricsModalThreadsComponent implements OnInit { - ThreadState = ThreadState; - threadStateFilter?: ThreadState; - threads?: Thread[]; - threadDumpAll = 0; - threadDumpBlocked = 0; - threadDumpRunnable = 0; - threadDumpTimedWaiting = 0; - threadDumpWaiting = 0; - - constructor(private activeModal: NgbActiveModal) {} - - ngOnInit(): void { - this.threads?.forEach(thread => { - if (thread.threadState === ThreadState.Runnable) { - this.threadDumpRunnable += 1; - } else if (thread.threadState === ThreadState.Waiting) { - this.threadDumpWaiting += 1; - } else if (thread.threadState === ThreadState.TimedWaiting) { - this.threadDumpTimedWaiting += 1; - } else if (thread.threadState === ThreadState.Blocked) { - this.threadDumpBlocked += 1; - } - }); - - this.threadDumpAll = this.threadDumpRunnable + this.threadDumpWaiting + this.threadDumpTimedWaiting + this.threadDumpBlocked; - } - - getBadgeClass(threadState: ThreadState): string { - if (threadState === ThreadState.Runnable) { - return 'bg-success'; - } else if (threadState === ThreadState.Waiting) { - return 'bg-info'; - } else if (threadState === ThreadState.TimedWaiting) { - return 'bg-warning'; - } else if (threadState === ThreadState.Blocked) { - return 'bg-danger'; - } - return ''; - } - - getThreads(): Thread[] { - return this.threads?.filter(thread => !this.threadStateFilter || thread.threadState === this.threadStateFilter) ?? []; - } - - dismiss(): void { - this.activeModal.dismiss(); - } -} diff --git a/src/main/webapp/app/admin/metrics/blocks/metrics-request/metrics-request.component.html b/src/main/webapp/app/admin/metrics/blocks/metrics-request/metrics-request.component.html deleted file mode 100644 index 331db1ad1..000000000 --- a/src/main/webapp/app/admin/metrics/blocks/metrics-request/metrics-request.component.html +++ /dev/null @@ -1,26 +0,0 @@ -

HTTP requests (time in millisecond)

- - - - - - - - - - - - - - - - - - -
CodeCountMeanMax
{{ entry.key }} - - {{ entry.value.count }} - - - {{ filterNaN(entry.value.mean) | number : '1.0-2' }} - {{ entry.value.max | number : '1.0-2' }}
diff --git a/src/main/webapp/app/admin/metrics/blocks/metrics-request/metrics-request.component.ts b/src/main/webapp/app/admin/metrics/blocks/metrics-request/metrics-request.component.ts deleted file mode 100644 index d19bb0591..000000000 --- a/src/main/webapp/app/admin/metrics/blocks/metrics-request/metrics-request.component.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; - -import SharedModule from 'app/shared/shared.module'; -import { HttpServerRequests } from 'app/admin/metrics/metrics.model'; -import { filterNaN } from 'app/core/util/operators'; - -@Component({ - standalone: true, - selector: 'jhi-metrics-request', - templateUrl: './metrics-request.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, - imports: [SharedModule], -}) -export class MetricsRequestComponent { - /** - * object containing http request related metrics - */ - @Input() requestMetrics?: HttpServerRequests; - - /** - * boolean field saying if the metrics are in the process of being updated - */ - @Input() updating?: boolean; - - filterNaN = (input: number): number => filterNaN(input); -} diff --git a/src/main/webapp/app/admin/metrics/blocks/metrics-system/metrics-system.component.html b/src/main/webapp/app/admin/metrics/blocks/metrics-system/metrics-system.component.html deleted file mode 100644 index ecd07dd0b..000000000 --- a/src/main/webapp/app/admin/metrics/blocks/metrics-system/metrics-system.component.html +++ /dev/null @@ -1,51 +0,0 @@ -

System

- - -
-
Uptime
-
{{ convertMillisecondsToDuration(systemMetrics['process.uptime']) }}
-
- -
-
Start time
-
{{ systemMetrics['process.start.time'] | date : 'full' }}
-
- -
-
Process CPU usage
-
{{ 100 * systemMetrics['process.cpu.usage'] | number : '1.0-2' }} %
-
- - - {{ 100 * systemMetrics['process.cpu.usage'] | number : '1.0-2' }} % - - -
-
System CPU usage
-
{{ 100 * systemMetrics['system.cpu.usage'] | number : '1.0-2' }} %
-
- - - {{ 100 * systemMetrics['system.cpu.usage'] | number : '1.0-2' }} % - - -
-
System CPU count
-
{{ systemMetrics['system.cpu.count'] }}
-
- -
-
System 1m Load average
-
{{ systemMetrics['system.load.average.1m'] | number : '1.0-2' }}
-
- -
-
Process files max
-
{{ systemMetrics['process.files.max'] | number : '1.0-0' }}
-
- -
-
Process files open
-
{{ systemMetrics['process.files.open'] | number : '1.0-0' }}
-
-
diff --git a/src/main/webapp/app/admin/metrics/blocks/metrics-system/metrics-system.component.ts b/src/main/webapp/app/admin/metrics/blocks/metrics-system/metrics-system.component.ts deleted file mode 100644 index 143298975..000000000 --- a/src/main/webapp/app/admin/metrics/blocks/metrics-system/metrics-system.component.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; - -import SharedModule from 'app/shared/shared.module'; -import { ProcessMetrics } from 'app/admin/metrics/metrics.model'; - -@Component({ - standalone: true, - selector: 'jhi-metrics-system', - templateUrl: './metrics-system.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, - imports: [SharedModule], -}) -export class MetricsSystemComponent { - /** - * object containing thread related metrics - */ - @Input() systemMetrics?: ProcessMetrics; - - /** - * boolean field saying if the metrics are in the process of being updated - */ - @Input() updating?: boolean; - - convertMillisecondsToDuration(ms: number): string { - const times = { - year: 31557600000, - month: 2629746000, - day: 86400000, - hour: 3600000, - minute: 60000, - second: 1000, - }; - let timeString = ''; - for (const [key, value] of Object.entries(times)) { - if (Math.floor(ms / value) > 0) { - let plural = ''; - if (Math.floor(ms / value) > 1) { - plural = 's'; - } - timeString += `${Math.floor(ms / value).toString()} ${key.toString()}${plural} `; - ms = ms - value * Math.floor(ms / value); - } - } - return timeString; - } -} diff --git a/src/main/webapp/app/admin/metrics/metrics.component.html b/src/main/webapp/app/admin/metrics/metrics.component.html deleted file mode 100644 index c59876ce8..000000000 --- a/src/main/webapp/app/admin/metrics/metrics.component.html +++ /dev/null @@ -1,51 +0,0 @@ -
-

- Application Metrics - - -

- -

JVM Metrics

- -
- - - - - -
- - - -
Updating...
- - - - - - - - -
diff --git a/src/main/webapp/app/admin/metrics/metrics.component.spec.ts b/src/main/webapp/app/admin/metrics/metrics.component.spec.ts deleted file mode 100644 index 4d01399e7..000000000 --- a/src/main/webapp/app/admin/metrics/metrics.component.spec.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { of } from 'rxjs'; - -import MetricsComponent from './metrics.component'; -import { MetricsService } from './metrics.service'; -import { Metrics } from './metrics.model'; - -describe('MetricsComponent', () => { - let comp: MetricsComponent; - let fixture: ComponentFixture; - let service: MetricsService; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, MetricsComponent], - }) - .overrideTemplate(MetricsComponent, '') - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(MetricsComponent); - comp = fixture.componentInstance; - service = TestBed.inject(MetricsService); - }); - - describe('refresh', () => { - it('should call refresh on init', () => { - // GIVEN - jest.spyOn(service, 'getMetrics').mockReturnValue(of({} as Metrics)); - - // WHEN - comp.ngOnInit(); - - // THEN - expect(service.getMetrics).toHaveBeenCalled(); - }); - }); -}); diff --git a/src/main/webapp/app/admin/metrics/metrics.component.ts b/src/main/webapp/app/admin/metrics/metrics.component.ts deleted file mode 100644 index 2397694f9..000000000 --- a/src/main/webapp/app/admin/metrics/metrics.component.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Component, OnInit, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; -import { combineLatest } from 'rxjs'; - -import SharedModule from 'app/shared/shared.module'; -import { MetricsService } from './metrics.service'; -import { Metrics, Thread } from './metrics.model'; -import { JvmMemoryComponent } from './blocks/jvm-memory/jvm-memory.component'; -import { JvmThreadsComponent } from './blocks/jvm-threads/jvm-threads.component'; -import { MetricsCacheComponent } from './blocks/metrics-cache/metrics-cache.component'; -import { MetricsDatasourceComponent } from './blocks/metrics-datasource/metrics-datasource.component'; -import { MetricsEndpointsRequestsComponent } from './blocks/metrics-endpoints-requests/metrics-endpoints-requests.component'; -import { MetricsGarbageCollectorComponent } from './blocks/metrics-garbagecollector/metrics-garbagecollector.component'; -import { MetricsModalThreadsComponent } from './blocks/metrics-modal-threads/metrics-modal-threads.component'; -import { MetricsRequestComponent } from './blocks/metrics-request/metrics-request.component'; -import { MetricsSystemComponent } from './blocks/metrics-system/metrics-system.component'; - -@Component({ - standalone: true, - selector: 'jhi-metrics', - templateUrl: './metrics.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, - imports: [ - SharedModule, - JvmMemoryComponent, - JvmThreadsComponent, - MetricsCacheComponent, - MetricsDatasourceComponent, - MetricsEndpointsRequestsComponent, - MetricsGarbageCollectorComponent, - MetricsModalThreadsComponent, - MetricsRequestComponent, - MetricsSystemComponent, - ], -}) -export default class MetricsComponent implements OnInit { - metrics?: Metrics; - threads?: Thread[]; - updatingMetrics = true; - - constructor(private metricsService: MetricsService, private changeDetector: ChangeDetectorRef) {} - - ngOnInit(): void { - this.refresh(); - } - - refresh(): void { - this.updatingMetrics = true; - combineLatest([this.metricsService.getMetrics(), this.metricsService.threadDump()]).subscribe(([metrics, threadDump]) => { - this.metrics = metrics; - this.threads = threadDump.threads; - this.updatingMetrics = false; - this.changeDetector.markForCheck(); - }); - } - - metricsKeyExists(key: keyof Metrics): boolean { - return Boolean(this.metrics?.[key]); - } - - metricsKeyExistsAndObjectNotEmpty(key: keyof Metrics): boolean { - return Boolean(this.metrics?.[key] && JSON.stringify(this.metrics[key]) !== '{}'); - } -} diff --git a/src/main/webapp/app/admin/metrics/metrics.model.ts b/src/main/webapp/app/admin/metrics/metrics.model.ts deleted file mode 100644 index d9576a903..000000000 --- a/src/main/webapp/app/admin/metrics/metrics.model.ts +++ /dev/null @@ -1,159 +0,0 @@ -export interface Metrics { - jvm: { [key: string]: JvmMetrics }; - databases: Databases; - 'http.server.requests': HttpServerRequests; - cache: { [key: string]: CacheMetrics }; - garbageCollector: GarbageCollector; - services: Services; - processMetrics: ProcessMetrics; -} - -export interface JvmMetrics { - committed: number; - max: number; - used: number; -} - -export interface Databases { - min: Value; - idle: Value; - max: Value; - usage: MetricsWithPercentile; - pending: Value; - active: Value; - acquire: MetricsWithPercentile; - creation: MetricsWithPercentile; - connections: Value; -} - -export interface Value { - value: number; -} - -export interface MetricsWithPercentile { - '0.0': number; - '1.0': number; - max: number; - totalTime: number; - mean: number; - '0.5': number; - count: number; - '0.99': number; - '0.75': number; - '0.95': number; -} - -export interface HttpServerRequests { - all: { - count: number; - }; - percode: { [key: string]: MaxMeanCount }; -} - -export interface MaxMeanCount { - max: number; - mean: number; - count: number; -} - -export interface CacheMetrics { - 'cache.gets.miss': number; - 'cache.puts': number; - 'cache.gets.hit': number; - 'cache.removals': number; - 'cache.evictions': number; -} - -export interface GarbageCollector { - 'jvm.gc.max.data.size': number; - 'jvm.gc.pause': MetricsWithPercentile; - 'jvm.gc.memory.promoted': number; - 'jvm.gc.memory.allocated': number; - classesLoaded: number; - 'jvm.gc.live.data.size': number; - classesUnloaded: number; -} - -export interface Services { - [key: string]: { - [key in HttpMethod]?: MaxMeanCount; - }; -} - -export enum HttpMethod { - Post = 'POST', - Get = 'GET', - Put = 'PUT', - Patch = 'PATCH', - Delete = 'DELETE', -} - -export interface ProcessMetrics { - 'system.cpu.usage': number; - 'system.cpu.count': number; - 'system.load.average.1m'?: number; - 'process.cpu.usage': number; - 'process.files.max'?: number; - 'process.files.open'?: number; - 'process.start.time': number; - 'process.uptime': number; -} - -export interface ThreadDump { - threads: Thread[]; -} - -export interface Thread { - threadName: string; - threadId: number; - blockedTime: number; - blockedCount: number; - waitedTime: number; - waitedCount: number; - lockName: string | null; - lockOwnerId: number; - lockOwnerName: string | null; - daemon: boolean; - inNative: boolean; - suspended: boolean; - threadState: ThreadState; - priority: number; - stackTrace: StackTrace[]; - lockedMonitors: LockedMonitor[]; - lockedSynchronizers: string[]; - lockInfo: LockInfo | null; - // custom field for showing-hiding thread dump - showThreadDump?: boolean; -} - -export interface LockInfo { - className: string; - identityHashCode: number; -} - -export interface LockedMonitor { - className: string; - identityHashCode: number; - lockedStackDepth: number; - lockedStackFrame: StackTrace; -} - -export interface StackTrace { - classLoaderName: string | null; - moduleName: string | null; - moduleVersion: string | null; - methodName: string; - fileName: string; - lineNumber: number; - className: string; - nativeMethod: boolean; -} - -export enum ThreadState { - Runnable = 'RUNNABLE', - TimedWaiting = 'TIMED_WAITING', - Waiting = 'WAITING', - Blocked = 'BLOCKED', - New = 'NEW', - Terminated = 'TERMINATED', -} diff --git a/src/main/webapp/app/admin/metrics/metrics.service.spec.ts b/src/main/webapp/app/admin/metrics/metrics.service.spec.ts deleted file mode 100644 index 468ebd52d..000000000 --- a/src/main/webapp/app/admin/metrics/metrics.service.spec.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; - -import { MetricsService } from './metrics.service'; -import { ThreadDump, ThreadState } from './metrics.model'; - -describe('Logs Service', () => { - let service: MetricsService; - let httpMock: HttpTestingController; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - }); - service = TestBed.inject(MetricsService); - httpMock = TestBed.inject(HttpTestingController); - }); - - afterEach(() => { - httpMock.verify(); - }); - - describe('Service methods', () => { - it('should return Metrics', () => { - let expectedResult; - const metrics = { - jvm: {}, - 'http.server.requests': {}, - cache: {}, - services: {}, - databases: {}, - garbageCollector: {}, - processMetrics: {}, - }; - - service.getMetrics().subscribe(received => { - expectedResult = received; - }); - - const req = httpMock.expectOne({ method: 'GET' }); - req.flush(metrics); - expect(expectedResult).toEqual(metrics); - }); - - it('should return Thread Dump', () => { - let expectedResult: ThreadDump | null = null; - const dump: ThreadDump = { - threads: [ - { - threadName: 'Reference Handler', - threadId: 2, - blockedTime: -1, - blockedCount: 7, - waitedTime: -1, - waitedCount: 0, - lockName: null, - lockOwnerId: -1, - lockOwnerName: null, - daemon: true, - inNative: false, - suspended: false, - threadState: ThreadState.Runnable, - priority: 10, - stackTrace: [], - lockedMonitors: [], - lockedSynchronizers: [], - lockInfo: null, - }, - ], - }; - - service.threadDump().subscribe(received => { - expectedResult = received; - }); - - const req = httpMock.expectOne({ method: 'GET' }); - req.flush(dump); - expect(expectedResult).toEqual(dump); - }); - }); -}); diff --git a/src/main/webapp/app/admin/metrics/metrics.service.ts b/src/main/webapp/app/admin/metrics/metrics.service.ts deleted file mode 100644 index 1d27f2b13..000000000 --- a/src/main/webapp/app/admin/metrics/metrics.service.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { Observable } from 'rxjs'; - -import { ApplicationConfigService } from 'app/core/config/application-config.service'; -import { Metrics, ThreadDump } from './metrics.model'; - -@Injectable({ providedIn: 'root' }) -export class MetricsService { - constructor(private http: HttpClient, private applicationConfigService: ApplicationConfigService) {} - - getMetrics(): Observable { - return this.http.get(this.applicationConfigService.getEndpointFor('management/jhimetrics')); - } - - threadDump(): Observable { - return this.http.get(this.applicationConfigService.getEndpointFor('management/threaddump')); - } -} diff --git a/src/main/webapp/app/admin/user-management/delete/user-management-delete-dialog.component.html b/src/main/webapp/app/admin/user-management/delete/user-management-delete-dialog.component.html deleted file mode 100644 index 0ae0c95bf..000000000 --- a/src/main/webapp/app/admin/user-management/delete/user-management-delete-dialog.component.html +++ /dev/null @@ -1,25 +0,0 @@ -
- - - - - -
diff --git a/src/main/webapp/app/admin/user-management/delete/user-management-delete-dialog.component.spec.ts b/src/main/webapp/app/admin/user-management/delete/user-management-delete-dialog.component.spec.ts deleted file mode 100644 index add011149..000000000 --- a/src/main/webapp/app/admin/user-management/delete/user-management-delete-dialog.component.spec.ts +++ /dev/null @@ -1,51 +0,0 @@ -jest.mock('@ng-bootstrap/ng-bootstrap'); - -import { ComponentFixture, TestBed, waitForAsync, inject, fakeAsync, tick } from '@angular/core/testing'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; -import { of } from 'rxjs'; - -import { UserManagementService } from '../service/user-management.service'; - -import UserManagementDeleteDialogComponent from './user-management-delete-dialog.component'; - -describe('User Management Delete Component', () => { - let comp: UserManagementDeleteDialogComponent; - let fixture: ComponentFixture; - let service: UserManagementService; - let mockActiveModal: NgbActiveModal; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, UserManagementDeleteDialogComponent], - providers: [NgbActiveModal], - }) - .overrideTemplate(UserManagementDeleteDialogComponent, '') - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(UserManagementDeleteDialogComponent); - comp = fixture.componentInstance; - service = TestBed.inject(UserManagementService); - mockActiveModal = TestBed.inject(NgbActiveModal); - }); - - describe('confirmDelete', () => { - it('Should call delete service on confirmDelete', inject( - [], - fakeAsync(() => { - // GIVEN - jest.spyOn(service, 'delete').mockReturnValue(of({})); - - // WHEN - comp.confirmDelete('user'); - tick(); - - // THEN - expect(service.delete).toHaveBeenCalledWith('user'); - expect(mockActiveModal.close).toHaveBeenCalledWith('deleted'); - }) - )); - }); -}); diff --git a/src/main/webapp/app/admin/user-management/delete/user-management-delete-dialog.component.ts b/src/main/webapp/app/admin/user-management/delete/user-management-delete-dialog.component.ts deleted file mode 100644 index 6e3840040..000000000 --- a/src/main/webapp/app/admin/user-management/delete/user-management-delete-dialog.component.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Component } from '@angular/core'; -import { FormsModule } from '@angular/forms'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; - -import SharedModule from 'app/shared/shared.module'; -import { User } from '../user-management.model'; -import { UserManagementService } from '../service/user-management.service'; - -@Component({ - standalone: true, - selector: 'jhi-user-mgmt-delete-dialog', - templateUrl: './user-management-delete-dialog.component.html', - imports: [SharedModule, FormsModule], -}) -export default class UserManagementDeleteDialogComponent { - user?: User; - - constructor(private userService: UserManagementService, private activeModal: NgbActiveModal) {} - - cancel(): void { - this.activeModal.dismiss(); - } - - confirmDelete(login: string): void { - this.userService.delete(login).subscribe(() => { - this.activeModal.close('deleted'); - }); - } -} diff --git a/src/main/webapp/app/admin/user-management/detail/user-management-detail.component.html b/src/main/webapp/app/admin/user-management/detail/user-management-detail.component.html deleted file mode 100644 index e19d112fd..000000000 --- a/src/main/webapp/app/admin/user-management/detail/user-management-detail.component.html +++ /dev/null @@ -1,56 +0,0 @@ -
-
-
-

- User [{{ user.login }}] -

- -
-
Login
-
- {{ user.login }} - Activated - Deactivated -
- -
First name
-
{{ user.firstName }}
- -
Last name
-
{{ user.lastName }}
- -
Email
-
{{ user.email }}
- -
Language
-
{{ user.langKey }}
- -
Created by
-
{{ user.createdBy }}
- -
Created date
-
{{ user.createdDate | date : 'dd/MM/yy HH:mm' }}
- -
Modified by
-
{{ user.lastModifiedBy }}
- -
Modified date
-
{{ user.lastModifiedDate | date : 'dd/MM/yy HH:mm' }}
- -
Profiles
-
-
    -
  • - {{ authority }} -
  • -
-
-
- - -
-
-
diff --git a/src/main/webapp/app/admin/user-management/detail/user-management-detail.component.spec.ts b/src/main/webapp/app/admin/user-management/detail/user-management-detail.component.spec.ts deleted file mode 100644 index 515ccbf42..000000000 --- a/src/main/webapp/app/admin/user-management/detail/user-management-detail.component.spec.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { ActivatedRoute } from '@angular/router'; -import { of } from 'rxjs'; - -import { Authority } from 'app/config/authority.constants'; -import { User } from '../user-management.model'; - -import UserManagementDetailComponent from './user-management-detail.component'; - -describe('User Management Detail Component', () => { - let comp: UserManagementDetailComponent; - let fixture: ComponentFixture; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [UserManagementDetailComponent], - providers: [ - { - provide: ActivatedRoute, - useValue: { - data: of({ user: new User(123, 'user', 'first', 'last', 'first@last.com', true, 'en', [Authority.USER], 'admin') }), - }, - }, - ], - }) - .overrideTemplate(UserManagementDetailComponent, '') - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(UserManagementDetailComponent); - comp = fixture.componentInstance; - }); - - describe('OnInit', () => { - it('Should call load all on init', () => { - // WHEN - comp.ngOnInit(); - - // THEN - expect(comp.user).toEqual( - expect.objectContaining({ - id: 123, - login: 'user', - firstName: 'first', - lastName: 'last', - email: 'first@last.com', - activated: true, - langKey: 'en', - authorities: [Authority.USER], - createdBy: 'admin', - }) - ); - }); - }); -}); diff --git a/src/main/webapp/app/admin/user-management/detail/user-management-detail.component.ts b/src/main/webapp/app/admin/user-management/detail/user-management-detail.component.ts deleted file mode 100644 index b8a7c8fed..000000000 --- a/src/main/webapp/app/admin/user-management/detail/user-management-detail.component.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import SharedModule from 'app/shared/shared.module'; - -import { User } from '../user-management.model'; - -@Component({ - standalone: true, - selector: 'jhi-user-mgmt-detail', - templateUrl: './user-management-detail.component.html', - imports: [SharedModule], -}) -export default class UserManagementDetailComponent implements OnInit { - user: User | null = null; - - constructor(private route: ActivatedRoute) {} - - ngOnInit(): void { - this.route.data.subscribe(({ user }) => { - this.user = user; - }); - } -} diff --git a/src/main/webapp/app/admin/user-management/list/user-management.component.html b/src/main/webapp/app/admin/user-management/list/user-management.component.html deleted file mode 100644 index 6fd89f8d1..000000000 --- a/src/main/webapp/app/admin/user-management/list/user-management.component.html +++ /dev/null @@ -1,124 +0,0 @@ -
-

- Users - -
- - -
-

- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ID Login Email - Language - Profiles - Created date - - Modified by - - Modified date -
- {{ user.id }} - {{ user.login }}{{ user.email }} - - - {{ user.langKey }} -
- {{ authority }} -
-
{{ user.createdDate | date : 'dd/MM/yy HH:mm' }}{{ user.lastModifiedBy }}{{ user.lastModifiedDate | date : 'dd/MM/yy HH:mm' }} -
- - - - - -
-
-
- -
-
- -
- -
- -
-
-
diff --git a/src/main/webapp/app/admin/user-management/list/user-management.component.spec.ts b/src/main/webapp/app/admin/user-management/list/user-management.component.spec.ts deleted file mode 100644 index 7a0ca2862..000000000 --- a/src/main/webapp/app/admin/user-management/list/user-management.component.spec.ts +++ /dev/null @@ -1,103 +0,0 @@ -jest.mock('app/core/auth/account.service'); - -import { ComponentFixture, TestBed, waitForAsync, inject, fakeAsync, tick } from '@angular/core/testing'; -import { HttpHeaders, HttpResponse } from '@angular/common/http'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { ActivatedRoute } from '@angular/router'; -import { RouterTestingModule } from '@angular/router/testing'; -import { of } from 'rxjs'; - -import { UserManagementService } from '../service/user-management.service'; -import { User } from '../user-management.model'; -import { AccountService } from 'app/core/auth/account.service'; - -import UserManagementComponent from './user-management.component'; - -describe('User Management Component', () => { - let comp: UserManagementComponent; - let fixture: ComponentFixture; - let service: UserManagementService; - let mockAccountService: AccountService; - const data = of({ - defaultSort: 'id,asc', - }); - const queryParamMap = of( - jest.requireActual('@angular/router').convertToParamMap({ - page: '1', - size: '1', - sort: 'id,desc', - }) - ); - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, RouterTestingModule.withRoutes([]), UserManagementComponent], - providers: [{ provide: ActivatedRoute, useValue: { data, queryParamMap } }, AccountService], - }) - .overrideTemplate(UserManagementComponent, '') - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(UserManagementComponent); - comp = fixture.componentInstance; - service = TestBed.inject(UserManagementService); - mockAccountService = TestBed.inject(AccountService); - mockAccountService.identity = jest.fn(() => of(null)); - }); - - describe('OnInit', () => { - it('Should call load all on init', inject( - [], - fakeAsync(() => { - // GIVEN - const headers = new HttpHeaders().append('link', 'link;link'); - jest.spyOn(service, 'query').mockReturnValue( - of( - new HttpResponse({ - body: [new User(123)], - headers, - }) - ) - ); - - // WHEN - comp.ngOnInit(); - tick(); // simulate async - - // THEN - expect(service.query).toHaveBeenCalled(); - expect(comp.users?.[0]).toEqual(expect.objectContaining({ id: 123 })); - }) - )); - }); - - describe('setActive', () => { - it('Should update user and call load all', inject( - [], - fakeAsync(() => { - // GIVEN - const headers = new HttpHeaders().append('link', 'link;link'); - const user = new User(123); - jest.spyOn(service, 'query').mockReturnValue( - of( - new HttpResponse({ - body: [user], - headers, - }) - ) - ); - jest.spyOn(service, 'update').mockReturnValue(of(user)); - - // WHEN - comp.setActive(user, true); - tick(); // simulate async - - // THEN - expect(service.update).toHaveBeenCalledWith({ ...user, activated: true }); - expect(service.query).toHaveBeenCalled(); - expect(comp.users?.[0]).toEqual(expect.objectContaining({ id: 123 })); - }) - )); - }); -}); diff --git a/src/main/webapp/app/admin/user-management/list/user-management.component.ts b/src/main/webapp/app/admin/user-management/list/user-management.component.ts deleted file mode 100644 index 2fd88a764..000000000 --- a/src/main/webapp/app/admin/user-management/list/user-management.component.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { RouterModule } from '@angular/router'; -import { HttpResponse, HttpHeaders } from '@angular/common/http'; -import { ActivatedRoute, Router } from '@angular/router'; -import { combineLatest } from 'rxjs'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; - -import SharedModule from 'app/shared/shared.module'; -import { SortDirective, SortByDirective } from 'app/shared/sort'; -import { ITEMS_PER_PAGE } from 'app/config/pagination.constants'; -import { ASC, DESC, SORT } from 'app/config/navigation.constants'; -import { ItemCountComponent } from 'app/shared/pagination'; -import { AccountService } from 'app/core/auth/account.service'; -import { Account } from 'app/core/auth/account.model'; -import { UserManagementService } from '../service/user-management.service'; -import { User } from '../user-management.model'; -import UserManagementDeleteDialogComponent from '../delete/user-management-delete-dialog.component'; - -@Component({ - standalone: true, - selector: 'jhi-user-mgmt', - templateUrl: './user-management.component.html', - imports: [RouterModule, SharedModule, SortDirective, SortByDirective, UserManagementDeleteDialogComponent, ItemCountComponent], -}) -export default class UserManagementComponent implements OnInit { - currentAccount: Account | null = null; - users: User[] | null = null; - isLoading = false; - totalItems = 0; - itemsPerPage = ITEMS_PER_PAGE; - page!: number; - predicate!: string; - ascending!: boolean; - - constructor( - private userService: UserManagementService, - private accountService: AccountService, - private activatedRoute: ActivatedRoute, - private router: Router, - private modalService: NgbModal - ) {} - - ngOnInit(): void { - this.accountService.identity().subscribe(account => (this.currentAccount = account)); - this.handleNavigation(); - } - - setActive(user: User, isActivated: boolean): void { - this.userService.update({ ...user, activated: isActivated }).subscribe(() => this.loadAll()); - } - - trackIdentity(_index: number, item: User): number { - return item.id!; - } - - deleteUser(user: User): void { - const modalRef = this.modalService.open(UserManagementDeleteDialogComponent, { size: 'lg', backdrop: 'static' }); - modalRef.componentInstance.user = user; - // unsubscribe not needed because closed completes on modal close - modalRef.closed.subscribe(reason => { - if (reason === 'deleted') { - this.loadAll(); - } - }); - } - - loadAll(): void { - this.isLoading = true; - this.userService - .query({ - page: this.page - 1, - size: this.itemsPerPage, - sort: this.sort(), - }) - .subscribe({ - next: (res: HttpResponse) => { - this.isLoading = false; - this.onSuccess(res.body, res.headers); - }, - error: () => (this.isLoading = false), - }); - } - - transition(): void { - this.router.navigate(['./'], { - relativeTo: this.activatedRoute.parent, - queryParams: { - page: this.page, - sort: `${this.predicate},${this.ascending ? ASC : DESC}`, - }, - }); - } - - private handleNavigation(): void { - combineLatest([this.activatedRoute.data, this.activatedRoute.queryParamMap]).subscribe(([data, params]) => { - const page = params.get('page'); - this.page = +(page ?? 1); - const sort = (params.get(SORT) ?? data['defaultSort']).split(','); - this.predicate = sort[0]; - this.ascending = sort[1] === ASC; - this.loadAll(); - }); - } - - private sort(): string[] { - const result = [`${this.predicate},${this.ascending ? ASC : DESC}`]; - if (this.predicate !== 'id') { - result.push('id'); - } - return result; - } - - private onSuccess(users: User[] | null, headers: HttpHeaders): void { - this.totalItems = Number(headers.get('X-Total-Count')); - this.users = users; - } -} diff --git a/src/main/webapp/app/admin/user-management/service/user-management.service.spec.ts b/src/main/webapp/app/admin/user-management/service/user-management.service.spec.ts deleted file mode 100644 index 41a6ec89d..000000000 --- a/src/main/webapp/app/admin/user-management/service/user-management.service.spec.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { HttpErrorResponse } from '@angular/common/http'; -import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; - -import { Authority } from 'app/config/authority.constants'; -import { User } from '../user-management.model'; - -import { UserManagementService } from './user-management.service'; - -describe('User Service', () => { - let service: UserManagementService; - let httpMock: HttpTestingController; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - }); - - service = TestBed.inject(UserManagementService); - httpMock = TestBed.inject(HttpTestingController); - }); - - afterEach(() => { - httpMock.verify(); - }); - - describe('Service methods', () => { - it('should return User', () => { - let expectedResult: string | undefined; - - service.find('user').subscribe(received => { - expectedResult = received.login; - }); - - const req = httpMock.expectOne({ method: 'GET' }); - req.flush(new User(123, 'user')); - expect(expectedResult).toEqual('user'); - }); - - it('should return Authorities', () => { - let expectedResult: string[] = []; - - service.authorities().subscribe(authorities => { - expectedResult = authorities; - }); - const req = httpMock.expectOne({ method: 'GET' }); - - req.flush([Authority.USER, Authority.ADMIN]); - expect(expectedResult).toEqual([Authority.USER, Authority.ADMIN]); - }); - - it('should propagate not found response', () => { - let expectedResult = 0; - - service.find('user').subscribe({ - error: (error: HttpErrorResponse) => (expectedResult = error.status), - }); - - const req = httpMock.expectOne({ method: 'GET' }); - req.flush('Invalid request parameters', { - status: 404, - statusText: 'Bad Request', - }); - expect(expectedResult).toEqual(404); - }); - }); -}); diff --git a/src/main/webapp/app/admin/user-management/service/user-management.service.ts b/src/main/webapp/app/admin/user-management/service/user-management.service.ts deleted file mode 100644 index 3c9a84260..000000000 --- a/src/main/webapp/app/admin/user-management/service/user-management.service.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient, HttpResponse } from '@angular/common/http'; -import { Observable } from 'rxjs'; - -import { ApplicationConfigService } from 'app/core/config/application-config.service'; -import { createRequestOption } from 'app/core/request/request-util'; -import { Pagination } from 'app/core/request/request.model'; -import { IUser } from '../user-management.model'; - -@Injectable({ providedIn: 'root' }) -export class UserManagementService { - private resourceUrl = this.applicationConfigService.getEndpointFor('api/admin/users'); - - constructor(private http: HttpClient, private applicationConfigService: ApplicationConfigService) {} - - create(user: IUser): Observable { - return this.http.post(this.resourceUrl, user); - } - - update(user: IUser): Observable { - return this.http.put(this.resourceUrl, user); - } - - find(login: string): Observable { - return this.http.get(`${this.resourceUrl}/${login}`); - } - - query(req?: Pagination): Observable> { - const options = createRequestOption(req); - return this.http.get(this.resourceUrl, { params: options, observe: 'response' }); - } - - delete(login: string): Observable<{}> { - return this.http.delete(`${this.resourceUrl}/${login}`); - } - - authorities(): Observable { - return this.http.get(this.applicationConfigService.getEndpointFor('api/authorities')); - } -} diff --git a/src/main/webapp/app/admin/user-management/update/user-management-update.component.html b/src/main/webapp/app/admin/user-management/update/user-management-update.component.html deleted file mode 100644 index 147040f18..000000000 --- a/src/main/webapp/app/admin/user-management/update/user-management-update.component.html +++ /dev/null @@ -1,142 +0,0 @@ -
-
-
-

Create or edit a user

- - - -
- - -
- -
- - - -
- - This field is required. - - - - This field cannot be longer than 50 characters. - - - - This field can only contain letters, digits and e-mail addresses. - -
-
- -
- - - -
- - This field cannot be longer than 50 characters. - -
-
- -
- - - -
- - This field cannot be longer than 50 characters. - -
-
- -
- - - -
- - This field is required. - - - - This field cannot be longer than 100 characters. - - - - This field is required to be at least 5 characters. - - - - Your email is invalid. - -
-
- -
- -
- -
- - -
- -
- - -
- - - -
-
-
diff --git a/src/main/webapp/app/admin/user-management/update/user-management-update.component.spec.ts b/src/main/webapp/app/admin/user-management/update/user-management-update.component.spec.ts deleted file mode 100644 index ee3ae4dfd..000000000 --- a/src/main/webapp/app/admin/user-management/update/user-management-update.component.spec.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync, inject, fakeAsync, tick } from '@angular/core/testing'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { FormBuilder } from '@angular/forms'; -import { ActivatedRoute } from '@angular/router'; -import { of } from 'rxjs'; - -import { Authority } from 'app/config/authority.constants'; -import { UserManagementService } from '../service/user-management.service'; -import { User } from '../user-management.model'; - -import UserManagementUpdateComponent from './user-management-update.component'; - -describe('User Management Update Component', () => { - let comp: UserManagementUpdateComponent; - let fixture: ComponentFixture; - let service: UserManagementService; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, UserManagementUpdateComponent], - providers: [ - FormBuilder, - { - provide: ActivatedRoute, - useValue: { - data: of({ user: new User(123, 'user', 'first', 'last', 'first@last.com', true, 'en', [Authority.USER], 'admin') }), - }, - }, - ], - }) - .overrideTemplate(UserManagementUpdateComponent, '') - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(UserManagementUpdateComponent); - comp = fixture.componentInstance; - service = TestBed.inject(UserManagementService); - }); - - describe('OnInit', () => { - it('Should load authorities and language on init', inject( - [], - fakeAsync(() => { - // GIVEN - jest.spyOn(service, 'authorities').mockReturnValue(of(['USER'])); - - // WHEN - comp.ngOnInit(); - - // THEN - expect(service.authorities).toHaveBeenCalled(); - expect(comp.authorities).toEqual(['USER']); - }) - )); - }); - - describe('save', () => { - it('Should call update service on save for existing user', inject( - [], - fakeAsync(() => { - // GIVEN - const entity = { id: 123 }; - jest.spyOn(service, 'update').mockReturnValue(of(entity)); - comp.editForm.patchValue(entity); - // WHEN - comp.save(); - tick(); // simulate async - - // THEN - expect(service.update).toHaveBeenCalledWith(expect.objectContaining(entity)); - expect(comp.isSaving).toEqual(false); - }) - )); - - it('Should call create service on save for new user', inject( - [], - fakeAsync(() => { - // GIVEN - const entity = { login: 'foo' } as User; - jest.spyOn(service, 'create').mockReturnValue(of(entity)); - comp.editForm.patchValue(entity); - // WHEN - comp.save(); - tick(); // simulate async - - // THEN - expect(comp.editForm.getRawValue().id).toBeNull(); - expect(service.create).toHaveBeenCalledWith(expect.objectContaining(entity)); - expect(comp.isSaving).toEqual(false); - }) - )); - }); -}); diff --git a/src/main/webapp/app/admin/user-management/update/user-management-update.component.ts b/src/main/webapp/app/admin/user-management/update/user-management-update.component.ts deleted file mode 100644 index 6da7102e9..000000000 --- a/src/main/webapp/app/admin/user-management/update/user-management-update.component.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { FormGroup, FormControl, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'; -import { ActivatedRoute } from '@angular/router'; - -import SharedModule from 'app/shared/shared.module'; -import { LANGUAGES } from 'app/config/language.constants'; -import { IUser } from '../user-management.model'; -import { UserManagementService } from '../service/user-management.service'; - -const userTemplate = {} as IUser; - -const newUser: IUser = { - langKey: 'en', - activated: true, -} as IUser; - -@Component({ - standalone: true, - selector: 'jhi-user-mgmt-update', - templateUrl: './user-management-update.component.html', - imports: [SharedModule, FormsModule, ReactiveFormsModule], -}) -export default class UserManagementUpdateComponent implements OnInit { - languages = LANGUAGES; - authorities: string[] = []; - isSaving = false; - - editForm = new FormGroup({ - id: new FormControl(userTemplate.id), - login: new FormControl(userTemplate.login, { - nonNullable: true, - validators: [ - Validators.required, - Validators.minLength(1), - Validators.maxLength(50), - Validators.pattern('^[a-zA-Z0-9!$&*+=?^_`{|}~.-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*$|^[_.@A-Za-z0-9-]+$'), - ], - }), - firstName: new FormControl(userTemplate.firstName, { validators: [Validators.maxLength(50)] }), - lastName: new FormControl(userTemplate.lastName, { validators: [Validators.maxLength(50)] }), - email: new FormControl(userTemplate.email, { - nonNullable: true, - validators: [Validators.minLength(5), Validators.maxLength(254), Validators.email], - }), - activated: new FormControl(userTemplate.activated, { nonNullable: true }), - langKey: new FormControl(userTemplate.langKey, { nonNullable: true }), - authorities: new FormControl(userTemplate.authorities, { nonNullable: true }), - }); - - constructor(private userService: UserManagementService, private route: ActivatedRoute) {} - - ngOnInit(): void { - this.route.data.subscribe(({ user }) => { - if (user) { - this.editForm.reset(user); - } else { - this.editForm.reset(newUser); - } - }); - this.userService.authorities().subscribe(authorities => (this.authorities = authorities)); - } - - previousState(): void { - window.history.back(); - } - - save(): void { - this.isSaving = true; - const user = this.editForm.getRawValue(); - if (user.id !== null) { - this.userService.update(user).subscribe({ - next: () => this.onSaveSuccess(), - error: () => this.onSaveError(), - }); - } else { - this.userService.create(user).subscribe({ - next: () => this.onSaveSuccess(), - error: () => this.onSaveError(), - }); - } - } - - private onSaveSuccess(): void { - this.isSaving = false; - this.previousState(); - } - - private onSaveError(): void { - this.isSaving = false; - } -} diff --git a/src/main/webapp/app/admin/user-management/user-management.model.ts b/src/main/webapp/app/admin/user-management/user-management.model.ts deleted file mode 100644 index 01684285c..000000000 --- a/src/main/webapp/app/admin/user-management/user-management.model.ts +++ /dev/null @@ -1,31 +0,0 @@ -export interface IUser { - id: number | null; - login?: string; - firstName?: string | null; - lastName?: string | null; - email?: string; - activated?: boolean; - langKey?: string; - authorities?: string[]; - createdBy?: string; - createdDate?: Date; - lastModifiedBy?: string; - lastModifiedDate?: Date; -} - -export class User implements IUser { - constructor( - public id: number | null, - public login?: string, - public firstName?: string | null, - public lastName?: string | null, - public email?: string, - public activated?: boolean, - public langKey?: string, - public authorities?: string[], - public createdBy?: string, - public createdDate?: Date, - public lastModifiedBy?: string, - public lastModifiedDate?: Date - ) {} -} diff --git a/src/main/webapp/app/admin/user-management/user-management.route.ts b/src/main/webapp/app/admin/user-management/user-management.route.ts deleted file mode 100644 index 1a8f76446..000000000 --- a/src/main/webapp/app/admin/user-management/user-management.route.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { inject } from '@angular/core'; -import { ActivatedRouteSnapshot, Routes, ResolveFn } from '@angular/router'; -import { of } from 'rxjs'; - -import { IUser } from './user-management.model'; -import { UserManagementService } from './service/user-management.service'; -import UserManagementComponent from './list/user-management.component'; -import UserManagementDetailComponent from './detail/user-management-detail.component'; -import UserManagementUpdateComponent from './update/user-management-update.component'; - -export const UserManagementResolve: ResolveFn = (route: ActivatedRouteSnapshot) => { - const login = route.paramMap.get('login'); - if (login) { - return inject(UserManagementService).find(login); - } - return of(null); -}; - -const userManagementRoute: Routes = [ - { - path: '', - component: UserManagementComponent, - data: { - defaultSort: 'id,asc', - }, - }, - { - path: ':login/view', - component: UserManagementDetailComponent, - resolve: { - user: UserManagementResolve, - }, - }, - { - path: 'new', - component: UserManagementUpdateComponent, - resolve: { - user: UserManagementResolve, - }, - }, - { - path: ':login/edit', - component: UserManagementUpdateComponent, - resolve: { - user: UserManagementResolve, - }, - }, -]; - -export default userManagementRoute; diff --git a/src/main/webapp/app/app-page-title-strategy.ts b/src/main/webapp/app/app-page-title-strategy.ts deleted file mode 100644 index afe66a4c8..000000000 --- a/src/main/webapp/app/app-page-title-strategy.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Injectable } from '@angular/core'; -import { RouterStateSnapshot, TitleStrategy } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; - -@Injectable() -export class AppPageTitleStrategy extends TitleStrategy { - constructor(private translateService: TranslateService) { - super(); - } - - override updateTitle(routerState: RouterStateSnapshot): void { - let pageTitle = this.buildTitle(routerState); - if (!pageTitle) { - pageTitle = 'global.title'; - } - this.translateService.get(pageTitle).subscribe(title => { - document.title = title; - }); - } -} diff --git a/src/main/webapp/app/app-routing.module.ts b/src/main/webapp/app/app-routing.module.ts deleted file mode 100644 index c506d05a6..000000000 --- a/src/main/webapp/app/app-routing.module.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; - -import { errorRoute } from './layouts/error/error.route'; -import { DEBUG_INFO_ENABLED } from 'app/app.constants'; -import { Authority } from 'app/config/authority.constants'; - -import HomeComponent from './home/home.component'; -import NavbarComponent from './layouts/navbar/navbar.component'; -import LoginComponent from './login/login.component'; - -import { UserRouteAccessService } from 'app/core/auth/user-route-access.service'; - -@NgModule({ - imports: [ - RouterModule.forRoot( - [ - { - path: '', - component: HomeComponent, - title: 'home.title', - }, - { - path: '', - component: NavbarComponent, - outlet: 'navbar', - }, - { - path: 'admin', - data: { - authorities: [Authority.ADMIN], - }, - canActivate: [UserRouteAccessService], - loadChildren: () => import('./admin/admin-routing.module'), - }, - { - path: 'account', - loadChildren: () => import('./account/account.route'), - }, - { - path: 'login', - component: LoginComponent, - title: 'login.title', - }, - { - path: '', - loadChildren: () => import(`./entities/entity-routing.module`).then(({ EntityRoutingModule }) => EntityRoutingModule), - }, - ...errorRoute, - ], - { enableTracing: DEBUG_INFO_ENABLED, bindToComponentInputs: true } - ), - ], - exports: [RouterModule], -}) -export class AppRoutingModule {} diff --git a/src/main/webapp/app/app.constants.ts b/src/main/webapp/app/app.constants.ts deleted file mode 100644 index 695015c41..000000000 --- a/src/main/webapp/app/app.constants.ts +++ /dev/null @@ -1,9 +0,0 @@ -// These constants are injected via webpack DefinePlugin variables. -// You can add more variables in webpack.common.js or in profile specific webpack..js files. -// If you change the values in the webpack config files, you need to re run webpack to update the application - -declare const __DEBUG_INFO_ENABLED__: boolean; -declare const __VERSION__: string; - -export const VERSION = __VERSION__; -export const DEBUG_INFO_ENABLED = __DEBUG_INFO_ENABLED__; diff --git a/src/main/webapp/app/app.module.ts b/src/main/webapp/app/app.module.ts deleted file mode 100644 index 28c084cb5..000000000 --- a/src/main/webapp/app/app.module.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { NgModule, LOCALE_ID } from '@angular/core'; -import { registerLocaleData } from '@angular/common'; -import { HttpClientModule } from '@angular/common/http'; -import locale from '@angular/common/locales/en'; -import { BrowserModule, Title } from '@angular/platform-browser'; -import { TitleStrategy } from '@angular/router'; -import { ServiceWorkerModule } from '@angular/service-worker'; -import { FaIconLibrary } from '@fortawesome/angular-fontawesome'; -import dayjs from 'dayjs/esm'; -import { NgbDateAdapter, NgbDatepickerConfig } from '@ng-bootstrap/ng-bootstrap'; - -import { ApplicationConfigService } from 'app/core/config/application-config.service'; -import './config/dayjs'; -import { TranslationModule } from 'app/shared/language/translation.module'; -import { AppRoutingModule } from './app-routing.module'; -// jhipster-needle-angular-add-module-import JHipster will add new module here -import { NgbDateDayjsAdapter } from './config/datepicker-adapter'; -import { fontAwesomeIcons } from './config/font-awesome-icons'; -import { httpInterceptorProviders } from 'app/core/interceptor/index'; -import MainComponent from './layouts/main/main.component'; -import MainModule from './layouts/main/main.module'; -import { AppPageTitleStrategy } from './app-page-title-strategy'; - -@NgModule({ - imports: [ - BrowserModule, - // jhipster-needle-angular-add-module JHipster will add new module here - AppRoutingModule, - // Set this to true to enable service worker (PWA) - ServiceWorkerModule.register('ngsw-worker.js', { enabled: false }), - HttpClientModule, - MainModule, - TranslationModule, - ], - providers: [ - Title, - { provide: LOCALE_ID, useValue: 'en' }, - { provide: NgbDateAdapter, useClass: NgbDateDayjsAdapter }, - httpInterceptorProviders, - { provide: TitleStrategy, useClass: AppPageTitleStrategy }, - ], - bootstrap: [MainComponent], -}) -export class AppModule { - constructor(applicationConfigService: ApplicationConfigService, iconLibrary: FaIconLibrary, dpConfig: NgbDatepickerConfig) { - applicationConfigService.setEndpointPrefix(SERVER_API_URL); - registerLocaleData(locale); - iconLibrary.addIcons(...fontAwesomeIcons); - dpConfig.minDate = { year: dayjs().subtract(100, 'year').year(), month: 1, day: 1 }; - } -} diff --git a/src/main/webapp/app/config/authority.constants.ts b/src/main/webapp/app/config/authority.constants.ts deleted file mode 100644 index 1501bcf4e..000000000 --- a/src/main/webapp/app/config/authority.constants.ts +++ /dev/null @@ -1,4 +0,0 @@ -export enum Authority { - ADMIN = 'ROLE_ADMIN', - USER = 'ROLE_USER', -} diff --git a/src/main/webapp/app/config/datepicker-adapter.ts b/src/main/webapp/app/config/datepicker-adapter.ts deleted file mode 100644 index 3f8b16c61..000000000 --- a/src/main/webapp/app/config/datepicker-adapter.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Angular bootstrap Date adapter - */ -import { Injectable } from '@angular/core'; -import { NgbDateAdapter, NgbDateStruct } from '@ng-bootstrap/ng-bootstrap'; -import dayjs from 'dayjs/esm'; - -@Injectable() -export class NgbDateDayjsAdapter extends NgbDateAdapter { - fromModel(date: dayjs.Dayjs | null): NgbDateStruct | null { - if (date && dayjs.isDayjs(date) && date.isValid()) { - return { year: date.year(), month: date.month() + 1, day: date.date() }; - } - return null; - } - - toModel(date: NgbDateStruct | null): dayjs.Dayjs | null { - return date ? dayjs(`${date.year}-${date.month}-${date.day}`) : null; - } -} diff --git a/src/main/webapp/app/config/dayjs.ts b/src/main/webapp/app/config/dayjs.ts deleted file mode 100644 index b0375e234..000000000 --- a/src/main/webapp/app/config/dayjs.ts +++ /dev/null @@ -1,12 +0,0 @@ -import dayjs from 'dayjs/esm'; -import customParseFormat from 'dayjs/esm/plugin/customParseFormat'; -import duration from 'dayjs/esm/plugin/duration'; -import relativeTime from 'dayjs/esm/plugin/relativeTime'; - -// jhipster-needle-i18n-language-dayjs-imports - JHipster will import languages from dayjs here -import 'dayjs/esm/locale/en'; - -// DAYJS CONFIGURATION -dayjs.extend(customParseFormat); -dayjs.extend(duration); -dayjs.extend(relativeTime); diff --git a/src/main/webapp/app/config/error.constants.ts b/src/main/webapp/app/config/error.constants.ts deleted file mode 100644 index eff19a30d..000000000 --- a/src/main/webapp/app/config/error.constants.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const PROBLEM_BASE_URL = 'https://www.jhipster.tech/problem'; -export const EMAIL_ALREADY_USED_TYPE = `${PROBLEM_BASE_URL}/email-already-used`; -export const LOGIN_ALREADY_USED_TYPE = `${PROBLEM_BASE_URL}/login-already-used`; diff --git a/src/main/webapp/app/config/font-awesome-icons.ts b/src/main/webapp/app/config/font-awesome-icons.ts deleted file mode 100644 index 7fcf1696c..000000000 --- a/src/main/webapp/app/config/font-awesome-icons.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { - faArrowLeft, - faAsterisk, - faBan, - faBars, - faBell, - faBook, - faCalendarAlt, - faCheck, - faCloud, - faCogs, - faDatabase, - faEye, - faFlag, - faHeart, - faHome, - faList, - faLock, - faPencilAlt, - faPlus, - faRoad, - faSave, - faSearch, - faSignOutAlt, - faSignInAlt, - faSort, - faSortDown, - faSortUp, - faSync, - faTachometerAlt, - faTasks, - faThList, - faTimes, - faTrashAlt, - faUser, - faUserPlus, - faUsers, - faUsersCog, - faWrench, - // jhipster-needle-add-icon-import -} from '@fortawesome/free-solid-svg-icons'; - -export const fontAwesomeIcons = [ - faArrowLeft, - faAsterisk, - faBan, - faBars, - faBell, - faBook, - faCalendarAlt, - faCheck, - faCloud, - faCogs, - faDatabase, - faEye, - faFlag, - faHeart, - faHome, - faList, - faLock, - faPencilAlt, - faPlus, - faRoad, - faSave, - faSearch, - faSignOutAlt, - faSignInAlt, - faSort, - faSortDown, - faSortUp, - faSync, - faTachometerAlt, - faTasks, - faThList, - faTimes, - faTrashAlt, - faUser, - faUserPlus, - faUsers, - faUsersCog, - faWrench, - // jhipster-needle-add-icon-import -]; diff --git a/src/main/webapp/app/config/input.constants.ts b/src/main/webapp/app/config/input.constants.ts deleted file mode 100644 index 1e3978a9b..000000000 --- a/src/main/webapp/app/config/input.constants.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const DATE_FORMAT = 'YYYY-MM-DD'; -export const DATE_TIME_FORMAT = 'YYYY-MM-DDTHH:mm'; diff --git a/src/main/webapp/app/config/language.constants.ts b/src/main/webapp/app/config/language.constants.ts deleted file mode 100644 index aa0720850..000000000 --- a/src/main/webapp/app/config/language.constants.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - Languages codes are ISO_639-1 codes, see http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes - They are written in English to avoid character encoding issues (not a perfect solution) -*/ -export const LANGUAGES: string[] = [ - 'en', - // jhipster-needle-i18n-language-constant - JHipster will add/remove languages in this array -]; diff --git a/src/main/webapp/app/config/navigation.constants.ts b/src/main/webapp/app/config/navigation.constants.ts deleted file mode 100644 index 609160d1b..000000000 --- a/src/main/webapp/app/config/navigation.constants.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const ASC = 'asc'; -export const DESC = 'desc'; -export const SORT = 'sort'; -export const ITEM_DELETED_EVENT = 'deleted'; -export const DEFAULT_SORT_DATA = 'defaultSort'; diff --git a/src/main/webapp/app/config/pagination.constants.ts b/src/main/webapp/app/config/pagination.constants.ts deleted file mode 100644 index 6bee3ff5a..000000000 --- a/src/main/webapp/app/config/pagination.constants.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const TOTAL_COUNT_RESPONSE_HEADER = 'X-Total-Count'; -export const PAGE_HEADER = 'page'; -export const ITEMS_PER_PAGE = 20; diff --git a/src/main/webapp/app/config/translation.config.ts b/src/main/webapp/app/config/translation.config.ts deleted file mode 100644 index b5ac12974..000000000 --- a/src/main/webapp/app/config/translation.config.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { HttpClient } from '@angular/common/http'; -import { MissingTranslationHandler, MissingTranslationHandlerParams, TranslateLoader } from '@ngx-translate/core'; -import { TranslateHttpLoader } from '@ngx-translate/http-loader'; - -export const translationNotFoundMessage = 'translation-not-found'; - -export class MissingTranslationHandlerImpl implements MissingTranslationHandler { - handle(params: MissingTranslationHandlerParams): string { - const key = params.key; - return `${translationNotFoundMessage}[${key}]`; - } -} - -export function translatePartialLoader(http: HttpClient): TranslateLoader { - return new TranslateHttpLoader(http, 'i18n/', `.json?_=${I18N_HASH}`); -} - -export function missingTranslationHandler(): MissingTranslationHandler { - return new MissingTranslationHandlerImpl(); -} diff --git a/src/main/webapp/app/config/uib-pagination.config.ts b/src/main/webapp/app/config/uib-pagination.config.ts deleted file mode 100644 index ecabe1655..000000000 --- a/src/main/webapp/app/config/uib-pagination.config.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Injectable } from '@angular/core'; -import { NgbPaginationConfig } from '@ng-bootstrap/ng-bootstrap'; - -import { ITEMS_PER_PAGE } from 'app/config/pagination.constants'; - -@Injectable({ providedIn: 'root' }) -export class PaginationConfig { - constructor(config: NgbPaginationConfig) { - config.boundaryLinks = true; - config.maxSize = 5; - config.pageSize = ITEMS_PER_PAGE; - config.size = 'sm'; - } -} diff --git a/src/main/webapp/app/core/auth/account.model.ts b/src/main/webapp/app/core/auth/account.model.ts deleted file mode 100644 index 22e083cf2..000000000 --- a/src/main/webapp/app/core/auth/account.model.ts +++ /dev/null @@ -1,12 +0,0 @@ -export class Account { - constructor( - public activated: boolean, - public authorities: string[], - public email: string, - public firstName: string | null, - public langKey: string, - public lastName: string | null, - public login: string, - public imageUrl: string | null - ) {} -} diff --git a/src/main/webapp/app/core/auth/account.service.spec.ts b/src/main/webapp/app/core/auth/account.service.spec.ts deleted file mode 100644 index 7ccd0aa36..000000000 --- a/src/main/webapp/app/core/auth/account.service.spec.ts +++ /dev/null @@ -1,248 +0,0 @@ -jest.mock('app/core/auth/state-storage.service'); - -import { Router } from '@angular/router'; -import { RouterTestingModule } from '@angular/router/testing'; -import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; -import { TestBed } from '@angular/core/testing'; -import { TranslateModule, TranslateService } from '@ngx-translate/core'; -import { of } from 'rxjs'; - -import { Account } from 'app/core/auth/account.model'; -import { Authority } from 'app/config/authority.constants'; -import { StateStorageService } from 'app/core/auth/state-storage.service'; -import { ApplicationConfigService } from 'app/core/config/application-config.service'; - -import { AccountService } from './account.service'; - -function accountWithAuthorities(authorities: string[]): Account { - return { - activated: true, - authorities, - email: '', - firstName: '', - langKey: '', - lastName: '', - login: '', - imageUrl: '', - }; -} - -describe('Account Service', () => { - let service: AccountService; - let applicationConfigService: ApplicationConfigService; - let httpMock: HttpTestingController; - let mockStorageService: StateStorageService; - let mockRouter: Router; - let mockTranslateService: TranslateService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot()], - providers: [StateStorageService], - }); - - service = TestBed.inject(AccountService); - applicationConfigService = TestBed.inject(ApplicationConfigService); - httpMock = TestBed.inject(HttpTestingController); - mockStorageService = TestBed.inject(StateStorageService); - mockRouter = TestBed.inject(Router); - jest.spyOn(mockRouter, 'navigateByUrl').mockImplementation(() => Promise.resolve(true)); - - mockTranslateService = TestBed.inject(TranslateService); - jest.spyOn(mockTranslateService, 'use').mockImplementation(() => of('')); - }); - - afterEach(() => { - httpMock.verify(); - }); - - describe('save', () => { - it('should call account saving endpoint with correct values', () => { - // GIVEN - const account = accountWithAuthorities([]); - - // WHEN - service.save(account).subscribe(); - const testRequest = httpMock.expectOne({ method: 'POST', url: applicationConfigService.getEndpointFor('api/account') }); - testRequest.flush({}); - - // THEN - expect(testRequest.request.body).toEqual(account); - }); - }); - - describe('authenticate', () => { - it('authenticationState should emit null if input is null', () => { - // GIVEN - let userIdentity: Account | null = accountWithAuthorities([]); - service.getAuthenticationState().subscribe(account => (userIdentity = account)); - - // WHEN - service.authenticate(null); - - // THEN - expect(userIdentity).toBeNull(); - expect(service.isAuthenticated()).toBe(false); - }); - - it('authenticationState should emit the same account as was in input parameter', () => { - // GIVEN - const expectedResult = accountWithAuthorities([]); - let userIdentity: Account | null = null; - service.getAuthenticationState().subscribe(account => (userIdentity = account)); - - // WHEN - service.authenticate(expectedResult); - - // THEN - expect(userIdentity).toEqual(expectedResult); - expect(service.isAuthenticated()).toBe(true); - }); - }); - - describe('identity', () => { - it('should call /account only once if last call have not returned', () => { - // When I call - service.identity().subscribe(); - // Once more - service.identity().subscribe(); - // Then there is only request - httpMock.expectOne({ method: 'GET' }); - }); - - it('should call /account only once if not logged out after first authentication and should call /account again if user has logged out', () => { - // Given the user is authenticated - service.identity().subscribe(); - httpMock.expectOne({ method: 'GET' }).flush({}); - - // When I call - service.identity().subscribe(); - - // Then there is no second request - httpMock.expectNone({ method: 'GET' }); - - // When I log out - service.authenticate(null); - // and then call - service.identity().subscribe(); - - // Then there is a new request - httpMock.expectOne({ method: 'GET' }); - }); - - describe('should change the language on authentication if necessary', () => { - it('should change language if user has not changed language manually', () => { - // GIVEN - mockStorageService.getLocale = jest.fn(() => null); - - // WHEN - service.identity().subscribe(); - httpMock.expectOne({ method: 'GET' }).flush({ ...accountWithAuthorities([]), langKey: 'accountLang' }); - - // THEN - expect(mockTranslateService.use).toHaveBeenCalledWith('accountLang'); - }); - - it('should not change language if user has changed language manually', () => { - // GIVEN - mockStorageService.getLocale = jest.fn(() => 'sessionLang'); - - // WHEN - service.identity().subscribe(); - httpMock.expectOne({ method: 'GET' }).flush({ ...accountWithAuthorities([]), langKey: 'accountLang' }); - - // THEN - expect(mockTranslateService.use).not.toHaveBeenCalled(); - }); - }); - - describe('navigateToStoredUrl', () => { - it('should navigate to the previous stored url post successful authentication', () => { - // GIVEN - mockStorageService.getUrl = jest.fn(() => 'admin/users?page=0'); - - // WHEN - service.identity().subscribe(); - httpMock.expectOne({ method: 'GET' }).flush({}); - - // THEN - expect(mockStorageService.getUrl).toHaveBeenCalledTimes(1); - expect(mockStorageService.clearUrl).toHaveBeenCalledTimes(1); - expect(mockRouter.navigateByUrl).toHaveBeenCalledWith('admin/users?page=0'); - }); - - it('should not navigate to the previous stored url when authentication fails', () => { - // WHEN - service.identity().subscribe(); - httpMock.expectOne({ method: 'GET' }).error(new ErrorEvent('')); - - // THEN - expect(mockStorageService.getUrl).not.toHaveBeenCalled(); - expect(mockStorageService.clearUrl).not.toHaveBeenCalled(); - expect(mockRouter.navigateByUrl).not.toHaveBeenCalled(); - }); - - it('should not navigate to the previous stored url when no such url exists post successful authentication', () => { - // GIVEN - mockStorageService.getUrl = jest.fn(() => null); - - // WHEN - service.identity().subscribe(); - httpMock.expectOne({ method: 'GET' }).flush({}); - - // THEN - expect(mockStorageService.getUrl).toHaveBeenCalledTimes(1); - expect(mockStorageService.clearUrl).not.toHaveBeenCalled(); - expect(mockRouter.navigateByUrl).not.toHaveBeenCalled(); - }); - }); - }); - - describe('hasAnyAuthority', () => { - describe('hasAnyAuthority string parameter', () => { - it('should return false if user is not logged', () => { - const hasAuthority = service.hasAnyAuthority(Authority.USER); - expect(hasAuthority).toBe(false); - }); - - it('should return false if user is logged and has not authority', () => { - service.authenticate(accountWithAuthorities([Authority.USER])); - - const hasAuthority = service.hasAnyAuthority(Authority.ADMIN); - - expect(hasAuthority).toBe(false); - }); - - it('should return true if user is logged and has authority', () => { - service.authenticate(accountWithAuthorities([Authority.USER])); - - const hasAuthority = service.hasAnyAuthority(Authority.USER); - - expect(hasAuthority).toBe(true); - }); - }); - - describe('hasAnyAuthority array parameter', () => { - it('should return false if user is not logged', () => { - const hasAuthority = service.hasAnyAuthority([Authority.USER]); - expect(hasAuthority).toBeFalsy(); - }); - - it('should return false if user is logged and has not authority', () => { - service.authenticate(accountWithAuthorities([Authority.USER])); - - const hasAuthority = service.hasAnyAuthority([Authority.ADMIN]); - - expect(hasAuthority).toBe(false); - }); - - it('should return true if user is logged and has authority', () => { - service.authenticate(accountWithAuthorities([Authority.USER])); - - const hasAuthority = service.hasAnyAuthority([Authority.USER, Authority.ADMIN]); - - expect(hasAuthority).toBe(true); - }); - }); - }); -}); diff --git a/src/main/webapp/app/core/auth/account.service.ts b/src/main/webapp/app/core/auth/account.service.ts deleted file mode 100644 index 2a37ea316..000000000 --- a/src/main/webapp/app/core/auth/account.service.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Router } from '@angular/router'; -import { HttpClient } from '@angular/common/http'; -import { TranslateService } from '@ngx-translate/core'; -import { Observable, ReplaySubject, of } from 'rxjs'; -import { shareReplay, tap, catchError } from 'rxjs/operators'; - -import { StateStorageService } from 'app/core/auth/state-storage.service'; -import { ApplicationConfigService } from '../config/application-config.service'; -import { Account } from 'app/core/auth/account.model'; - -@Injectable({ providedIn: 'root' }) -export class AccountService { - private userIdentity: Account | null = null; - private authenticationState = new ReplaySubject(1); - private accountCache$?: Observable | null; - - constructor( - private translateService: TranslateService, - private http: HttpClient, - private stateStorageService: StateStorageService, - private router: Router, - private applicationConfigService: ApplicationConfigService - ) {} - - save(account: Account): Observable<{}> { - return this.http.post(this.applicationConfigService.getEndpointFor('api/account'), account); - } - - authenticate(identity: Account | null): void { - this.userIdentity = identity; - this.authenticationState.next(this.userIdentity); - if (!identity) { - this.accountCache$ = null; - } - } - - hasAnyAuthority(authorities: string[] | string): boolean { - if (!this.userIdentity) { - return false; - } - if (!Array.isArray(authorities)) { - authorities = [authorities]; - } - return this.userIdentity.authorities.some((authority: string) => authorities.includes(authority)); - } - - identity(force?: boolean): Observable { - if (!this.accountCache$ || force) { - this.accountCache$ = this.fetch().pipe( - tap((account: Account) => { - this.authenticate(account); - - // After retrieve the account info, the language will be changed to - // the user's preferred language configured in the account setting - // unless user have choosed other language in the current session - if (!this.stateStorageService.getLocale()) { - this.translateService.use(account.langKey); - } - - this.navigateToStoredUrl(); - }), - shareReplay() - ); - } - return this.accountCache$.pipe(catchError(() => of(null))); - } - - isAuthenticated(): boolean { - return this.userIdentity !== null; - } - - getAuthenticationState(): Observable { - return this.authenticationState.asObservable(); - } - - private fetch(): Observable { - return this.http.get(this.applicationConfigService.getEndpointFor('api/account')); - } - - private navigateToStoredUrl(): void { - // previousState can be set in the authExpiredInterceptor and in the userRouteAccessService - // if login is successful, go to stored previousState and clear previousState - const previousUrl = this.stateStorageService.getUrl(); - if (previousUrl) { - this.stateStorageService.clearUrl(); - this.router.navigateByUrl(previousUrl); - } - } -} diff --git a/src/main/webapp/app/core/auth/auth-jwt.service.spec.ts b/src/main/webapp/app/core/auth/auth-jwt.service.spec.ts deleted file mode 100644 index 5b0e83c66..000000000 --- a/src/main/webapp/app/core/auth/auth-jwt.service.spec.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; -import { AuthServerProvider } from 'app/core/auth/auth-jwt.service'; -import { StateStorageService } from './state-storage.service'; - -describe('Auth JWT', () => { - let service: AuthServerProvider; - let httpMock: HttpTestingController; - let mockStorageService: StateStorageService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - }); - - mockStorageService = TestBed.inject(StateStorageService); - httpMock = TestBed.inject(HttpTestingController); - service = TestBed.inject(AuthServerProvider); - }); - - describe('Get Token', () => { - it('should return empty token if not found in local storage nor session storage', () => { - const result = service.getToken(); - expect(result).toEqual(''); - }); - - it('should return token from session storage if local storage is empty', () => { - sessionStorage.setItem('jhi-authenticationToken', JSON.stringify('sessionStorageToken')); - const result = service.getToken(); - expect(result).toEqual('sessionStorageToken'); - }); - - it('should return token from localstorage storage', () => { - localStorage.setItem('jhi-authenticationToken', JSON.stringify('localStorageToken')); - const result = service.getToken(); - expect(result).toEqual('localStorageToken'); - }); - }); - - describe('Login', () => { - it('should clear session storage and save in local storage when rememberMe is true', () => { - // GIVEN - mockStorageService.storeAuthenticationToken = jest.fn(); - - // WHEN - service.login({ username: 'John', password: '123', rememberMe: true }).subscribe(); - httpMock.expectOne('api/authenticate').flush({ id_token: '1' }); - - // THEN - httpMock.verify(); - expect(mockStorageService.storeAuthenticationToken).toHaveBeenCalledWith('1', true); - }); - - it('should clear local storage and save in session storage when rememberMe is false', () => { - // GIVEN - mockStorageService.storeAuthenticationToken = jest.fn(); - - // WHEN - service.login({ username: 'John', password: '123', rememberMe: false }).subscribe(); - httpMock.expectOne('api/authenticate').flush({ id_token: '1' }); - - // THEN - httpMock.verify(); - expect(mockStorageService.storeAuthenticationToken).toHaveBeenCalledWith('1', false); - }); - }); - - describe('Logout', () => { - it('should clear storage', () => { - // GIVEN - mockStorageService.clearAuthenticationToken = jest.fn(); - - // WHEN - service.logout().subscribe(); - - // THEN - expect(mockStorageService.clearAuthenticationToken).toHaveBeenCalled(); - }); - }); -}); diff --git a/src/main/webapp/app/core/auth/auth-jwt.service.ts b/src/main/webapp/app/core/auth/auth-jwt.service.ts deleted file mode 100644 index 55739a7e6..000000000 --- a/src/main/webapp/app/core/auth/auth-jwt.service.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; - -import { Login } from 'app/login/login.model'; -import { StateStorageService } from './state-storage.service'; -import { ApplicationConfigService } from '../config/application-config.service'; - -type JwtToken = { - id_token: string; -}; - -@Injectable({ providedIn: 'root' }) -export class AuthServerProvider { - constructor( - private http: HttpClient, - private stateStorageService: StateStorageService, - private applicationConfigService: ApplicationConfigService - ) {} - - getToken(): string { - return this.stateStorageService.getAuthenticationToken() ?? ''; - } - - login(credentials: Login): Observable { - return this.http - .post(this.applicationConfigService.getEndpointFor('api/authenticate'), credentials) - .pipe(map(response => this.authenticateSuccess(response, credentials.rememberMe))); - } - - logout(): Observable { - return new Observable(observer => { - this.stateStorageService.clearAuthenticationToken(); - observer.complete(); - }); - } - - private authenticateSuccess(response: JwtToken, rememberMe: boolean): void { - this.stateStorageService.storeAuthenticationToken(response.id_token, rememberMe); - } -} diff --git a/src/main/webapp/app/core/auth/state-storage.service.ts b/src/main/webapp/app/core/auth/state-storage.service.ts deleted file mode 100644 index 14eec1bf4..000000000 --- a/src/main/webapp/app/core/auth/state-storage.service.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { Injectable } from '@angular/core'; - -@Injectable({ providedIn: 'root' }) -export class StateStorageService { - private previousUrlKey = 'previousUrl'; - private authenticationKey = 'jhi-authenticationToken'; - private localeKey = 'locale'; - - storeUrl(url: string): void { - sessionStorage.setItem(this.previousUrlKey, JSON.stringify(url)); - } - - getUrl(): string | null { - const previousUrl = sessionStorage.getItem(this.previousUrlKey); - return previousUrl ? (JSON.parse(previousUrl) as string | null) : previousUrl; - } - - clearUrl(): void { - sessionStorage.removeItem(this.previousUrlKey); - } - - storeAuthenticationToken(authenticationToken: string, rememberMe: boolean): void { - authenticationToken = JSON.stringify(authenticationToken); - this.clearAuthenticationToken(); - if (rememberMe) { - localStorage.setItem(this.authenticationKey, authenticationToken); - } else { - sessionStorage.setItem(this.authenticationKey, authenticationToken); - } - } - - getAuthenticationToken(): string | null { - const authenticationToken = localStorage.getItem(this.authenticationKey) ?? sessionStorage.getItem(this.authenticationKey); - return authenticationToken ? (JSON.parse(authenticationToken) as string | null) : authenticationToken; - } - - clearAuthenticationToken(): void { - sessionStorage.removeItem(this.authenticationKey); - localStorage.removeItem(this.authenticationKey); - } - - storeLocale(locale: string): void { - sessionStorage.setItem(this.localeKey, locale); - } - - getLocale(): string | null { - return sessionStorage.getItem(this.localeKey); - } - - clearLocale(): void { - sessionStorage.removeItem(this.localeKey); - } -} diff --git a/src/main/webapp/app/core/auth/user-route-access.service.ts b/src/main/webapp/app/core/auth/user-route-access.service.ts deleted file mode 100644 index 17481e92c..000000000 --- a/src/main/webapp/app/core/auth/user-route-access.service.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { inject, isDevMode } from '@angular/core'; -import { ActivatedRouteSnapshot, CanActivateFn, Router, RouterStateSnapshot } from '@angular/router'; -import { map } from 'rxjs/operators'; - -import { AccountService } from 'app/core/auth/account.service'; -import { StateStorageService } from './state-storage.service'; - -export const UserRouteAccessService: CanActivateFn = (next: ActivatedRouteSnapshot, state: RouterStateSnapshot) => { - const accountService = inject(AccountService); - const router = inject(Router); - const stateStorageService = inject(StateStorageService); - return accountService.identity().pipe( - map(account => { - if (account) { - const authorities = next.data['authorities']; - - if (!authorities || authorities.length === 0 || accountService.hasAnyAuthority(authorities)) { - return true; - } - - if (isDevMode()) { - console.error('User has not any of required authorities: ', authorities); - } - router.navigate(['accessdenied']); - return false; - } - - stateStorageService.storeUrl(state.url); - router.navigate(['/login']); - return false; - }) - ); -}; diff --git a/src/main/webapp/app/core/config/application-config.service.spec.ts b/src/main/webapp/app/core/config/application-config.service.spec.ts deleted file mode 100644 index 4451c9bb8..000000000 --- a/src/main/webapp/app/core/config/application-config.service.spec.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { ApplicationConfigService } from './application-config.service'; - -describe('ApplicationConfigService', () => { - let service: ApplicationConfigService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(ApplicationConfigService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); - - describe('without prefix', () => { - it('should return correctly', () => { - expect(service.getEndpointFor('api')).toEqual('api'); - }); - - it('should return correctly when passing microservice', () => { - expect(service.getEndpointFor('api', 'microservice')).toEqual('services/microservice/api'); - }); - }); - - describe('with prefix', () => { - beforeEach(() => { - service.setEndpointPrefix('prefix/'); - }); - - it('should return correctly', () => { - expect(service.getEndpointFor('api')).toEqual('prefix/api'); - }); - - it('should return correctly when passing microservice', () => { - expect(service.getEndpointFor('api', 'microservice')).toEqual('prefix/services/microservice/api'); - }); - }); -}); diff --git a/src/main/webapp/app/core/config/application-config.service.ts b/src/main/webapp/app/core/config/application-config.service.ts deleted file mode 100644 index 0102e5f03..000000000 --- a/src/main/webapp/app/core/config/application-config.service.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Injectable } from '@angular/core'; - -@Injectable({ - providedIn: 'root', -}) -export class ApplicationConfigService { - private endpointPrefix = ''; - private microfrontend = false; - - setEndpointPrefix(endpointPrefix: string): void { - this.endpointPrefix = endpointPrefix; - } - - setMicrofrontend(microfrontend = true): void { - this.microfrontend = microfrontend; - } - - isMicrofrontend(): boolean { - return this.microfrontend; - } - - getEndpointFor(api: string, microservice?: string): string { - if (microservice) { - return `${this.endpointPrefix}services/${microservice}/${api}`; - } - return `${this.endpointPrefix}${api}`; - } -} diff --git a/src/main/webapp/app/core/interceptor/auth-expired.interceptor.ts b/src/main/webapp/app/core/interceptor/auth-expired.interceptor.ts deleted file mode 100644 index bdc8e8a1d..000000000 --- a/src/main/webapp/app/core/interceptor/auth-expired.interceptor.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { tap } from 'rxjs/operators'; -import { Router } from '@angular/router'; - -import { LoginService } from 'app/login/login.service'; -import { StateStorageService } from 'app/core/auth/state-storage.service'; -import { AccountService } from 'app/core/auth/account.service'; - -@Injectable() -export class AuthExpiredInterceptor implements HttpInterceptor { - constructor( - private loginService: LoginService, - private stateStorageService: StateStorageService, - private router: Router, - private accountService: AccountService - ) {} - - intercept(request: HttpRequest, next: HttpHandler): Observable> { - return next.handle(request).pipe( - tap({ - error: (err: HttpErrorResponse) => { - if (err.status === 401 && err.url && !err.url.includes('api/account') && this.accountService.isAuthenticated()) { - this.stateStorageService.storeUrl(this.router.routerState.snapshot.url); - this.loginService.logout(); - this.router.navigate(['/login']); - } - }, - }) - ); - } -} diff --git a/src/main/webapp/app/core/interceptor/auth.interceptor.ts b/src/main/webapp/app/core/interceptor/auth.interceptor.ts deleted file mode 100644 index c14c2afef..000000000 --- a/src/main/webapp/app/core/interceptor/auth.interceptor.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http'; -import { Observable } from 'rxjs'; - -import { StateStorageService } from 'app/core/auth/state-storage.service'; -import { ApplicationConfigService } from '../config/application-config.service'; - -@Injectable() -export class AuthInterceptor implements HttpInterceptor { - constructor(private stateStorageService: StateStorageService, private applicationConfigService: ApplicationConfigService) {} - - intercept(request: HttpRequest, next: HttpHandler): Observable> { - const serverApiUrl = this.applicationConfigService.getEndpointFor(''); - if (!request.url || (request.url.startsWith('http') && !(serverApiUrl && request.url.startsWith(serverApiUrl)))) { - return next.handle(request); - } - - const token: string | null = this.stateStorageService.getAuthenticationToken(); - if (token) { - request = request.clone({ - setHeaders: { - Authorization: `Bearer ${token}`, - }, - }); - } - return next.handle(request); - } -} diff --git a/src/main/webapp/app/core/interceptor/error-handler.interceptor.ts b/src/main/webapp/app/core/interceptor/error-handler.interceptor.ts deleted file mode 100644 index 022ea1244..000000000 --- a/src/main/webapp/app/core/interceptor/error-handler.interceptor.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpInterceptor, HttpRequest, HttpErrorResponse, HttpHandler, HttpEvent } from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { tap } from 'rxjs/operators'; - -import { EventManager, EventWithContent } from 'app/core/util/event-manager.service'; - -@Injectable() -export class ErrorHandlerInterceptor implements HttpInterceptor { - constructor(private eventManager: EventManager) {} - - intercept(request: HttpRequest, next: HttpHandler): Observable> { - return next.handle(request).pipe( - tap({ - error: (err: HttpErrorResponse) => { - if (!(err.status === 401 && (err.message === '' || err.url?.includes('api/account')))) { - this.eventManager.broadcast(new EventWithContent('jhipsterSampleApplicationApp.httpError', err)); - } - }, - }) - ); - } -} diff --git a/src/main/webapp/app/core/interceptor/index.ts b/src/main/webapp/app/core/interceptor/index.ts deleted file mode 100644 index f7e72e3a9..000000000 --- a/src/main/webapp/app/core/interceptor/index.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { HTTP_INTERCEPTORS } from '@angular/common/http'; - -import { AuthInterceptor } from 'app/core/interceptor/auth.interceptor'; -import { AuthExpiredInterceptor } from 'app/core/interceptor/auth-expired.interceptor'; -import { ErrorHandlerInterceptor } from 'app/core/interceptor/error-handler.interceptor'; -import { NotificationInterceptor } from 'app/core/interceptor/notification.interceptor'; - -export const httpInterceptorProviders = [ - { - provide: HTTP_INTERCEPTORS, - useClass: AuthInterceptor, - multi: true, - }, - { - provide: HTTP_INTERCEPTORS, - useClass: AuthExpiredInterceptor, - multi: true, - }, - { - provide: HTTP_INTERCEPTORS, - useClass: ErrorHandlerInterceptor, - multi: true, - }, - { - provide: HTTP_INTERCEPTORS, - useClass: NotificationInterceptor, - multi: true, - }, -]; diff --git a/src/main/webapp/app/core/interceptor/notification.interceptor.ts b/src/main/webapp/app/core/interceptor/notification.interceptor.ts deleted file mode 100644 index 513132f9c..000000000 --- a/src/main/webapp/app/core/interceptor/notification.interceptor.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { HttpInterceptor, HttpRequest, HttpResponse, HttpHandler, HttpEvent } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { tap } from 'rxjs/operators'; - -import { AlertService } from 'app/core/util/alert.service'; - -@Injectable() -export class NotificationInterceptor implements HttpInterceptor { - constructor(private alertService: AlertService) {} - - intercept(request: HttpRequest, next: HttpHandler): Observable> { - return next.handle(request).pipe( - tap((event: HttpEvent) => { - if (event instanceof HttpResponse) { - let alert: string | null = null; - let alertParams: string | null = null; - - for (const headerKey of event.headers.keys()) { - if (headerKey.toLowerCase().endsWith('app-alert')) { - alert = event.headers.get(headerKey); - } else if (headerKey.toLowerCase().endsWith('app-params')) { - alertParams = decodeURIComponent(event.headers.get(headerKey)!.replace(/\+/g, ' ')); - } - } - - if (alert) { - this.alertService.addAlert({ - type: 'success', - translationKey: alert, - translationParams: { param: alertParams }, - }); - } - } - }) - ); - } -} diff --git a/src/main/webapp/app/core/request/request-util.ts b/src/main/webapp/app/core/request/request-util.ts deleted file mode 100644 index 694a238a9..000000000 --- a/src/main/webapp/app/core/request/request-util.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { HttpParams } from '@angular/common/http'; - -export const createRequestOption = (req?: any): HttpParams => { - let options: HttpParams = new HttpParams(); - - if (req) { - Object.keys(req).forEach(key => { - if (key !== 'sort' && req[key] !== undefined) { - for (const value of [].concat(req[key]).filter(v => v !== '')) { - options = options.append(key, value); - } - } - }); - - if (req.sort) { - req.sort.forEach((val: string) => { - options = options.append('sort', val); - }); - } - } - - return options; -}; diff --git a/src/main/webapp/app/core/request/request.model.ts b/src/main/webapp/app/core/request/request.model.ts deleted file mode 100644 index 5de2b69a8..000000000 --- a/src/main/webapp/app/core/request/request.model.ts +++ /dev/null @@ -1,11 +0,0 @@ -export interface Pagination { - page: number; - size: number; - sort: string[]; -} - -export interface Search { - query: string; -} - -export interface SearchWithPagination extends Search, Pagination {} diff --git a/src/main/webapp/app/core/util/alert.service.spec.ts b/src/main/webapp/app/core/util/alert.service.spec.ts deleted file mode 100644 index 934188c79..000000000 --- a/src/main/webapp/app/core/util/alert.service.spec.ts +++ /dev/null @@ -1,285 +0,0 @@ -import { inject, TestBed } from '@angular/core/testing'; -import { TranslateModule, TranslateService, MissingTranslationHandler } from '@ngx-translate/core'; -import { missingTranslationHandler } from '../../config/translation.config'; - -import { Alert, AlertService } from './alert.service'; - -describe('Alert service test', () => { - describe('Alert Service Test', () => { - let extAlerts: Alert[]; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - TranslateModule.forRoot({ - missingTranslationHandler: { - provide: MissingTranslationHandler, - useFactory: missingTranslationHandler, - }, - }), - ], - }); - const translateService = TestBed.inject(TranslateService); - translateService.setDefaultLang('en'); - jest.useFakeTimers(); - extAlerts = []; - }); - - it('should produce a proper alert object and fetch it', inject([AlertService], (service: AlertService) => { - expect( - service.addAlert({ - type: 'success', - message: 'Hello Jhipster', - timeout: 3000, - toast: true, - position: 'top left', - }) - ).toEqual( - expect.objectContaining({ - type: 'success', - message: 'Hello Jhipster', - id: 0, - timeout: 3000, - toast: true, - position: 'top left', - } as Alert) - ); - - expect(service.get().length).toBe(1); - expect(service.get()[0]).toEqual( - expect.objectContaining({ - type: 'success', - message: 'Hello Jhipster', - id: 0, - timeout: 3000, - toast: true, - position: 'top left', - } as Alert) - ); - })); - - it('should produce a proper alert object and add it to external alert objects array', inject( - [AlertService], - (service: AlertService) => { - expect( - service.addAlert( - { - type: 'success', - message: 'Hello Jhipster', - timeout: 3000, - toast: true, - position: 'top left', - }, - extAlerts - ) - ).toEqual( - expect.objectContaining({ - type: 'success', - message: 'Hello Jhipster', - id: 0, - timeout: 3000, - toast: true, - position: 'top left', - } as Alert) - ); - - expect(extAlerts.length).toBe(1); - expect(extAlerts[0]).toEqual( - expect.objectContaining({ - type: 'success', - message: 'Hello Jhipster', - id: 0, - timeout: 3000, - toast: true, - position: 'top left', - } as Alert) - ); - } - )); - - it('should produce an alert object with correct id', inject([AlertService], (service: AlertService) => { - service.addAlert({ type: 'info', message: 'Hello Jhipster info' }); - expect(service.addAlert({ type: 'success', message: 'Hello Jhipster success' })).toEqual( - expect.objectContaining({ - type: 'success', - message: 'Hello Jhipster success', - id: 1, - } as Alert) - ); - - expect(service.get().length).toBe(2); - expect(service.get()[1]).toEqual( - expect.objectContaining({ - type: 'success', - message: 'Hello Jhipster success', - id: 1, - } as Alert) - ); - })); - - it('should close an alert correctly', inject([AlertService], (service: AlertService) => { - const alert0 = service.addAlert({ type: 'info', message: 'Hello Jhipster info' }); - const alert1 = service.addAlert({ type: 'info', message: 'Hello Jhipster info 2' }); - const alert2 = service.addAlert({ type: 'success', message: 'Hello Jhipster success' }); - expect(alert2).toEqual( - expect.objectContaining({ - type: 'success', - message: 'Hello Jhipster success', - id: 2, - } as Alert) - ); - - expect(service.get().length).toBe(3); - alert1.close?.(service.get()); - expect(service.get().length).toBe(2); - expect(service.get()[1]).not.toEqual( - expect.objectContaining({ - type: 'info', - message: 'Hello Jhipster info 2', - id: 1, - } as Alert) - ); - alert2.close?.(service.get()); - expect(service.get().length).toBe(1); - expect(service.get()[0]).not.toEqual( - expect.objectContaining({ - type: 'success', - message: 'Hello Jhipster success', - id: 2, - } as Alert) - ); - alert0.close?.(service.get()); - expect(service.get().length).toBe(0); - })); - - it('should close an alert on timeout correctly', inject([AlertService], (service: AlertService) => { - service.addAlert({ type: 'info', message: 'Hello Jhipster info' }); - - expect(service.get().length).toBe(1); - - jest.advanceTimersByTime(6000); - - expect(service.get().length).toBe(0); - })); - - it('should clear alerts', inject([AlertService], (service: AlertService) => { - service.addAlert({ type: 'info', message: 'Hello Jhipster info' }); - service.addAlert({ type: 'danger', message: 'Hello Jhipster info' }); - service.addAlert({ type: 'success', message: 'Hello Jhipster info' }); - expect(service.get().length).toBe(3); - service.clear(); - expect(service.get().length).toBe(0); - })); - - it('should produce a scoped alert', inject([AlertService], (service: AlertService) => { - expect( - service.addAlert( - { - type: 'success', - message: 'Hello Jhipster', - timeout: 3000, - toast: true, - position: 'top left', - }, - [] - ) - ).toEqual( - expect.objectContaining({ - type: 'success', - message: 'Hello Jhipster', - id: 0, - timeout: 3000, - toast: true, - position: 'top left', - } as Alert) - ); - - expect(service.get().length).toBe(0); - })); - - it('should produce a success message', inject([AlertService], (service: AlertService) => { - expect(service.addAlert({ type: 'success', message: 'Hello Jhipster' })).toEqual( - expect.objectContaining({ - type: 'success', - message: 'Hello Jhipster', - } as Alert) - ); - })); - - it('should produce a success message with custom position', inject([AlertService], (service: AlertService) => { - expect(service.addAlert({ type: 'success', message: 'Hello Jhipster', position: 'bottom left' })).toEqual( - expect.objectContaining({ - type: 'success', - message: 'Hello Jhipster', - position: 'bottom left', - } as Alert) - ); - })); - - it('should produce a error message', inject([AlertService], (service: AlertService) => { - expect(service.addAlert({ type: 'danger', message: 'Hello Jhipster' })).toEqual( - expect.objectContaining({ - type: 'danger', - message: 'Hello Jhipster', - } as Alert) - ); - })); - - it('should produce a warning message', inject([AlertService], (service: AlertService) => { - expect(service.addAlert({ type: 'warning', message: 'Hello Jhipster' })).toEqual( - expect.objectContaining({ - type: 'warning', - message: 'Hello Jhipster', - } as Alert) - ); - })); - - it('should produce a info message', inject([AlertService], (service: AlertService) => { - expect(service.addAlert({ type: 'info', message: 'Hello Jhipster' })).toEqual( - expect.objectContaining({ - type: 'info', - message: 'Hello Jhipster', - } as Alert) - ); - })); - - it('should produce a info message with translated message if key exists', inject( - [AlertService, TranslateService], - (service: AlertService, translateService: TranslateService) => { - translateService.setTranslation('en', { - 'hello.jhipster': 'Translated message', - }); - expect(service.addAlert({ type: 'info', message: 'Hello Jhipster', translationKey: 'hello.jhipster' })).toEqual( - expect.objectContaining({ - type: 'info', - message: 'Translated message', - } as Alert) - ); - } - )); - - it('should produce a info message with provided message if key does not exists', inject( - [AlertService, TranslateService], - (service: AlertService) => { - expect(service.addAlert({ type: 'info', message: 'Hello Jhipster', translationKey: 'hello.jhipster' })).toEqual( - expect.objectContaining({ - type: 'info', - message: 'Hello Jhipster', - } as Alert) - ); - } - )); - - it('should produce a info message with provided key if transltion key does not exist in translations and message is not provided', inject( - [AlertService, TranslateService], - (service: AlertService) => { - expect(service.addAlert({ type: 'info', translationKey: 'hello.jhipster' })).toEqual( - expect.objectContaining({ - type: 'info', - message: 'hello.jhipster', - } as Alert) - ); - } - )); - }); -}); diff --git a/src/main/webapp/app/core/util/alert.service.ts b/src/main/webapp/app/core/util/alert.service.ts deleted file mode 100644 index 7dd2cd41e..000000000 --- a/src/main/webapp/app/core/util/alert.service.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { Injectable, SecurityContext, NgZone } from '@angular/core'; -import { DomSanitizer } from '@angular/platform-browser'; -import { TranslateService } from '@ngx-translate/core'; - -import { translationNotFoundMessage } from 'app/config/translation.config'; - -export type AlertType = 'success' | 'danger' | 'warning' | 'info'; - -export interface Alert { - id?: number; - type: AlertType; - message?: string; - translationKey?: string; - translationParams?: { [key: string]: unknown }; - timeout?: number; - toast?: boolean; - position?: string; - close?: (alerts: Alert[]) => void; -} - -@Injectable({ - providedIn: 'root', -}) -export class AlertService { - timeout = 5000; - toast = false; - position = 'top right'; - - // unique id for each alert. Starts from 0. - private alertId = 0; - private alerts: Alert[] = []; - - constructor(private sanitizer: DomSanitizer, private ngZone: NgZone, private translateService: TranslateService) {} - - clear(): void { - this.alerts = []; - } - - get(): Alert[] { - return this.alerts; - } - - /** - * Adds alert to alerts array and returns added alert. - * @param alert Alert to add. If `timeout`, `toast` or `position` is missing then applying default value. - * If `translateKey` is available then it's translation else `message` is used for showing. - * @param extAlerts If missing then adding `alert` to `AlertService` internal array and alerts can be retrieved by `get()`. - * Else adding `alert` to `extAlerts`. - * @returns Added alert - */ - addAlert(alert: Alert, extAlerts?: Alert[]): Alert { - alert.id = this.alertId++; - - if (alert.translationKey) { - const translatedMessage = this.translateService.instant(alert.translationKey, alert.translationParams); - // if translation key exists - if (translatedMessage !== `${translationNotFoundMessage}[${alert.translationKey}]`) { - alert.message = translatedMessage; - } else if (!alert.message) { - alert.message = alert.translationKey; - } - } - - alert.message = this.sanitizer.sanitize(SecurityContext.HTML, alert.message ?? '') ?? ''; - alert.timeout = alert.timeout ?? this.timeout; - alert.toast = alert.toast ?? this.toast; - alert.position = alert.position ?? this.position; - alert.close = (alertsArray: Alert[]) => this.closeAlert(alert.id!, alertsArray); - - (extAlerts ?? this.alerts).push(alert); - - if (alert.timeout > 0) { - setTimeout(() => { - this.closeAlert(alert.id!, extAlerts ?? this.alerts); - }, alert.timeout); - } - - return alert; - } - - private closeAlert(alertId: number, extAlerts?: Alert[]): void { - const alerts = extAlerts ?? this.alerts; - const alertIndex = alerts.map(alert => alert.id).indexOf(alertId); - // if found alert then remove - if (alertIndex >= 0) { - alerts.splice(alertIndex, 1); - } - } -} diff --git a/src/main/webapp/app/core/util/data-util.service.spec.ts b/src/main/webapp/app/core/util/data-util.service.spec.ts deleted file mode 100644 index fccbcc646..000000000 --- a/src/main/webapp/app/core/util/data-util.service.spec.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { DataUtils } from './data-util.service'; - -describe('Data Utils Service Test', () => { - let service: DataUtils; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [DataUtils], - }); - service = TestBed.inject(DataUtils); - }); - - describe('byteSize', () => { - it('should return the bytesize of the text', () => { - expect(service.byteSize('Hello JHipster')).toBe(`10.5 bytes`); - }); - }); - - describe('openFile', () => { - it('should open the file in the new window', () => { - const newWindow = { ...window }; - newWindow.document.write = jest.fn(); - window.open = jest.fn(() => newWindow); - window.URL.createObjectURL = jest.fn(); - // 'JHipster' in base64 is 'SkhpcHN0ZXI=' - const data = 'SkhpcHN0ZXI='; - const contentType = 'text/plain'; - service.openFile(data, contentType); - expect(window.open).toHaveBeenCalledTimes(1); - }); - }); -}); diff --git a/src/main/webapp/app/core/util/data-util.service.ts b/src/main/webapp/app/core/util/data-util.service.ts deleted file mode 100644 index 37e0387e9..000000000 --- a/src/main/webapp/app/core/util/data-util.service.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { Injectable } from '@angular/core'; -import { FormGroup } from '@angular/forms'; -import { Observable, Observer } from 'rxjs'; -import { Buffer } from 'buffer'; - -export type FileLoadErrorType = 'not.image' | 'could.not.extract'; - -export interface FileLoadError { - message: string; - key: FileLoadErrorType; - params?: any; -} - -/** - * An utility service for data. - */ -@Injectable({ - providedIn: 'root', -}) -export class DataUtils { - /** - * Method to find the byte size of the string provides - */ - byteSize(base64String: string): string { - return this.formatAsBytes(this.size(base64String)); - } - - /** - * Method to open file - */ - openFile(data: string, contentType: string | null | undefined): void { - contentType = contentType ?? ''; - - const byteCharacters = Buffer.from(data, 'base64').toString('binary'); - const byteNumbers = new Array(byteCharacters.length); - for (let i = 0; i < byteCharacters.length; i++) { - byteNumbers[i] = byteCharacters.charCodeAt(i); - } - const byteArray = new Uint8Array(byteNumbers); - const blob = new Blob([byteArray], { - type: contentType, - }); - const fileURL = window.URL.createObjectURL(blob); - const win = window.open(fileURL); - win!.onload = function () { - URL.revokeObjectURL(fileURL); - }; - } - - /** - * Sets the base 64 data & file type of the 1st file on the event (event.target.files[0]) in the passed entity object - * and returns an observable. - * - * @param event the object containing the file (at event.target.files[0]) - * @param editForm the form group where the input field is located - * @param field the field name to set the file's 'base 64 data' on - * @param isImage boolean representing if the file represented by the event is an image - * @returns an observable that loads file to form field and completes if sussessful - * or returns error as FileLoadError on failure - */ - loadFileToForm(event: Event, editForm: FormGroup, field: string, isImage: boolean): Observable { - return new Observable((observer: Observer) => { - const eventTarget: HTMLInputElement | null = event.target as HTMLInputElement | null; - if (eventTarget?.files?.[0]) { - const file: File = eventTarget.files[0]; - if (isImage && !file.type.startsWith('image/')) { - const error: FileLoadError = { - message: `File was expected to be an image but was found to be '${file.type}'`, - key: 'not.image', - params: { fileType: file.type }, - }; - observer.error(error); - } else { - const fieldContentType: string = field + 'ContentType'; - this.toBase64(file, (base64Data: string) => { - editForm.patchValue({ - [field]: base64Data, - [fieldContentType]: file.type, - }); - observer.next(); - observer.complete(); - }); - } - } else { - const error: FileLoadError = { - message: 'Could not extract file', - key: 'could.not.extract', - params: { event }, - }; - observer.error(error); - } - }); - } - - /** - * Method to convert the file to base64 - */ - private toBase64(file: File, callback: (base64Data: string) => void): void { - const fileReader: FileReader = new FileReader(); - fileReader.onload = (e: ProgressEvent) => { - if (typeof e.target?.result === 'string') { - const base64Data: string = e.target.result.substring(e.target.result.indexOf('base64,') + 'base64,'.length); - callback(base64Data); - } - }; - fileReader.readAsDataURL(file); - } - - private endsWith(suffix: string, str: string): boolean { - return str.includes(suffix, str.length - suffix.length); - } - - private paddingSize(value: string): number { - if (this.endsWith('==', value)) { - return 2; - } - if (this.endsWith('=', value)) { - return 1; - } - return 0; - } - - private size(value: string): number { - return (value.length / 4) * 3 - this.paddingSize(value); - } - - private formatAsBytes(size: number): string { - return size.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ' ') + ' bytes'; // NOSONAR - } -} diff --git a/src/main/webapp/app/core/util/event-manager.service.spec.ts b/src/main/webapp/app/core/util/event-manager.service.spec.ts deleted file mode 100644 index 910009c9c..000000000 --- a/src/main/webapp/app/core/util/event-manager.service.spec.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { inject, TestBed } from '@angular/core/testing'; - -import { EventManager, EventWithContent } from './event-manager.service'; - -describe('Event Manager tests', () => { - describe('EventWithContent', () => { - it('should create correctly EventWithContent', () => { - // WHEN - const eventWithContent = new EventWithContent('name', 'content'); - - // THEN - expect(eventWithContent).toEqual({ name: 'name', content: 'content' }); - }); - }); - - describe('EventManager', () => { - let recievedEvent: EventWithContent | string | null; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [EventManager], - }); - recievedEvent = null; - }); - - it('should not fail when nosubscriber and broadcasting', inject([EventManager], (eventManager: EventManager) => { - expect(eventManager.observer).toBeUndefined(); - eventManager.broadcast({ name: 'modifier', content: 'modified something' }); - })); - - it('should create an observable and callback when broadcasted EventWithContent', inject( - [EventManager], - (eventManager: EventManager) => { - // GIVEN - eventManager.subscribe('modifier', (event: EventWithContent | string) => (recievedEvent = event)); - - // WHEN - eventManager.broadcast({ name: 'unrelatedModifier', content: 'unreleated modification' }); - // THEN - expect(recievedEvent).toBeNull(); - - // WHEN - eventManager.broadcast({ name: 'modifier', content: 'modified something' }); - // THEN - expect(recievedEvent).toEqual({ name: 'modifier', content: 'modified something' }); - } - )); - - it('should create an observable and callback when broadcasted string', inject([EventManager], (eventManager: EventManager) => { - // GIVEN - eventManager.subscribe('modifier', (event: EventWithContent | string) => (recievedEvent = event)); - - // WHEN - eventManager.broadcast('unrelatedModifier'); - // THEN - expect(recievedEvent).toBeNull(); - - // WHEN - eventManager.broadcast('modifier'); - // THEN - expect(recievedEvent).toEqual('modifier'); - })); - - it('should subscribe to multiple events', inject([EventManager], (eventManager: EventManager) => { - // GIVEN - eventManager.subscribe(['modifier', 'modifier2'], (event: EventWithContent | string) => (recievedEvent = event)); - - // WHEN - eventManager.broadcast('unrelatedModifier'); - // THEN - expect(recievedEvent).toBeNull(); - - // WHEN - eventManager.broadcast({ name: 'modifier', content: 'modified something' }); - // THEN - expect(recievedEvent).toEqual({ name: 'modifier', content: 'modified something' }); - - // WHEN - eventManager.broadcast('modifier2'); - // THEN - expect(recievedEvent).toEqual('modifier2'); - })); - }); -}); diff --git a/src/main/webapp/app/core/util/event-manager.service.ts b/src/main/webapp/app/core/util/event-manager.service.ts deleted file mode 100644 index 1730369ba..000000000 --- a/src/main/webapp/app/core/util/event-manager.service.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable, Observer, Subscription } from 'rxjs'; -import { filter, share } from 'rxjs/operators'; - -export class EventWithContent { - constructor(public name: string, public content: T) {} -} - -/** - * An utility class to manage RX events - */ -@Injectable({ - providedIn: 'root', -}) -export class EventManager { - observable: Observable | string>; - observer?: Observer | string>; - - constructor() { - this.observable = new Observable((observer: Observer | string>) => { - this.observer = observer; - }).pipe(share()); - } - - /** - * Method to broadcast the event to observer - */ - broadcast(event: EventWithContent | string): void { - if (this.observer) { - this.observer.next(event); - } - } - - /** - * Method to subscribe to an event with callback - * @param eventNames Single event name or array of event names to what subscribe - * @param callback Callback to run when the event occurs - */ - subscribe(eventNames: string | string[], callback: (event: EventWithContent | string) => void): Subscription { - if (typeof eventNames === 'string') { - eventNames = [eventNames]; - } - return this.observable - .pipe( - filter((event: EventWithContent | string) => { - for (const eventName of eventNames) { - if ((typeof event === 'string' && event === eventName) || (typeof event !== 'string' && event.name === eventName)) { - return true; - } - } - return false; - }) - ) - .subscribe(callback); - } - - /** - * Method to unsubscribe the subscription - */ - destroy(subscriber: Subscription): void { - subscriber.unsubscribe(); - } -} diff --git a/src/main/webapp/app/core/util/operators.spec.ts b/src/main/webapp/app/core/util/operators.spec.ts deleted file mode 100644 index 429647c47..000000000 --- a/src/main/webapp/app/core/util/operators.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { filterNaN, isPresent } from './operators'; - -describe('Operators Test', () => { - describe('isPresent', () => { - it('should remove null and undefined values', () => { - expect([1, null, undefined].filter(isPresent)).toEqual([1]); - }); - }); - - describe('filterNaN', () => { - it('should return 0 for NaN', () => { - expect(filterNaN(NaN)).toBe(0); - }); - it('should return number for a number', () => { - expect(filterNaN(12345)).toBe(12345); - }); - }); -}); diff --git a/src/main/webapp/app/core/util/operators.ts b/src/main/webapp/app/core/util/operators.ts deleted file mode 100644 index c22459296..000000000 --- a/src/main/webapp/app/core/util/operators.ts +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Function used to workaround https://github.com/microsoft/TypeScript/issues/16069 - * es2019 alternative `const filteredArr = myArr.flatMap((x) => x ? x : []);` - */ -export function isPresent(t: T | undefined | null | void): t is T { - return t !== undefined && t !== null; -} - -export const filterNaN = (input: number): number => (isNaN(input) ? 0 : input); diff --git a/src/main/webapp/app/core/util/parse-links.service.spec.ts b/src/main/webapp/app/core/util/parse-links.service.spec.ts deleted file mode 100644 index 40b6c75cf..000000000 --- a/src/main/webapp/app/core/util/parse-links.service.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { inject, TestBed } from '@angular/core/testing'; - -import { ParseLinks } from './parse-links.service'; - -describe('Parse links service test', () => { - describe('Parse Links Service Test', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [ParseLinks], - }); - }); - - it('should throw an error when passed an empty string', inject([ParseLinks], (service: ParseLinks) => { - expect(function () { - service.parse(''); - }).toThrow(new Error('input must not be of zero length')); - })); - - it('should throw an error when passed without comma', inject([ParseLinks], (service: ParseLinks) => { - expect(function () { - service.parse('test'); - }).toThrow(new Error('section could not be split on ";"')); - })); - - it('should throw an error when passed without semicolon', inject([ParseLinks], (service: ParseLinks) => { - expect(function () { - service.parse('test,test2'); - }).toThrow(new Error('section could not be split on ";"')); - })); - - it('should return links when headers are passed', inject([ParseLinks], (service: ParseLinks) => { - const links = { last: 0, first: 0 }; - expect(service.parse(' ; rel="last",; rel="first"')).toEqual(links); - })); - }); -}); diff --git a/src/main/webapp/app/core/util/parse-links.service.ts b/src/main/webapp/app/core/util/parse-links.service.ts deleted file mode 100644 index dc1eb0e91..000000000 --- a/src/main/webapp/app/core/util/parse-links.service.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Injectable } from '@angular/core'; - -/** - * An utility service for link parsing. - */ -@Injectable({ - providedIn: 'root', -}) -export class ParseLinks { - /** - * Method to parse the links - */ - parse(header: string): { [key: string]: number } { - if (header.length === 0) { - throw new Error('input must not be of zero length'); - } - - // Split parts by comma - const parts: string[] = header.split(','); - const links: { [key: string]: number } = {}; - - // Parse each part into a named link - parts.forEach(p => { - const section: string[] = p.split(';'); - - if (section.length !== 2) { - throw new Error('section could not be split on ";"'); - } - - const url: string = section[0].replace(/<(.*)>/, '$1').trim(); // NOSONAR - const queryString: { [key: string]: string | undefined } = {}; - - url.replace(/([^?=&]+)(=([^&]*))?/g, (_$0: string, $1: string | undefined, _$2: string | undefined, $3: string | undefined) => { - if ($1 !== undefined) { - queryString[$1] = $3; - } - return $3 ?? ''; - }); - - if (queryString.page !== undefined) { - const name: string = section[1].replace(/rel="(.*)"/, '$1').trim(); - links[name] = parseInt(queryString.page, 10); - } - }); - return links; - } -} diff --git a/src/main/webapp/app/entities/bank-account/bank-account.model.ts b/src/main/webapp/app/entities/bank-account/bank-account.model.ts deleted file mode 100644 index e71ae8450..000000000 --- a/src/main/webapp/app/entities/bank-account/bank-account.model.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { IUser } from 'app/entities/user/user.model'; - -export interface IBankAccount { - id: number; - name?: string | null; - balance?: number | null; - user?: Pick | null; -} - -export type NewBankAccount = Omit & { id: null }; diff --git a/src/main/webapp/app/entities/bank-account/bank-account.routes.ts b/src/main/webapp/app/entities/bank-account/bank-account.routes.ts deleted file mode 100644 index 72f639b1f..000000000 --- a/src/main/webapp/app/entities/bank-account/bank-account.routes.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Routes } from '@angular/router'; - -import { UserRouteAccessService } from 'app/core/auth/user-route-access.service'; -import { BankAccountComponent } from './list/bank-account.component'; -import { BankAccountDetailComponent } from './detail/bank-account-detail.component'; -import { BankAccountUpdateComponent } from './update/bank-account-update.component'; -import BankAccountResolve from './route/bank-account-routing-resolve.service'; -import { ASC } from 'app/config/navigation.constants'; - -const bankAccountRoute: Routes = [ - { - path: '', - component: BankAccountComponent, - data: { - defaultSort: 'id,' + ASC, - }, - canActivate: [UserRouteAccessService], - }, - { - path: ':id/view', - component: BankAccountDetailComponent, - resolve: { - bankAccount: BankAccountResolve, - }, - canActivate: [UserRouteAccessService], - }, - { - path: 'new', - component: BankAccountUpdateComponent, - resolve: { - bankAccount: BankAccountResolve, - }, - canActivate: [UserRouteAccessService], - }, - { - path: ':id/edit', - component: BankAccountUpdateComponent, - resolve: { - bankAccount: BankAccountResolve, - }, - canActivate: [UserRouteAccessService], - }, -]; - -export default bankAccountRoute; diff --git a/src/main/webapp/app/entities/bank-account/bank-account.test-samples.ts b/src/main/webapp/app/entities/bank-account/bank-account.test-samples.ts deleted file mode 100644 index 54019d078..000000000 --- a/src/main/webapp/app/entities/bank-account/bank-account.test-samples.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { IBankAccount, NewBankAccount } from './bank-account.model'; - -export const sampleWithRequiredData: IBankAccount = { - id: 7094, - name: 'woman', - balance: 744, -}; - -export const sampleWithPartialData: IBankAccount = { - id: 8492, - name: 'Fitness deposit', - balance: 2195, -}; - -export const sampleWithFullData: IBankAccount = { - id: 28147, - name: 'Future Rupee', - balance: 1743, -}; - -export const sampleWithNewData: NewBankAccount = { - name: 'Bicycle', - balance: 6523, - id: null, -}; - -Object.freeze(sampleWithNewData); -Object.freeze(sampleWithRequiredData); -Object.freeze(sampleWithPartialData); -Object.freeze(sampleWithFullData); diff --git a/src/main/webapp/app/entities/bank-account/delete/bank-account-delete-dialog.component.html b/src/main/webapp/app/entities/bank-account/delete/bank-account-delete-dialog.component.html deleted file mode 100644 index a588f7ff2..000000000 --- a/src/main/webapp/app/entities/bank-account/delete/bank-account-delete-dialog.component.html +++ /dev/null @@ -1,28 +0,0 @@ -
- - - - - -
diff --git a/src/main/webapp/app/entities/bank-account/delete/bank-account-delete-dialog.component.spec.ts b/src/main/webapp/app/entities/bank-account/delete/bank-account-delete-dialog.component.spec.ts deleted file mode 100644 index 3368a2a68..000000000 --- a/src/main/webapp/app/entities/bank-account/delete/bank-account-delete-dialog.component.spec.ts +++ /dev/null @@ -1,62 +0,0 @@ -jest.mock('@ng-bootstrap/ng-bootstrap'); - -import { ComponentFixture, TestBed, inject, fakeAsync, tick } from '@angular/core/testing'; -import { HttpResponse } from '@angular/common/http'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { of } from 'rxjs'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; - -import { BankAccountService } from '../service/bank-account.service'; - -import { BankAccountDeleteDialogComponent } from './bank-account-delete-dialog.component'; - -describe('BankAccount Management Delete Component', () => { - let comp: BankAccountDeleteDialogComponent; - let fixture: ComponentFixture; - let service: BankAccountService; - let mockActiveModal: NgbActiveModal; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, BankAccountDeleteDialogComponent], - providers: [NgbActiveModal], - }) - .overrideTemplate(BankAccountDeleteDialogComponent, '') - .compileComponents(); - fixture = TestBed.createComponent(BankAccountDeleteDialogComponent); - comp = fixture.componentInstance; - service = TestBed.inject(BankAccountService); - mockActiveModal = TestBed.inject(NgbActiveModal); - }); - - describe('confirmDelete', () => { - it('Should call delete service on confirmDelete', inject( - [], - fakeAsync(() => { - // GIVEN - jest.spyOn(service, 'delete').mockReturnValue(of(new HttpResponse({ body: {} }))); - - // WHEN - comp.confirmDelete(123); - tick(); - - // THEN - expect(service.delete).toHaveBeenCalledWith(123); - expect(mockActiveModal.close).toHaveBeenCalledWith('deleted'); - }) - )); - - it('Should not call delete service on clear', () => { - // GIVEN - jest.spyOn(service, 'delete'); - - // WHEN - comp.cancel(); - - // THEN - expect(service.delete).not.toHaveBeenCalled(); - expect(mockActiveModal.close).not.toHaveBeenCalled(); - expect(mockActiveModal.dismiss).toHaveBeenCalled(); - }); - }); -}); diff --git a/src/main/webapp/app/entities/bank-account/delete/bank-account-delete-dialog.component.ts b/src/main/webapp/app/entities/bank-account/delete/bank-account-delete-dialog.component.ts deleted file mode 100644 index 2b28a6f6c..000000000 --- a/src/main/webapp/app/entities/bank-account/delete/bank-account-delete-dialog.component.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Component } from '@angular/core'; -import { FormsModule } from '@angular/forms'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; - -import SharedModule from 'app/shared/shared.module'; -import { IBankAccount } from '../bank-account.model'; -import { BankAccountService } from '../service/bank-account.service'; -import { ITEM_DELETED_EVENT } from 'app/config/navigation.constants'; - -@Component({ - standalone: true, - templateUrl: './bank-account-delete-dialog.component.html', - imports: [SharedModule, FormsModule], -}) -export class BankAccountDeleteDialogComponent { - bankAccount?: IBankAccount; - - constructor(protected bankAccountService: BankAccountService, protected activeModal: NgbActiveModal) {} - - cancel(): void { - this.activeModal.dismiss(); - } - - confirmDelete(id: number): void { - this.bankAccountService.delete(id).subscribe(() => { - this.activeModal.close(ITEM_DELETED_EVENT); - }); - } -} diff --git a/src/main/webapp/app/entities/bank-account/detail/bank-account-detail.component.html b/src/main/webapp/app/entities/bank-account/detail/bank-account-detail.component.html deleted file mode 100644 index cb01a02e8..000000000 --- a/src/main/webapp/app/entities/bank-account/detail/bank-account-detail.component.html +++ /dev/null @@ -1,42 +0,0 @@ -
-
-
-

- Bank Account -

- -
- - - - - -
-
ID
-
- {{ bankAccount.id }} -
-
Name
-
- {{ bankAccount.name }} -
-
Balance
-
- {{ bankAccount.balance }} -
-
User
-
- {{ bankAccount.user?.login }} -
-
- - - - -
-
-
diff --git a/src/main/webapp/app/entities/bank-account/detail/bank-account-detail.component.spec.ts b/src/main/webapp/app/entities/bank-account/detail/bank-account-detail.component.spec.ts deleted file mode 100644 index efbf47947..000000000 --- a/src/main/webapp/app/entities/bank-account/detail/bank-account-detail.component.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { provideRouter, withComponentInputBinding } from '@angular/router'; -import { RouterTestingHarness, RouterTestingModule } from '@angular/router/testing'; -import { of } from 'rxjs'; - -import { BankAccountDetailComponent } from './bank-account-detail.component'; - -describe('BankAccount Management Detail Component', () => { - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [BankAccountDetailComponent, RouterTestingModule.withRoutes([], { bindToComponentInputs: true })], - providers: [ - provideRouter( - [ - { - path: '**', - component: BankAccountDetailComponent, - resolve: { bankAccount: () => of({ id: 123 }) }, - }, - ], - withComponentInputBinding() - ), - ], - }) - .overrideTemplate(BankAccountDetailComponent, '') - .compileComponents(); - }); - - describe('OnInit', () => { - it('Should load bankAccount on init', async () => { - const harness = await RouterTestingHarness.create(); - const instance = await harness.navigateByUrl('/', BankAccountDetailComponent); - - // THEN - expect(instance.bankAccount).toEqual(expect.objectContaining({ id: 123 })); - }); - }); -}); diff --git a/src/main/webapp/app/entities/bank-account/detail/bank-account-detail.component.ts b/src/main/webapp/app/entities/bank-account/detail/bank-account-detail.component.ts deleted file mode 100644 index b12f270bf..000000000 --- a/src/main/webapp/app/entities/bank-account/detail/bank-account-detail.component.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { ActivatedRoute, RouterModule } from '@angular/router'; - -import SharedModule from 'app/shared/shared.module'; -import { DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe } from 'app/shared/date'; -import { IBankAccount } from '../bank-account.model'; - -@Component({ - standalone: true, - selector: 'jhi-bank-account-detail', - templateUrl: './bank-account-detail.component.html', - imports: [SharedModule, RouterModule, DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe], -}) -export class BankAccountDetailComponent { - @Input() bankAccount: IBankAccount | null = null; - - constructor(protected activatedRoute: ActivatedRoute) {} - - previousState(): void { - window.history.back(); - } -} diff --git a/src/main/webapp/app/entities/bank-account/list/bank-account.component.html b/src/main/webapp/app/entities/bank-account/list/bank-account.component.html deleted file mode 100644 index a3ca5b9fe..000000000 --- a/src/main/webapp/app/entities/bank-account/list/bank-account.component.html +++ /dev/null @@ -1,104 +0,0 @@ -
-

- Bank Accounts - -
- - - -
-

- - - - - -
- No Bank Accounts found -
- -
- - - - - - - - - - - - - - - - - - - -
-
- ID - -
-
-
- Name - -
-
-
- Balance - -
-
-
- User - -
-
- {{ bankAccount.id }} - {{ bankAccount.name }}{{ bankAccount.balance }} - {{ bankAccount.user?.login }} - -
- - - - - -
-
-
-
diff --git a/src/main/webapp/app/entities/bank-account/list/bank-account.component.spec.ts b/src/main/webapp/app/entities/bank-account/list/bank-account.component.spec.ts deleted file mode 100644 index 2ce5bab30..000000000 --- a/src/main/webapp/app/entities/bank-account/list/bank-account.component.spec.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { HttpHeaders, HttpResponse } from '@angular/common/http'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { ActivatedRoute } from '@angular/router'; -import { RouterTestingModule } from '@angular/router/testing'; -import { of } from 'rxjs'; - -import { BankAccountService } from '../service/bank-account.service'; - -import { BankAccountComponent } from './bank-account.component'; - -describe('BankAccount Management Component', () => { - let comp: BankAccountComponent; - let fixture: ComponentFixture; - let service: BankAccountService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - RouterTestingModule.withRoutes([{ path: 'bank-account', component: BankAccountComponent }]), - HttpClientTestingModule, - BankAccountComponent, - ], - providers: [ - { - provide: ActivatedRoute, - useValue: { - data: of({ - defaultSort: 'id,asc', - }), - queryParamMap: of( - jest.requireActual('@angular/router').convertToParamMap({ - page: '1', - size: '1', - sort: 'id,desc', - }) - ), - snapshot: { queryParams: {} }, - }, - }, - ], - }) - .overrideTemplate(BankAccountComponent, '') - .compileComponents(); - - fixture = TestBed.createComponent(BankAccountComponent); - comp = fixture.componentInstance; - service = TestBed.inject(BankAccountService); - - const headers = new HttpHeaders(); - jest.spyOn(service, 'query').mockReturnValue( - of( - new HttpResponse({ - body: [{ id: 123 }], - headers, - }) - ) - ); - }); - - it('Should call load all on init', () => { - // WHEN - comp.ngOnInit(); - - // THEN - expect(service.query).toHaveBeenCalled(); - expect(comp.bankAccounts?.[0]).toEqual(expect.objectContaining({ id: 123 })); - }); - - describe('trackId', () => { - it('Should forward to bankAccountService', () => { - const entity = { id: 123 }; - jest.spyOn(service, 'getBankAccountIdentifier'); - const id = comp.trackId(0, entity); - expect(service.getBankAccountIdentifier).toHaveBeenCalledWith(entity); - expect(id).toBe(entity.id); - }); - }); -}); diff --git a/src/main/webapp/app/entities/bank-account/list/bank-account.component.ts b/src/main/webapp/app/entities/bank-account/list/bank-account.component.ts deleted file mode 100644 index 6a6e4471a..000000000 --- a/src/main/webapp/app/entities/bank-account/list/bank-account.component.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute, Data, ParamMap, Router, RouterModule } from '@angular/router'; -import { combineLatest, filter, Observable, switchMap, tap } from 'rxjs'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; - -import SharedModule from 'app/shared/shared.module'; -import { SortDirective, SortByDirective } from 'app/shared/sort'; -import { DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe } from 'app/shared/date'; -import { FormsModule } from '@angular/forms'; -import { IBankAccount } from '../bank-account.model'; -import { ASC, DESC, SORT, ITEM_DELETED_EVENT, DEFAULT_SORT_DATA } from 'app/config/navigation.constants'; -import { EntityArrayResponseType, BankAccountService } from '../service/bank-account.service'; -import { BankAccountDeleteDialogComponent } from '../delete/bank-account-delete-dialog.component'; -import { SortService } from 'app/shared/sort/sort.service'; - -@Component({ - standalone: true, - selector: 'jhi-bank-account', - templateUrl: './bank-account.component.html', - imports: [ - RouterModule, - FormsModule, - SharedModule, - SortDirective, - SortByDirective, - DurationPipe, - FormatMediumDatetimePipe, - FormatMediumDatePipe, - ], -}) -export class BankAccountComponent implements OnInit { - bankAccounts?: IBankAccount[]; - isLoading = false; - - predicate = 'id'; - ascending = true; - - constructor( - protected bankAccountService: BankAccountService, - protected activatedRoute: ActivatedRoute, - public router: Router, - protected sortService: SortService, - protected modalService: NgbModal - ) {} - - trackId = (_index: number, item: IBankAccount): number => this.bankAccountService.getBankAccountIdentifier(item); - - ngOnInit(): void { - this.load(); - } - - delete(bankAccount: IBankAccount): void { - const modalRef = this.modalService.open(BankAccountDeleteDialogComponent, { size: 'lg', backdrop: 'static' }); - modalRef.componentInstance.bankAccount = bankAccount; - // unsubscribe not needed because closed completes on modal close - modalRef.closed - .pipe( - filter(reason => reason === ITEM_DELETED_EVENT), - switchMap(() => this.loadFromBackendWithRouteInformations()) - ) - .subscribe({ - next: (res: EntityArrayResponseType) => { - this.onResponseSuccess(res); - }, - }); - } - - load(): void { - this.loadFromBackendWithRouteInformations().subscribe({ - next: (res: EntityArrayResponseType) => { - this.onResponseSuccess(res); - }, - }); - } - - navigateToWithComponentValues(): void { - this.handleNavigation(this.predicate, this.ascending); - } - - protected loadFromBackendWithRouteInformations(): Observable { - return combineLatest([this.activatedRoute.queryParamMap, this.activatedRoute.data]).pipe( - tap(([params, data]) => this.fillComponentAttributeFromRoute(params, data)), - switchMap(() => this.queryBackend(this.predicate, this.ascending)) - ); - } - - protected fillComponentAttributeFromRoute(params: ParamMap, data: Data): void { - const sort = (params.get(SORT) ?? data[DEFAULT_SORT_DATA]).split(','); - this.predicate = sort[0]; - this.ascending = sort[1] === ASC; - } - - protected onResponseSuccess(response: EntityArrayResponseType): void { - const dataFromBody = this.fillComponentAttributesFromResponseBody(response.body); - this.bankAccounts = this.refineData(dataFromBody); - } - - protected refineData(data: IBankAccount[]): IBankAccount[] { - return data.sort(this.sortService.startSort(this.predicate, this.ascending ? 1 : -1)); - } - - protected fillComponentAttributesFromResponseBody(data: IBankAccount[] | null): IBankAccount[] { - return data ?? []; - } - - protected queryBackend(predicate?: string, ascending?: boolean): Observable { - this.isLoading = true; - const queryObject: any = { - eagerload: true, - sort: this.getSortQueryParam(predicate, ascending), - }; - return this.bankAccountService.query(queryObject).pipe(tap(() => (this.isLoading = false))); - } - - protected handleNavigation(predicate?: string, ascending?: boolean): void { - const queryParamsObj = { - sort: this.getSortQueryParam(predicate, ascending), - }; - - this.router.navigate(['./'], { - relativeTo: this.activatedRoute, - queryParams: queryParamsObj, - }); - } - - protected getSortQueryParam(predicate = this.predicate, ascending = this.ascending): string[] { - const ascendingQueryParam = ascending ? ASC : DESC; - if (predicate === '') { - return []; - } else { - return [predicate + ',' + ascendingQueryParam]; - } - } -} diff --git a/src/main/webapp/app/entities/bank-account/route/bank-account-routing-resolve.service.spec.ts b/src/main/webapp/app/entities/bank-account/route/bank-account-routing-resolve.service.spec.ts deleted file mode 100644 index 4ee7115c8..000000000 --- a/src/main/webapp/app/entities/bank-account/route/bank-account-routing-resolve.service.spec.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { HttpResponse } from '@angular/common/http'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { ActivatedRouteSnapshot, ActivatedRoute, Router, convertToParamMap, RouterStateSnapshot } from '@angular/router'; -import { RouterTestingModule } from '@angular/router/testing'; -import { of } from 'rxjs'; - -import { IBankAccount } from '../bank-account.model'; -import { BankAccountService } from '../service/bank-account.service'; - -import bankAccountResolve from './bank-account-routing-resolve.service'; - -describe('BankAccount routing resolve service', () => { - let mockRouter: Router; - let mockActivatedRouteSnapshot: ActivatedRouteSnapshot; - let service: BankAccountService; - let resultBankAccount: IBankAccount | null | undefined; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, RouterTestingModule.withRoutes([])], - providers: [ - { - provide: ActivatedRoute, - useValue: { - snapshot: { - paramMap: convertToParamMap({}), - }, - }, - }, - ], - }); - mockRouter = TestBed.inject(Router); - jest.spyOn(mockRouter, 'navigate').mockImplementation(() => Promise.resolve(true)); - mockActivatedRouteSnapshot = TestBed.inject(ActivatedRoute).snapshot; - service = TestBed.inject(BankAccountService); - resultBankAccount = undefined; - }); - - describe('resolve', () => { - it('should return IBankAccount returned by find', () => { - // GIVEN - service.find = jest.fn(id => of(new HttpResponse({ body: { id } }))); - mockActivatedRouteSnapshot.params = { id: 123 }; - - // WHEN - TestBed.runInInjectionContext(() => { - bankAccountResolve(mockActivatedRouteSnapshot).subscribe({ - next(result) { - resultBankAccount = result; - }, - }); - }); - - // THEN - expect(service.find).toBeCalledWith(123); - expect(resultBankAccount).toEqual({ id: 123 }); - }); - - it('should return null if id is not provided', () => { - // GIVEN - service.find = jest.fn(); - mockActivatedRouteSnapshot.params = {}; - - // WHEN - TestBed.runInInjectionContext(() => { - bankAccountResolve(mockActivatedRouteSnapshot).subscribe({ - next(result) { - resultBankAccount = result; - }, - }); - }); - - // THEN - expect(service.find).not.toBeCalled(); - expect(resultBankAccount).toEqual(null); - }); - - it('should route to 404 page if data not found in server', () => { - // GIVEN - jest.spyOn(service, 'find').mockReturnValue(of(new HttpResponse({ body: null }))); - mockActivatedRouteSnapshot.params = { id: 123 }; - - // WHEN - TestBed.runInInjectionContext(() => { - bankAccountResolve(mockActivatedRouteSnapshot).subscribe({ - next(result) { - resultBankAccount = result; - }, - }); - }); - - // THEN - expect(service.find).toBeCalledWith(123); - expect(resultBankAccount).toEqual(undefined); - expect(mockRouter.navigate).toHaveBeenCalledWith(['404']); - }); - }); -}); diff --git a/src/main/webapp/app/entities/bank-account/route/bank-account-routing-resolve.service.ts b/src/main/webapp/app/entities/bank-account/route/bank-account-routing-resolve.service.ts deleted file mode 100644 index 971ac21f7..000000000 --- a/src/main/webapp/app/entities/bank-account/route/bank-account-routing-resolve.service.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { inject } from '@angular/core'; -import { HttpResponse } from '@angular/common/http'; -import { ActivatedRouteSnapshot, Router } from '@angular/router'; -import { of, EMPTY, Observable } from 'rxjs'; -import { mergeMap } from 'rxjs/operators'; - -import { IBankAccount } from '../bank-account.model'; -import { BankAccountService } from '../service/bank-account.service'; - -export const bankAccountResolve = (route: ActivatedRouteSnapshot): Observable => { - const id = route.params['id']; - if (id) { - return inject(BankAccountService) - .find(id) - .pipe( - mergeMap((bankAccount: HttpResponse) => { - if (bankAccount.body) { - return of(bankAccount.body); - } else { - inject(Router).navigate(['404']); - return EMPTY; - } - }) - ); - } - return of(null); -}; - -export default bankAccountResolve; diff --git a/src/main/webapp/app/entities/bank-account/service/bank-account.service.spec.ts b/src/main/webapp/app/entities/bank-account/service/bank-account.service.spec.ts deleted file mode 100644 index 106ef2fc1..000000000 --- a/src/main/webapp/app/entities/bank-account/service/bank-account.service.spec.ts +++ /dev/null @@ -1,205 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; - -import { IBankAccount } from '../bank-account.model'; -import { sampleWithRequiredData, sampleWithNewData, sampleWithPartialData, sampleWithFullData } from '../bank-account.test-samples'; - -import { BankAccountService } from './bank-account.service'; - -const requireRestSample: IBankAccount = { - ...sampleWithRequiredData, -}; - -describe('BankAccount Service', () => { - let service: BankAccountService; - let httpMock: HttpTestingController; - let expectedResult: IBankAccount | IBankAccount[] | boolean | null; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - }); - expectedResult = null; - service = TestBed.inject(BankAccountService); - httpMock = TestBed.inject(HttpTestingController); - }); - - describe('Service methods', () => { - it('should find an element', () => { - const returnedFromService = { ...requireRestSample }; - const expected = { ...sampleWithRequiredData }; - - service.find(123).subscribe(resp => (expectedResult = resp.body)); - - const req = httpMock.expectOne({ method: 'GET' }); - req.flush(returnedFromService); - expect(expectedResult).toMatchObject(expected); - }); - - it('should create a BankAccount', () => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const bankAccount = { ...sampleWithNewData }; - const returnedFromService = { ...requireRestSample }; - const expected = { ...sampleWithRequiredData }; - - service.create(bankAccount).subscribe(resp => (expectedResult = resp.body)); - - const req = httpMock.expectOne({ method: 'POST' }); - req.flush(returnedFromService); - expect(expectedResult).toMatchObject(expected); - }); - - it('should update a BankAccount', () => { - const bankAccount = { ...sampleWithRequiredData }; - const returnedFromService = { ...requireRestSample }; - const expected = { ...sampleWithRequiredData }; - - service.update(bankAccount).subscribe(resp => (expectedResult = resp.body)); - - const req = httpMock.expectOne({ method: 'PUT' }); - req.flush(returnedFromService); - expect(expectedResult).toMatchObject(expected); - }); - - it('should partial update a BankAccount', () => { - const patchObject = { ...sampleWithPartialData }; - const returnedFromService = { ...requireRestSample }; - const expected = { ...sampleWithRequiredData }; - - service.partialUpdate(patchObject).subscribe(resp => (expectedResult = resp.body)); - - const req = httpMock.expectOne({ method: 'PATCH' }); - req.flush(returnedFromService); - expect(expectedResult).toMatchObject(expected); - }); - - it('should return a list of BankAccount', () => { - const returnedFromService = { ...requireRestSample }; - - const expected = { ...sampleWithRequiredData }; - - service.query().subscribe(resp => (expectedResult = resp.body)); - - const req = httpMock.expectOne({ method: 'GET' }); - req.flush([returnedFromService]); - httpMock.verify(); - expect(expectedResult).toMatchObject([expected]); - }); - - it('should delete a BankAccount', () => { - const expected = true; - - service.delete(123).subscribe(resp => (expectedResult = resp.ok)); - - const req = httpMock.expectOne({ method: 'DELETE' }); - req.flush({ status: 200 }); - expect(expectedResult).toBe(expected); - }); - - describe('addBankAccountToCollectionIfMissing', () => { - it('should add a BankAccount to an empty array', () => { - const bankAccount: IBankAccount = sampleWithRequiredData; - expectedResult = service.addBankAccountToCollectionIfMissing([], bankAccount); - expect(expectedResult).toHaveLength(1); - expect(expectedResult).toContain(bankAccount); - }); - - it('should not add a BankAccount to an array that contains it', () => { - const bankAccount: IBankAccount = sampleWithRequiredData; - const bankAccountCollection: IBankAccount[] = [ - { - ...bankAccount, - }, - sampleWithPartialData, - ]; - expectedResult = service.addBankAccountToCollectionIfMissing(bankAccountCollection, bankAccount); - expect(expectedResult).toHaveLength(2); - }); - - it("should add a BankAccount to an array that doesn't contain it", () => { - const bankAccount: IBankAccount = sampleWithRequiredData; - const bankAccountCollection: IBankAccount[] = [sampleWithPartialData]; - expectedResult = service.addBankAccountToCollectionIfMissing(bankAccountCollection, bankAccount); - expect(expectedResult).toHaveLength(2); - expect(expectedResult).toContain(bankAccount); - }); - - it('should add only unique BankAccount to an array', () => { - const bankAccountArray: IBankAccount[] = [sampleWithRequiredData, sampleWithPartialData, sampleWithFullData]; - const bankAccountCollection: IBankAccount[] = [sampleWithRequiredData]; - expectedResult = service.addBankAccountToCollectionIfMissing(bankAccountCollection, ...bankAccountArray); - expect(expectedResult).toHaveLength(3); - }); - - it('should accept varargs', () => { - const bankAccount: IBankAccount = sampleWithRequiredData; - const bankAccount2: IBankAccount = sampleWithPartialData; - expectedResult = service.addBankAccountToCollectionIfMissing([], bankAccount, bankAccount2); - expect(expectedResult).toHaveLength(2); - expect(expectedResult).toContain(bankAccount); - expect(expectedResult).toContain(bankAccount2); - }); - - it('should accept null and undefined values', () => { - const bankAccount: IBankAccount = sampleWithRequiredData; - expectedResult = service.addBankAccountToCollectionIfMissing([], null, bankAccount, undefined); - expect(expectedResult).toHaveLength(1); - expect(expectedResult).toContain(bankAccount); - }); - - it('should return initial array if no BankAccount is added', () => { - const bankAccountCollection: IBankAccount[] = [sampleWithRequiredData]; - expectedResult = service.addBankAccountToCollectionIfMissing(bankAccountCollection, undefined, null); - expect(expectedResult).toEqual(bankAccountCollection); - }); - }); - - describe('compareBankAccount', () => { - it('Should return true if both entities are null', () => { - const entity1 = null; - const entity2 = null; - - const compareResult = service.compareBankAccount(entity1, entity2); - - expect(compareResult).toEqual(true); - }); - - it('Should return false if one entity is null', () => { - const entity1 = { id: 123 }; - const entity2 = null; - - const compareResult1 = service.compareBankAccount(entity1, entity2); - const compareResult2 = service.compareBankAccount(entity2, entity1); - - expect(compareResult1).toEqual(false); - expect(compareResult2).toEqual(false); - }); - - it('Should return false if primaryKey differs', () => { - const entity1 = { id: 123 }; - const entity2 = { id: 456 }; - - const compareResult1 = service.compareBankAccount(entity1, entity2); - const compareResult2 = service.compareBankAccount(entity2, entity1); - - expect(compareResult1).toEqual(false); - expect(compareResult2).toEqual(false); - }); - - it('Should return false if primaryKey matches', () => { - const entity1 = { id: 123 }; - const entity2 = { id: 123 }; - - const compareResult1 = service.compareBankAccount(entity1, entity2); - const compareResult2 = service.compareBankAccount(entity2, entity1); - - expect(compareResult1).toEqual(true); - expect(compareResult2).toEqual(true); - }); - }); - }); - - afterEach(() => { - httpMock.verify(); - }); -}); diff --git a/src/main/webapp/app/entities/bank-account/service/bank-account.service.ts b/src/main/webapp/app/entities/bank-account/service/bank-account.service.ts deleted file mode 100644 index a88b6727e..000000000 --- a/src/main/webapp/app/entities/bank-account/service/bank-account.service.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient, HttpResponse } from '@angular/common/http'; -import { Observable } from 'rxjs'; - -import { isPresent } from 'app/core/util/operators'; -import { ApplicationConfigService } from 'app/core/config/application-config.service'; -import { createRequestOption } from 'app/core/request/request-util'; -import { IBankAccount, NewBankAccount } from '../bank-account.model'; - -export type PartialUpdateBankAccount = Partial & Pick; - -export type EntityResponseType = HttpResponse; -export type EntityArrayResponseType = HttpResponse; - -@Injectable({ providedIn: 'root' }) -export class BankAccountService { - protected resourceUrl = this.applicationConfigService.getEndpointFor('api/bank-accounts'); - - constructor(protected http: HttpClient, protected applicationConfigService: ApplicationConfigService) {} - - create(bankAccount: NewBankAccount): Observable { - return this.http.post(this.resourceUrl, bankAccount, { observe: 'response' }); - } - - update(bankAccount: IBankAccount): Observable { - return this.http.put(`${this.resourceUrl}/${this.getBankAccountIdentifier(bankAccount)}`, bankAccount, { - observe: 'response', - }); - } - - partialUpdate(bankAccount: PartialUpdateBankAccount): Observable { - return this.http.patch(`${this.resourceUrl}/${this.getBankAccountIdentifier(bankAccount)}`, bankAccount, { - observe: 'response', - }); - } - - find(id: number): Observable { - return this.http.get(`${this.resourceUrl}/${id}`, { observe: 'response' }); - } - - query(req?: any): Observable { - const options = createRequestOption(req); - return this.http.get(this.resourceUrl, { params: options, observe: 'response' }); - } - - delete(id: number): Observable> { - return this.http.delete(`${this.resourceUrl}/${id}`, { observe: 'response' }); - } - - getBankAccountIdentifier(bankAccount: Pick): number { - return bankAccount.id; - } - - compareBankAccount(o1: Pick | null, o2: Pick | null): boolean { - return o1 && o2 ? this.getBankAccountIdentifier(o1) === this.getBankAccountIdentifier(o2) : o1 === o2; - } - - addBankAccountToCollectionIfMissing>( - bankAccountCollection: Type[], - ...bankAccountsToCheck: (Type | null | undefined)[] - ): Type[] { - const bankAccounts: Type[] = bankAccountsToCheck.filter(isPresent); - if (bankAccounts.length > 0) { - const bankAccountCollectionIdentifiers = bankAccountCollection.map( - bankAccountItem => this.getBankAccountIdentifier(bankAccountItem)! - ); - const bankAccountsToAdd = bankAccounts.filter(bankAccountItem => { - const bankAccountIdentifier = this.getBankAccountIdentifier(bankAccountItem); - if (bankAccountCollectionIdentifiers.includes(bankAccountIdentifier)) { - return false; - } - bankAccountCollectionIdentifiers.push(bankAccountIdentifier); - return true; - }); - return [...bankAccountsToAdd, ...bankAccountCollection]; - } - return bankAccountCollection; - } -} diff --git a/src/main/webapp/app/entities/bank-account/update/bank-account-form.service.spec.ts b/src/main/webapp/app/entities/bank-account/update/bank-account-form.service.spec.ts deleted file mode 100644 index c117bb6bf..000000000 --- a/src/main/webapp/app/entities/bank-account/update/bank-account-form.service.spec.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { sampleWithRequiredData, sampleWithNewData } from '../bank-account.test-samples'; - -import { BankAccountFormService } from './bank-account-form.service'; - -describe('BankAccount Form Service', () => { - let service: BankAccountFormService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(BankAccountFormService); - }); - - describe('Service methods', () => { - describe('createBankAccountFormGroup', () => { - it('should create a new form with FormControl', () => { - const formGroup = service.createBankAccountFormGroup(); - - expect(formGroup.controls).toEqual( - expect.objectContaining({ - id: expect.any(Object), - name: expect.any(Object), - balance: expect.any(Object), - user: expect.any(Object), - }) - ); - }); - - it('passing IBankAccount should create a new form with FormGroup', () => { - const formGroup = service.createBankAccountFormGroup(sampleWithRequiredData); - - expect(formGroup.controls).toEqual( - expect.objectContaining({ - id: expect.any(Object), - name: expect.any(Object), - balance: expect.any(Object), - user: expect.any(Object), - }) - ); - }); - }); - - describe('getBankAccount', () => { - it('should return NewBankAccount for default BankAccount initial value', () => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const formGroup = service.createBankAccountFormGroup(sampleWithNewData); - - const bankAccount = service.getBankAccount(formGroup) as any; - - expect(bankAccount).toMatchObject(sampleWithNewData); - }); - - it('should return NewBankAccount for empty BankAccount initial value', () => { - const formGroup = service.createBankAccountFormGroup(); - - const bankAccount = service.getBankAccount(formGroup) as any; - - expect(bankAccount).toMatchObject({}); - }); - - it('should return IBankAccount', () => { - const formGroup = service.createBankAccountFormGroup(sampleWithRequiredData); - - const bankAccount = service.getBankAccount(formGroup) as any; - - expect(bankAccount).toMatchObject(sampleWithRequiredData); - }); - }); - - describe('resetForm', () => { - it('passing IBankAccount should not enable id FormControl', () => { - const formGroup = service.createBankAccountFormGroup(); - expect(formGroup.controls.id.disabled).toBe(true); - - service.resetForm(formGroup, sampleWithRequiredData); - - expect(formGroup.controls.id.disabled).toBe(true); - }); - - it('passing NewBankAccount should disable id FormControl', () => { - const formGroup = service.createBankAccountFormGroup(sampleWithRequiredData); - expect(formGroup.controls.id.disabled).toBe(true); - - service.resetForm(formGroup, { id: null }); - - expect(formGroup.controls.id.disabled).toBe(true); - }); - }); - }); -}); diff --git a/src/main/webapp/app/entities/bank-account/update/bank-account-form.service.ts b/src/main/webapp/app/entities/bank-account/update/bank-account-form.service.ts deleted file mode 100644 index 91ab16fcf..000000000 --- a/src/main/webapp/app/entities/bank-account/update/bank-account-form.service.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { Injectable } from '@angular/core'; -import { FormGroup, FormControl, Validators } from '@angular/forms'; - -import { IBankAccount, NewBankAccount } from '../bank-account.model'; - -/** - * A partial Type with required key is used as form input. - */ -type PartialWithRequiredKeyOf = Partial> & { id: T['id'] }; - -/** - * Type for createFormGroup and resetForm argument. - * It accepts IBankAccount for edit and NewBankAccountFormGroupInput for create. - */ -type BankAccountFormGroupInput = IBankAccount | PartialWithRequiredKeyOf; - -type BankAccountFormDefaults = Pick; - -type BankAccountFormGroupContent = { - id: FormControl; - name: FormControl; - balance: FormControl; - user: FormControl; -}; - -export type BankAccountFormGroup = FormGroup; - -@Injectable({ providedIn: 'root' }) -export class BankAccountFormService { - createBankAccountFormGroup(bankAccount: BankAccountFormGroupInput = { id: null }): BankAccountFormGroup { - const bankAccountRawValue = { - ...this.getFormDefaults(), - ...bankAccount, - }; - return new FormGroup({ - id: new FormControl( - { value: bankAccountRawValue.id, disabled: true }, - { - nonNullable: true, - validators: [Validators.required], - } - ), - name: new FormControl(bankAccountRawValue.name, { - validators: [Validators.required], - }), - balance: new FormControl(bankAccountRawValue.balance, { - validators: [Validators.required], - }), - user: new FormControl(bankAccountRawValue.user), - }); - } - - getBankAccount(form: BankAccountFormGroup): IBankAccount | NewBankAccount { - return form.getRawValue() as IBankAccount | NewBankAccount; - } - - resetForm(form: BankAccountFormGroup, bankAccount: BankAccountFormGroupInput): void { - const bankAccountRawValue = { ...this.getFormDefaults(), ...bankAccount }; - form.reset( - { - ...bankAccountRawValue, - id: { value: bankAccountRawValue.id, disabled: true }, - } as any /* cast to workaround https://github.com/angular/angular/issues/46458 */ - ); - } - - private getFormDefaults(): BankAccountFormDefaults { - return { - id: null, - }; - } -} diff --git a/src/main/webapp/app/entities/bank-account/update/bank-account-update.component.html b/src/main/webapp/app/entities/bank-account/update/bank-account-update.component.html deleted file mode 100644 index b4493fe80..000000000 --- a/src/main/webapp/app/entities/bank-account/update/bank-account-update.component.html +++ /dev/null @@ -1,77 +0,0 @@ -
-
-
-

- Create or edit a Bank Account -

- -
- - -
- - -
- -
- - -
- - This field is required. - -
-
- -
- - -
- - This field is required. - - - This field should be a number. - -
-
- -
- - -
-
- -
- - - -
-
-
-
diff --git a/src/main/webapp/app/entities/bank-account/update/bank-account-update.component.spec.ts b/src/main/webapp/app/entities/bank-account/update/bank-account-update.component.spec.ts deleted file mode 100644 index c456429b4..000000000 --- a/src/main/webapp/app/entities/bank-account/update/bank-account-update.component.spec.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { HttpResponse } from '@angular/common/http'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { FormBuilder } from '@angular/forms'; -import { ActivatedRoute } from '@angular/router'; -import { RouterTestingModule } from '@angular/router/testing'; -import { of, Subject, from } from 'rxjs'; - -import { BankAccountFormService } from './bank-account-form.service'; -import { BankAccountService } from '../service/bank-account.service'; -import { IBankAccount } from '../bank-account.model'; - -import { IUser } from 'app/entities/user/user.model'; -import { UserService } from 'app/entities/user/user.service'; - -import { BankAccountUpdateComponent } from './bank-account-update.component'; - -describe('BankAccount Management Update Component', () => { - let comp: BankAccountUpdateComponent; - let fixture: ComponentFixture; - let activatedRoute: ActivatedRoute; - let bankAccountFormService: BankAccountFormService; - let bankAccountService: BankAccountService; - let userService: UserService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, RouterTestingModule.withRoutes([]), BankAccountUpdateComponent], - providers: [ - FormBuilder, - { - provide: ActivatedRoute, - useValue: { - params: from([{}]), - }, - }, - ], - }) - .overrideTemplate(BankAccountUpdateComponent, '') - .compileComponents(); - - fixture = TestBed.createComponent(BankAccountUpdateComponent); - activatedRoute = TestBed.inject(ActivatedRoute); - bankAccountFormService = TestBed.inject(BankAccountFormService); - bankAccountService = TestBed.inject(BankAccountService); - userService = TestBed.inject(UserService); - - comp = fixture.componentInstance; - }); - - describe('ngOnInit', () => { - it('Should call User query and add missing value', () => { - const bankAccount: IBankAccount = { id: 456 }; - const user: IUser = { id: 3995 }; - bankAccount.user = user; - - const userCollection: IUser[] = [{ id: 28177 }]; - jest.spyOn(userService, 'query').mockReturnValue(of(new HttpResponse({ body: userCollection }))); - const additionalUsers = [user]; - const expectedCollection: IUser[] = [...additionalUsers, ...userCollection]; - jest.spyOn(userService, 'addUserToCollectionIfMissing').mockReturnValue(expectedCollection); - - activatedRoute.data = of({ bankAccount }); - comp.ngOnInit(); - - expect(userService.query).toHaveBeenCalled(); - expect(userService.addUserToCollectionIfMissing).toHaveBeenCalledWith( - userCollection, - ...additionalUsers.map(expect.objectContaining) - ); - expect(comp.usersSharedCollection).toEqual(expectedCollection); - }); - - it('Should update editForm', () => { - const bankAccount: IBankAccount = { id: 456 }; - const user: IUser = { id: 7253 }; - bankAccount.user = user; - - activatedRoute.data = of({ bankAccount }); - comp.ngOnInit(); - - expect(comp.usersSharedCollection).toContain(user); - expect(comp.bankAccount).toEqual(bankAccount); - }); - }); - - describe('save', () => { - it('Should call update service on save for existing entity', () => { - // GIVEN - const saveSubject = new Subject>(); - const bankAccount = { id: 123 }; - jest.spyOn(bankAccountFormService, 'getBankAccount').mockReturnValue(bankAccount); - jest.spyOn(bankAccountService, 'update').mockReturnValue(saveSubject); - jest.spyOn(comp, 'previousState'); - activatedRoute.data = of({ bankAccount }); - comp.ngOnInit(); - - // WHEN - comp.save(); - expect(comp.isSaving).toEqual(true); - saveSubject.next(new HttpResponse({ body: bankAccount })); - saveSubject.complete(); - - // THEN - expect(bankAccountFormService.getBankAccount).toHaveBeenCalled(); - expect(comp.previousState).toHaveBeenCalled(); - expect(bankAccountService.update).toHaveBeenCalledWith(expect.objectContaining(bankAccount)); - expect(comp.isSaving).toEqual(false); - }); - - it('Should call create service on save for new entity', () => { - // GIVEN - const saveSubject = new Subject>(); - const bankAccount = { id: 123 }; - jest.spyOn(bankAccountFormService, 'getBankAccount').mockReturnValue({ id: null }); - jest.spyOn(bankAccountService, 'create').mockReturnValue(saveSubject); - jest.spyOn(comp, 'previousState'); - activatedRoute.data = of({ bankAccount: null }); - comp.ngOnInit(); - - // WHEN - comp.save(); - expect(comp.isSaving).toEqual(true); - saveSubject.next(new HttpResponse({ body: bankAccount })); - saveSubject.complete(); - - // THEN - expect(bankAccountFormService.getBankAccount).toHaveBeenCalled(); - expect(bankAccountService.create).toHaveBeenCalled(); - expect(comp.isSaving).toEqual(false); - expect(comp.previousState).toHaveBeenCalled(); - }); - - it('Should set isSaving to false on error', () => { - // GIVEN - const saveSubject = new Subject>(); - const bankAccount = { id: 123 }; - jest.spyOn(bankAccountService, 'update').mockReturnValue(saveSubject); - jest.spyOn(comp, 'previousState'); - activatedRoute.data = of({ bankAccount }); - comp.ngOnInit(); - - // WHEN - comp.save(); - expect(comp.isSaving).toEqual(true); - saveSubject.error('This is an error!'); - - // THEN - expect(bankAccountService.update).toHaveBeenCalled(); - expect(comp.isSaving).toEqual(false); - expect(comp.previousState).not.toHaveBeenCalled(); - }); - }); - - describe('Compare relationships', () => { - describe('compareUser', () => { - it('Should forward to userService', () => { - const entity = { id: 123 }; - const entity2 = { id: 456 }; - jest.spyOn(userService, 'compareUser'); - comp.compareUser(entity, entity2); - expect(userService.compareUser).toHaveBeenCalledWith(entity, entity2); - }); - }); - }); -}); diff --git a/src/main/webapp/app/entities/bank-account/update/bank-account-update.component.ts b/src/main/webapp/app/entities/bank-account/update/bank-account-update.component.ts deleted file mode 100644 index bb684a05e..000000000 --- a/src/main/webapp/app/entities/bank-account/update/bank-account-update.component.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { HttpResponse } from '@angular/common/http'; -import { ActivatedRoute } from '@angular/router'; -import { Observable } from 'rxjs'; -import { finalize, map } from 'rxjs/operators'; - -import SharedModule from 'app/shared/shared.module'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; - -import { BankAccountFormService, BankAccountFormGroup } from './bank-account-form.service'; -import { IBankAccount } from '../bank-account.model'; -import { BankAccountService } from '../service/bank-account.service'; -import { IUser } from 'app/entities/user/user.model'; -import { UserService } from 'app/entities/user/user.service'; - -@Component({ - standalone: true, - selector: 'jhi-bank-account-update', - templateUrl: './bank-account-update.component.html', - imports: [SharedModule, FormsModule, ReactiveFormsModule], -}) -export class BankAccountUpdateComponent implements OnInit { - isSaving = false; - bankAccount: IBankAccount | null = null; - - usersSharedCollection: IUser[] = []; - - editForm: BankAccountFormGroup = this.bankAccountFormService.createBankAccountFormGroup(); - - constructor( - protected bankAccountService: BankAccountService, - protected bankAccountFormService: BankAccountFormService, - protected userService: UserService, - protected activatedRoute: ActivatedRoute - ) {} - - compareUser = (o1: IUser | null, o2: IUser | null): boolean => this.userService.compareUser(o1, o2); - - ngOnInit(): void { - this.activatedRoute.data.subscribe(({ bankAccount }) => { - this.bankAccount = bankAccount; - if (bankAccount) { - this.updateForm(bankAccount); - } - - this.loadRelationshipsOptions(); - }); - } - - previousState(): void { - window.history.back(); - } - - save(): void { - this.isSaving = true; - const bankAccount = this.bankAccountFormService.getBankAccount(this.editForm); - if (bankAccount.id !== null) { - this.subscribeToSaveResponse(this.bankAccountService.update(bankAccount)); - } else { - this.subscribeToSaveResponse(this.bankAccountService.create(bankAccount)); - } - } - - protected subscribeToSaveResponse(result: Observable>): void { - result.pipe(finalize(() => this.onSaveFinalize())).subscribe({ - next: () => this.onSaveSuccess(), - error: () => this.onSaveError(), - }); - } - - protected onSaveSuccess(): void { - this.previousState(); - } - - protected onSaveError(): void { - // Api for inheritance. - } - - protected onSaveFinalize(): void { - this.isSaving = false; - } - - protected updateForm(bankAccount: IBankAccount): void { - this.bankAccount = bankAccount; - this.bankAccountFormService.resetForm(this.editForm, bankAccount); - - this.usersSharedCollection = this.userService.addUserToCollectionIfMissing(this.usersSharedCollection, bankAccount.user); - } - - protected loadRelationshipsOptions(): void { - this.userService - .query() - .pipe(map((res: HttpResponse) => res.body ?? [])) - .pipe(map((users: IUser[]) => this.userService.addUserToCollectionIfMissing(users, this.bankAccount?.user))) - .subscribe((users: IUser[]) => (this.usersSharedCollection = users)); - } -} diff --git a/src/main/webapp/app/entities/entity-navbar-items.ts b/src/main/webapp/app/entities/entity-navbar-items.ts deleted file mode 100644 index 7308848db..000000000 --- a/src/main/webapp/app/entities/entity-navbar-items.ts +++ /dev/null @@ -1,19 +0,0 @@ -import NavbarItem from 'app/layouts/navbar/navbar-item.model'; - -export const EntityNavbarItems: NavbarItem[] = [ - { - name: 'BankAccount', - route: '/bank-account', - translationKey: 'global.menu.entities.bankAccount', - }, - { - name: 'Label', - route: '/label', - translationKey: 'global.menu.entities.label', - }, - { - name: 'Operation', - route: '/operation', - translationKey: 'global.menu.entities.operation', - }, -]; diff --git a/src/main/webapp/app/entities/entity-routing.module.ts b/src/main/webapp/app/entities/entity-routing.module.ts deleted file mode 100644 index 386cea95f..000000000 --- a/src/main/webapp/app/entities/entity-routing.module.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; - -@NgModule({ - imports: [ - RouterModule.forChild([ - { - path: 'bank-account', - data: { pageTitle: 'jhipsterSampleApplicationApp.bankAccount.home.title' }, - loadChildren: () => import('./bank-account/bank-account.routes'), - }, - { - path: 'label', - data: { pageTitle: 'jhipsterSampleApplicationApp.label.home.title' }, - loadChildren: () => import('./label/label.routes'), - }, - { - path: 'operation', - data: { pageTitle: 'jhipsterSampleApplicationApp.operation.home.title' }, - loadChildren: () => import('./operation/operation.routes'), - }, - /* jhipster-needle-add-entity-route - JHipster will add entity modules routes here */ - ]), - ], -}) -export class EntityRoutingModule {} diff --git a/src/main/webapp/app/entities/label/delete/label-delete-dialog.component.html b/src/main/webapp/app/entities/label/delete/label-delete-dialog.component.html deleted file mode 100644 index 5cebedaf1..000000000 --- a/src/main/webapp/app/entities/label/delete/label-delete-dialog.component.html +++ /dev/null @@ -1,24 +0,0 @@ -
- - - - - -
diff --git a/src/main/webapp/app/entities/label/delete/label-delete-dialog.component.spec.ts b/src/main/webapp/app/entities/label/delete/label-delete-dialog.component.spec.ts deleted file mode 100644 index 1578aaf80..000000000 --- a/src/main/webapp/app/entities/label/delete/label-delete-dialog.component.spec.ts +++ /dev/null @@ -1,62 +0,0 @@ -jest.mock('@ng-bootstrap/ng-bootstrap'); - -import { ComponentFixture, TestBed, inject, fakeAsync, tick } from '@angular/core/testing'; -import { HttpResponse } from '@angular/common/http'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { of } from 'rxjs'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; - -import { LabelService } from '../service/label.service'; - -import { LabelDeleteDialogComponent } from './label-delete-dialog.component'; - -describe('Label Management Delete Component', () => { - let comp: LabelDeleteDialogComponent; - let fixture: ComponentFixture; - let service: LabelService; - let mockActiveModal: NgbActiveModal; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, LabelDeleteDialogComponent], - providers: [NgbActiveModal], - }) - .overrideTemplate(LabelDeleteDialogComponent, '') - .compileComponents(); - fixture = TestBed.createComponent(LabelDeleteDialogComponent); - comp = fixture.componentInstance; - service = TestBed.inject(LabelService); - mockActiveModal = TestBed.inject(NgbActiveModal); - }); - - describe('confirmDelete', () => { - it('Should call delete service on confirmDelete', inject( - [], - fakeAsync(() => { - // GIVEN - jest.spyOn(service, 'delete').mockReturnValue(of(new HttpResponse({ body: {} }))); - - // WHEN - comp.confirmDelete(123); - tick(); - - // THEN - expect(service.delete).toHaveBeenCalledWith(123); - expect(mockActiveModal.close).toHaveBeenCalledWith('deleted'); - }) - )); - - it('Should not call delete service on clear', () => { - // GIVEN - jest.spyOn(service, 'delete'); - - // WHEN - comp.cancel(); - - // THEN - expect(service.delete).not.toHaveBeenCalled(); - expect(mockActiveModal.close).not.toHaveBeenCalled(); - expect(mockActiveModal.dismiss).toHaveBeenCalled(); - }); - }); -}); diff --git a/src/main/webapp/app/entities/label/delete/label-delete-dialog.component.ts b/src/main/webapp/app/entities/label/delete/label-delete-dialog.component.ts deleted file mode 100644 index 5c4e55525..000000000 --- a/src/main/webapp/app/entities/label/delete/label-delete-dialog.component.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Component } from '@angular/core'; -import { FormsModule } from '@angular/forms'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; - -import SharedModule from 'app/shared/shared.module'; -import { ILabel } from '../label.model'; -import { LabelService } from '../service/label.service'; -import { ITEM_DELETED_EVENT } from 'app/config/navigation.constants'; - -@Component({ - standalone: true, - templateUrl: './label-delete-dialog.component.html', - imports: [SharedModule, FormsModule], -}) -export class LabelDeleteDialogComponent { - label?: ILabel; - - constructor(protected labelService: LabelService, protected activeModal: NgbActiveModal) {} - - cancel(): void { - this.activeModal.dismiss(); - } - - confirmDelete(id: number): void { - this.labelService.delete(id).subscribe(() => { - this.activeModal.close(ITEM_DELETED_EVENT); - }); - } -} diff --git a/src/main/webapp/app/entities/label/detail/label-detail.component.html b/src/main/webapp/app/entities/label/detail/label-detail.component.html deleted file mode 100644 index 09d132da2..000000000 --- a/src/main/webapp/app/entities/label/detail/label-detail.component.html +++ /dev/null @@ -1,32 +0,0 @@ -
-
-
-

Label

- -
- - - - - -
-
ID
-
- {{ label.id }} -
-
Label
-
- {{ label.label }} -
-
- - - - -
-
-
diff --git a/src/main/webapp/app/entities/label/detail/label-detail.component.spec.ts b/src/main/webapp/app/entities/label/detail/label-detail.component.spec.ts deleted file mode 100644 index e5da36af2..000000000 --- a/src/main/webapp/app/entities/label/detail/label-detail.component.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { provideRouter, withComponentInputBinding } from '@angular/router'; -import { RouterTestingHarness, RouterTestingModule } from '@angular/router/testing'; -import { of } from 'rxjs'; - -import { LabelDetailComponent } from './label-detail.component'; - -describe('Label Management Detail Component', () => { - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [LabelDetailComponent, RouterTestingModule.withRoutes([], { bindToComponentInputs: true })], - providers: [ - provideRouter( - [ - { - path: '**', - component: LabelDetailComponent, - resolve: { label: () => of({ id: 123 }) }, - }, - ], - withComponentInputBinding() - ), - ], - }) - .overrideTemplate(LabelDetailComponent, '') - .compileComponents(); - }); - - describe('OnInit', () => { - it('Should load label on init', async () => { - const harness = await RouterTestingHarness.create(); - const instance = await harness.navigateByUrl('/', LabelDetailComponent); - - // THEN - expect(instance.label).toEqual(expect.objectContaining({ id: 123 })); - }); - }); -}); diff --git a/src/main/webapp/app/entities/label/detail/label-detail.component.ts b/src/main/webapp/app/entities/label/detail/label-detail.component.ts deleted file mode 100644 index 26c7a6301..000000000 --- a/src/main/webapp/app/entities/label/detail/label-detail.component.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { ActivatedRoute, RouterModule } from '@angular/router'; - -import SharedModule from 'app/shared/shared.module'; -import { DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe } from 'app/shared/date'; -import { ILabel } from '../label.model'; - -@Component({ - standalone: true, - selector: 'jhi-label-detail', - templateUrl: './label-detail.component.html', - imports: [SharedModule, RouterModule, DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe], -}) -export class LabelDetailComponent { - @Input() label: ILabel | null = null; - - constructor(protected activatedRoute: ActivatedRoute) {} - - previousState(): void { - window.history.back(); - } -} diff --git a/src/main/webapp/app/entities/label/label.model.ts b/src/main/webapp/app/entities/label/label.model.ts deleted file mode 100644 index 54468d7de..000000000 --- a/src/main/webapp/app/entities/label/label.model.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { IOperation } from 'app/entities/operation/operation.model'; - -export interface ILabel { - id: number; - label?: string | null; - operations?: Pick[] | null; -} - -export type NewLabel = Omit & { id: null }; diff --git a/src/main/webapp/app/entities/label/label.routes.ts b/src/main/webapp/app/entities/label/label.routes.ts deleted file mode 100644 index d8b4681fa..000000000 --- a/src/main/webapp/app/entities/label/label.routes.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Routes } from '@angular/router'; - -import { UserRouteAccessService } from 'app/core/auth/user-route-access.service'; -import { LabelComponent } from './list/label.component'; -import { LabelDetailComponent } from './detail/label-detail.component'; -import { LabelUpdateComponent } from './update/label-update.component'; -import LabelResolve from './route/label-routing-resolve.service'; -import { ASC } from 'app/config/navigation.constants'; - -const labelRoute: Routes = [ - { - path: '', - component: LabelComponent, - data: { - defaultSort: 'id,' + ASC, - }, - canActivate: [UserRouteAccessService], - }, - { - path: ':id/view', - component: LabelDetailComponent, - resolve: { - label: LabelResolve, - }, - canActivate: [UserRouteAccessService], - }, - { - path: 'new', - component: LabelUpdateComponent, - resolve: { - label: LabelResolve, - }, - canActivate: [UserRouteAccessService], - }, - { - path: ':id/edit', - component: LabelUpdateComponent, - resolve: { - label: LabelResolve, - }, - canActivate: [UserRouteAccessService], - }, -]; - -export default labelRoute; diff --git a/src/main/webapp/app/entities/label/label.test-samples.ts b/src/main/webapp/app/entities/label/label.test-samples.ts deleted file mode 100644 index a86ee88a7..000000000 --- a/src/main/webapp/app/entities/label/label.test-samples.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { ILabel, NewLabel } from './label.model'; - -export const sampleWithRequiredData: ILabel = { - id: 3315, - label: 'Designer', -}; - -export const sampleWithPartialData: ILabel = { - id: 28734, - label: 'Tools purple Lead', -}; - -export const sampleWithFullData: ILabel = { - id: 12754, - label: 'Bicycle', -}; - -export const sampleWithNewData: NewLabel = { - label: 'magenta Progressive', - id: null, -}; - -Object.freeze(sampleWithNewData); -Object.freeze(sampleWithRequiredData); -Object.freeze(sampleWithPartialData); -Object.freeze(sampleWithFullData); diff --git a/src/main/webapp/app/entities/label/list/label.component.html b/src/main/webapp/app/entities/label/list/label.component.html deleted file mode 100644 index d0b98967b..000000000 --- a/src/main/webapp/app/entities/label/list/label.component.html +++ /dev/null @@ -1,78 +0,0 @@ -
-

- Labels - -
- - - -
-

- - - - - -
- No Labels found -
- -
- - - - - - - - - - - - - - - -
-
- ID - -
-
-
- Label - -
-
- {{ label.id }} - {{ label.label }} -
- - - - - -
-
-
-
diff --git a/src/main/webapp/app/entities/label/list/label.component.spec.ts b/src/main/webapp/app/entities/label/list/label.component.spec.ts deleted file mode 100644 index 4279652ed..000000000 --- a/src/main/webapp/app/entities/label/list/label.component.spec.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { HttpHeaders, HttpResponse } from '@angular/common/http'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { ActivatedRoute } from '@angular/router'; -import { RouterTestingModule } from '@angular/router/testing'; -import { of } from 'rxjs'; - -import { LabelService } from '../service/label.service'; - -import { LabelComponent } from './label.component'; - -describe('Label Management Component', () => { - let comp: LabelComponent; - let fixture: ComponentFixture; - let service: LabelService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [RouterTestingModule.withRoutes([{ path: 'label', component: LabelComponent }]), HttpClientTestingModule, LabelComponent], - providers: [ - { - provide: ActivatedRoute, - useValue: { - data: of({ - defaultSort: 'id,asc', - }), - queryParamMap: of( - jest.requireActual('@angular/router').convertToParamMap({ - page: '1', - size: '1', - sort: 'id,desc', - }) - ), - snapshot: { queryParams: {} }, - }, - }, - ], - }) - .overrideTemplate(LabelComponent, '') - .compileComponents(); - - fixture = TestBed.createComponent(LabelComponent); - comp = fixture.componentInstance; - service = TestBed.inject(LabelService); - - const headers = new HttpHeaders(); - jest.spyOn(service, 'query').mockReturnValue( - of( - new HttpResponse({ - body: [{ id: 123 }], - headers, - }) - ) - ); - }); - - it('Should call load all on init', () => { - // WHEN - comp.ngOnInit(); - - // THEN - expect(service.query).toHaveBeenCalled(); - expect(comp.labels?.[0]).toEqual(expect.objectContaining({ id: 123 })); - }); - - describe('trackId', () => { - it('Should forward to labelService', () => { - const entity = { id: 123 }; - jest.spyOn(service, 'getLabelIdentifier'); - const id = comp.trackId(0, entity); - expect(service.getLabelIdentifier).toHaveBeenCalledWith(entity); - expect(id).toBe(entity.id); - }); - }); -}); diff --git a/src/main/webapp/app/entities/label/list/label.component.ts b/src/main/webapp/app/entities/label/list/label.component.ts deleted file mode 100644 index f8b5b4ade..000000000 --- a/src/main/webapp/app/entities/label/list/label.component.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute, Data, ParamMap, Router, RouterModule } from '@angular/router'; -import { combineLatest, filter, Observable, switchMap, tap } from 'rxjs'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; - -import SharedModule from 'app/shared/shared.module'; -import { SortDirective, SortByDirective } from 'app/shared/sort'; -import { DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe } from 'app/shared/date'; -import { FormsModule } from '@angular/forms'; -import { ILabel } from '../label.model'; -import { ASC, DESC, SORT, ITEM_DELETED_EVENT, DEFAULT_SORT_DATA } from 'app/config/navigation.constants'; -import { EntityArrayResponseType, LabelService } from '../service/label.service'; -import { LabelDeleteDialogComponent } from '../delete/label-delete-dialog.component'; -import { SortService } from 'app/shared/sort/sort.service'; - -@Component({ - standalone: true, - selector: 'jhi-label', - templateUrl: './label.component.html', - imports: [ - RouterModule, - FormsModule, - SharedModule, - SortDirective, - SortByDirective, - DurationPipe, - FormatMediumDatetimePipe, - FormatMediumDatePipe, - ], -}) -export class LabelComponent implements OnInit { - labels?: ILabel[]; - isLoading = false; - - predicate = 'id'; - ascending = true; - - constructor( - protected labelService: LabelService, - protected activatedRoute: ActivatedRoute, - public router: Router, - protected sortService: SortService, - protected modalService: NgbModal - ) {} - - trackId = (_index: number, item: ILabel): number => this.labelService.getLabelIdentifier(item); - - ngOnInit(): void { - this.load(); - } - - delete(label: ILabel): void { - const modalRef = this.modalService.open(LabelDeleteDialogComponent, { size: 'lg', backdrop: 'static' }); - modalRef.componentInstance.label = label; - // unsubscribe not needed because closed completes on modal close - modalRef.closed - .pipe( - filter(reason => reason === ITEM_DELETED_EVENT), - switchMap(() => this.loadFromBackendWithRouteInformations()) - ) - .subscribe({ - next: (res: EntityArrayResponseType) => { - this.onResponseSuccess(res); - }, - }); - } - - load(): void { - this.loadFromBackendWithRouteInformations().subscribe({ - next: (res: EntityArrayResponseType) => { - this.onResponseSuccess(res); - }, - }); - } - - navigateToWithComponentValues(): void { - this.handleNavigation(this.predicate, this.ascending); - } - - protected loadFromBackendWithRouteInformations(): Observable { - return combineLatest([this.activatedRoute.queryParamMap, this.activatedRoute.data]).pipe( - tap(([params, data]) => this.fillComponentAttributeFromRoute(params, data)), - switchMap(() => this.queryBackend(this.predicate, this.ascending)) - ); - } - - protected fillComponentAttributeFromRoute(params: ParamMap, data: Data): void { - const sort = (params.get(SORT) ?? data[DEFAULT_SORT_DATA]).split(','); - this.predicate = sort[0]; - this.ascending = sort[1] === ASC; - } - - protected onResponseSuccess(response: EntityArrayResponseType): void { - const dataFromBody = this.fillComponentAttributesFromResponseBody(response.body); - this.labels = this.refineData(dataFromBody); - } - - protected refineData(data: ILabel[]): ILabel[] { - return data.sort(this.sortService.startSort(this.predicate, this.ascending ? 1 : -1)); - } - - protected fillComponentAttributesFromResponseBody(data: ILabel[] | null): ILabel[] { - return data ?? []; - } - - protected queryBackend(predicate?: string, ascending?: boolean): Observable { - this.isLoading = true; - const queryObject: any = { - sort: this.getSortQueryParam(predicate, ascending), - }; - return this.labelService.query(queryObject).pipe(tap(() => (this.isLoading = false))); - } - - protected handleNavigation(predicate?: string, ascending?: boolean): void { - const queryParamsObj = { - sort: this.getSortQueryParam(predicate, ascending), - }; - - this.router.navigate(['./'], { - relativeTo: this.activatedRoute, - queryParams: queryParamsObj, - }); - } - - protected getSortQueryParam(predicate = this.predicate, ascending = this.ascending): string[] { - const ascendingQueryParam = ascending ? ASC : DESC; - if (predicate === '') { - return []; - } else { - return [predicate + ',' + ascendingQueryParam]; - } - } -} diff --git a/src/main/webapp/app/entities/label/route/label-routing-resolve.service.spec.ts b/src/main/webapp/app/entities/label/route/label-routing-resolve.service.spec.ts deleted file mode 100644 index 1ec5c5622..000000000 --- a/src/main/webapp/app/entities/label/route/label-routing-resolve.service.spec.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { HttpResponse } from '@angular/common/http'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { ActivatedRouteSnapshot, ActivatedRoute, Router, convertToParamMap, RouterStateSnapshot } from '@angular/router'; -import { RouterTestingModule } from '@angular/router/testing'; -import { of } from 'rxjs'; - -import { ILabel } from '../label.model'; -import { LabelService } from '../service/label.service'; - -import labelResolve from './label-routing-resolve.service'; - -describe('Label routing resolve service', () => { - let mockRouter: Router; - let mockActivatedRouteSnapshot: ActivatedRouteSnapshot; - let service: LabelService; - let resultLabel: ILabel | null | undefined; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, RouterTestingModule.withRoutes([])], - providers: [ - { - provide: ActivatedRoute, - useValue: { - snapshot: { - paramMap: convertToParamMap({}), - }, - }, - }, - ], - }); - mockRouter = TestBed.inject(Router); - jest.spyOn(mockRouter, 'navigate').mockImplementation(() => Promise.resolve(true)); - mockActivatedRouteSnapshot = TestBed.inject(ActivatedRoute).snapshot; - service = TestBed.inject(LabelService); - resultLabel = undefined; - }); - - describe('resolve', () => { - it('should return ILabel returned by find', () => { - // GIVEN - service.find = jest.fn(id => of(new HttpResponse({ body: { id } }))); - mockActivatedRouteSnapshot.params = { id: 123 }; - - // WHEN - TestBed.runInInjectionContext(() => { - labelResolve(mockActivatedRouteSnapshot).subscribe({ - next(result) { - resultLabel = result; - }, - }); - }); - - // THEN - expect(service.find).toBeCalledWith(123); - expect(resultLabel).toEqual({ id: 123 }); - }); - - it('should return null if id is not provided', () => { - // GIVEN - service.find = jest.fn(); - mockActivatedRouteSnapshot.params = {}; - - // WHEN - TestBed.runInInjectionContext(() => { - labelResolve(mockActivatedRouteSnapshot).subscribe({ - next(result) { - resultLabel = result; - }, - }); - }); - - // THEN - expect(service.find).not.toBeCalled(); - expect(resultLabel).toEqual(null); - }); - - it('should route to 404 page if data not found in server', () => { - // GIVEN - jest.spyOn(service, 'find').mockReturnValue(of(new HttpResponse({ body: null }))); - mockActivatedRouteSnapshot.params = { id: 123 }; - - // WHEN - TestBed.runInInjectionContext(() => { - labelResolve(mockActivatedRouteSnapshot).subscribe({ - next(result) { - resultLabel = result; - }, - }); - }); - - // THEN - expect(service.find).toBeCalledWith(123); - expect(resultLabel).toEqual(undefined); - expect(mockRouter.navigate).toHaveBeenCalledWith(['404']); - }); - }); -}); diff --git a/src/main/webapp/app/entities/label/route/label-routing-resolve.service.ts b/src/main/webapp/app/entities/label/route/label-routing-resolve.service.ts deleted file mode 100644 index 38ff4f928..000000000 --- a/src/main/webapp/app/entities/label/route/label-routing-resolve.service.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { inject } from '@angular/core'; -import { HttpResponse } from '@angular/common/http'; -import { ActivatedRouteSnapshot, Router } from '@angular/router'; -import { of, EMPTY, Observable } from 'rxjs'; -import { mergeMap } from 'rxjs/operators'; - -import { ILabel } from '../label.model'; -import { LabelService } from '../service/label.service'; - -export const labelResolve = (route: ActivatedRouteSnapshot): Observable => { - const id = route.params['id']; - if (id) { - return inject(LabelService) - .find(id) - .pipe( - mergeMap((label: HttpResponse) => { - if (label.body) { - return of(label.body); - } else { - inject(Router).navigate(['404']); - return EMPTY; - } - }) - ); - } - return of(null); -}; - -export default labelResolve; diff --git a/src/main/webapp/app/entities/label/service/label.service.spec.ts b/src/main/webapp/app/entities/label/service/label.service.spec.ts deleted file mode 100644 index 0251897b4..000000000 --- a/src/main/webapp/app/entities/label/service/label.service.spec.ts +++ /dev/null @@ -1,205 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; - -import { ILabel } from '../label.model'; -import { sampleWithRequiredData, sampleWithNewData, sampleWithPartialData, sampleWithFullData } from '../label.test-samples'; - -import { LabelService } from './label.service'; - -const requireRestSample: ILabel = { - ...sampleWithRequiredData, -}; - -describe('Label Service', () => { - let service: LabelService; - let httpMock: HttpTestingController; - let expectedResult: ILabel | ILabel[] | boolean | null; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - }); - expectedResult = null; - service = TestBed.inject(LabelService); - httpMock = TestBed.inject(HttpTestingController); - }); - - describe('Service methods', () => { - it('should find an element', () => { - const returnedFromService = { ...requireRestSample }; - const expected = { ...sampleWithRequiredData }; - - service.find(123).subscribe(resp => (expectedResult = resp.body)); - - const req = httpMock.expectOne({ method: 'GET' }); - req.flush(returnedFromService); - expect(expectedResult).toMatchObject(expected); - }); - - it('should create a Label', () => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const label = { ...sampleWithNewData }; - const returnedFromService = { ...requireRestSample }; - const expected = { ...sampleWithRequiredData }; - - service.create(label).subscribe(resp => (expectedResult = resp.body)); - - const req = httpMock.expectOne({ method: 'POST' }); - req.flush(returnedFromService); - expect(expectedResult).toMatchObject(expected); - }); - - it('should update a Label', () => { - const label = { ...sampleWithRequiredData }; - const returnedFromService = { ...requireRestSample }; - const expected = { ...sampleWithRequiredData }; - - service.update(label).subscribe(resp => (expectedResult = resp.body)); - - const req = httpMock.expectOne({ method: 'PUT' }); - req.flush(returnedFromService); - expect(expectedResult).toMatchObject(expected); - }); - - it('should partial update a Label', () => { - const patchObject = { ...sampleWithPartialData }; - const returnedFromService = { ...requireRestSample }; - const expected = { ...sampleWithRequiredData }; - - service.partialUpdate(patchObject).subscribe(resp => (expectedResult = resp.body)); - - const req = httpMock.expectOne({ method: 'PATCH' }); - req.flush(returnedFromService); - expect(expectedResult).toMatchObject(expected); - }); - - it('should return a list of Label', () => { - const returnedFromService = { ...requireRestSample }; - - const expected = { ...sampleWithRequiredData }; - - service.query().subscribe(resp => (expectedResult = resp.body)); - - const req = httpMock.expectOne({ method: 'GET' }); - req.flush([returnedFromService]); - httpMock.verify(); - expect(expectedResult).toMatchObject([expected]); - }); - - it('should delete a Label', () => { - const expected = true; - - service.delete(123).subscribe(resp => (expectedResult = resp.ok)); - - const req = httpMock.expectOne({ method: 'DELETE' }); - req.flush({ status: 200 }); - expect(expectedResult).toBe(expected); - }); - - describe('addLabelToCollectionIfMissing', () => { - it('should add a Label to an empty array', () => { - const label: ILabel = sampleWithRequiredData; - expectedResult = service.addLabelToCollectionIfMissing([], label); - expect(expectedResult).toHaveLength(1); - expect(expectedResult).toContain(label); - }); - - it('should not add a Label to an array that contains it', () => { - const label: ILabel = sampleWithRequiredData; - const labelCollection: ILabel[] = [ - { - ...label, - }, - sampleWithPartialData, - ]; - expectedResult = service.addLabelToCollectionIfMissing(labelCollection, label); - expect(expectedResult).toHaveLength(2); - }); - - it("should add a Label to an array that doesn't contain it", () => { - const label: ILabel = sampleWithRequiredData; - const labelCollection: ILabel[] = [sampleWithPartialData]; - expectedResult = service.addLabelToCollectionIfMissing(labelCollection, label); - expect(expectedResult).toHaveLength(2); - expect(expectedResult).toContain(label); - }); - - it('should add only unique Label to an array', () => { - const labelArray: ILabel[] = [sampleWithRequiredData, sampleWithPartialData, sampleWithFullData]; - const labelCollection: ILabel[] = [sampleWithRequiredData]; - expectedResult = service.addLabelToCollectionIfMissing(labelCollection, ...labelArray); - expect(expectedResult).toHaveLength(3); - }); - - it('should accept varargs', () => { - const label: ILabel = sampleWithRequiredData; - const label2: ILabel = sampleWithPartialData; - expectedResult = service.addLabelToCollectionIfMissing([], label, label2); - expect(expectedResult).toHaveLength(2); - expect(expectedResult).toContain(label); - expect(expectedResult).toContain(label2); - }); - - it('should accept null and undefined values', () => { - const label: ILabel = sampleWithRequiredData; - expectedResult = service.addLabelToCollectionIfMissing([], null, label, undefined); - expect(expectedResult).toHaveLength(1); - expect(expectedResult).toContain(label); - }); - - it('should return initial array if no Label is added', () => { - const labelCollection: ILabel[] = [sampleWithRequiredData]; - expectedResult = service.addLabelToCollectionIfMissing(labelCollection, undefined, null); - expect(expectedResult).toEqual(labelCollection); - }); - }); - - describe('compareLabel', () => { - it('Should return true if both entities are null', () => { - const entity1 = null; - const entity2 = null; - - const compareResult = service.compareLabel(entity1, entity2); - - expect(compareResult).toEqual(true); - }); - - it('Should return false if one entity is null', () => { - const entity1 = { id: 123 }; - const entity2 = null; - - const compareResult1 = service.compareLabel(entity1, entity2); - const compareResult2 = service.compareLabel(entity2, entity1); - - expect(compareResult1).toEqual(false); - expect(compareResult2).toEqual(false); - }); - - it('Should return false if primaryKey differs', () => { - const entity1 = { id: 123 }; - const entity2 = { id: 456 }; - - const compareResult1 = service.compareLabel(entity1, entity2); - const compareResult2 = service.compareLabel(entity2, entity1); - - expect(compareResult1).toEqual(false); - expect(compareResult2).toEqual(false); - }); - - it('Should return false if primaryKey matches', () => { - const entity1 = { id: 123 }; - const entity2 = { id: 123 }; - - const compareResult1 = service.compareLabel(entity1, entity2); - const compareResult2 = service.compareLabel(entity2, entity1); - - expect(compareResult1).toEqual(true); - expect(compareResult2).toEqual(true); - }); - }); - }); - - afterEach(() => { - httpMock.verify(); - }); -}); diff --git a/src/main/webapp/app/entities/label/service/label.service.ts b/src/main/webapp/app/entities/label/service/label.service.ts deleted file mode 100644 index 8e8cbf188..000000000 --- a/src/main/webapp/app/entities/label/service/label.service.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient, HttpResponse } from '@angular/common/http'; -import { Observable } from 'rxjs'; - -import { isPresent } from 'app/core/util/operators'; -import { ApplicationConfigService } from 'app/core/config/application-config.service'; -import { createRequestOption } from 'app/core/request/request-util'; -import { ILabel, NewLabel } from '../label.model'; - -export type PartialUpdateLabel = Partial & Pick; - -export type EntityResponseType = HttpResponse; -export type EntityArrayResponseType = HttpResponse; - -@Injectable({ providedIn: 'root' }) -export class LabelService { - protected resourceUrl = this.applicationConfigService.getEndpointFor('api/labels'); - - constructor(protected http: HttpClient, protected applicationConfigService: ApplicationConfigService) {} - - create(label: NewLabel): Observable { - return this.http.post(this.resourceUrl, label, { observe: 'response' }); - } - - update(label: ILabel): Observable { - return this.http.put(`${this.resourceUrl}/${this.getLabelIdentifier(label)}`, label, { observe: 'response' }); - } - - partialUpdate(label: PartialUpdateLabel): Observable { - return this.http.patch(`${this.resourceUrl}/${this.getLabelIdentifier(label)}`, label, { observe: 'response' }); - } - - find(id: number): Observable { - return this.http.get(`${this.resourceUrl}/${id}`, { observe: 'response' }); - } - - query(req?: any): Observable { - const options = createRequestOption(req); - return this.http.get(this.resourceUrl, { params: options, observe: 'response' }); - } - - delete(id: number): Observable> { - return this.http.delete(`${this.resourceUrl}/${id}`, { observe: 'response' }); - } - - getLabelIdentifier(label: Pick): number { - return label.id; - } - - compareLabel(o1: Pick | null, o2: Pick | null): boolean { - return o1 && o2 ? this.getLabelIdentifier(o1) === this.getLabelIdentifier(o2) : o1 === o2; - } - - addLabelToCollectionIfMissing>( - labelCollection: Type[], - ...labelsToCheck: (Type | null | undefined)[] - ): Type[] { - const labels: Type[] = labelsToCheck.filter(isPresent); - if (labels.length > 0) { - const labelCollectionIdentifiers = labelCollection.map(labelItem => this.getLabelIdentifier(labelItem)!); - const labelsToAdd = labels.filter(labelItem => { - const labelIdentifier = this.getLabelIdentifier(labelItem); - if (labelCollectionIdentifiers.includes(labelIdentifier)) { - return false; - } - labelCollectionIdentifiers.push(labelIdentifier); - return true; - }); - return [...labelsToAdd, ...labelCollection]; - } - return labelCollection; - } -} diff --git a/src/main/webapp/app/entities/label/update/label-form.service.spec.ts b/src/main/webapp/app/entities/label/update/label-form.service.spec.ts deleted file mode 100644 index 5406f05f7..000000000 --- a/src/main/webapp/app/entities/label/update/label-form.service.spec.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { sampleWithRequiredData, sampleWithNewData } from '../label.test-samples'; - -import { LabelFormService } from './label-form.service'; - -describe('Label Form Service', () => { - let service: LabelFormService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(LabelFormService); - }); - - describe('Service methods', () => { - describe('createLabelFormGroup', () => { - it('should create a new form with FormControl', () => { - const formGroup = service.createLabelFormGroup(); - - expect(formGroup.controls).toEqual( - expect.objectContaining({ - id: expect.any(Object), - label: expect.any(Object), - operations: expect.any(Object), - }) - ); - }); - - it('passing ILabel should create a new form with FormGroup', () => { - const formGroup = service.createLabelFormGroup(sampleWithRequiredData); - - expect(formGroup.controls).toEqual( - expect.objectContaining({ - id: expect.any(Object), - label: expect.any(Object), - operations: expect.any(Object), - }) - ); - }); - }); - - describe('getLabel', () => { - it('should return NewLabel for default Label initial value', () => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const formGroup = service.createLabelFormGroup(sampleWithNewData); - - const label = service.getLabel(formGroup) as any; - - expect(label).toMatchObject(sampleWithNewData); - }); - - it('should return NewLabel for empty Label initial value', () => { - const formGroup = service.createLabelFormGroup(); - - const label = service.getLabel(formGroup) as any; - - expect(label).toMatchObject({}); - }); - - it('should return ILabel', () => { - const formGroup = service.createLabelFormGroup(sampleWithRequiredData); - - const label = service.getLabel(formGroup) as any; - - expect(label).toMatchObject(sampleWithRequiredData); - }); - }); - - describe('resetForm', () => { - it('passing ILabel should not enable id FormControl', () => { - const formGroup = service.createLabelFormGroup(); - expect(formGroup.controls.id.disabled).toBe(true); - - service.resetForm(formGroup, sampleWithRequiredData); - - expect(formGroup.controls.id.disabled).toBe(true); - }); - - it('passing NewLabel should disable id FormControl', () => { - const formGroup = service.createLabelFormGroup(sampleWithRequiredData); - expect(formGroup.controls.id.disabled).toBe(true); - - service.resetForm(formGroup, { id: null }); - - expect(formGroup.controls.id.disabled).toBe(true); - }); - }); - }); -}); diff --git a/src/main/webapp/app/entities/label/update/label-form.service.ts b/src/main/webapp/app/entities/label/update/label-form.service.ts deleted file mode 100644 index db06d5f76..000000000 --- a/src/main/webapp/app/entities/label/update/label-form.service.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Injectable } from '@angular/core'; -import { FormGroup, FormControl, Validators } from '@angular/forms'; - -import { ILabel, NewLabel } from '../label.model'; - -/** - * A partial Type with required key is used as form input. - */ -type PartialWithRequiredKeyOf = Partial> & { id: T['id'] }; - -/** - * Type for createFormGroup and resetForm argument. - * It accepts ILabel for edit and NewLabelFormGroupInput for create. - */ -type LabelFormGroupInput = ILabel | PartialWithRequiredKeyOf; - -type LabelFormDefaults = Pick; - -type LabelFormGroupContent = { - id: FormControl; - label: FormControl; - operations: FormControl; -}; - -export type LabelFormGroup = FormGroup; - -@Injectable({ providedIn: 'root' }) -export class LabelFormService { - createLabelFormGroup(label: LabelFormGroupInput = { id: null }): LabelFormGroup { - const labelRawValue = { - ...this.getFormDefaults(), - ...label, - }; - return new FormGroup({ - id: new FormControl( - { value: labelRawValue.id, disabled: true }, - { - nonNullable: true, - validators: [Validators.required], - } - ), - label: new FormControl(labelRawValue.label, { - validators: [Validators.required, Validators.minLength(3)], - }), - operations: new FormControl(labelRawValue.operations ?? []), - }); - } - - getLabel(form: LabelFormGroup): ILabel | NewLabel { - return form.getRawValue() as ILabel | NewLabel; - } - - resetForm(form: LabelFormGroup, label: LabelFormGroupInput): void { - const labelRawValue = { ...this.getFormDefaults(), ...label }; - form.reset( - { - ...labelRawValue, - id: { value: labelRawValue.id, disabled: true }, - } as any /* cast to workaround https://github.com/angular/angular/issues/46458 */ - ); - } - - private getFormDefaults(): LabelFormDefaults { - return { - id: null, - operations: [], - }; - } -} diff --git a/src/main/webapp/app/entities/label/update/label-update.component.html b/src/main/webapp/app/entities/label/update/label-update.component.html deleted file mode 100644 index 7d5b08f51..000000000 --- a/src/main/webapp/app/entities/label/update/label-update.component.html +++ /dev/null @@ -1,56 +0,0 @@ -
-
-
-

- Create or edit a Label -

- -
- - -
- - -
- -
- - -
- - This field is required. - - - This field is required to be at least 3 characters. - -
-
-
- -
- - - -
-
-
-
diff --git a/src/main/webapp/app/entities/label/update/label-update.component.spec.ts b/src/main/webapp/app/entities/label/update/label-update.component.spec.ts deleted file mode 100644 index 4a0314d58..000000000 --- a/src/main/webapp/app/entities/label/update/label-update.component.spec.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { HttpResponse } from '@angular/common/http'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { FormBuilder } from '@angular/forms'; -import { ActivatedRoute } from '@angular/router'; -import { RouterTestingModule } from '@angular/router/testing'; -import { of, Subject, from } from 'rxjs'; - -import { LabelFormService } from './label-form.service'; -import { LabelService } from '../service/label.service'; -import { ILabel } from '../label.model'; - -import { LabelUpdateComponent } from './label-update.component'; - -describe('Label Management Update Component', () => { - let comp: LabelUpdateComponent; - let fixture: ComponentFixture; - let activatedRoute: ActivatedRoute; - let labelFormService: LabelFormService; - let labelService: LabelService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, RouterTestingModule.withRoutes([]), LabelUpdateComponent], - providers: [ - FormBuilder, - { - provide: ActivatedRoute, - useValue: { - params: from([{}]), - }, - }, - ], - }) - .overrideTemplate(LabelUpdateComponent, '') - .compileComponents(); - - fixture = TestBed.createComponent(LabelUpdateComponent); - activatedRoute = TestBed.inject(ActivatedRoute); - labelFormService = TestBed.inject(LabelFormService); - labelService = TestBed.inject(LabelService); - - comp = fixture.componentInstance; - }); - - describe('ngOnInit', () => { - it('Should update editForm', () => { - const label: ILabel = { id: 456 }; - - activatedRoute.data = of({ label }); - comp.ngOnInit(); - - expect(comp.label).toEqual(label); - }); - }); - - describe('save', () => { - it('Should call update service on save for existing entity', () => { - // GIVEN - const saveSubject = new Subject>(); - const label = { id: 123 }; - jest.spyOn(labelFormService, 'getLabel').mockReturnValue(label); - jest.spyOn(labelService, 'update').mockReturnValue(saveSubject); - jest.spyOn(comp, 'previousState'); - activatedRoute.data = of({ label }); - comp.ngOnInit(); - - // WHEN - comp.save(); - expect(comp.isSaving).toEqual(true); - saveSubject.next(new HttpResponse({ body: label })); - saveSubject.complete(); - - // THEN - expect(labelFormService.getLabel).toHaveBeenCalled(); - expect(comp.previousState).toHaveBeenCalled(); - expect(labelService.update).toHaveBeenCalledWith(expect.objectContaining(label)); - expect(comp.isSaving).toEqual(false); - }); - - it('Should call create service on save for new entity', () => { - // GIVEN - const saveSubject = new Subject>(); - const label = { id: 123 }; - jest.spyOn(labelFormService, 'getLabel').mockReturnValue({ id: null }); - jest.spyOn(labelService, 'create').mockReturnValue(saveSubject); - jest.spyOn(comp, 'previousState'); - activatedRoute.data = of({ label: null }); - comp.ngOnInit(); - - // WHEN - comp.save(); - expect(comp.isSaving).toEqual(true); - saveSubject.next(new HttpResponse({ body: label })); - saveSubject.complete(); - - // THEN - expect(labelFormService.getLabel).toHaveBeenCalled(); - expect(labelService.create).toHaveBeenCalled(); - expect(comp.isSaving).toEqual(false); - expect(comp.previousState).toHaveBeenCalled(); - }); - - it('Should set isSaving to false on error', () => { - // GIVEN - const saveSubject = new Subject>(); - const label = { id: 123 }; - jest.spyOn(labelService, 'update').mockReturnValue(saveSubject); - jest.spyOn(comp, 'previousState'); - activatedRoute.data = of({ label }); - comp.ngOnInit(); - - // WHEN - comp.save(); - expect(comp.isSaving).toEqual(true); - saveSubject.error('This is an error!'); - - // THEN - expect(labelService.update).toHaveBeenCalled(); - expect(comp.isSaving).toEqual(false); - expect(comp.previousState).not.toHaveBeenCalled(); - }); - }); -}); diff --git a/src/main/webapp/app/entities/label/update/label-update.component.ts b/src/main/webapp/app/entities/label/update/label-update.component.ts deleted file mode 100644 index 67e6787fe..000000000 --- a/src/main/webapp/app/entities/label/update/label-update.component.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { HttpResponse } from '@angular/common/http'; -import { ActivatedRoute } from '@angular/router'; -import { Observable } from 'rxjs'; -import { finalize } from 'rxjs/operators'; - -import SharedModule from 'app/shared/shared.module'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; - -import { LabelFormService, LabelFormGroup } from './label-form.service'; -import { ILabel } from '../label.model'; -import { LabelService } from '../service/label.service'; - -@Component({ - standalone: true, - selector: 'jhi-label-update', - templateUrl: './label-update.component.html', - imports: [SharedModule, FormsModule, ReactiveFormsModule], -}) -export class LabelUpdateComponent implements OnInit { - isSaving = false; - label: ILabel | null = null; - - editForm: LabelFormGroup = this.labelFormService.createLabelFormGroup(); - - constructor( - protected labelService: LabelService, - protected labelFormService: LabelFormService, - protected activatedRoute: ActivatedRoute - ) {} - - ngOnInit(): void { - this.activatedRoute.data.subscribe(({ label }) => { - this.label = label; - if (label) { - this.updateForm(label); - } - }); - } - - previousState(): void { - window.history.back(); - } - - save(): void { - this.isSaving = true; - const label = this.labelFormService.getLabel(this.editForm); - if (label.id !== null) { - this.subscribeToSaveResponse(this.labelService.update(label)); - } else { - this.subscribeToSaveResponse(this.labelService.create(label)); - } - } - - protected subscribeToSaveResponse(result: Observable>): void { - result.pipe(finalize(() => this.onSaveFinalize())).subscribe({ - next: () => this.onSaveSuccess(), - error: () => this.onSaveError(), - }); - } - - protected onSaveSuccess(): void { - this.previousState(); - } - - protected onSaveError(): void { - // Api for inheritance. - } - - protected onSaveFinalize(): void { - this.isSaving = false; - } - - protected updateForm(label: ILabel): void { - this.label = label; - this.labelFormService.resetForm(this.editForm, label); - } -} diff --git a/src/main/webapp/app/entities/operation/delete/operation-delete-dialog.component.html b/src/main/webapp/app/entities/operation/delete/operation-delete-dialog.component.html deleted file mode 100644 index b16678d3c..000000000 --- a/src/main/webapp/app/entities/operation/delete/operation-delete-dialog.component.html +++ /dev/null @@ -1,28 +0,0 @@ -
- - - - - -
diff --git a/src/main/webapp/app/entities/operation/delete/operation-delete-dialog.component.spec.ts b/src/main/webapp/app/entities/operation/delete/operation-delete-dialog.component.spec.ts deleted file mode 100644 index e4057b7e7..000000000 --- a/src/main/webapp/app/entities/operation/delete/operation-delete-dialog.component.spec.ts +++ /dev/null @@ -1,62 +0,0 @@ -jest.mock('@ng-bootstrap/ng-bootstrap'); - -import { ComponentFixture, TestBed, inject, fakeAsync, tick } from '@angular/core/testing'; -import { HttpResponse } from '@angular/common/http'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { of } from 'rxjs'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; - -import { OperationService } from '../service/operation.service'; - -import { OperationDeleteDialogComponent } from './operation-delete-dialog.component'; - -describe('Operation Management Delete Component', () => { - let comp: OperationDeleteDialogComponent; - let fixture: ComponentFixture; - let service: OperationService; - let mockActiveModal: NgbActiveModal; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, OperationDeleteDialogComponent], - providers: [NgbActiveModal], - }) - .overrideTemplate(OperationDeleteDialogComponent, '') - .compileComponents(); - fixture = TestBed.createComponent(OperationDeleteDialogComponent); - comp = fixture.componentInstance; - service = TestBed.inject(OperationService); - mockActiveModal = TestBed.inject(NgbActiveModal); - }); - - describe('confirmDelete', () => { - it('Should call delete service on confirmDelete', inject( - [], - fakeAsync(() => { - // GIVEN - jest.spyOn(service, 'delete').mockReturnValue(of(new HttpResponse({ body: {} }))); - - // WHEN - comp.confirmDelete(123); - tick(); - - // THEN - expect(service.delete).toHaveBeenCalledWith(123); - expect(mockActiveModal.close).toHaveBeenCalledWith('deleted'); - }) - )); - - it('Should not call delete service on clear', () => { - // GIVEN - jest.spyOn(service, 'delete'); - - // WHEN - comp.cancel(); - - // THEN - expect(service.delete).not.toHaveBeenCalled(); - expect(mockActiveModal.close).not.toHaveBeenCalled(); - expect(mockActiveModal.dismiss).toHaveBeenCalled(); - }); - }); -}); diff --git a/src/main/webapp/app/entities/operation/delete/operation-delete-dialog.component.ts b/src/main/webapp/app/entities/operation/delete/operation-delete-dialog.component.ts deleted file mode 100644 index a254fbeb0..000000000 --- a/src/main/webapp/app/entities/operation/delete/operation-delete-dialog.component.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Component } from '@angular/core'; -import { FormsModule } from '@angular/forms'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; - -import SharedModule from 'app/shared/shared.module'; -import { IOperation } from '../operation.model'; -import { OperationService } from '../service/operation.service'; -import { ITEM_DELETED_EVENT } from 'app/config/navigation.constants'; - -@Component({ - standalone: true, - templateUrl: './operation-delete-dialog.component.html', - imports: [SharedModule, FormsModule], -}) -export class OperationDeleteDialogComponent { - operation?: IOperation; - - constructor(protected operationService: OperationService, protected activeModal: NgbActiveModal) {} - - cancel(): void { - this.activeModal.dismiss(); - } - - confirmDelete(id: number): void { - this.operationService.delete(id).subscribe(() => { - this.activeModal.close(ITEM_DELETED_EVENT); - }); - } -} diff --git a/src/main/webapp/app/entities/operation/detail/operation-detail.component.html b/src/main/webapp/app/entities/operation/detail/operation-detail.component.html deleted file mode 100644 index ef0a36052..000000000 --- a/src/main/webapp/app/entities/operation/detail/operation-detail.component.html +++ /dev/null @@ -1,53 +0,0 @@ -
-
-
-

Operation

- -
- - - - - -
-
ID
-
- {{ operation.id }} -
-
Date
-
- {{ operation.date | formatMediumDatetime }} -
-
Description
-
- {{ operation.description }} -
-
Amount
-
- {{ operation.amount }} -
-
Bank Account
-
- -
-
Label
-
- - {{ label.label }}{{ last ? '' : ', ' }} - -
-
- - - - -
-
-
diff --git a/src/main/webapp/app/entities/operation/detail/operation-detail.component.spec.ts b/src/main/webapp/app/entities/operation/detail/operation-detail.component.spec.ts deleted file mode 100644 index 1dccbb348..000000000 --- a/src/main/webapp/app/entities/operation/detail/operation-detail.component.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { provideRouter, withComponentInputBinding } from '@angular/router'; -import { RouterTestingHarness, RouterTestingModule } from '@angular/router/testing'; -import { of } from 'rxjs'; - -import { OperationDetailComponent } from './operation-detail.component'; - -describe('Operation Management Detail Component', () => { - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [OperationDetailComponent, RouterTestingModule.withRoutes([], { bindToComponentInputs: true })], - providers: [ - provideRouter( - [ - { - path: '**', - component: OperationDetailComponent, - resolve: { operation: () => of({ id: 123 }) }, - }, - ], - withComponentInputBinding() - ), - ], - }) - .overrideTemplate(OperationDetailComponent, '') - .compileComponents(); - }); - - describe('OnInit', () => { - it('Should load operation on init', async () => { - const harness = await RouterTestingHarness.create(); - const instance = await harness.navigateByUrl('/', OperationDetailComponent); - - // THEN - expect(instance.operation).toEqual(expect.objectContaining({ id: 123 })); - }); - }); -}); diff --git a/src/main/webapp/app/entities/operation/detail/operation-detail.component.ts b/src/main/webapp/app/entities/operation/detail/operation-detail.component.ts deleted file mode 100644 index 707f07d9e..000000000 --- a/src/main/webapp/app/entities/operation/detail/operation-detail.component.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { ActivatedRoute, RouterModule } from '@angular/router'; - -import SharedModule from 'app/shared/shared.module'; -import { DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe } from 'app/shared/date'; -import { IOperation } from '../operation.model'; - -@Component({ - standalone: true, - selector: 'jhi-operation-detail', - templateUrl: './operation-detail.component.html', - imports: [SharedModule, RouterModule, DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe], -}) -export class OperationDetailComponent { - @Input() operation: IOperation | null = null; - - constructor(protected activatedRoute: ActivatedRoute) {} - - previousState(): void { - window.history.back(); - } -} diff --git a/src/main/webapp/app/entities/operation/list/operation.component.html b/src/main/webapp/app/entities/operation/list/operation.component.html deleted file mode 100644 index 80f02f13c..000000000 --- a/src/main/webapp/app/entities/operation/list/operation.component.html +++ /dev/null @@ -1,118 +0,0 @@ -
-

- Operations - -
- - - -
-

- - - - - -
- No Operations found -
- -
- - - - - - - - - - - - - - - - - - - - - -
-
- ID - -
-
-
- Date - -
-
-
- Description - -
-
-
- Amount - -
-
-
- Bank Account - -
-
- {{ operation.id }} - {{ operation.date | formatMediumDatetime }}{{ operation.description }}{{ operation.amount }} - - -
- - - - - -
-
-
-
diff --git a/src/main/webapp/app/entities/operation/list/operation.component.spec.ts b/src/main/webapp/app/entities/operation/list/operation.component.spec.ts deleted file mode 100644 index bcc171b05..000000000 --- a/src/main/webapp/app/entities/operation/list/operation.component.spec.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { HttpHeaders, HttpResponse } from '@angular/common/http'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { ActivatedRoute } from '@angular/router'; -import { RouterTestingModule } from '@angular/router/testing'; -import { of } from 'rxjs'; - -import { OperationService } from '../service/operation.service'; - -import { OperationComponent } from './operation.component'; -import SpyInstance = jest.SpyInstance; - -describe('Operation Management Component', () => { - let comp: OperationComponent; - let fixture: ComponentFixture; - let service: OperationService; - let routerNavigateSpy: SpyInstance>; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - RouterTestingModule.withRoutes([{ path: 'operation', component: OperationComponent }]), - HttpClientTestingModule, - OperationComponent, - ], - providers: [ - { - provide: ActivatedRoute, - useValue: { - data: of({ - defaultSort: 'id,asc', - }), - queryParamMap: of( - jest.requireActual('@angular/router').convertToParamMap({ - page: '1', - size: '1', - sort: 'id,desc', - }) - ), - snapshot: { queryParams: {} }, - }, - }, - ], - }) - .overrideTemplate(OperationComponent, '') - .compileComponents(); - - fixture = TestBed.createComponent(OperationComponent); - comp = fixture.componentInstance; - service = TestBed.inject(OperationService); - routerNavigateSpy = jest.spyOn(comp.router, 'navigate'); - - const headers = new HttpHeaders(); - jest.spyOn(service, 'query').mockReturnValue( - of( - new HttpResponse({ - body: [{ id: 123 }], - headers, - }) - ) - ); - }); - - it('Should call load all on init', () => { - // WHEN - comp.ngOnInit(); - - // THEN - expect(service.query).toHaveBeenCalled(); - expect(comp.operations?.[0]).toEqual(expect.objectContaining({ id: 123 })); - }); - - describe('trackId', () => { - it('Should forward to operationService', () => { - const entity = { id: 123 }; - jest.spyOn(service, 'getOperationIdentifier'); - const id = comp.trackId(0, entity); - expect(service.getOperationIdentifier).toHaveBeenCalledWith(entity); - expect(id).toBe(entity.id); - }); - }); - - it('should load a page', () => { - // WHEN - comp.navigateToPage(1); - - // THEN - expect(routerNavigateSpy).toHaveBeenCalled(); - }); - - it('should calculate the sort attribute for an id', () => { - // WHEN - comp.ngOnInit(); - - // THEN - expect(service.query).toHaveBeenLastCalledWith(expect.objectContaining({ sort: ['id,desc'] })); - }); - - it('should calculate the sort attribute for a non-id attribute', () => { - // GIVEN - comp.predicate = 'name'; - - // WHEN - comp.navigateToWithComponentValues(); - - // THEN - expect(routerNavigateSpy).toHaveBeenLastCalledWith( - expect.anything(), - expect.objectContaining({ - queryParams: expect.objectContaining({ - sort: ['name,asc'], - }), - }) - ); - }); - - it('should re-initialize the page', () => { - // WHEN - comp.loadPage(1); - comp.reset(); - - // THEN - expect(comp.page).toEqual(1); - expect(service.query).toHaveBeenCalledTimes(2); - expect(comp.operations?.[0]).toEqual(expect.objectContaining({ id: 123 })); - }); -}); diff --git a/src/main/webapp/app/entities/operation/list/operation.component.ts b/src/main/webapp/app/entities/operation/list/operation.component.ts deleted file mode 100644 index 52017530d..000000000 --- a/src/main/webapp/app/entities/operation/list/operation.component.ts +++ /dev/null @@ -1,185 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { HttpHeaders } from '@angular/common/http'; -import { ActivatedRoute, Data, ParamMap, Router, RouterModule } from '@angular/router'; -import { combineLatest, filter, Observable, switchMap, tap } from 'rxjs'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; - -import SharedModule from 'app/shared/shared.module'; -import { SortDirective, SortByDirective } from 'app/shared/sort'; -import { DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe } from 'app/shared/date'; -import { FormsModule } from '@angular/forms'; -import { IOperation } from '../operation.model'; - -import { ITEMS_PER_PAGE } from 'app/config/pagination.constants'; -import { ASC, DESC, SORT, ITEM_DELETED_EVENT, DEFAULT_SORT_DATA } from 'app/config/navigation.constants'; -import { EntityArrayResponseType, OperationService } from '../service/operation.service'; -import { OperationDeleteDialogComponent } from '../delete/operation-delete-dialog.component'; -import { ParseLinks } from 'app/core/util/parse-links.service'; -import { InfiniteScrollModule } from 'ngx-infinite-scroll'; - -@Component({ - standalone: true, - selector: 'jhi-operation', - templateUrl: './operation.component.html', - imports: [ - RouterModule, - FormsModule, - SharedModule, - SortDirective, - SortByDirective, - DurationPipe, - FormatMediumDatetimePipe, - FormatMediumDatePipe, - InfiniteScrollModule, - ], -}) -export class OperationComponent implements OnInit { - operations?: IOperation[]; - isLoading = false; - - predicate = 'id'; - ascending = true; - - itemsPerPage = ITEMS_PER_PAGE; - links: { [key: string]: number } = { - last: 0, - }; - page = 1; - - constructor( - protected operationService: OperationService, - protected activatedRoute: ActivatedRoute, - public router: Router, - protected parseLinks: ParseLinks, - protected modalService: NgbModal - ) {} - - reset(): void { - this.page = 1; - this.operations = []; - this.load(); - } - - loadPage(page: number): void { - this.page = page; - this.load(); - } - - trackId = (_index: number, item: IOperation): number => this.operationService.getOperationIdentifier(item); - - ngOnInit(): void { - this.load(); - } - - delete(operation: IOperation): void { - const modalRef = this.modalService.open(OperationDeleteDialogComponent, { size: 'lg', backdrop: 'static' }); - modalRef.componentInstance.operation = operation; - // unsubscribe not needed because closed completes on modal close - modalRef.closed - .pipe( - filter(reason => reason === ITEM_DELETED_EVENT), - switchMap(() => this.loadFromBackendWithRouteInformations()) - ) - .subscribe({ - next: (res: EntityArrayResponseType) => { - this.onResponseSuccess(res); - }, - }); - } - - load(): void { - this.loadFromBackendWithRouteInformations().subscribe({ - next: (res: EntityArrayResponseType) => { - this.onResponseSuccess(res); - }, - }); - } - - navigateToWithComponentValues(): void { - this.handleNavigation(this.page, this.predicate, this.ascending); - } - - navigateToPage(page = this.page): void { - this.handleNavigation(page, this.predicate, this.ascending); - } - - protected loadFromBackendWithRouteInformations(): Observable { - return combineLatest([this.activatedRoute.queryParamMap, this.activatedRoute.data]).pipe( - tap(([params, data]) => this.fillComponentAttributeFromRoute(params, data)), - switchMap(() => this.queryBackend(this.page, this.predicate, this.ascending)) - ); - } - - protected fillComponentAttributeFromRoute(params: ParamMap, data: Data): void { - const sort = (params.get(SORT) ?? data[DEFAULT_SORT_DATA]).split(','); - this.predicate = sort[0]; - this.ascending = sort[1] === ASC; - } - - protected onResponseSuccess(response: EntityArrayResponseType): void { - this.fillComponentAttributesFromResponseHeader(response.headers); - const dataFromBody = this.fillComponentAttributesFromResponseBody(response.body); - this.operations = dataFromBody; - } - - protected fillComponentAttributesFromResponseBody(data: IOperation[] | null): IOperation[] { - // If there is previus link, data is a infinite scroll pagination content. - if ('prev' in this.links) { - const operationsNew = this.operations ?? []; - if (data) { - for (const d of data) { - if (operationsNew.map(op => op.id).indexOf(d.id) === -1) { - operationsNew.push(d); - } - } - } - return operationsNew; - } - return data ?? []; - } - - protected fillComponentAttributesFromResponseHeader(headers: HttpHeaders): void { - const linkHeader = headers.get('link'); - if (linkHeader) { - this.links = this.parseLinks.parse(linkHeader); - } else { - this.links = { - last: 0, - }; - } - } - - protected queryBackend(page?: number, predicate?: string, ascending?: boolean): Observable { - this.isLoading = true; - const pageToLoad: number = page ?? 1; - const queryObject: any = { - page: pageToLoad - 1, - size: this.itemsPerPage, - eagerload: true, - sort: this.getSortQueryParam(predicate, ascending), - }; - return this.operationService.query(queryObject).pipe(tap(() => (this.isLoading = false))); - } - - protected handleNavigation(page = this.page, predicate?: string, ascending?: boolean): void { - const queryParamsObj = { - page, - size: this.itemsPerPage, - sort: this.getSortQueryParam(predicate, ascending), - }; - - this.router.navigate(['./'], { - relativeTo: this.activatedRoute, - queryParams: queryParamsObj, - }); - } - - protected getSortQueryParam(predicate = this.predicate, ascending = this.ascending): string[] { - const ascendingQueryParam = ascending ? ASC : DESC; - if (predicate === '') { - return []; - } else { - return [predicate + ',' + ascendingQueryParam]; - } - } -} diff --git a/src/main/webapp/app/entities/operation/operation.model.ts b/src/main/webapp/app/entities/operation/operation.model.ts deleted file mode 100644 index 1e4fbf473..000000000 --- a/src/main/webapp/app/entities/operation/operation.model.ts +++ /dev/null @@ -1,14 +0,0 @@ -import dayjs from 'dayjs/esm'; -import { IBankAccount } from 'app/entities/bank-account/bank-account.model'; -import { ILabel } from 'app/entities/label/label.model'; - -export interface IOperation { - id: number; - date?: dayjs.Dayjs | null; - description?: string | null; - amount?: number | null; - bankAccount?: Pick | null; - labels?: Pick[] | null; -} - -export type NewOperation = Omit & { id: null }; diff --git a/src/main/webapp/app/entities/operation/operation.routes.ts b/src/main/webapp/app/entities/operation/operation.routes.ts deleted file mode 100644 index cb46cce0b..000000000 --- a/src/main/webapp/app/entities/operation/operation.routes.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Routes } from '@angular/router'; - -import { UserRouteAccessService } from 'app/core/auth/user-route-access.service'; -import { OperationComponent } from './list/operation.component'; -import { OperationDetailComponent } from './detail/operation-detail.component'; -import { OperationUpdateComponent } from './update/operation-update.component'; -import OperationResolve from './route/operation-routing-resolve.service'; -import { ASC } from 'app/config/navigation.constants'; - -const operationRoute: Routes = [ - { - path: '', - component: OperationComponent, - data: { - defaultSort: 'id,' + ASC, - }, - canActivate: [UserRouteAccessService], - }, - { - path: ':id/view', - component: OperationDetailComponent, - resolve: { - operation: OperationResolve, - }, - canActivate: [UserRouteAccessService], - }, - { - path: 'new', - component: OperationUpdateComponent, - resolve: { - operation: OperationResolve, - }, - canActivate: [UserRouteAccessService], - }, - { - path: ':id/edit', - component: OperationUpdateComponent, - resolve: { - operation: OperationResolve, - }, - canActivate: [UserRouteAccessService], - }, -]; - -export default operationRoute; diff --git a/src/main/webapp/app/entities/operation/operation.test-samples.ts b/src/main/webapp/app/entities/operation/operation.test-samples.ts deleted file mode 100644 index eb25e9a57..000000000 --- a/src/main/webapp/app/entities/operation/operation.test-samples.ts +++ /dev/null @@ -1,34 +0,0 @@ -import dayjs from 'dayjs/esm'; - -import { IOperation, NewOperation } from './operation.model'; - -export const sampleWithRequiredData: IOperation = { - id: 17097, - date: dayjs('2015-08-05T05:46'), - amount: 507, -}; - -export const sampleWithPartialData: IOperation = { - id: 27922, - date: dayjs('2015-08-05T10:26'), - description: 'Southeast', - amount: 3199, -}; - -export const sampleWithFullData: IOperation = { - id: 23014, - date: dayjs('2015-08-05T08:57'), - description: 'cyan Gasoline Livermorium', - amount: 13122, -}; - -export const sampleWithNewData: NewOperation = { - date: dayjs('2015-08-05T09:46'), - amount: 16908, - id: null, -}; - -Object.freeze(sampleWithNewData); -Object.freeze(sampleWithRequiredData); -Object.freeze(sampleWithPartialData); -Object.freeze(sampleWithFullData); diff --git a/src/main/webapp/app/entities/operation/route/operation-routing-resolve.service.spec.ts b/src/main/webapp/app/entities/operation/route/operation-routing-resolve.service.spec.ts deleted file mode 100644 index d4ea97baa..000000000 --- a/src/main/webapp/app/entities/operation/route/operation-routing-resolve.service.spec.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { HttpResponse } from '@angular/common/http'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { ActivatedRouteSnapshot, ActivatedRoute, Router, convertToParamMap, RouterStateSnapshot } from '@angular/router'; -import { RouterTestingModule } from '@angular/router/testing'; -import { of } from 'rxjs'; - -import { IOperation } from '../operation.model'; -import { OperationService } from '../service/operation.service'; - -import operationResolve from './operation-routing-resolve.service'; - -describe('Operation routing resolve service', () => { - let mockRouter: Router; - let mockActivatedRouteSnapshot: ActivatedRouteSnapshot; - let service: OperationService; - let resultOperation: IOperation | null | undefined; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, RouterTestingModule.withRoutes([])], - providers: [ - { - provide: ActivatedRoute, - useValue: { - snapshot: { - paramMap: convertToParamMap({}), - }, - }, - }, - ], - }); - mockRouter = TestBed.inject(Router); - jest.spyOn(mockRouter, 'navigate').mockImplementation(() => Promise.resolve(true)); - mockActivatedRouteSnapshot = TestBed.inject(ActivatedRoute).snapshot; - service = TestBed.inject(OperationService); - resultOperation = undefined; - }); - - describe('resolve', () => { - it('should return IOperation returned by find', () => { - // GIVEN - service.find = jest.fn(id => of(new HttpResponse({ body: { id } }))); - mockActivatedRouteSnapshot.params = { id: 123 }; - - // WHEN - TestBed.runInInjectionContext(() => { - operationResolve(mockActivatedRouteSnapshot).subscribe({ - next(result) { - resultOperation = result; - }, - }); - }); - - // THEN - expect(service.find).toBeCalledWith(123); - expect(resultOperation).toEqual({ id: 123 }); - }); - - it('should return null if id is not provided', () => { - // GIVEN - service.find = jest.fn(); - mockActivatedRouteSnapshot.params = {}; - - // WHEN - TestBed.runInInjectionContext(() => { - operationResolve(mockActivatedRouteSnapshot).subscribe({ - next(result) { - resultOperation = result; - }, - }); - }); - - // THEN - expect(service.find).not.toBeCalled(); - expect(resultOperation).toEqual(null); - }); - - it('should route to 404 page if data not found in server', () => { - // GIVEN - jest.spyOn(service, 'find').mockReturnValue(of(new HttpResponse({ body: null }))); - mockActivatedRouteSnapshot.params = { id: 123 }; - - // WHEN - TestBed.runInInjectionContext(() => { - operationResolve(mockActivatedRouteSnapshot).subscribe({ - next(result) { - resultOperation = result; - }, - }); - }); - - // THEN - expect(service.find).toBeCalledWith(123); - expect(resultOperation).toEqual(undefined); - expect(mockRouter.navigate).toHaveBeenCalledWith(['404']); - }); - }); -}); diff --git a/src/main/webapp/app/entities/operation/route/operation-routing-resolve.service.ts b/src/main/webapp/app/entities/operation/route/operation-routing-resolve.service.ts deleted file mode 100644 index 1d3154e53..000000000 --- a/src/main/webapp/app/entities/operation/route/operation-routing-resolve.service.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { inject } from '@angular/core'; -import { HttpResponse } from '@angular/common/http'; -import { ActivatedRouteSnapshot, Router } from '@angular/router'; -import { of, EMPTY, Observable } from 'rxjs'; -import { mergeMap } from 'rxjs/operators'; - -import { IOperation } from '../operation.model'; -import { OperationService } from '../service/operation.service'; - -export const operationResolve = (route: ActivatedRouteSnapshot): Observable => { - const id = route.params['id']; - if (id) { - return inject(OperationService) - .find(id) - .pipe( - mergeMap((operation: HttpResponse) => { - if (operation.body) { - return of(operation.body); - } else { - inject(Router).navigate(['404']); - return EMPTY; - } - }) - ); - } - return of(null); -}; - -export default operationResolve; diff --git a/src/main/webapp/app/entities/operation/service/operation.service.spec.ts b/src/main/webapp/app/entities/operation/service/operation.service.spec.ts deleted file mode 100644 index c512b2f48..000000000 --- a/src/main/webapp/app/entities/operation/service/operation.service.spec.ts +++ /dev/null @@ -1,206 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; - -import { IOperation } from '../operation.model'; -import { sampleWithRequiredData, sampleWithNewData, sampleWithPartialData, sampleWithFullData } from '../operation.test-samples'; - -import { OperationService, RestOperation } from './operation.service'; - -const requireRestSample: RestOperation = { - ...sampleWithRequiredData, - date: sampleWithRequiredData.date?.toJSON(), -}; - -describe('Operation Service', () => { - let service: OperationService; - let httpMock: HttpTestingController; - let expectedResult: IOperation | IOperation[] | boolean | null; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - }); - expectedResult = null; - service = TestBed.inject(OperationService); - httpMock = TestBed.inject(HttpTestingController); - }); - - describe('Service methods', () => { - it('should find an element', () => { - const returnedFromService = { ...requireRestSample }; - const expected = { ...sampleWithRequiredData }; - - service.find(123).subscribe(resp => (expectedResult = resp.body)); - - const req = httpMock.expectOne({ method: 'GET' }); - req.flush(returnedFromService); - expect(expectedResult).toMatchObject(expected); - }); - - it('should create a Operation', () => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const operation = { ...sampleWithNewData }; - const returnedFromService = { ...requireRestSample }; - const expected = { ...sampleWithRequiredData }; - - service.create(operation).subscribe(resp => (expectedResult = resp.body)); - - const req = httpMock.expectOne({ method: 'POST' }); - req.flush(returnedFromService); - expect(expectedResult).toMatchObject(expected); - }); - - it('should update a Operation', () => { - const operation = { ...sampleWithRequiredData }; - const returnedFromService = { ...requireRestSample }; - const expected = { ...sampleWithRequiredData }; - - service.update(operation).subscribe(resp => (expectedResult = resp.body)); - - const req = httpMock.expectOne({ method: 'PUT' }); - req.flush(returnedFromService); - expect(expectedResult).toMatchObject(expected); - }); - - it('should partial update a Operation', () => { - const patchObject = { ...sampleWithPartialData }; - const returnedFromService = { ...requireRestSample }; - const expected = { ...sampleWithRequiredData }; - - service.partialUpdate(patchObject).subscribe(resp => (expectedResult = resp.body)); - - const req = httpMock.expectOne({ method: 'PATCH' }); - req.flush(returnedFromService); - expect(expectedResult).toMatchObject(expected); - }); - - it('should return a list of Operation', () => { - const returnedFromService = { ...requireRestSample }; - - const expected = { ...sampleWithRequiredData }; - - service.query().subscribe(resp => (expectedResult = resp.body)); - - const req = httpMock.expectOne({ method: 'GET' }); - req.flush([returnedFromService]); - httpMock.verify(); - expect(expectedResult).toMatchObject([expected]); - }); - - it('should delete a Operation', () => { - const expected = true; - - service.delete(123).subscribe(resp => (expectedResult = resp.ok)); - - const req = httpMock.expectOne({ method: 'DELETE' }); - req.flush({ status: 200 }); - expect(expectedResult).toBe(expected); - }); - - describe('addOperationToCollectionIfMissing', () => { - it('should add a Operation to an empty array', () => { - const operation: IOperation = sampleWithRequiredData; - expectedResult = service.addOperationToCollectionIfMissing([], operation); - expect(expectedResult).toHaveLength(1); - expect(expectedResult).toContain(operation); - }); - - it('should not add a Operation to an array that contains it', () => { - const operation: IOperation = sampleWithRequiredData; - const operationCollection: IOperation[] = [ - { - ...operation, - }, - sampleWithPartialData, - ]; - expectedResult = service.addOperationToCollectionIfMissing(operationCollection, operation); - expect(expectedResult).toHaveLength(2); - }); - - it("should add a Operation to an array that doesn't contain it", () => { - const operation: IOperation = sampleWithRequiredData; - const operationCollection: IOperation[] = [sampleWithPartialData]; - expectedResult = service.addOperationToCollectionIfMissing(operationCollection, operation); - expect(expectedResult).toHaveLength(2); - expect(expectedResult).toContain(operation); - }); - - it('should add only unique Operation to an array', () => { - const operationArray: IOperation[] = [sampleWithRequiredData, sampleWithPartialData, sampleWithFullData]; - const operationCollection: IOperation[] = [sampleWithRequiredData]; - expectedResult = service.addOperationToCollectionIfMissing(operationCollection, ...operationArray); - expect(expectedResult).toHaveLength(3); - }); - - it('should accept varargs', () => { - const operation: IOperation = sampleWithRequiredData; - const operation2: IOperation = sampleWithPartialData; - expectedResult = service.addOperationToCollectionIfMissing([], operation, operation2); - expect(expectedResult).toHaveLength(2); - expect(expectedResult).toContain(operation); - expect(expectedResult).toContain(operation2); - }); - - it('should accept null and undefined values', () => { - const operation: IOperation = sampleWithRequiredData; - expectedResult = service.addOperationToCollectionIfMissing([], null, operation, undefined); - expect(expectedResult).toHaveLength(1); - expect(expectedResult).toContain(operation); - }); - - it('should return initial array if no Operation is added', () => { - const operationCollection: IOperation[] = [sampleWithRequiredData]; - expectedResult = service.addOperationToCollectionIfMissing(operationCollection, undefined, null); - expect(expectedResult).toEqual(operationCollection); - }); - }); - - describe('compareOperation', () => { - it('Should return true if both entities are null', () => { - const entity1 = null; - const entity2 = null; - - const compareResult = service.compareOperation(entity1, entity2); - - expect(compareResult).toEqual(true); - }); - - it('Should return false if one entity is null', () => { - const entity1 = { id: 123 }; - const entity2 = null; - - const compareResult1 = service.compareOperation(entity1, entity2); - const compareResult2 = service.compareOperation(entity2, entity1); - - expect(compareResult1).toEqual(false); - expect(compareResult2).toEqual(false); - }); - - it('Should return false if primaryKey differs', () => { - const entity1 = { id: 123 }; - const entity2 = { id: 456 }; - - const compareResult1 = service.compareOperation(entity1, entity2); - const compareResult2 = service.compareOperation(entity2, entity1); - - expect(compareResult1).toEqual(false); - expect(compareResult2).toEqual(false); - }); - - it('Should return false if primaryKey matches', () => { - const entity1 = { id: 123 }; - const entity2 = { id: 123 }; - - const compareResult1 = service.compareOperation(entity1, entity2); - const compareResult2 = service.compareOperation(entity2, entity1); - - expect(compareResult1).toEqual(true); - expect(compareResult2).toEqual(true); - }); - }); - }); - - afterEach(() => { - httpMock.verify(); - }); -}); diff --git a/src/main/webapp/app/entities/operation/service/operation.service.ts b/src/main/webapp/app/entities/operation/service/operation.service.ts deleted file mode 100644 index c961d2601..000000000 --- a/src/main/webapp/app/entities/operation/service/operation.service.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient, HttpResponse } from '@angular/common/http'; -import { Observable } from 'rxjs'; - -import { map } from 'rxjs/operators'; - -import dayjs from 'dayjs/esm'; - -import { isPresent } from 'app/core/util/operators'; -import { ApplicationConfigService } from 'app/core/config/application-config.service'; -import { createRequestOption } from 'app/core/request/request-util'; -import { IOperation, NewOperation } from '../operation.model'; - -export type PartialUpdateOperation = Partial & Pick; - -type RestOf = Omit & { - date?: string | null; -}; - -export type RestOperation = RestOf; - -export type NewRestOperation = RestOf; - -export type PartialUpdateRestOperation = RestOf; - -export type EntityResponseType = HttpResponse; -export type EntityArrayResponseType = HttpResponse; - -@Injectable({ providedIn: 'root' }) -export class OperationService { - protected resourceUrl = this.applicationConfigService.getEndpointFor('api/operations'); - - constructor(protected http: HttpClient, protected applicationConfigService: ApplicationConfigService) {} - - create(operation: NewOperation): Observable { - const copy = this.convertDateFromClient(operation); - return this.http - .post(this.resourceUrl, copy, { observe: 'response' }) - .pipe(map(res => this.convertResponseFromServer(res))); - } - - update(operation: IOperation): Observable { - const copy = this.convertDateFromClient(operation); - return this.http - .put(`${this.resourceUrl}/${this.getOperationIdentifier(operation)}`, copy, { observe: 'response' }) - .pipe(map(res => this.convertResponseFromServer(res))); - } - - partialUpdate(operation: PartialUpdateOperation): Observable { - const copy = this.convertDateFromClient(operation); - return this.http - .patch(`${this.resourceUrl}/${this.getOperationIdentifier(operation)}`, copy, { observe: 'response' }) - .pipe(map(res => this.convertResponseFromServer(res))); - } - - find(id: number): Observable { - return this.http - .get(`${this.resourceUrl}/${id}`, { observe: 'response' }) - .pipe(map(res => this.convertResponseFromServer(res))); - } - - query(req?: any): Observable { - const options = createRequestOption(req); - return this.http - .get(this.resourceUrl, { params: options, observe: 'response' }) - .pipe(map(res => this.convertResponseArrayFromServer(res))); - } - - delete(id: number): Observable> { - return this.http.delete(`${this.resourceUrl}/${id}`, { observe: 'response' }); - } - - getOperationIdentifier(operation: Pick): number { - return operation.id; - } - - compareOperation(o1: Pick | null, o2: Pick | null): boolean { - return o1 && o2 ? this.getOperationIdentifier(o1) === this.getOperationIdentifier(o2) : o1 === o2; - } - - addOperationToCollectionIfMissing>( - operationCollection: Type[], - ...operationsToCheck: (Type | null | undefined)[] - ): Type[] { - const operations: Type[] = operationsToCheck.filter(isPresent); - if (operations.length > 0) { - const operationCollectionIdentifiers = operationCollection.map(operationItem => this.getOperationIdentifier(operationItem)!); - const operationsToAdd = operations.filter(operationItem => { - const operationIdentifier = this.getOperationIdentifier(operationItem); - if (operationCollectionIdentifiers.includes(operationIdentifier)) { - return false; - } - operationCollectionIdentifiers.push(operationIdentifier); - return true; - }); - return [...operationsToAdd, ...operationCollection]; - } - return operationCollection; - } - - protected convertDateFromClient(operation: T): RestOf { - return { - ...operation, - date: operation.date?.toJSON() ?? null, - }; - } - - protected convertDateFromServer(restOperation: RestOperation): IOperation { - return { - ...restOperation, - date: restOperation.date ? dayjs(restOperation.date) : undefined, - }; - } - - protected convertResponseFromServer(res: HttpResponse): HttpResponse { - return res.clone({ - body: res.body ? this.convertDateFromServer(res.body) : null, - }); - } - - protected convertResponseArrayFromServer(res: HttpResponse): HttpResponse { - return res.clone({ - body: res.body ? res.body.map(item => this.convertDateFromServer(item)) : null, - }); - } -} diff --git a/src/main/webapp/app/entities/operation/update/operation-form.service.spec.ts b/src/main/webapp/app/entities/operation/update/operation-form.service.spec.ts deleted file mode 100644 index fca198a35..000000000 --- a/src/main/webapp/app/entities/operation/update/operation-form.service.spec.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { sampleWithRequiredData, sampleWithNewData } from '../operation.test-samples'; - -import { OperationFormService } from './operation-form.service'; - -describe('Operation Form Service', () => { - let service: OperationFormService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(OperationFormService); - }); - - describe('Service methods', () => { - describe('createOperationFormGroup', () => { - it('should create a new form with FormControl', () => { - const formGroup = service.createOperationFormGroup(); - - expect(formGroup.controls).toEqual( - expect.objectContaining({ - id: expect.any(Object), - date: expect.any(Object), - description: expect.any(Object), - amount: expect.any(Object), - bankAccount: expect.any(Object), - labels: expect.any(Object), - }) - ); - }); - - it('passing IOperation should create a new form with FormGroup', () => { - const formGroup = service.createOperationFormGroup(sampleWithRequiredData); - - expect(formGroup.controls).toEqual( - expect.objectContaining({ - id: expect.any(Object), - date: expect.any(Object), - description: expect.any(Object), - amount: expect.any(Object), - bankAccount: expect.any(Object), - labels: expect.any(Object), - }) - ); - }); - }); - - describe('getOperation', () => { - it('should return NewOperation for default Operation initial value', () => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const formGroup = service.createOperationFormGroup(sampleWithNewData); - - const operation = service.getOperation(formGroup) as any; - - expect(operation).toMatchObject(sampleWithNewData); - }); - - it('should return NewOperation for empty Operation initial value', () => { - const formGroup = service.createOperationFormGroup(); - - const operation = service.getOperation(formGroup) as any; - - expect(operation).toMatchObject({}); - }); - - it('should return IOperation', () => { - const formGroup = service.createOperationFormGroup(sampleWithRequiredData); - - const operation = service.getOperation(formGroup) as any; - - expect(operation).toMatchObject(sampleWithRequiredData); - }); - }); - - describe('resetForm', () => { - it('passing IOperation should not enable id FormControl', () => { - const formGroup = service.createOperationFormGroup(); - expect(formGroup.controls.id.disabled).toBe(true); - - service.resetForm(formGroup, sampleWithRequiredData); - - expect(formGroup.controls.id.disabled).toBe(true); - }); - - it('passing NewOperation should disable id FormControl', () => { - const formGroup = service.createOperationFormGroup(sampleWithRequiredData); - expect(formGroup.controls.id.disabled).toBe(true); - - service.resetForm(formGroup, { id: null }); - - expect(formGroup.controls.id.disabled).toBe(true); - }); - }); - }); -}); diff --git a/src/main/webapp/app/entities/operation/update/operation-form.service.ts b/src/main/webapp/app/entities/operation/update/operation-form.service.ts deleted file mode 100644 index 996a626ce..000000000 --- a/src/main/webapp/app/entities/operation/update/operation-form.service.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { Injectable } from '@angular/core'; -import { FormGroup, FormControl, Validators } from '@angular/forms'; - -import dayjs from 'dayjs/esm'; -import { DATE_TIME_FORMAT } from 'app/config/input.constants'; -import { IOperation, NewOperation } from '../operation.model'; - -/** - * A partial Type with required key is used as form input. - */ -type PartialWithRequiredKeyOf = Partial> & { id: T['id'] }; - -/** - * Type for createFormGroup and resetForm argument. - * It accepts IOperation for edit and NewOperationFormGroupInput for create. - */ -type OperationFormGroupInput = IOperation | PartialWithRequiredKeyOf; - -/** - * Type that converts some properties for forms. - */ -type FormValueOf = Omit & { - date?: string | null; -}; - -type OperationFormRawValue = FormValueOf; - -type NewOperationFormRawValue = FormValueOf; - -type OperationFormDefaults = Pick; - -type OperationFormGroupContent = { - id: FormControl; - date: FormControl; - description: FormControl; - amount: FormControl; - bankAccount: FormControl; - labels: FormControl; -}; - -export type OperationFormGroup = FormGroup; - -@Injectable({ providedIn: 'root' }) -export class OperationFormService { - createOperationFormGroup(operation: OperationFormGroupInput = { id: null }): OperationFormGroup { - const operationRawValue = this.convertOperationToOperationRawValue({ - ...this.getFormDefaults(), - ...operation, - }); - return new FormGroup({ - id: new FormControl( - { value: operationRawValue.id, disabled: true }, - { - nonNullable: true, - validators: [Validators.required], - } - ), - date: new FormControl(operationRawValue.date, { - validators: [Validators.required], - }), - description: new FormControl(operationRawValue.description), - amount: new FormControl(operationRawValue.amount, { - validators: [Validators.required], - }), - bankAccount: new FormControl(operationRawValue.bankAccount), - labels: new FormControl(operationRawValue.labels ?? []), - }); - } - - getOperation(form: OperationFormGroup): IOperation | NewOperation { - return this.convertOperationRawValueToOperation(form.getRawValue() as OperationFormRawValue | NewOperationFormRawValue); - } - - resetForm(form: OperationFormGroup, operation: OperationFormGroupInput): void { - const operationRawValue = this.convertOperationToOperationRawValue({ ...this.getFormDefaults(), ...operation }); - form.reset( - { - ...operationRawValue, - id: { value: operationRawValue.id, disabled: true }, - } as any /* cast to workaround https://github.com/angular/angular/issues/46458 */ - ); - } - - private getFormDefaults(): OperationFormDefaults { - const currentTime = dayjs(); - - return { - id: null, - date: currentTime, - labels: [], - }; - } - - private convertOperationRawValueToOperation(rawOperation: OperationFormRawValue | NewOperationFormRawValue): IOperation | NewOperation { - return { - ...rawOperation, - date: dayjs(rawOperation.date, DATE_TIME_FORMAT), - }; - } - - private convertOperationToOperationRawValue( - operation: IOperation | (Partial & OperationFormDefaults) - ): OperationFormRawValue | PartialWithRequiredKeyOf { - return { - ...operation, - date: operation.date ? operation.date.format(DATE_TIME_FORMAT) : undefined, - labels: operation.labels ?? [], - }; - } -} diff --git a/src/main/webapp/app/entities/operation/update/operation-update.component.html b/src/main/webapp/app/entities/operation/update/operation-update.component.html deleted file mode 100644 index 3d62e1bda..000000000 --- a/src/main/webapp/app/entities/operation/update/operation-update.component.html +++ /dev/null @@ -1,126 +0,0 @@ -
-
-
-

- Create or edit a Operation -

- -
- - -
- - -
- -
- -
- -
-
- - This field is required. - - - This field should be a date and time. - -
-
- -
- - -
- -
- - -
- - This field is required. - - - This field should be a number. - -
-
- -
- - -
- -
- - -
-
- -
- - - -
-
-
-
diff --git a/src/main/webapp/app/entities/operation/update/operation-update.component.spec.ts b/src/main/webapp/app/entities/operation/update/operation-update.component.spec.ts deleted file mode 100644 index 4a6c67a15..000000000 --- a/src/main/webapp/app/entities/operation/update/operation-update.component.spec.ts +++ /dev/null @@ -1,204 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { HttpResponse } from '@angular/common/http'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { FormBuilder } from '@angular/forms'; -import { ActivatedRoute } from '@angular/router'; -import { RouterTestingModule } from '@angular/router/testing'; -import { of, Subject, from } from 'rxjs'; - -import { OperationFormService } from './operation-form.service'; -import { OperationService } from '../service/operation.service'; -import { IOperation } from '../operation.model'; -import { IBankAccount } from 'app/entities/bank-account/bank-account.model'; -import { BankAccountService } from 'app/entities/bank-account/service/bank-account.service'; -import { ILabel } from 'app/entities/label/label.model'; -import { LabelService } from 'app/entities/label/service/label.service'; - -import { OperationUpdateComponent } from './operation-update.component'; - -describe('Operation Management Update Component', () => { - let comp: OperationUpdateComponent; - let fixture: ComponentFixture; - let activatedRoute: ActivatedRoute; - let operationFormService: OperationFormService; - let operationService: OperationService; - let bankAccountService: BankAccountService; - let labelService: LabelService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, RouterTestingModule.withRoutes([]), OperationUpdateComponent], - providers: [ - FormBuilder, - { - provide: ActivatedRoute, - useValue: { - params: from([{}]), - }, - }, - ], - }) - .overrideTemplate(OperationUpdateComponent, '') - .compileComponents(); - - fixture = TestBed.createComponent(OperationUpdateComponent); - activatedRoute = TestBed.inject(ActivatedRoute); - operationFormService = TestBed.inject(OperationFormService); - operationService = TestBed.inject(OperationService); - bankAccountService = TestBed.inject(BankAccountService); - labelService = TestBed.inject(LabelService); - - comp = fixture.componentInstance; - }); - - describe('ngOnInit', () => { - it('Should call BankAccount query and add missing value', () => { - const operation: IOperation = { id: 456 }; - const bankAccount: IBankAccount = { id: 17714 }; - operation.bankAccount = bankAccount; - - const bankAccountCollection: IBankAccount[] = [{ id: 8898 }]; - jest.spyOn(bankAccountService, 'query').mockReturnValue(of(new HttpResponse({ body: bankAccountCollection }))); - const additionalBankAccounts = [bankAccount]; - const expectedCollection: IBankAccount[] = [...additionalBankAccounts, ...bankAccountCollection]; - jest.spyOn(bankAccountService, 'addBankAccountToCollectionIfMissing').mockReturnValue(expectedCollection); - - activatedRoute.data = of({ operation }); - comp.ngOnInit(); - - expect(bankAccountService.query).toHaveBeenCalled(); - expect(bankAccountService.addBankAccountToCollectionIfMissing).toHaveBeenCalledWith( - bankAccountCollection, - ...additionalBankAccounts.map(expect.objectContaining) - ); - expect(comp.bankAccountsSharedCollection).toEqual(expectedCollection); - }); - - it('Should call Label query and add missing value', () => { - const operation: IOperation = { id: 456 }; - const labels: ILabel[] = [{ id: 31727 }]; - operation.labels = labels; - - const labelCollection: ILabel[] = [{ id: 3503 }]; - jest.spyOn(labelService, 'query').mockReturnValue(of(new HttpResponse({ body: labelCollection }))); - const additionalLabels = [...labels]; - const expectedCollection: ILabel[] = [...additionalLabels, ...labelCollection]; - jest.spyOn(labelService, 'addLabelToCollectionIfMissing').mockReturnValue(expectedCollection); - - activatedRoute.data = of({ operation }); - comp.ngOnInit(); - - expect(labelService.query).toHaveBeenCalled(); - expect(labelService.addLabelToCollectionIfMissing).toHaveBeenCalledWith( - labelCollection, - ...additionalLabels.map(expect.objectContaining) - ); - expect(comp.labelsSharedCollection).toEqual(expectedCollection); - }); - - it('Should update editForm', () => { - const operation: IOperation = { id: 456 }; - const bankAccount: IBankAccount = { id: 19142 }; - operation.bankAccount = bankAccount; - const label: ILabel = { id: 16279 }; - operation.labels = [label]; - - activatedRoute.data = of({ operation }); - comp.ngOnInit(); - - expect(comp.bankAccountsSharedCollection).toContain(bankAccount); - expect(comp.labelsSharedCollection).toContain(label); - expect(comp.operation).toEqual(operation); - }); - }); - - describe('save', () => { - it('Should call update service on save for existing entity', () => { - // GIVEN - const saveSubject = new Subject>(); - const operation = { id: 123 }; - jest.spyOn(operationFormService, 'getOperation').mockReturnValue(operation); - jest.spyOn(operationService, 'update').mockReturnValue(saveSubject); - jest.spyOn(comp, 'previousState'); - activatedRoute.data = of({ operation }); - comp.ngOnInit(); - - // WHEN - comp.save(); - expect(comp.isSaving).toEqual(true); - saveSubject.next(new HttpResponse({ body: operation })); - saveSubject.complete(); - - // THEN - expect(operationFormService.getOperation).toHaveBeenCalled(); - expect(comp.previousState).toHaveBeenCalled(); - expect(operationService.update).toHaveBeenCalledWith(expect.objectContaining(operation)); - expect(comp.isSaving).toEqual(false); - }); - - it('Should call create service on save for new entity', () => { - // GIVEN - const saveSubject = new Subject>(); - const operation = { id: 123 }; - jest.spyOn(operationFormService, 'getOperation').mockReturnValue({ id: null }); - jest.spyOn(operationService, 'create').mockReturnValue(saveSubject); - jest.spyOn(comp, 'previousState'); - activatedRoute.data = of({ operation: null }); - comp.ngOnInit(); - - // WHEN - comp.save(); - expect(comp.isSaving).toEqual(true); - saveSubject.next(new HttpResponse({ body: operation })); - saveSubject.complete(); - - // THEN - expect(operationFormService.getOperation).toHaveBeenCalled(); - expect(operationService.create).toHaveBeenCalled(); - expect(comp.isSaving).toEqual(false); - expect(comp.previousState).toHaveBeenCalled(); - }); - - it('Should set isSaving to false on error', () => { - // GIVEN - const saveSubject = new Subject>(); - const operation = { id: 123 }; - jest.spyOn(operationService, 'update').mockReturnValue(saveSubject); - jest.spyOn(comp, 'previousState'); - activatedRoute.data = of({ operation }); - comp.ngOnInit(); - - // WHEN - comp.save(); - expect(comp.isSaving).toEqual(true); - saveSubject.error('This is an error!'); - - // THEN - expect(operationService.update).toHaveBeenCalled(); - expect(comp.isSaving).toEqual(false); - expect(comp.previousState).not.toHaveBeenCalled(); - }); - }); - - describe('Compare relationships', () => { - describe('compareBankAccount', () => { - it('Should forward to bankAccountService', () => { - const entity = { id: 123 }; - const entity2 = { id: 456 }; - jest.spyOn(bankAccountService, 'compareBankAccount'); - comp.compareBankAccount(entity, entity2); - expect(bankAccountService.compareBankAccount).toHaveBeenCalledWith(entity, entity2); - }); - }); - - describe('compareLabel', () => { - it('Should forward to labelService', () => { - const entity = { id: 123 }; - const entity2 = { id: 456 }; - jest.spyOn(labelService, 'compareLabel'); - comp.compareLabel(entity, entity2); - expect(labelService.compareLabel).toHaveBeenCalledWith(entity, entity2); - }); - }); - }); -}); diff --git a/src/main/webapp/app/entities/operation/update/operation-update.component.ts b/src/main/webapp/app/entities/operation/update/operation-update.component.ts deleted file mode 100644 index 0e0814e73..000000000 --- a/src/main/webapp/app/entities/operation/update/operation-update.component.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { HttpResponse } from '@angular/common/http'; -import { ActivatedRoute } from '@angular/router'; -import { Observable } from 'rxjs'; -import { finalize, map } from 'rxjs/operators'; - -import SharedModule from 'app/shared/shared.module'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; - -import { OperationFormService, OperationFormGroup } from './operation-form.service'; -import { IOperation } from '../operation.model'; -import { OperationService } from '../service/operation.service'; -import { IBankAccount } from 'app/entities/bank-account/bank-account.model'; -import { BankAccountService } from 'app/entities/bank-account/service/bank-account.service'; -import { ILabel } from 'app/entities/label/label.model'; -import { LabelService } from 'app/entities/label/service/label.service'; - -@Component({ - standalone: true, - selector: 'jhi-operation-update', - templateUrl: './operation-update.component.html', - imports: [SharedModule, FormsModule, ReactiveFormsModule], -}) -export class OperationUpdateComponent implements OnInit { - isSaving = false; - operation: IOperation | null = null; - - bankAccountsSharedCollection: IBankAccount[] = []; - labelsSharedCollection: ILabel[] = []; - - editForm: OperationFormGroup = this.operationFormService.createOperationFormGroup(); - - constructor( - protected operationService: OperationService, - protected operationFormService: OperationFormService, - protected bankAccountService: BankAccountService, - protected labelService: LabelService, - protected activatedRoute: ActivatedRoute - ) {} - - compareBankAccount = (o1: IBankAccount | null, o2: IBankAccount | null): boolean => this.bankAccountService.compareBankAccount(o1, o2); - - compareLabel = (o1: ILabel | null, o2: ILabel | null): boolean => this.labelService.compareLabel(o1, o2); - - ngOnInit(): void { - this.activatedRoute.data.subscribe(({ operation }) => { - this.operation = operation; - if (operation) { - this.updateForm(operation); - } - - this.loadRelationshipsOptions(); - }); - } - - previousState(): void { - window.history.back(); - } - - save(): void { - this.isSaving = true; - const operation = this.operationFormService.getOperation(this.editForm); - if (operation.id !== null) { - this.subscribeToSaveResponse(this.operationService.update(operation)); - } else { - this.subscribeToSaveResponse(this.operationService.create(operation)); - } - } - - protected subscribeToSaveResponse(result: Observable>): void { - result.pipe(finalize(() => this.onSaveFinalize())).subscribe({ - next: () => this.onSaveSuccess(), - error: () => this.onSaveError(), - }); - } - - protected onSaveSuccess(): void { - this.previousState(); - } - - protected onSaveError(): void { - // Api for inheritance. - } - - protected onSaveFinalize(): void { - this.isSaving = false; - } - - protected updateForm(operation: IOperation): void { - this.operation = operation; - this.operationFormService.resetForm(this.editForm, operation); - - this.bankAccountsSharedCollection = this.bankAccountService.addBankAccountToCollectionIfMissing( - this.bankAccountsSharedCollection, - operation.bankAccount - ); - this.labelsSharedCollection = this.labelService.addLabelToCollectionIfMissing( - this.labelsSharedCollection, - ...(operation.labels ?? []) - ); - } - - protected loadRelationshipsOptions(): void { - this.bankAccountService - .query() - .pipe(map((res: HttpResponse) => res.body ?? [])) - .pipe( - map((bankAccounts: IBankAccount[]) => - this.bankAccountService.addBankAccountToCollectionIfMissing(bankAccounts, this.operation?.bankAccount) - ) - ) - .subscribe((bankAccounts: IBankAccount[]) => (this.bankAccountsSharedCollection = bankAccounts)); - - this.labelService - .query() - .pipe(map((res: HttpResponse) => res.body ?? [])) - .pipe(map((labels: ILabel[]) => this.labelService.addLabelToCollectionIfMissing(labels, ...(this.operation?.labels ?? [])))) - .subscribe((labels: ILabel[]) => (this.labelsSharedCollection = labels)); - } -} diff --git a/src/main/webapp/app/entities/user/user.model.ts b/src/main/webapp/app/entities/user/user.model.ts deleted file mode 100644 index 202428ebf..000000000 --- a/src/main/webapp/app/entities/user/user.model.ts +++ /dev/null @@ -1,12 +0,0 @@ -export interface IUser { - id: number; - login?: string; -} - -export class User implements IUser { - constructor(public id: number, public login: string) {} -} - -export function getUserIdentifier(user: IUser): number { - return user.id; -} diff --git a/src/main/webapp/app/entities/user/user.service.spec.ts b/src/main/webapp/app/entities/user/user.service.spec.ts deleted file mode 100644 index 27fd86056..000000000 --- a/src/main/webapp/app/entities/user/user.service.spec.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { HttpErrorResponse } from '@angular/common/http'; -import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; - -import { User, IUser } from './user.model'; - -import { UserService } from './user.service'; - -describe('User Service', () => { - let service: UserService; - let httpMock: HttpTestingController; - let expectedResult: IUser | IUser[] | boolean | number | null; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - }); - expectedResult = null; - service = TestBed.inject(UserService); - httpMock = TestBed.inject(HttpTestingController); - }); - - afterEach(() => { - httpMock.verify(); - }); - - describe('Service methods', () => { - it('should return Users', () => { - service.query().subscribe(received => { - expectedResult = received.body; - }); - - const req = httpMock.expectOne({ method: 'GET' }); - req.flush([new User(123, 'user')]); - expect(expectedResult).toEqual([{ id: 123, login: 'user' }]); - }); - - it('should propagate not found response', () => { - service.query().subscribe({ - error: (error: HttpErrorResponse) => (expectedResult = error.status), - }); - - const req = httpMock.expectOne({ method: 'GET' }); - req.flush('Internal Server Error', { - status: 500, - statusText: 'Inernal Server Error', - }); - expect(expectedResult).toEqual(500); - }); - - describe('addUserToCollectionIfMissing', () => { - it('should add a User to an empty array', () => { - const user: IUser = { id: 123 }; - expectedResult = service.addUserToCollectionIfMissing([], user); - expect(expectedResult).toHaveLength(1); - expect(expectedResult).toContain(user); - }); - - it('should not add a User to an array that contains it', () => { - const user: IUser = { id: 123 }; - const userCollection: IUser[] = [ - { - ...user, - }, - { id: 456 }, - ]; - expectedResult = service.addUserToCollectionIfMissing(userCollection, user); - expect(expectedResult).toHaveLength(2); - }); - - it("should add a User to an array that doesn't contain it", () => { - const user: IUser = { id: 123 }; - const userCollection: IUser[] = [{ id: 456 }]; - expectedResult = service.addUserToCollectionIfMissing(userCollection, user); - expect(expectedResult).toHaveLength(2); - expect(expectedResult).toContain(user); - }); - - it('should add only unique User to an array', () => { - const userArray: IUser[] = [{ id: 123 }, { id: 456 }, { id: 9396 }]; - const userCollection: IUser[] = [{ id: 456 }]; - expectedResult = service.addUserToCollectionIfMissing(userCollection, ...userArray); - expect(expectedResult).toHaveLength(3); - }); - - it('should accept varargs', () => { - const user: IUser = { id: 123 }; - const user2: IUser = { id: 456 }; - expectedResult = service.addUserToCollectionIfMissing([], user, user2); - expect(expectedResult).toHaveLength(2); - expect(expectedResult).toContain(user); - expect(expectedResult).toContain(user2); - }); - - it('should accept null and undefined values', () => { - const user: IUser = { id: 123 }; - expectedResult = service.addUserToCollectionIfMissing([], null, user, undefined); - expect(expectedResult).toHaveLength(1); - expect(expectedResult).toContain(user); - }); - - it('should return initial array if no users is added', () => { - const userCollection: IUser[] = [{ id: 456 }]; - expectedResult = service.addUserToCollectionIfMissing(userCollection, null, undefined); - expect(expectedResult).toEqual(userCollection); - }); - }); - }); -}); diff --git a/src/main/webapp/app/entities/user/user.service.ts b/src/main/webapp/app/entities/user/user.service.ts deleted file mode 100644 index b1daba8ba..000000000 --- a/src/main/webapp/app/entities/user/user.service.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient, HttpResponse } from '@angular/common/http'; -import { Observable } from 'rxjs'; - -import { ApplicationConfigService } from 'app/core/config/application-config.service'; -import { createRequestOption } from 'app/core/request/request-util'; -import { isPresent } from 'app/core/util/operators'; -import { Pagination } from 'app/core/request/request.model'; -import { IUser, getUserIdentifier } from './user.model'; - -@Injectable({ providedIn: 'root' }) -export class UserService { - private resourceUrl = this.applicationConfigService.getEndpointFor('api/users'); - - constructor(private http: HttpClient, private applicationConfigService: ApplicationConfigService) {} - - query(req?: Pagination): Observable> { - const options = createRequestOption(req); - return this.http.get(this.resourceUrl, { params: options, observe: 'response' }); - } - - compareUser(o1: Pick | null, o2: Pick | null): boolean { - return o1 && o2 ? o1.id === o2.id : o1 === o2; - } - - addUserToCollectionIfMissing & Pick>( - userCollection: Type[], - ...usersToCheck: (Type | null | undefined)[] - ): IUser[] { - const users: Type[] = usersToCheck.filter(isPresent); - if (users.length > 0) { - const userCollectionIdentifiers = userCollection.map(userItem => getUserIdentifier(userItem)!); - const usersToAdd = users.filter(userItem => { - const userIdentifier = getUserIdentifier(userItem); - if (userCollectionIdentifiers.includes(userIdentifier)) { - return false; - } - userCollectionIdentifiers.push(userIdentifier); - return true; - }); - return [...usersToAdd, ...userCollection]; - } - return userCollection; - } -} diff --git a/src/main/webapp/app/home/home.component.html b/src/main/webapp/app/home/home.component.html deleted file mode 100644 index 9945eb119..000000000 --- a/src/main/webapp/app/home/home.component.html +++ /dev/null @@ -1,78 +0,0 @@ -
-
- -
- -
-

Welcome, Java Hipster! (Jhipster Sample Application)

- -

This is your homepage

- -
-
- You are logged in as user "{{ account.login }}". -
- -
- If you want to - sign in, you can try the default accounts:
- Administrator (login="admin" and password="admin")
- User (login="user" and - password="user").
-
- -
- You don't have an account yet?  - Register a new account -
-
- -

If you have any question on JHipster:

- - - -

- If you like JHipster, don't forget to give us a star on - GitHub! -

-
-
diff --git a/src/main/webapp/app/home/home.component.scss b/src/main/webapp/app/home/home.component.scss deleted file mode 100644 index 95a2263f5..000000000 --- a/src/main/webapp/app/home/home.component.scss +++ /dev/null @@ -1,23 +0,0 @@ -/* ========================================================================== -Main page styles -========================================================================== */ - -.hipster { - display: inline-block; - width: 347px; - height: 497px; - background: url('/content/images/jhipster_family_member_1.svg') no-repeat center top; - background-size: contain; -} - -/* wait autoprefixer update to allow simple generation of high pixel density media query */ -@media only screen and (-webkit-min-device-pixel-ratio: 2), - only screen and (-moz-min-device-pixel-ratio: 2), - only screen and (-o-min-device-pixel-ratio: 2/1), - only screen and (min-resolution: 192dpi), - only screen and (min-resolution: 2dppx) { - .hipster { - background: url('/content/images/jhipster_family_member_1.svg') no-repeat center top; - background-size: contain; - } -} diff --git a/src/main/webapp/app/home/home.component.spec.ts b/src/main/webapp/app/home/home.component.spec.ts deleted file mode 100644 index c5122231f..000000000 --- a/src/main/webapp/app/home/home.component.spec.ts +++ /dev/null @@ -1,111 +0,0 @@ -jest.mock('app/core/auth/account.service'); - -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { Router } from '@angular/router'; -import { RouterTestingModule } from '@angular/router/testing'; -import { of, Subject } from 'rxjs'; - -import { AccountService } from 'app/core/auth/account.service'; -import { Account } from 'app/core/auth/account.model'; - -import HomeComponent from './home.component'; - -describe('Home Component', () => { - let comp: HomeComponent; - let fixture: ComponentFixture; - let mockAccountService: AccountService; - let mockRouter: Router; - const account: Account = { - activated: true, - authorities: [], - email: '', - firstName: null, - langKey: '', - lastName: null, - login: 'login', - imageUrl: null, - }; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [HomeComponent, RouterTestingModule.withRoutes([])], - providers: [AccountService], - }) - .overrideTemplate(HomeComponent, '') - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(HomeComponent); - comp = fixture.componentInstance; - mockAccountService = TestBed.inject(AccountService); - mockAccountService.identity = jest.fn(() => of(null)); - mockAccountService.getAuthenticationState = jest.fn(() => of(null)); - - mockRouter = TestBed.inject(Router); - jest.spyOn(mockRouter, 'navigate').mockImplementation(() => Promise.resolve(true)); - }); - - describe('ngOnInit', () => { - it('Should synchronize account variable with current account', () => { - // GIVEN - const authenticationState = new Subject(); - mockAccountService.getAuthenticationState = jest.fn(() => authenticationState.asObservable()); - - // WHEN - comp.ngOnInit(); - - // THEN - expect(comp.account).toBeNull(); - - // WHEN - authenticationState.next(account); - - // THEN - expect(comp.account).toEqual(account); - - // WHEN - authenticationState.next(null); - - // THEN - expect(comp.account).toBeNull(); - }); - }); - - describe('login', () => { - it('Should navigate to /login on login', () => { - // WHEN - comp.login(); - - // THEN - expect(mockRouter.navigate).toHaveBeenCalledWith(['/login']); - }); - }); - - describe('ngOnDestroy', () => { - it('Should destroy authentication state subscription on component destroy', () => { - // GIVEN - const authenticationState = new Subject(); - mockAccountService.getAuthenticationState = jest.fn(() => authenticationState.asObservable()); - - // WHEN - comp.ngOnInit(); - - // THEN - expect(comp.account).toBeNull(); - - // WHEN - authenticationState.next(account); - - // THEN - expect(comp.account).toEqual(account); - - // WHEN - comp.ngOnDestroy(); - authenticationState.next(null); - - // THEN - expect(comp.account).toEqual(account); - }); - }); -}); diff --git a/src/main/webapp/app/home/home.component.ts b/src/main/webapp/app/home/home.component.ts deleted file mode 100644 index 92c8e878c..000000000 --- a/src/main/webapp/app/home/home.component.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Component, OnInit, OnDestroy } from '@angular/core'; -import { Router, RouterModule } from '@angular/router'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; - -import SharedModule from 'app/shared/shared.module'; -import { AccountService } from 'app/core/auth/account.service'; -import { Account } from 'app/core/auth/account.model'; - -@Component({ - standalone: true, - selector: 'jhi-home', - templateUrl: './home.component.html', - styleUrls: ['./home.component.scss'], - imports: [SharedModule, RouterModule], -}) -export default class HomeComponent implements OnInit, OnDestroy { - account: Account | null = null; - - private readonly destroy$ = new Subject(); - - constructor(private accountService: AccountService, private router: Router) {} - - ngOnInit(): void { - this.accountService - .getAuthenticationState() - .pipe(takeUntil(this.destroy$)) - .subscribe(account => (this.account = account)); - } - - login(): void { - this.router.navigate(['/login']); - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } -} diff --git a/src/main/webapp/app/layouts/error/error.component.html b/src/main/webapp/app/layouts/error/error.component.html deleted file mode 100644 index c1b52a551..000000000 --- a/src/main/webapp/app/layouts/error/error.component.html +++ /dev/null @@ -1,15 +0,0 @@ -
-
-
- -
- -
-

Error page!

- -
-
{{ errorMessage }}
-
-
-
-
diff --git a/src/main/webapp/app/layouts/error/error.component.ts b/src/main/webapp/app/layouts/error/error.component.ts deleted file mode 100644 index 2d1d225b1..000000000 --- a/src/main/webapp/app/layouts/error/error.component.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Component, OnInit, OnDestroy } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Subscription } from 'rxjs'; -import { TranslateService } from '@ngx-translate/core'; -import SharedModule from 'app/shared/shared.module'; - -@Component({ - standalone: true, - selector: 'jhi-error', - templateUrl: './error.component.html', - imports: [SharedModule], -}) -export default class ErrorComponent implements OnInit, OnDestroy { - errorMessage?: string; - errorKey?: string; - langChangeSubscription?: Subscription; - - constructor(private translateService: TranslateService, private route: ActivatedRoute) {} - - ngOnInit(): void { - this.route.data.subscribe(routeData => { - if (routeData.errorMessage) { - this.errorKey = routeData.errorMessage; - this.getErrorMessageTranslation(); - this.langChangeSubscription = this.translateService.onLangChange.subscribe(() => this.getErrorMessageTranslation()); - } - }); - } - - ngOnDestroy(): void { - if (this.langChangeSubscription) { - this.langChangeSubscription.unsubscribe(); - } - } - - private getErrorMessageTranslation(): void { - this.errorMessage = ''; - if (this.errorKey) { - this.translateService.get(this.errorKey).subscribe(translatedErrorMessage => { - this.errorMessage = translatedErrorMessage; - }); - } - } -} diff --git a/src/main/webapp/app/layouts/error/error.route.ts b/src/main/webapp/app/layouts/error/error.route.ts deleted file mode 100644 index 85f911b5f..000000000 --- a/src/main/webapp/app/layouts/error/error.route.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Routes } from '@angular/router'; - -import ErrorComponent from './error.component'; - -export const errorRoute: Routes = [ - { - path: 'error', - component: ErrorComponent, - title: 'error.title', - }, - { - path: 'accessdenied', - component: ErrorComponent, - data: { - errorMessage: 'error.http.403', - }, - title: 'error.title', - }, - { - path: '404', - component: ErrorComponent, - data: { - errorMessage: 'error.http.404', - }, - title: 'error.title', - }, - { - path: '**', - redirectTo: '/404', - }, -]; diff --git a/src/main/webapp/app/layouts/footer/footer.component.html b/src/main/webapp/app/layouts/footer/footer.component.html deleted file mode 100644 index 30aca31d3..000000000 --- a/src/main/webapp/app/layouts/footer/footer.component.html +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/src/main/webapp/app/layouts/footer/footer.component.ts b/src/main/webapp/app/layouts/footer/footer.component.ts deleted file mode 100644 index 7ab093848..000000000 --- a/src/main/webapp/app/layouts/footer/footer.component.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - standalone: true, - selector: 'jhi-footer', - templateUrl: './footer.component.html', -}) -export default class FooterComponent {} diff --git a/src/main/webapp/app/layouts/main/main.component.html b/src/main/webapp/app/layouts/main/main.component.html deleted file mode 100644 index 3ac9be942..000000000 --- a/src/main/webapp/app/layouts/main/main.component.html +++ /dev/null @@ -1,13 +0,0 @@ - - -
- -
- -
-
- -
- - -
diff --git a/src/main/webapp/app/layouts/main/main.component.spec.ts b/src/main/webapp/app/layouts/main/main.component.spec.ts deleted file mode 100644 index 7f1ac9380..000000000 --- a/src/main/webapp/app/layouts/main/main.component.spec.ts +++ /dev/null @@ -1,230 +0,0 @@ -jest.mock('app/core/auth/account.service'); - -import { waitForAsync, ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; -import { Router, TitleStrategy } from '@angular/router'; -import { Title } from '@angular/platform-browser'; -import { RouterTestingModule } from '@angular/router/testing'; -import { DOCUMENT } from '@angular/common'; -import { Component } from '@angular/core'; -import { of } from 'rxjs'; -import { TranslateModule, TranslateService, LangChangeEvent } from '@ngx-translate/core'; - -import { AccountService } from 'app/core/auth/account.service'; - -import MainComponent from './main.component'; -import { AppPageTitleStrategy } from 'app/app-page-title-strategy'; - -describe('MainComponent', () => { - let comp: MainComponent; - let fixture: ComponentFixture; - let titleService: Title; - let translateService: TranslateService; - let mockAccountService: AccountService; - const routerState: any = { snapshot: { root: { data: {} } } }; - let router: Router; - let document: Document; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot(), RouterTestingModule], - declarations: [MainComponent], - providers: [Title, AccountService, { provide: TitleStrategy, useClass: AppPageTitleStrategy }], - }) - .overrideTemplate(MainComponent, '') - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(MainComponent); - comp = fixture.componentInstance; - titleService = TestBed.inject(Title); - translateService = TestBed.inject(TranslateService); - mockAccountService = TestBed.inject(AccountService); - mockAccountService.identity = jest.fn(() => of(null)); - mockAccountService.getAuthenticationState = jest.fn(() => of(null)); - router = TestBed.inject(Router); - document = TestBed.inject(DOCUMENT); - }); - - describe('page title', () => { - const defaultPageTitle = 'global.title'; - const parentRoutePageTitle = 'parentTitle'; - const childRoutePageTitle = 'childTitle'; - const langChangeEvent: LangChangeEvent = { lang: 'en', translations: null }; - - beforeEach(() => { - routerState.snapshot.root = { data: {} }; - jest.spyOn(translateService, 'get').mockImplementation((key: string | string[]) => of(`${key as string} translated`)); - translateService.currentLang = 'en'; - jest.spyOn(titleService, 'setTitle'); - comp.ngOnInit(); - }); - - describe('navigation end', () => { - it('should set page title to default title if pageTitle is missing on routes', fakeAsync(() => { - // WHEN - router.navigateByUrl(''); - tick(); - - // THEN - expect(document.title).toBe(defaultPageTitle + ' translated'); - })); - - it('should set page title to root route pageTitle if there is no child routes', fakeAsync(() => { - // GIVEN - router.resetConfig([{ path: '', title: parentRoutePageTitle, component: BlankComponent }]); - - // WHEN - router.navigateByUrl(''); - tick(); - - // THEN - expect(document.title).toBe(parentRoutePageTitle + ' translated'); - })); - - it('should set page title to child route pageTitle if child routes exist and pageTitle is set for child route', fakeAsync(() => { - // GIVEN - router.resetConfig([ - { - path: 'home', - title: parentRoutePageTitle, - children: [{ path: '', title: childRoutePageTitle, component: BlankComponent }], - }, - ]); - - // WHEN - router.navigateByUrl('home'); - tick(); - - // THEN - expect(document.title).toBe(childRoutePageTitle + ' translated'); - })); - - it('should set page title to parent route pageTitle if child routes exists but pageTitle is not set for child route data', fakeAsync(() => { - // GIVEN - router.resetConfig([ - { - path: 'home', - title: parentRoutePageTitle, - children: [{ path: '', component: BlankComponent }], - }, - ]); - - // WHEN - router.navigateByUrl('home'); - tick(); - - // THEN - expect(document.title).toBe(parentRoutePageTitle + ' translated'); - })); - }); - - describe('language change', () => { - it('should set page title to default title if pageTitle is missing on routes', () => { - // WHEN - translateService.onLangChange.emit(langChangeEvent); - - // THEN - expect(document.title).toBe(defaultPageTitle + ' translated'); - }); - - it('should set page title to root route pageTitle if there is no child routes', fakeAsync(() => { - // GIVEN - routerState.snapshot.root.data = { pageTitle: parentRoutePageTitle }; - router.resetConfig([{ path: '', title: parentRoutePageTitle, component: BlankComponent }]); - - // WHEN - router.navigateByUrl(''); - tick(); - - // THEN - expect(document.title).toBe(parentRoutePageTitle + ' translated'); - - // GIVEN - document.title = 'other title'; - - // WHEN - translateService.onLangChange.emit(langChangeEvent); - - // THEN - expect(document.title).toBe(parentRoutePageTitle + ' translated'); - })); - - it('should set page title to child route pageTitle if child routes exist and pageTitle is set for child route', fakeAsync(() => { - // GIVEN - router.resetConfig([ - { - path: 'home', - title: parentRoutePageTitle, - children: [{ path: '', title: childRoutePageTitle, component: BlankComponent }], - }, - ]); - - // WHEN - router.navigateByUrl('home'); - tick(); - - // THEN - expect(document.title).toBe(childRoutePageTitle + ' translated'); - - // GIVEN - document.title = 'other title'; - - // WHEN - translateService.onLangChange.emit(langChangeEvent); - - // THEN - expect(document.title).toBe(childRoutePageTitle + ' translated'); - })); - - it('should set page title to parent route pageTitle if child routes exists but pageTitle is not set for child route data', fakeAsync(() => { - // GIVEN - router.resetConfig([ - { - path: 'home', - title: parentRoutePageTitle, - children: [{ path: '', component: BlankComponent }], - }, - ]); - - // WHEN - router.navigateByUrl('home'); - tick(); - - // THEN - expect(document.title).toBe(parentRoutePageTitle + ' translated'); - - // GIVEN - document.title = 'other title'; - - // WHEN - translateService.onLangChange.emit(langChangeEvent); - - // THEN - expect(document.title).toBe(parentRoutePageTitle + ' translated'); - })); - }); - }); - - describe('page language attribute', () => { - it('should change page language attribute on language change', () => { - // GIVEN - comp.ngOnInit(); - - // WHEN - translateService.onLangChange.emit({ lang: 'lang1', translations: null }); - - // THEN - expect(document.querySelector('html')?.getAttribute('lang')).toEqual('lang1'); - - // WHEN - translateService.onLangChange.emit({ lang: 'lang2', translations: null }); - - // THEN - expect(document.querySelector('html')?.getAttribute('lang')).toEqual('lang2'); - }); - }); -}); - -@Component({ template: '' }) -export class BlankComponent {} diff --git a/src/main/webapp/app/layouts/main/main.component.ts b/src/main/webapp/app/layouts/main/main.component.ts deleted file mode 100644 index 7595066ab..000000000 --- a/src/main/webapp/app/layouts/main/main.component.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Component, OnInit, RendererFactory2, Renderer2 } from '@angular/core'; -import { TranslateService, LangChangeEvent } from '@ngx-translate/core'; -import dayjs from 'dayjs/esm'; - -import { AccountService } from 'app/core/auth/account.service'; -import { AppPageTitleStrategy } from 'app/app-page-title-strategy'; -import { Router } from '@angular/router'; - -@Component({ - selector: 'jhi-main', - templateUrl: './main.component.html', - providers: [AppPageTitleStrategy], -}) -export default class MainComponent implements OnInit { - private renderer: Renderer2; - - constructor( - private router: Router, - private appPageTitleStrategy: AppPageTitleStrategy, - private accountService: AccountService, - private translateService: TranslateService, - rootRenderer: RendererFactory2 - ) { - this.renderer = rootRenderer.createRenderer(document.querySelector('html'), null); - } - - ngOnInit(): void { - // try to log in automatically - this.accountService.identity().subscribe(); - - this.translateService.onLangChange.subscribe((langChangeEvent: LangChangeEvent) => { - this.appPageTitleStrategy.updateTitle(this.router.routerState.snapshot); - dayjs.locale(langChangeEvent.lang); - this.renderer.setAttribute(document.querySelector('html'), 'lang', langChangeEvent.lang); - }); - } -} diff --git a/src/main/webapp/app/layouts/main/main.module.ts b/src/main/webapp/app/layouts/main/main.module.ts deleted file mode 100644 index b2f56765a..000000000 --- a/src/main/webapp/app/layouts/main/main.module.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; - -import SharedModule from 'app/shared/shared.module'; -import MainComponent from './main.component'; -import FooterComponent from '../footer/footer.component'; -import PageRibbonComponent from '../profiles/page-ribbon.component'; - -@NgModule({ - imports: [SharedModule, RouterModule, FooterComponent, PageRibbonComponent], - declarations: [MainComponent], -}) -export default class MainModule {} diff --git a/src/main/webapp/app/layouts/navbar/active-menu.directive.ts b/src/main/webapp/app/layouts/navbar/active-menu.directive.ts deleted file mode 100644 index 67edf7b9e..000000000 --- a/src/main/webapp/app/layouts/navbar/active-menu.directive.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Directive, OnInit, ElementRef, Renderer2, Input } from '@angular/core'; -import { TranslateService, LangChangeEvent } from '@ngx-translate/core'; - -@Directive({ - standalone: true, - selector: '[jhiActiveMenu]', -}) -export default class ActiveMenuDirective implements OnInit { - @Input() jhiActiveMenu?: string; - - constructor(private el: ElementRef, private renderer: Renderer2, private translateService: TranslateService) {} - - ngOnInit(): void { - this.translateService.onLangChange.subscribe((event: LangChangeEvent) => { - this.updateActiveFlag(event.lang); - }); - - this.updateActiveFlag(this.translateService.currentLang); - } - - updateActiveFlag(selectedLanguage: string): void { - if (this.jhiActiveMenu === selectedLanguage) { - this.renderer.addClass(this.el.nativeElement, 'active'); - } else { - this.renderer.removeClass(this.el.nativeElement, 'active'); - } - } -} diff --git a/src/main/webapp/app/layouts/navbar/navbar-item.model.d.ts b/src/main/webapp/app/layouts/navbar/navbar-item.model.d.ts deleted file mode 100644 index d6f1cca11..000000000 --- a/src/main/webapp/app/layouts/navbar/navbar-item.model.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -type NavbarItem = { - name: string; - route: string; - translationKey: string; -}; - -export default NavbarItem; diff --git a/src/main/webapp/app/layouts/navbar/navbar.component.html b/src/main/webapp/app/layouts/navbar/navbar.component.html deleted file mode 100644 index 396564c0b..000000000 --- a/src/main/webapp/app/layouts/navbar/navbar.component.html +++ /dev/null @@ -1,234 +0,0 @@ - diff --git a/src/main/webapp/app/layouts/navbar/navbar.component.scss b/src/main/webapp/app/layouts/navbar/navbar.component.scss deleted file mode 100644 index 4c038a267..000000000 --- a/src/main/webapp/app/layouts/navbar/navbar.component.scss +++ /dev/null @@ -1,36 +0,0 @@ -@import 'bootstrap/scss/functions'; -@import 'bootstrap/scss/variables'; - -/* ========================================================================== -Navbar -========================================================================== */ - -.navbar-version { - font-size: 0.65em; - color: $navbar-dark-color; -} - -.profile-image { - height: 1.75em; - width: 1.75em; -} - -.navbar { - padding: 0.2rem 1rem; - - a.nav-link { - font-weight: 400; - } -} - -/* ========================================================================== -Logo styles -========================================================================== */ -.logo-img { - height: 45px; - width: 45px; - display: inline-block; - vertical-align: middle; - background: url('/content/images/logo-jhipster.png') no-repeat center center; - background-size: contain; -} diff --git a/src/main/webapp/app/layouts/navbar/navbar.component.spec.ts b/src/main/webapp/app/layouts/navbar/navbar.component.spec.ts deleted file mode 100644 index 983b1c594..000000000 --- a/src/main/webapp/app/layouts/navbar/navbar.component.spec.ts +++ /dev/null @@ -1,96 +0,0 @@ -jest.mock('app/login/login.service'); - -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { RouterTestingModule } from '@angular/router/testing'; -import { of } from 'rxjs'; -import { TranslateModule } from '@ngx-translate/core'; - -import { ProfileInfo } from 'app/layouts/profiles/profile-info.model'; -import { Account } from 'app/core/auth/account.model'; -import { AccountService } from 'app/core/auth/account.service'; -import { ProfileService } from 'app/layouts/profiles/profile.service'; -import { LoginService } from 'app/login/login.service'; - -import NavbarComponent from './navbar.component'; - -describe('Navbar Component', () => { - let comp: NavbarComponent; - let fixture: ComponentFixture; - let accountService: AccountService; - let profileService: ProfileService; - const account: Account = { - activated: true, - authorities: [], - email: '', - firstName: 'John', - langKey: '', - lastName: 'Doe', - login: 'john.doe', - imageUrl: '', - }; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [NavbarComponent, HttpClientTestingModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot()], - providers: [LoginService], - }) - .overrideTemplate(NavbarComponent, '') - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(NavbarComponent); - comp = fixture.componentInstance; - accountService = TestBed.inject(AccountService); - profileService = TestBed.inject(ProfileService); - }); - - it('Should call profileService.getProfileInfo on init', () => { - // GIVEN - jest.spyOn(profileService, 'getProfileInfo').mockReturnValue(of(new ProfileInfo())); - - // WHEN - comp.ngOnInit(); - - // THEN - expect(profileService.getProfileInfo).toHaveBeenCalled(); - }); - - it('Should hold current authenticated user in variable account', () => { - // WHEN - comp.ngOnInit(); - - // THEN - expect(comp.account).toBeNull(); - - // WHEN - accountService.authenticate(account); - - // THEN - expect(comp.account).toEqual(account); - - // WHEN - accountService.authenticate(null); - - // THEN - expect(comp.account).toBeNull(); - }); - - it('Should hold current authenticated user in variable account if user is authenticated before page load', () => { - // GIVEN - accountService.authenticate(account); - - // WHEN - comp.ngOnInit(); - - // THEN - expect(comp.account).toEqual(account); - - // WHEN - accountService.authenticate(null); - - // THEN - expect(comp.account).toBeNull(); - }); -}); diff --git a/src/main/webapp/app/layouts/navbar/navbar.component.ts b/src/main/webapp/app/layouts/navbar/navbar.component.ts deleted file mode 100644 index e76351a74..000000000 --- a/src/main/webapp/app/layouts/navbar/navbar.component.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { Router, RouterModule } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; - -import { StateStorageService } from 'app/core/auth/state-storage.service'; -import SharedModule from 'app/shared/shared.module'; -import HasAnyAuthorityDirective from 'app/shared/auth/has-any-authority.directive'; -import { VERSION } from 'app/app.constants'; -import { LANGUAGES } from 'app/config/language.constants'; -import ActiveMenuDirective from './active-menu.directive'; -import { Account } from 'app/core/auth/account.model'; -import { AccountService } from 'app/core/auth/account.service'; -import { LoginService } from 'app/login/login.service'; -import { ProfileService } from 'app/layouts/profiles/profile.service'; -import { EntityNavbarItems } from 'app/entities/entity-navbar-items'; -import NavbarItem from './navbar-item.model'; - -@Component({ - standalone: true, - selector: 'jhi-navbar', - templateUrl: './navbar.component.html', - styleUrls: ['./navbar.component.scss'], - imports: [RouterModule, SharedModule, HasAnyAuthorityDirective, ActiveMenuDirective], -}) -export default class NavbarComponent implements OnInit { - inProduction?: boolean; - isNavbarCollapsed = true; - languages = LANGUAGES; - openAPIEnabled?: boolean; - version = ''; - account: Account | null = null; - entitiesNavbarItems: NavbarItem[] = []; - - constructor( - private loginService: LoginService, - private translateService: TranslateService, - private stateStorageService: StateStorageService, - private accountService: AccountService, - private profileService: ProfileService, - private router: Router - ) { - if (VERSION) { - this.version = VERSION.toLowerCase().startsWith('v') ? VERSION : `v${VERSION}`; - } - } - - ngOnInit(): void { - this.entitiesNavbarItems = EntityNavbarItems; - this.profileService.getProfileInfo().subscribe(profileInfo => { - this.inProduction = profileInfo.inProduction; - this.openAPIEnabled = profileInfo.openAPIEnabled; - }); - - this.accountService.getAuthenticationState().subscribe(account => { - this.account = account; - }); - } - - changeLanguage(languageKey: string): void { - this.stateStorageService.storeLocale(languageKey); - this.translateService.use(languageKey); - } - - collapseNavbar(): void { - this.isNavbarCollapsed = true; - } - - login(): void { - this.router.navigate(['/login']); - } - - logout(): void { - this.collapseNavbar(); - this.loginService.logout(); - this.router.navigate(['']); - } - - toggleNavbar(): void { - this.isNavbarCollapsed = !this.isNavbarCollapsed; - } -} diff --git a/src/main/webapp/app/layouts/profiles/page-ribbon.component.scss b/src/main/webapp/app/layouts/profiles/page-ribbon.component.scss deleted file mode 100644 index 88b060226..000000000 --- a/src/main/webapp/app/layouts/profiles/page-ribbon.component.scss +++ /dev/null @@ -1,25 +0,0 @@ -/* ========================================================================== -Developement Ribbon -========================================================================== */ -.ribbon { - background-color: rgba(170, 0, 0, 0.5); - overflow: hidden; - position: absolute; - top: 40px; - white-space: nowrap; - width: 15em; - z-index: 9999; - pointer-events: none; - opacity: 0.75; - a { - color: #fff; - display: block; - font-weight: 400; - margin: 1px 0; - padding: 10px 50px; - text-align: center; - text-decoration: none; - text-shadow: 0 0 5px #444; - pointer-events: none; - } -} diff --git a/src/main/webapp/app/layouts/profiles/page-ribbon.component.spec.ts b/src/main/webapp/app/layouts/profiles/page-ribbon.component.spec.ts deleted file mode 100644 index 4d5176cda..000000000 --- a/src/main/webapp/app/layouts/profiles/page-ribbon.component.spec.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { of } from 'rxjs'; - -import { ProfileInfo } from 'app/layouts/profiles/profile-info.model'; -import { ProfileService } from 'app/layouts/profiles/profile.service'; - -import PageRibbonComponent from './page-ribbon.component'; - -describe('Page Ribbon Component', () => { - let comp: PageRibbonComponent; - let fixture: ComponentFixture; - let profileService: ProfileService; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, PageRibbonComponent], - }) - .overrideTemplate(PageRibbonComponent, '') - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(PageRibbonComponent); - comp = fixture.componentInstance; - profileService = TestBed.inject(ProfileService); - }); - - it('Should call profileService.getProfileInfo on init', () => { - // GIVEN - jest.spyOn(profileService, 'getProfileInfo').mockReturnValue(of(new ProfileInfo())); - - // WHEN - comp.ngOnInit(); - - // THEN - expect(profileService.getProfileInfo).toHaveBeenCalled(); - }); -}); diff --git a/src/main/webapp/app/layouts/profiles/page-ribbon.component.ts b/src/main/webapp/app/layouts/profiles/page-ribbon.component.ts deleted file mode 100644 index 1cd00f64f..000000000 --- a/src/main/webapp/app/layouts/profiles/page-ribbon.component.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; - -import SharedModule from 'app/shared/shared.module'; -import { ProfileService } from './profile.service'; - -@Component({ - standalone: true, - selector: 'jhi-page-ribbon', - template: ` - - `, - styleUrls: ['./page-ribbon.component.scss'], - imports: [SharedModule], -}) -export default class PageRibbonComponent implements OnInit { - ribbonEnv$?: Observable; - - constructor(private profileService: ProfileService) {} - - ngOnInit(): void { - this.ribbonEnv$ = this.profileService.getProfileInfo().pipe(map(profileInfo => profileInfo.ribbonEnv)); - } -} diff --git a/src/main/webapp/app/layouts/profiles/profile-info.model.ts b/src/main/webapp/app/layouts/profiles/profile-info.model.ts deleted file mode 100644 index 8c769c740..000000000 --- a/src/main/webapp/app/layouts/profiles/profile-info.model.ts +++ /dev/null @@ -1,15 +0,0 @@ -export interface InfoResponse { - 'display-ribbon-on-profiles'?: string; - git?: any; - build?: any; - activeProfiles?: string[]; -} - -export class ProfileInfo { - constructor( - public activeProfiles?: string[], - public ribbonEnv?: string, - public inProduction?: boolean, - public openAPIEnabled?: boolean - ) {} -} diff --git a/src/main/webapp/app/layouts/profiles/profile.service.ts b/src/main/webapp/app/layouts/profiles/profile.service.ts deleted file mode 100644 index b379d3cbb..000000000 --- a/src/main/webapp/app/layouts/profiles/profile.service.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { map, shareReplay } from 'rxjs/operators'; -import { Observable } from 'rxjs'; - -import { ApplicationConfigService } from 'app/core/config/application-config.service'; -import { ProfileInfo, InfoResponse } from './profile-info.model'; - -@Injectable({ providedIn: 'root' }) -export class ProfileService { - private infoUrl = this.applicationConfigService.getEndpointFor('management/info'); - private profileInfo$?: Observable; - - constructor(private http: HttpClient, private applicationConfigService: ApplicationConfigService) {} - - getProfileInfo(): Observable { - if (this.profileInfo$) { - return this.profileInfo$; - } - - this.profileInfo$ = this.http.get(this.infoUrl).pipe( - map((response: InfoResponse) => { - const profileInfo: ProfileInfo = { - activeProfiles: response.activeProfiles, - inProduction: response.activeProfiles?.includes('prod'), - openAPIEnabled: response.activeProfiles?.includes('api-docs'), - }; - if (response.activeProfiles && response['display-ribbon-on-profiles']) { - const displayRibbonOnProfiles = response['display-ribbon-on-profiles'].split(','); - const ribbonProfiles = displayRibbonOnProfiles.filter(profile => response.activeProfiles?.includes(profile)); - if (ribbonProfiles.length > 0) { - profileInfo.ribbonEnv = ribbonProfiles[0]; - } - } - return profileInfo; - }), - shareReplay() - ); - return this.profileInfo$; - } -} diff --git a/src/main/webapp/app/login/login.component.html b/src/main/webapp/app/login/login.component.html deleted file mode 100644 index f4e6b31bb..000000000 --- a/src/main/webapp/app/login/login.component.html +++ /dev/null @@ -1,57 +0,0 @@ -
-
-
-

Sign in

-
- Failed to sign in! Please check your credentials and try again. -
-
-
- - -
- -
- - -
- -
- -
- - -
- - -
- You don't have an account yet? - Register a new account -
-
-
-
diff --git a/src/main/webapp/app/login/login.component.spec.ts b/src/main/webapp/app/login/login.component.spec.ts deleted file mode 100644 index b537b6020..000000000 --- a/src/main/webapp/app/login/login.component.spec.ts +++ /dev/null @@ -1,152 +0,0 @@ -jest.mock('app/core/auth/account.service'); -jest.mock('app/login/login.service'); - -import { ElementRef } from '@angular/core'; -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { FormBuilder } from '@angular/forms'; -import { Router, Navigation } from '@angular/router'; -import { RouterTestingModule } from '@angular/router/testing'; -import { of, throwError } from 'rxjs'; - -import { AccountService } from 'app/core/auth/account.service'; - -import { LoginService } from './login.service'; -import LoginComponent from './login.component'; - -describe('LoginComponent', () => { - let comp: LoginComponent; - let fixture: ComponentFixture; - let mockRouter: Router; - let mockAccountService: AccountService; - let mockLoginService: LoginService; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [RouterTestingModule.withRoutes([]), LoginComponent], - providers: [ - FormBuilder, - AccountService, - { - provide: LoginService, - useValue: { - login: jest.fn(() => of({})), - }, - }, - ], - }) - .overrideTemplate(LoginComponent, '') - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(LoginComponent); - comp = fixture.componentInstance; - mockRouter = TestBed.inject(Router); - jest.spyOn(mockRouter, 'navigate').mockImplementation(() => Promise.resolve(true)); - mockLoginService = TestBed.inject(LoginService); - mockAccountService = TestBed.inject(AccountService); - }); - - describe('ngOnInit', () => { - it('Should call accountService.identity on Init', () => { - // GIVEN - mockAccountService.identity = jest.fn(() => of(null)); - mockAccountService.getAuthenticationState = jest.fn(() => of(null)); - - // WHEN - comp.ngOnInit(); - - // THEN - expect(mockAccountService.identity).toHaveBeenCalled(); - }); - - it('Should call accountService.isAuthenticated on Init', () => { - // GIVEN - mockAccountService.identity = jest.fn(() => of(null)); - - // WHEN - comp.ngOnInit(); - - // THEN - expect(mockAccountService.isAuthenticated).toHaveBeenCalled(); - }); - - it('should navigate to home page on Init if authenticated=true', () => { - // GIVEN - mockAccountService.identity = jest.fn(() => of(null)); - mockAccountService.getAuthenticationState = jest.fn(() => of(null)); - mockAccountService.isAuthenticated = () => true; - - // WHEN - comp.ngOnInit(); - - // THEN - expect(mockRouter.navigate).toHaveBeenCalledWith(['']); - }); - }); - - describe('ngAfterViewInit', () => { - it('shoult set focus to username input after the view has been initialized', () => { - // GIVEN - const node = { - focus: jest.fn(), - }; - comp.username = new ElementRef(node); - - // WHEN - comp.ngAfterViewInit(); - - // THEN - expect(node.focus).toHaveBeenCalled(); - }); - }); - - describe('login', () => { - it('should authenticate the user and navigate to home page', () => { - // GIVEN - const credentials = { - username: 'admin', - password: 'admin', - rememberMe: true, - }; - - comp.loginForm.patchValue({ - username: 'admin', - password: 'admin', - rememberMe: true, - }); - - // WHEN - comp.login(); - - // THEN - expect(comp.authenticationError).toEqual(false); - expect(mockLoginService.login).toHaveBeenCalledWith(credentials); - expect(mockRouter.navigate).toHaveBeenCalledWith(['']); - }); - - it('should authenticate the user but not navigate to home page if authentication process is already routing to cached url from localstorage', () => { - // GIVEN - jest.spyOn(mockRouter, 'getCurrentNavigation').mockReturnValue({} as Navigation); - - // WHEN - comp.login(); - - // THEN - expect(comp.authenticationError).toEqual(false); - expect(mockRouter.navigate).not.toHaveBeenCalled(); - }); - - it('should stay on login form and show error message on login error', () => { - // GIVEN - mockLoginService.login = jest.fn(() => throwError({})); - - // WHEN - comp.login(); - - // THEN - expect(comp.authenticationError).toEqual(true); - expect(mockRouter.navigate).not.toHaveBeenCalled(); - }); - }); -}); diff --git a/src/main/webapp/app/login/login.component.ts b/src/main/webapp/app/login/login.component.ts deleted file mode 100644 index 517e7c71e..000000000 --- a/src/main/webapp/app/login/login.component.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { Component, ViewChild, OnInit, AfterViewInit, ElementRef } from '@angular/core'; -import { FormGroup, FormControl, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { Router, RouterModule } from '@angular/router'; - -import SharedModule from 'app/shared/shared.module'; -import { LoginService } from 'app/login/login.service'; -import { AccountService } from 'app/core/auth/account.service'; - -@Component({ - selector: 'jhi-login', - standalone: true, - imports: [SharedModule, FormsModule, ReactiveFormsModule, RouterModule], - templateUrl: './login.component.html', -}) -export default class LoginComponent implements OnInit, AfterViewInit { - @ViewChild('username', { static: false }) - username!: ElementRef; - - authenticationError = false; - - loginForm = new FormGroup({ - username: new FormControl('', { nonNullable: true, validators: [Validators.required] }), - password: new FormControl('', { nonNullable: true, validators: [Validators.required] }), - rememberMe: new FormControl(false, { nonNullable: true, validators: [Validators.required] }), - }); - - constructor(private accountService: AccountService, private loginService: LoginService, private router: Router) {} - - ngOnInit(): void { - // if already authenticated then navigate to home page - this.accountService.identity().subscribe(() => { - if (this.accountService.isAuthenticated()) { - this.router.navigate(['']); - } - }); - } - - ngAfterViewInit(): void { - this.username.nativeElement.focus(); - } - - login(): void { - this.loginService.login(this.loginForm.getRawValue()).subscribe({ - next: () => { - this.authenticationError = false; - if (!this.router.getCurrentNavigation()) { - // There were no routing during login (eg from navigationToStoredUrl) - this.router.navigate(['']); - } - }, - error: () => (this.authenticationError = true), - }); - } -} diff --git a/src/main/webapp/app/login/login.model.ts b/src/main/webapp/app/login/login.model.ts deleted file mode 100644 index 422fce9a0..000000000 --- a/src/main/webapp/app/login/login.model.ts +++ /dev/null @@ -1,3 +0,0 @@ -export class Login { - constructor(public username: string, public password: string, public rememberMe: boolean) {} -} diff --git a/src/main/webapp/app/login/login.service.ts b/src/main/webapp/app/login/login.service.ts deleted file mode 100644 index bc97be6e2..000000000 --- a/src/main/webapp/app/login/login.service.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { mergeMap } from 'rxjs/operators'; - -import { Account } from 'app/core/auth/account.model'; -import { AccountService } from 'app/core/auth/account.service'; -import { AuthServerProvider } from 'app/core/auth/auth-jwt.service'; -import { Login } from './login.model'; - -@Injectable({ providedIn: 'root' }) -export class LoginService { - constructor(private accountService: AccountService, private authServerProvider: AuthServerProvider) {} - - login(credentials: Login): Observable { - return this.authServerProvider.login(credentials).pipe(mergeMap(() => this.accountService.identity(true))); - } - - logout(): void { - this.authServerProvider.logout().subscribe({ complete: () => this.accountService.authenticate(null) }); - } -} diff --git a/src/main/webapp/app/shared/alert/alert-error.component.html b/src/main/webapp/app/shared/alert/alert-error.component.html deleted file mode 100644 index 76ff881dd..000000000 --- a/src/main/webapp/app/shared/alert/alert-error.component.html +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/src/main/webapp/app/shared/alert/alert-error.component.spec.ts b/src/main/webapp/app/shared/alert/alert-error.component.spec.ts deleted file mode 100644 index ef51799b0..000000000 --- a/src/main/webapp/app/shared/alert/alert-error.component.spec.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { HttpErrorResponse, HttpHeaders } from '@angular/common/http'; -import { TranslateModule } from '@ngx-translate/core'; - -import { EventManager } from 'app/core/util/event-manager.service'; -import { Alert, AlertService } from 'app/core/util/alert.service'; - -import { AlertErrorComponent } from './alert-error.component'; - -describe('Alert Error Component', () => { - let comp: AlertErrorComponent; - let fixture: ComponentFixture; - let eventManager: EventManager; - let alertService: AlertService; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot(), AlertErrorComponent], - providers: [EventManager, AlertService], - }) - .overrideTemplate(AlertErrorComponent, '') - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(AlertErrorComponent); - comp = fixture.componentInstance; - eventManager = TestBed.inject(EventManager); - alertService = TestBed.inject(AlertService); - alertService.addAlert = (alert: Alert, alerts?: Alert[]) => { - if (alerts) { - alerts.push(alert); - } - return alert; - }; - }); - - describe('Error Handling', () => { - it('Should display an alert on status 0', () => { - // GIVEN - eventManager.broadcast({ name: 'jhipsterSampleApplicationApp.httpError', content: { status: 0 } }); - // THEN - expect(comp.alerts.length).toBe(1); - expect(comp.alerts[0].translationKey).toBe('error.server.not.reachable'); - }); - - it('Should display an alert on status 404', () => { - // GIVEN - eventManager.broadcast({ name: 'jhipsterSampleApplicationApp.httpError', content: { status: 404 } }); - // THEN - expect(comp.alerts.length).toBe(1); - expect(comp.alerts[0].translationKey).toBe('error.url.not.found'); - }); - - it('Should display an alert on generic error', () => { - // GIVEN - eventManager.broadcast({ name: 'jhipsterSampleApplicationApp.httpError', content: { error: { message: 'Error Message' } } }); - eventManager.broadcast({ name: 'jhipsterSampleApplicationApp.httpError', content: { error: 'Second Error Message' } }); - // THEN - expect(comp.alerts.length).toBe(2); - expect(comp.alerts[0].translationKey).toBe('Error Message'); - expect(comp.alerts[1].translationKey).toBe('Second Error Message'); - }); - - it('Should display an alert on status 400 for generic error', () => { - // GIVEN - const response = new HttpErrorResponse({ - url: 'http://localhost:8080/api/foos', - headers: new HttpHeaders(), - status: 400, - statusText: 'Bad Request', - error: { - type: 'https://www.jhipster.tech/problem/constraint-violation', - title: 'Bad Request', - status: 400, - path: '/api/foos', - message: 'error.validation', - }, - }); - eventManager.broadcast({ name: 'jhipsterSampleApplicationApp.httpError', content: response }); - // THEN - expect(comp.alerts.length).toBe(1); - expect(comp.alerts[0].translationKey).toBe('error.validation'); - }); - - it('Should display an alert on status 400 for generic error without message', () => { - // GIVEN - const response = new HttpErrorResponse({ - url: 'http://localhost:8080/api/foos', - headers: new HttpHeaders(), - status: 400, - error: 'Bad Request', - }); - eventManager.broadcast({ name: 'jhipsterSampleApplicationApp.httpError', content: response }); - // THEN - expect(comp.alerts.length).toBe(1); - expect(comp.alerts[0].translationKey).toBe('Bad Request'); - }); - - it('Should display an alert on status 400 for invalid parameters', () => { - // GIVEN - const response = new HttpErrorResponse({ - url: 'http://localhost:8080/api/foos', - headers: new HttpHeaders(), - status: 400, - statusText: 'Bad Request', - error: { - type: 'https://www.jhipster.tech/problem/constraint-violation', - title: 'Method argument not valid', - status: 400, - path: '/api/foos', - message: 'error.validation', - fieldErrors: [{ objectName: 'foo', field: 'minField', message: 'Min' }], - }, - }); - eventManager.broadcast({ name: 'jhipsterSampleApplicationApp.httpError', content: response }); - // THEN - expect(comp.alerts.length).toBe(1); - expect(comp.alerts[0].translationKey).toBe('error.Size'); - }); - - it('Should display an alert on status 400 for error headers', () => { - // GIVEN - const response = new HttpErrorResponse({ - url: 'http://localhost:8080/api/foos', - headers: new HttpHeaders().append('app-error', 'Error Message').append('app-params', 'foo'), - status: 400, - statusText: 'Bad Request', - error: { - status: 400, - message: 'error.validation', - }, - }); - eventManager.broadcast({ name: 'jhipsterSampleApplicationApp.httpError', content: response }); - // THEN - expect(comp.alerts.length).toBe(1); - expect(comp.alerts[0].translationKey).toBe('Error Message'); - }); - - it('Should display an alert on status 500 with detail', () => { - // GIVEN - const response = new HttpErrorResponse({ - url: 'http://localhost:8080/api/foos', - headers: new HttpHeaders(), - status: 500, - statusText: 'Internal server error', - error: { - status: 500, - message: 'error.http.500', - detail: 'Detailed error message', - }, - }); - eventManager.broadcast({ name: 'jhipsterSampleApplicationApp.httpError', content: response }); - // THEN - expect(comp.alerts.length).toBe(1); - expect(comp.alerts[0].translationKey).toBe('error.http.500'); - }); - }); -}); diff --git a/src/main/webapp/app/shared/alert/alert-error.component.ts b/src/main/webapp/app/shared/alert/alert-error.component.ts deleted file mode 100644 index a6268542b..000000000 --- a/src/main/webapp/app/shared/alert/alert-error.component.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { Component, OnDestroy } from '@angular/core'; -import { HttpErrorResponse } from '@angular/common/http'; -import { Subscription } from 'rxjs'; -import { CommonModule } from '@angular/common'; -import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; -import { TranslateService } from '@ngx-translate/core'; - -import { AlertError } from './alert-error.model'; -import { Alert, AlertService } from 'app/core/util/alert.service'; -import { EventManager, EventWithContent } from 'app/core/util/event-manager.service'; - -@Component({ - standalone: true, - selector: 'jhi-alert-error', - templateUrl: './alert-error.component.html', - imports: [CommonModule, NgbModule], -}) -export class AlertErrorComponent implements OnDestroy { - alerts: Alert[] = []; - errorListener: Subscription; - httpErrorListener: Subscription; - - constructor(private alertService: AlertService, private eventManager: EventManager, translateService: TranslateService) { - this.errorListener = eventManager.subscribe('jhipsterSampleApplicationApp.error', (response: EventWithContent | string) => { - const errorResponse = (response as EventWithContent).content; - this.addErrorAlert(errorResponse.message, errorResponse.key, errorResponse.params); - }); - - this.httpErrorListener = eventManager.subscribe( - 'jhipsterSampleApplicationApp.httpError', - (response: EventWithContent | string) => { - const httpErrorResponse = (response as EventWithContent).content; - switch (httpErrorResponse.status) { - // connection refused, server not reachable - case 0: - this.addErrorAlert('Server not reachable', 'error.server.not.reachable'); - break; - - case 400: { - const arr = httpErrorResponse.headers.keys(); - let errorHeader: string | null = null; - let entityKey: string | null = null; - for (const entry of arr) { - if (entry.toLowerCase().endsWith('app-error')) { - errorHeader = httpErrorResponse.headers.get(entry); - } else if (entry.toLowerCase().endsWith('app-params')) { - entityKey = httpErrorResponse.headers.get(entry); - } - } - if (errorHeader) { - const alertData = entityKey ? { entityName: translateService.instant(`global.menu.entities.${entityKey}`) } : undefined; - this.addErrorAlert(errorHeader, errorHeader, alertData); - } else if (httpErrorResponse.error !== '' && httpErrorResponse.error.fieldErrors) { - const fieldErrors = httpErrorResponse.error.fieldErrors; - for (const fieldError of fieldErrors) { - if (['Min', 'Max', 'DecimalMin', 'DecimalMax'].includes(fieldError.message)) { - fieldError.message = 'Size'; - } - // convert 'something[14].other[4].id' to 'something[].other[].id' so translations can be written to it - const convertedField: string = fieldError.field.replace(/\[\d*\]/g, '[]'); - const fieldName: string = translateService.instant( - `jhipsterSampleApplicationApp.${fieldError.objectName as string}.${convertedField}` - ); - this.addErrorAlert(`Error on field "${fieldName}"`, `error.${fieldError.message as string}`, { fieldName }); - } - } else if (httpErrorResponse.error !== '' && httpErrorResponse.error.message) { - this.addErrorAlert( - httpErrorResponse.error.detail ?? httpErrorResponse.error.message, - httpErrorResponse.error.message, - httpErrorResponse.error.params - ); - } else { - this.addErrorAlert(httpErrorResponse.error, httpErrorResponse.error); - } - break; - } - - case 404: - this.addErrorAlert('Not found', 'error.url.not.found'); - break; - - default: - if (httpErrorResponse.error !== '' && httpErrorResponse.error.message) { - this.addErrorAlert( - httpErrorResponse.error.detail ?? httpErrorResponse.error.message, - httpErrorResponse.error.message, - httpErrorResponse.error.params - ); - } else { - this.addErrorAlert(httpErrorResponse.error, httpErrorResponse.error); - } - } - } - ); - } - - setClasses(alert: Alert): { [key: string]: boolean } { - const classes = { 'jhi-toast': Boolean(alert.toast) }; - if (alert.position) { - return { ...classes, [alert.position]: true }; - } - return classes; - } - - ngOnDestroy(): void { - this.eventManager.destroy(this.errorListener); - this.eventManager.destroy(this.httpErrorListener); - } - - close(alert: Alert): void { - alert.close?.(this.alerts); - } - - private addErrorAlert(message?: string, translationKey?: string, translationParams?: { [key: string]: unknown }): void { - this.alertService.addAlert({ type: 'danger', message, translationKey, translationParams }, this.alerts); - } -} diff --git a/src/main/webapp/app/shared/alert/alert-error.model.ts b/src/main/webapp/app/shared/alert/alert-error.model.ts deleted file mode 100644 index 4fca767cc..000000000 --- a/src/main/webapp/app/shared/alert/alert-error.model.ts +++ /dev/null @@ -1,3 +0,0 @@ -export class AlertError { - constructor(public message: string, public key?: string, public params?: { [key: string]: unknown }) {} -} diff --git a/src/main/webapp/app/shared/alert/alert.component.html b/src/main/webapp/app/shared/alert/alert.component.html deleted file mode 100644 index 76ff881dd..000000000 --- a/src/main/webapp/app/shared/alert/alert.component.html +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/src/main/webapp/app/shared/alert/alert.component.spec.ts b/src/main/webapp/app/shared/alert/alert.component.spec.ts deleted file mode 100644 index 79fe41fa4..000000000 --- a/src/main/webapp/app/shared/alert/alert.component.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -jest.mock('app/core/util/alert.service'); - -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; - -import { AlertService } from 'app/core/util/alert.service'; - -import { AlertComponent } from './alert.component'; - -describe('Alert Component', () => { - let comp: AlertComponent; - let fixture: ComponentFixture; - let mockAlertService: AlertService; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [AlertComponent], - providers: [AlertService], - }) - .overrideTemplate(AlertComponent, '') - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(AlertComponent); - comp = fixture.componentInstance; - mockAlertService = TestBed.inject(AlertService); - }); - - it('Should call alertService.get on init', () => { - // WHEN - comp.ngOnInit(); - - // THEN - expect(mockAlertService.get).toHaveBeenCalled(); - }); - - it('Should call alertService.clear on destroy', () => { - // WHEN - comp.ngOnDestroy(); - - // THEN - expect(mockAlertService.clear).toHaveBeenCalled(); - }); -}); diff --git a/src/main/webapp/app/shared/alert/alert.component.ts b/src/main/webapp/app/shared/alert/alert.component.ts deleted file mode 100644 index 098a90f54..000000000 --- a/src/main/webapp/app/shared/alert/alert.component.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; - -import { AlertService, Alert } from 'app/core/util/alert.service'; - -@Component({ - standalone: true, - selector: 'jhi-alert', - templateUrl: './alert.component.html', - imports: [CommonModule, NgbModule], -}) -export class AlertComponent implements OnInit, OnDestroy { - alerts: Alert[] = []; - - constructor(private alertService: AlertService) {} - - ngOnInit(): void { - this.alerts = this.alertService.get(); - } - - setClasses(alert: Alert): { [key: string]: boolean } { - const classes = { 'jhi-toast': Boolean(alert.toast) }; - if (alert.position) { - return { ...classes, [alert.position]: true }; - } - return classes; - } - - ngOnDestroy(): void { - this.alertService.clear(); - } - - close(alert: Alert): void { - alert.close?.(this.alerts); - } -} diff --git a/src/main/webapp/app/shared/auth/has-any-authority.directive.spec.ts b/src/main/webapp/app/shared/auth/has-any-authority.directive.spec.ts deleted file mode 100644 index 3b8c21a28..000000000 --- a/src/main/webapp/app/shared/auth/has-any-authority.directive.spec.ts +++ /dev/null @@ -1,131 +0,0 @@ -jest.mock('app/core/auth/account.service'); - -import { Component, ElementRef, ViewChild } from '@angular/core'; -import { TestBed, waitForAsync } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { Subject } from 'rxjs'; - -import { AccountService } from 'app/core/auth/account.service'; -import { Account } from 'app/core/auth/account.model'; - -import HasAnyAuthorityDirective from './has-any-authority.directive'; - -@Component({ - template: `
`, -}) -class TestHasAnyAuthorityDirectiveComponent { - @ViewChild('content', { static: false }) - content?: ElementRef; -} - -describe('HasAnyAuthorityDirective tests', () => { - let mockAccountService: AccountService; - const authenticationState = new Subject(); - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [HasAnyAuthorityDirective], - declarations: [TestHasAnyAuthorityDirectiveComponent], - providers: [AccountService], - }); - })); - - beforeEach(() => { - mockAccountService = TestBed.inject(AccountService); - mockAccountService.getAuthenticationState = jest.fn(() => authenticationState.asObservable()); - }); - - describe('set jhiHasAnyAuthority', () => { - it('should show restricted content to user if user has required role', () => { - // GIVEN - mockAccountService.hasAnyAuthority = jest.fn(() => true); - const fixture = TestBed.createComponent(TestHasAnyAuthorityDirectiveComponent); - const comp = fixture.componentInstance; - - // WHEN - fixture.detectChanges(); - - // THEN - expect(comp.content).toBeDefined(); - }); - - it('should not show restricted content to user if user has not required role', () => { - // GIVEN - mockAccountService.hasAnyAuthority = jest.fn(() => false); - const fixture = TestBed.createComponent(TestHasAnyAuthorityDirectiveComponent); - const comp = fixture.componentInstance; - - // WHEN - fixture.detectChanges(); - - // THEN - expect(comp.content).toBeUndefined(); - }); - }); - - describe('change authorities', () => { - it('should show or not show restricted content correctly if user authorities are changing', () => { - // GIVEN - mockAccountService.hasAnyAuthority = jest.fn(() => true); - const fixture = TestBed.createComponent(TestHasAnyAuthorityDirectiveComponent); - const comp = fixture.componentInstance; - - // WHEN - fixture.detectChanges(); - - // THEN - expect(comp.content).toBeDefined(); - - // GIVEN - mockAccountService.hasAnyAuthority = jest.fn(() => false); - - // WHEN - authenticationState.next(null); - fixture.detectChanges(); - - // THEN - expect(comp.content).toBeUndefined(); - - // GIVEN - mockAccountService.hasAnyAuthority = jest.fn(() => true); - - // WHEN - authenticationState.next(null); - fixture.detectChanges(); - - // THEN - expect(comp.content).toBeDefined(); - }); - }); - - describe('ngOnDestroy', () => { - it('should destroy authentication state subscription on component destroy', () => { - // GIVEN - mockAccountService.hasAnyAuthority = jest.fn(() => true); - const fixture = TestBed.createComponent(TestHasAnyAuthorityDirectiveComponent); - const div = fixture.debugElement.queryAllNodes(By.directive(HasAnyAuthorityDirective))[0]; - const hasAnyAuthorityDirective = div.injector.get(HasAnyAuthorityDirective); - - // WHEN - fixture.detectChanges(); - - // THEN - expect(mockAccountService.hasAnyAuthority).toHaveBeenCalled(); - - // WHEN - jest.clearAllMocks(); - authenticationState.next(null); - - // THEN - expect(mockAccountService.hasAnyAuthority).toHaveBeenCalled(); - - // WHEN - jest.clearAllMocks(); - hasAnyAuthorityDirective.ngOnDestroy(); - authenticationState.next(null); - - // THEN - expect(mockAccountService.hasAnyAuthority).not.toHaveBeenCalled(); - }); - }); -}); diff --git a/src/main/webapp/app/shared/auth/has-any-authority.directive.ts b/src/main/webapp/app/shared/auth/has-any-authority.directive.ts deleted file mode 100644 index b7be41e87..000000000 --- a/src/main/webapp/app/shared/auth/has-any-authority.directive.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { Directive, Input, TemplateRef, ViewContainerRef, OnDestroy } from '@angular/core'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; - -import { AccountService } from 'app/core/auth/account.service'; - -/** - * @whatItDoes Conditionally includes an HTML element if current user has any - * of the authorities passed as the `expression`. - * - * @howToUse - * ``` - * ... - * - * ... - * ``` - */ -@Directive({ - standalone: true, - selector: '[jhiHasAnyAuthority]', -}) -export default class HasAnyAuthorityDirective implements OnDestroy { - private authorities!: string | string[]; - - private readonly destroy$ = new Subject(); - - constructor(private accountService: AccountService, private templateRef: TemplateRef, private viewContainerRef: ViewContainerRef) {} - - @Input() - set jhiHasAnyAuthority(value: string | string[]) { - this.authorities = value; - this.updateView(); - // Get notified each time authentication state changes. - this.accountService - .getAuthenticationState() - .pipe(takeUntil(this.destroy$)) - .subscribe(() => { - this.updateView(); - }); - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - private updateView(): void { - const hasAnyAuthority = this.accountService.hasAnyAuthority(this.authorities); - this.viewContainerRef.clear(); - if (hasAnyAuthority) { - this.viewContainerRef.createEmbeddedView(this.templateRef); - } - } -} diff --git a/src/main/webapp/app/shared/date/duration.pipe.ts b/src/main/webapp/app/shared/date/duration.pipe.ts deleted file mode 100644 index fda99e3a8..000000000 --- a/src/main/webapp/app/shared/date/duration.pipe.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -import dayjs from 'dayjs/esm'; - -@Pipe({ - standalone: true, - name: 'duration', -}) -export default class DurationPipe implements PipeTransform { - transform(value: any): string { - if (value) { - return dayjs.duration(value).humanize(); - } - return ''; - } -} diff --git a/src/main/webapp/app/shared/date/format-medium-date.pipe.spec.ts b/src/main/webapp/app/shared/date/format-medium-date.pipe.spec.ts deleted file mode 100644 index bdb618e41..000000000 --- a/src/main/webapp/app/shared/date/format-medium-date.pipe.spec.ts +++ /dev/null @@ -1,19 +0,0 @@ -import dayjs from 'dayjs/esm'; - -import FormatMediumDatePipe from './format-medium-date.pipe'; - -describe('FormatMediumDatePipe', () => { - const formatMediumDatePipe = new FormatMediumDatePipe(); - - it('should return an empty string when receive undefined', () => { - expect(formatMediumDatePipe.transform(undefined)).toBe(''); - }); - - it('should return an empty string when receive null', () => { - expect(formatMediumDatePipe.transform(null)).toBe(''); - }); - - it('should format date like this D MMM YYYY', () => { - expect(formatMediumDatePipe.transform(dayjs('2020-11-16').locale('fr'))).toBe('16 Nov 2020'); - }); -}); diff --git a/src/main/webapp/app/shared/date/format-medium-date.pipe.ts b/src/main/webapp/app/shared/date/format-medium-date.pipe.ts deleted file mode 100644 index 96b679b27..000000000 --- a/src/main/webapp/app/shared/date/format-medium-date.pipe.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -import dayjs from 'dayjs/esm'; - -@Pipe({ - standalone: true, - name: 'formatMediumDate', -}) -export default class FormatMediumDatePipe implements PipeTransform { - transform(day: dayjs.Dayjs | null | undefined): string { - return day ? day.format('D MMM YYYY') : ''; - } -} diff --git a/src/main/webapp/app/shared/date/format-medium-datetime.pipe.spec.ts b/src/main/webapp/app/shared/date/format-medium-datetime.pipe.spec.ts deleted file mode 100644 index c08aa47a6..000000000 --- a/src/main/webapp/app/shared/date/format-medium-datetime.pipe.spec.ts +++ /dev/null @@ -1,19 +0,0 @@ -import dayjs from 'dayjs/esm'; - -import FormatMediumDatetimePipe from './format-medium-datetime.pipe'; - -describe('FormatMediumDatePipe', () => { - const formatMediumDatetimePipe = new FormatMediumDatetimePipe(); - - it('should return an empty string when receive undefined', () => { - expect(formatMediumDatetimePipe.transform(undefined)).toBe(''); - }); - - it('should return an empty string when receive null', () => { - expect(formatMediumDatetimePipe.transform(null)).toBe(''); - }); - - it('should format date like this D MMM YYYY', () => { - expect(formatMediumDatetimePipe.transform(dayjs('2020-11-16').locale('fr'))).toBe('16 Nov 2020 00:00:00'); - }); -}); diff --git a/src/main/webapp/app/shared/date/format-medium-datetime.pipe.ts b/src/main/webapp/app/shared/date/format-medium-datetime.pipe.ts deleted file mode 100644 index bd09cfbfa..000000000 --- a/src/main/webapp/app/shared/date/format-medium-datetime.pipe.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -import dayjs from 'dayjs/esm'; - -@Pipe({ - standalone: true, - name: 'formatMediumDatetime', -}) -export default class FormatMediumDatetimePipe implements PipeTransform { - transform(day: dayjs.Dayjs | null | undefined): string { - return day ? day.format('D MMM YYYY HH:mm:ss') : ''; - } -} diff --git a/src/main/webapp/app/shared/date/index.ts b/src/main/webapp/app/shared/date/index.ts deleted file mode 100644 index 5372ce8ab..000000000 --- a/src/main/webapp/app/shared/date/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { default as DurationPipe } from './duration.pipe'; -export { default as FormatMediumDatePipe } from './format-medium-date.pipe'; -export { default as FormatMediumDatetimePipe } from './format-medium-datetime.pipe'; diff --git a/src/main/webapp/app/shared/filter/filter.component.html b/src/main/webapp/app/shared/filter/filter.component.html deleted file mode 100644 index 092a93197..000000000 --- a/src/main/webapp/app/shared/filter/filter.component.html +++ /dev/null @@ -1,12 +0,0 @@ -
- Following filters are set - -
    - -
  • - {{ filterOption.name }}: {{ value }} - -
  • -
    -
-
diff --git a/src/main/webapp/app/shared/filter/filter.component.ts b/src/main/webapp/app/shared/filter/filter.component.ts deleted file mode 100644 index e4d76af32..000000000 --- a/src/main/webapp/app/shared/filter/filter.component.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { IFilterOptions } from './filter.model'; -import SharedModule from '../shared.module'; - -@Component({ - selector: 'jhi-filter', - standalone: true, - imports: [SharedModule], - templateUrl: './filter.component.html', -}) -export default class FilterComponent { - @Input() filters!: IFilterOptions; - - clearAllFilters(): void { - this.filters.clear(); - } - - clearFilter(filterName: string, value: string): void { - this.filters.removeFilter(filterName, value); - } -} diff --git a/src/main/webapp/app/shared/filter/filter.model.spec.ts b/src/main/webapp/app/shared/filter/filter.model.spec.ts deleted file mode 100644 index 6c42c911d..000000000 --- a/src/main/webapp/app/shared/filter/filter.model.spec.ts +++ /dev/null @@ -1,242 +0,0 @@ -import { convertToParamMap, ParamMap, Params } from '@angular/router'; -import { FilterOptions, FilterOption } from './filter.model'; - -describe('FilterModel Tests', () => { - describe('FilterOption', () => { - let filterOption: FilterOption; - - beforeEach(() => { - filterOption = new FilterOption('foo', ['bar', 'bar2']); - }); - - it('nameAsQueryParam returns query key', () => { - expect(filterOption.nameAsQueryParam()).toEqual('filter[foo]'); - }); - - describe('addValue', () => { - it('adds multiples unique values and returns true', () => { - const ret = filterOption.addValue('bar2', 'bar3', 'bar4'); - expect(filterOption.values).toMatchObject(['bar', 'bar2', 'bar3', 'bar4']); - expect(ret).toBe(true); - }); - it("doesn't adds duplicated values and return false", () => { - const ret = filterOption.addValue('bar', 'bar2'); - expect(filterOption.values).toMatchObject(['bar', 'bar2']); - expect(ret).toBe(false); - }); - }); - - describe('removeValue', () => { - it('removes the exiting value and return true', () => { - const ret = filterOption.removeValue('bar'); - expect(filterOption.values).toMatchObject(['bar2']); - expect(ret).toBe(true); - }); - it("doesn't removes the value and return false", () => { - const ret = filterOption.removeValue('foo'); - expect(filterOption.values).toMatchObject(['bar', 'bar2']); - expect(ret).toBe(false); - }); - }); - - describe('equals', () => { - it('returns true to matching options', () => { - const otherFilterOption = new FilterOption(filterOption.name, filterOption.values.concat()); - expect(filterOption.equals(otherFilterOption)).toBe(true); - expect(otherFilterOption.equals(filterOption)).toBe(true); - }); - it('returns false to different name', () => { - const otherFilterOption = new FilterOption('bar', filterOption.values.concat()); - expect(filterOption.equals(otherFilterOption)).toBe(false); - expect(otherFilterOption.equals(filterOption)).toBe(false); - }); - it('returns false to different values', () => { - const otherFilterOption = new FilterOption('bar', []); - expect(filterOption.equals(otherFilterOption)).toBe(false); - expect(otherFilterOption.equals(filterOption)).toBe(false); - }); - }); - }); - - describe('FilterOptions', () => { - describe('hasAnyFilterSet', () => { - it('with empty options returns false', () => { - const filters = new FilterOptions(); - expect(filters.hasAnyFilterSet()).toBe(false); - }); - it('with options and empty values returns false', () => { - const filters = new FilterOptions([new FilterOption('foo'), new FilterOption('bar')]); - expect(filters.hasAnyFilterSet()).toBe(false); - }); - it('with option and value returns true', () => { - const filters = new FilterOptions([new FilterOption('foo', ['bar'])]); - expect(filters.hasAnyFilterSet()).toBe(true); - }); - }); - - describe('clear', () => { - it("removes empty filters and dosn't emit next element", () => { - const filters = new FilterOptions([new FilterOption('foo'), new FilterOption('bar')]); - jest.spyOn(filters.filterChanges, 'next'); - - filters.clear(); - - expect(filters.filterChanges.next).not.toBeCalled(); - expect(filters.filterOptions).toMatchObject([]); - }); - it('removes empty filters and emits next element', () => { - const filters = new FilterOptions([new FilterOption('foo', ['existingFoo1']), new FilterOption('bar')]); - jest.spyOn(filters.filterChanges, 'next'); - - filters.clear(); - - expect(filters.filterChanges.next).toHaveBeenCalledTimes(1); - expect(filters.filterOptions).toMatchObject([]); - }); - }); - - describe('addFilter', () => { - it('adds a non existing FilterOption, returns true and emit next element', () => { - const filters = new FilterOptions([new FilterOption('foo', ['existingFoo1', 'existingFoo2']), new FilterOption('bar')]); - jest.spyOn(filters.filterChanges, 'next'); - - const result = filters.addFilter('addedFilter', 'addedValue'); - - expect(result).toBe(true); - expect(filters.filterChanges.next).toHaveBeenCalledTimes(1); - expect(filters.filterOptions).toMatchObject([ - { name: 'foo', values: ['existingFoo1', 'existingFoo2'] }, - { name: 'addedFilter', values: ['addedValue'] }, - ]); - }); - it('adds a non existing value to FilterOption, returns true and emit next element', () => { - const filters = new FilterOptions([new FilterOption('foo', ['existingFoo1', 'existingFoo2']), new FilterOption('bar')]); - jest.spyOn(filters.filterChanges, 'next'); - - const result = filters.addFilter('foo', 'addedValue1', 'addedValue2'); - - expect(result).toBe(true); - expect(filters.filterChanges.next).toHaveBeenCalledTimes(1); - expect(filters.filterOptions).toMatchObject([ - { name: 'foo', values: ['existingFoo1', 'existingFoo2', 'addedValue1', 'addedValue2'] }, - ]); - }); - it("doesn't add FilterOption values already added, returns false and doesn't emit next element", () => { - const filters = new FilterOptions([new FilterOption('foo', ['existingFoo1', 'existingFoo2']), new FilterOption('bar')]); - jest.spyOn(filters.filterChanges, 'next'); - - const result = filters.addFilter('foo', 'existingFoo1', 'existingFoo2'); - - expect(result).toBe(false); - expect(filters.filterChanges.next).not.toBeCalled(); - expect(filters.filterOptions).toMatchObject([{ name: 'foo', values: ['existingFoo1', 'existingFoo2'] }]); - }); - }); - - describe('removeFilter', () => { - it('removes an existing FilterOptions and returns true', () => { - const filters = new FilterOptions([new FilterOption('foo', ['existingFoo1', 'existingFoo2']), new FilterOption('bar')]); - jest.spyOn(filters.filterChanges, 'next'); - - const result = filters.removeFilter('foo', 'existingFoo1'); - - expect(result).toBe(true); - expect(filters.filterChanges.next).toHaveBeenCalledTimes(1); - expect(filters.filterOptions).toMatchObject([{ name: 'foo', values: ['existingFoo2'] }]); - }); - it("doesn't remove a non existing FilterOptions values returns false", () => { - const filters = new FilterOptions([new FilterOption('foo', ['existingFoo1', 'existingFoo2']), new FilterOption('bar')]); - jest.spyOn(filters.filterChanges, 'next'); - - const result = filters.removeFilter('foo', 'nonExisting1'); - - expect(result).toBe(false); - expect(filters.filterChanges.next).not.toBeCalled(); - expect(filters.filterOptions).toMatchObject([{ name: 'foo', values: ['existingFoo1', 'existingFoo2'] }]); - }); - it("doesn't remove a non existing FilterOptions returns false", () => { - const filters = new FilterOptions([new FilterOption('foo', ['existingFoo1', 'existingFoo2']), new FilterOption('bar')]); - jest.spyOn(filters.filterChanges, 'next'); - - const result = filters.removeFilter('nonExisting', 'nonExisting1'); - - expect(result).toBe(false); - expect(filters.filterChanges.next).not.toBeCalled(); - expect(filters.filterOptions).toMatchObject([{ name: 'foo', values: ['existingFoo1', 'existingFoo2'] }]); - }); - }); - - describe('initializeFromParams', () => { - const oneValidParam: Params = { - test: 'blub', - 'filter[hello.in]': 'world', - 'filter[invalid': 'invalid', - filter_invalid2: 'invalid', - }; - - const noValidParam: Params = { - test: 'blub', - 'filter[invalid': 'invalid', - filter_invalid2: 'invalid', - }; - - const paramWithTwoValues: Params = { - 'filter[hello.in]': ['world', 'world2'], - }; - - const paramWithTwoKeys: Params = { - 'filter[hello.in]': ['world', 'world2'], - 'filter[hello.notIn]': ['world3', 'world4'], - }; - - it('should parse from Params if there are any and not emit next element', () => { - const filters: FilterOptions = new FilterOptions([new FilterOption('foo', ['bar'])]); - jest.spyOn(filters.filterChanges, 'next'); - const paramMap: ParamMap = convertToParamMap(oneValidParam); - - filters.initializeFromParams(paramMap); - - expect(filters.filterChanges.next).not.toHaveBeenCalled(); - expect(filters.filterOptions).toMatchObject([{ name: 'hello.in', values: ['world'] }]); - }); - - it('should parse from Params and have none if there are none', () => { - const filters: FilterOptions = new FilterOptions(); - const paramMap: ParamMap = convertToParamMap(noValidParam); - jest.spyOn(filters.filterChanges, 'next'); - - filters.initializeFromParams(paramMap); - - expect(filters.filterChanges.next).not.toHaveBeenCalled(); - expect(filters.filterOptions).toMatchObject([]); - }); - - it('should parse from Params and have a parameter with 2 values and one aditional value', () => { - const filters: FilterOptions = new FilterOptions([new FilterOption('hello.in', ['world'])]); - jest.spyOn(filters.filterChanges, 'next'); - - const paramMap: ParamMap = convertToParamMap(paramWithTwoValues); - - filters.initializeFromParams(paramMap); - - expect(filters.filterChanges.next).not.toHaveBeenCalled(); - expect(filters.filterOptions).toMatchObject([{ name: 'hello.in', values: ['world', 'world2'] }]); - }); - - it('should parse from Params and have a parameter with 2 keys', () => { - const filters: FilterOptions = new FilterOptions(); - jest.spyOn(filters.filterChanges, 'next'); - - const paramMap: ParamMap = convertToParamMap(paramWithTwoKeys); - - filters.initializeFromParams(paramMap); - - expect(filters.filterChanges.next).not.toHaveBeenCalled(); - expect(filters.filterOptions).toMatchObject([ - { name: 'hello.in', values: ['world', 'world2'] }, - { name: 'hello.notIn', values: ['world3', 'world4'] }, - ]); - }); - }); - }); -}); diff --git a/src/main/webapp/app/shared/filter/filter.model.ts b/src/main/webapp/app/shared/filter/filter.model.ts deleted file mode 100644 index 5afc648bd..000000000 --- a/src/main/webapp/app/shared/filter/filter.model.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { ParamMap } from '@angular/router'; -import { Subject } from 'rxjs'; - -export interface IFilterOptions { - readonly filterChanges: Subject; - get filterOptions(): IFilterOption[]; - hasAnyFilterSet(): boolean; - clear(): boolean; - initializeFromParams(params: ParamMap): boolean; - addFilter(name: string, ...values: string[]): boolean; - removeFilter(name: string, value: string): boolean; -} - -export interface IFilterOption { - name: string; - values: string[]; - nameAsQueryParam(): string; -} - -export class FilterOption implements IFilterOption { - constructor(public name: string, public values: string[] = []) { - this.values = [...new Set(values)]; - } - - nameAsQueryParam(): string { - return 'filter[' + this.name + ']'; - } - - isSet(): boolean { - return this.values.length > 0; - } - - addValue(...values: string[]): boolean { - const missingValues = values.filter(value => value && !this.values.includes(value)); - if (missingValues.length > 0) { - this.values.push(...missingValues); - return true; - } - return false; - } - - removeValue(value: string): boolean { - const indexOf = this.values.indexOf(value); - if (indexOf === -1) { - return false; - } - - this.values.splice(indexOf, 1); - return true; - } - - clone(): FilterOption { - return new FilterOption(this.name, this.values.concat()); - } - - equals(other: IFilterOption): boolean { - return ( - this.name === other.name && - this.values.length === other.values.length && - this.values.every(thisValue => other.values.includes(thisValue)) && - other.values.every(otherValue => this.values.includes(otherValue)) - ); - } -} - -export class FilterOptions implements IFilterOptions { - readonly filterChanges: Subject = new Subject(); - private _filterOptions: FilterOption[]; - - constructor(filterOptions: FilterOption[] = []) { - this._filterOptions = filterOptions; - } - - get filterOptions(): FilterOption[] { - return this._filterOptions.filter(option => option.isSet()); - } - - hasAnyFilterSet(): boolean { - return this._filterOptions.some(e => e.isSet()); - } - - clear(): boolean { - const hasFields = this.hasAnyFilterSet(); - this._filterOptions = []; - if (hasFields) { - this.changed(); - } - return hasFields; - } - - initializeFromParams(params: ParamMap): boolean { - const oldFilters: FilterOptions = this.clone(); - - this._filterOptions = []; - - const filterRegex = /filter\[(.+)\]/; - params.keys - .filter(paramKey => filterRegex.test(paramKey)) - .forEach(matchingParam => { - const matches = filterRegex.exec(matchingParam); - if (matches && matches.length > 1) { - this.getFilterOptionByName(matches[1], true).addValue(...params.getAll(matchingParam)); - } - }); - - if (oldFilters.equals(this)) { - return false; - } - return true; - } - - addFilter(name: string, ...values: string[]): boolean { - if (this.getFilterOptionByName(name, true).addValue(...values)) { - this.changed(); - return true; - } - return false; - } - - removeFilter(name: string, value: string): boolean { - if (this.getFilterOptionByName(name)?.removeValue(value)) { - this.changed(); - return true; - } - return false; - } - - protected changed(): void { - this.filterChanges.next(this.filterOptions.map(option => option.clone())); - } - - protected equals(other: FilterOptions): boolean { - const thisFilters = this.filterOptions; - const otherFilters = other.filterOptions; - if (thisFilters.length !== otherFilters.length) { - return false; - } - return thisFilters.every(option => other.getFilterOptionByName(option.name)?.equals(option)); - } - - protected clone(): FilterOptions { - return new FilterOptions(this.filterOptions.map(option => new FilterOption(option.name, option.values.concat()))); - } - - protected getFilterOptionByName(name: string, add: true): FilterOption; - protected getFilterOptionByName(name: string, add: false): FilterOption | null; - protected getFilterOptionByName(name: string): FilterOption | null; - protected getFilterOptionByName(name: string, add = false): FilterOption | null { - const addOption = (option: FilterOption): FilterOption => { - this._filterOptions.push(option); - return option; - }; - - return this._filterOptions.find(thisOption => thisOption.name === name) ?? (add ? addOption(new FilterOption(name)) : null); - } -} diff --git a/src/main/webapp/app/shared/filter/index.ts b/src/main/webapp/app/shared/filter/index.ts deleted file mode 100644 index ae0af5a7b..000000000 --- a/src/main/webapp/app/shared/filter/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default as FilterComponent } from './filter.component'; -export * from './filter.model'; diff --git a/src/main/webapp/app/shared/language/find-language-from-key.pipe.ts b/src/main/webapp/app/shared/language/find-language-from-key.pipe.ts deleted file mode 100644 index 1c2e3e09b..000000000 --- a/src/main/webapp/app/shared/language/find-language-from-key.pipe.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -@Pipe({ - standalone: true, - name: 'findLanguageFromKey', -}) -export default class FindLanguageFromKeyPipe implements PipeTransform { - private languages: { [key: string]: { name: string; rtl?: boolean } } = { - en: { name: 'English' }, - // jhipster-needle-i18n-language-key-pipe - JHipster will add/remove languages in this object - }; - - transform(lang: string): string { - return this.languages[lang].name; - } -} diff --git a/src/main/webapp/app/shared/language/index.ts b/src/main/webapp/app/shared/language/index.ts deleted file mode 100644 index 3446ac20c..000000000 --- a/src/main/webapp/app/shared/language/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default as TranslateDirective } from './translate.directive'; -export { default as FindLanguageFromKeyPipe } from './find-language-from-key.pipe'; diff --git a/src/main/webapp/app/shared/language/translate.directive.spec.ts b/src/main/webapp/app/shared/language/translate.directive.spec.ts deleted file mode 100644 index b7b5657d1..000000000 --- a/src/main/webapp/app/shared/language/translate.directive.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Component } from '@angular/core'; -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { TranslateModule, TranslateService } from '@ngx-translate/core'; - -import TranslateDirective from './translate.directive'; - -@Component({ - template: `
`, -}) -class TestTranslateDirectiveComponent {} - -describe('TranslateDirective Tests', () => { - let fixture: ComponentFixture; - let translateService: TranslateService; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot(), TranslateDirective], - declarations: [TestTranslateDirectiveComponent], - }); - })); - - beforeEach(() => { - translateService = TestBed.inject(TranslateService); - fixture = TestBed.createComponent(TestTranslateDirectiveComponent); - }); - - it('should change HTML', () => { - const spy = jest.spyOn(translateService, 'get'); - - fixture.detectChanges(); - - expect(spy).toHaveBeenCalled(); - }); -}); diff --git a/src/main/webapp/app/shared/language/translate.directive.ts b/src/main/webapp/app/shared/language/translate.directive.ts deleted file mode 100644 index e8c889f59..000000000 --- a/src/main/webapp/app/shared/language/translate.directive.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Input, Directive, ElementRef, OnChanges, OnInit, OnDestroy } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; - -import { translationNotFoundMessage } from 'app/config/translation.config'; - -/** - * A wrapper directive on top of the translate pipe as the inbuilt translate directive from ngx-translate is too verbose and buggy - */ -@Directive({ - standalone: true, - selector: '[jhiTranslate]', -}) -export default class TranslateDirective implements OnChanges, OnInit, OnDestroy { - @Input() jhiTranslate!: string; - @Input() translateValues?: { [key: string]: unknown }; - - private readonly directiveDestroyed = new Subject(); - - constructor(private el: ElementRef, private translateService: TranslateService) {} - - ngOnInit(): void { - this.translateService.onLangChange.pipe(takeUntil(this.directiveDestroyed)).subscribe(() => { - this.getTranslation(); - }); - this.translateService.onTranslationChange.pipe(takeUntil(this.directiveDestroyed)).subscribe(() => { - this.getTranslation(); - }); - } - - ngOnChanges(): void { - this.getTranslation(); - } - - ngOnDestroy(): void { - this.directiveDestroyed.next(null); - this.directiveDestroyed.complete(); - } - - private getTranslation(): void { - this.translateService - .get(this.jhiTranslate, this.translateValues) - .pipe(takeUntil(this.directiveDestroyed)) - .subscribe({ - next: value => { - this.el.nativeElement.innerHTML = value; - }, - error: () => `${translationNotFoundMessage}[${this.jhiTranslate}]`, - }); - } -} diff --git a/src/main/webapp/app/shared/language/translation.module.ts b/src/main/webapp/app/shared/language/translation.module.ts deleted file mode 100644 index 543b3f0e3..000000000 --- a/src/main/webapp/app/shared/language/translation.module.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { NgModule } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { TranslateModule, TranslateService, TranslateLoader, MissingTranslationHandler } from '@ngx-translate/core'; -import { translatePartialLoader, missingTranslationHandler } from 'app/config/translation.config'; -import { StateStorageService } from 'app/core/auth/state-storage.service'; - -@NgModule({ - imports: [ - TranslateModule.forRoot({ - loader: { - provide: TranslateLoader, - useFactory: translatePartialLoader, - deps: [HttpClient], - }, - missingTranslationHandler: { - provide: MissingTranslationHandler, - useFactory: missingTranslationHandler, - }, - }), - ], -}) -export class TranslationModule { - constructor(private translateService: TranslateService, private stateStorageService: StateStorageService) { - this.translateService.setDefaultLang('en'); - // if user have changed language and navigates away from the application and back to the application then use previously choosed language - const langKey = this.stateStorageService.getLocale() ?? 'en'; - this.translateService.use(langKey); - } -} diff --git a/src/main/webapp/app/shared/pagination/index.ts b/src/main/webapp/app/shared/pagination/index.ts deleted file mode 100644 index 395ed882f..000000000 --- a/src/main/webapp/app/shared/pagination/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ItemCountComponent } from './item-count.component'; diff --git a/src/main/webapp/app/shared/pagination/item-count.component.spec.ts b/src/main/webapp/app/shared/pagination/item-count.component.spec.ts deleted file mode 100644 index 9e91b1d45..000000000 --- a/src/main/webapp/app/shared/pagination/item-count.component.spec.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; -import { TranslateModule } from '@ngx-translate/core'; - -import TranslateDirective from 'app/shared/language/translate.directive'; - -import ItemCountComponent from './item-count.component'; - -describe('ItemCountComponent test', () => { - let comp: ItemCountComponent; - let fixture: ComponentFixture; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [ItemCountComponent, TranslateModule.forRoot(), TranslateDirective], - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(ItemCountComponent); - comp = fixture.componentInstance; - }); - - describe('UI logic tests', () => { - it('should initialize with undefined', () => { - expect(comp.first).toBeUndefined(); - expect(comp.second).toBeUndefined(); - expect(comp.total).toBeUndefined(); - }); - - it('should set calculated numbers to undefined if the page value is not yet defined', () => { - // GIVEN - comp.params = { page: undefined, totalItems: 0, itemsPerPage: 10 }; - - // THEN - expect(comp.first).toBeUndefined(); - expect(comp.second).toBeUndefined(); - }); - - it('should change the content on page change', () => { - // GIVEN - comp.params = { page: 1, totalItems: 100, itemsPerPage: 10 }; - - // THEN - expect(comp.first).toBe(1); - expect(comp.second).toBe(10); - expect(comp.total).toBe(100); - - // GIVEN - comp.params = { page: 2, totalItems: 100, itemsPerPage: 10 }; - - // THEN - expect(comp.first).toBe(11); - expect(comp.second).toBe(20); - expect(comp.total).toBe(100); - }); - - it('should set the second number to totalItems if this is the last page which contains less than itemsPerPage items', () => { - // GIVEN - comp.params = { page: 2, totalItems: 16, itemsPerPage: 10 }; - - // THEN - expect(comp.first).toBe(11); - expect(comp.second).toBe(16); - expect(comp.total).toBe(16); - }); - }); -}); diff --git a/src/main/webapp/app/shared/pagination/item-count.component.ts b/src/main/webapp/app/shared/pagination/item-count.component.ts deleted file mode 100644 index 0ac352101..000000000 --- a/src/main/webapp/app/shared/pagination/item-count.component.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Component, Input } from '@angular/core'; -import TranslateDirective from '../language/translate.directive'; - -/** - * A component that will take care of item count statistics of a pagination. - */ -@Component({ - standalone: true, - selector: 'jhi-item-count', - template: `
`, - imports: [TranslateDirective], -}) -export default class ItemCountComponent { - /** - * @param params Contains parameters for component: - * page Current page number - * totalItems Total number of items - * itemsPerPage Number of items per page - */ - @Input() set params(params: { page?: number; totalItems?: number; itemsPerPage?: number }) { - if (params.page && params.totalItems !== undefined && params.itemsPerPage) { - this.first = (params.page - 1) * params.itemsPerPage + 1; - this.second = params.page * params.itemsPerPage < params.totalItems ? params.page * params.itemsPerPage : params.totalItems; - } else { - this.first = undefined; - this.second = undefined; - } - this.total = params.totalItems; - } - - first?: number; - second?: number; - total?: number; -} diff --git a/src/main/webapp/app/shared/shared.module.ts b/src/main/webapp/app/shared/shared.module.ts deleted file mode 100644 index 6511f7bc4..000000000 --- a/src/main/webapp/app/shared/shared.module.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; -import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; -import { TranslateModule } from '@ngx-translate/core'; - -import FindLanguageFromKeyPipe from './language/find-language-from-key.pipe'; -import TranslateDirective from './language/translate.directive'; -import { AlertComponent } from './alert/alert.component'; -import { AlertErrorComponent } from './alert/alert-error.component'; - -/** - * Application wide Module - */ -@NgModule({ - imports: [AlertComponent, AlertErrorComponent, FindLanguageFromKeyPipe, TranslateDirective], - exports: [ - CommonModule, - NgbModule, - FontAwesomeModule, - AlertComponent, - AlertErrorComponent, - TranslateModule, - FindLanguageFromKeyPipe, - TranslateDirective, - ], -}) -export default class SharedModule {} diff --git a/src/main/webapp/app/shared/sort/index.ts b/src/main/webapp/app/shared/sort/index.ts deleted file mode 100644 index 1a04bec6f..000000000 --- a/src/main/webapp/app/shared/sort/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default as SortDirective } from './sort.directive'; -export { default as SortByDirective } from './sort-by.directive'; diff --git a/src/main/webapp/app/shared/sort/sort-by.directive.spec.ts b/src/main/webapp/app/shared/sort/sort-by.directive.spec.ts deleted file mode 100644 index 51fef72d7..000000000 --- a/src/main/webapp/app/shared/sort/sort-by.directive.spec.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { Component, DebugElement } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { FaIconComponent, FaIconLibrary } from '@fortawesome/angular-fontawesome'; -import { fas, faSort, faSortDown, faSortUp } from '@fortawesome/free-solid-svg-icons'; - -import SortByDirective from './sort-by.directive'; -import SortDirective from './sort.directive'; - -@Component({ - template: ` - - - - - - -
ID
- `, -}) -class TestSortByDirectiveComponent { - predicate?: string; - ascending?: boolean; - sortAllowed = true; - transition = jest.fn(); - - constructor(library: FaIconLibrary) { - library.addIconPacks(fas); - library.addIcons(faSort, faSortDown, faSortUp); - } -} - -describe('Directive: SortByDirective', () => { - let component: TestSortByDirectiveComponent; - let fixture: ComponentFixture; - let tableHead: DebugElement; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [SortDirective, SortByDirective], - declarations: [TestSortByDirectiveComponent, FaIconComponent], - }); - fixture = TestBed.createComponent(TestSortByDirectiveComponent); - component = fixture.componentInstance; - tableHead = fixture.debugElement.query(By.directive(SortByDirective)); - }); - - it('should initialize predicate, order, icon when initial component predicate differs from column predicate', () => { - // GIVEN - component.predicate = 'id'; - const sortByDirective = tableHead.injector.get(SortByDirective); - - // WHEN - fixture.detectChanges(); - - // THEN - expect(sortByDirective.jhiSortBy).toEqual('name'); - expect(component.predicate).toEqual('id'); - expect(sortByDirective.iconComponent?.icon).toEqual('sort'); - expect(component.transition).toHaveBeenCalledTimes(0); - }); - - it('should initialize predicate, order, icon when initial component predicate is same as column predicate', () => { - // GIVEN - component.predicate = 'name'; - component.ascending = true; - const sortByDirective = tableHead.injector.get(SortByDirective); - - // WHEN - fixture.detectChanges(); - - // THEN - expect(sortByDirective.jhiSortBy).toEqual('name'); - expect(component.predicate).toEqual('name'); - expect(component.ascending).toEqual(true); - expect(sortByDirective.iconComponent?.icon).toEqual(faSortUp.iconName); - expect(component.transition).toHaveBeenCalledTimes(0); - }); - - it('should update component predicate, order, icon when user clicks on column header', () => { - // GIVEN - component.predicate = 'name'; - component.ascending = true; - const sortByDirective = tableHead.injector.get(SortByDirective); - - // WHEN - fixture.detectChanges(); - tableHead.triggerEventHandler('click', null); - fixture.detectChanges(); - - // THEN - expect(component.predicate).toEqual('name'); - expect(component.ascending).toEqual(false); - expect(sortByDirective.iconComponent?.icon).toEqual(faSortDown.iconName); - expect(component.transition).toHaveBeenCalledTimes(1); - expect(component.transition).toHaveBeenCalledWith({ predicate: 'name', ascending: false }); - }); - - it('should update component predicate, order, icon when user double clicks on column header', () => { - // GIVEN - component.predicate = 'name'; - component.ascending = true; - const sortByDirective = tableHead.injector.get(SortByDirective); - - // WHEN - fixture.detectChanges(); - - tableHead.triggerEventHandler('click', null); - fixture.detectChanges(); - - tableHead.triggerEventHandler('click', null); - fixture.detectChanges(); - - // THEN - expect(component.predicate).toEqual('name'); - expect(component.ascending).toEqual(true); - expect(sortByDirective.iconComponent?.icon).toEqual(faSortUp.iconName); - expect(component.transition).toHaveBeenCalledTimes(2); - expect(component.transition).toHaveBeenNthCalledWith(1, { predicate: 'name', ascending: false }); - expect(component.transition).toHaveBeenNthCalledWith(2, { predicate: 'name', ascending: true }); - }); - - it('should not run sorting on click if sorting icon is hidden', () => { - // GIVEN - component.predicate = 'id'; - component.ascending = false; - component.sortAllowed = false; - - // WHEN - fixture.detectChanges(); - - tableHead.triggerEventHandler('click', null); - fixture.detectChanges(); - - // THEN - expect(component.predicate).toEqual('id'); - expect(component.ascending).toEqual(false); - expect(component.transition).not.toHaveBeenCalled(); - }); -}); diff --git a/src/main/webapp/app/shared/sort/sort-by.directive.ts b/src/main/webapp/app/shared/sort/sort-by.directive.ts deleted file mode 100644 index 1e8eda6ec..000000000 --- a/src/main/webapp/app/shared/sort/sort-by.directive.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { AfterContentInit, ContentChild, Directive, Host, HostListener, Input, OnDestroy } from '@angular/core'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; -import { FaIconComponent } from '@fortawesome/angular-fontawesome'; -import { faSort, faSortDown, faSortUp, IconDefinition } from '@fortawesome/free-solid-svg-icons'; - -import SortDirective from './sort.directive'; - -@Directive({ - standalone: true, - selector: '[jhiSortBy]', -}) -export default class SortByDirective implements AfterContentInit, OnDestroy { - @Input() jhiSortBy!: T; - - @ContentChild(FaIconComponent, { static: false }) - iconComponent?: FaIconComponent; - - sortIcon = faSort; - sortAscIcon = faSortUp; - sortDescIcon = faSortDown; - - private readonly destroy$ = new Subject(); - - constructor(@Host() private sort: SortDirective) { - sort.predicateChange.pipe(takeUntil(this.destroy$)).subscribe(() => this.updateIconDefinition()); - sort.ascendingChange.pipe(takeUntil(this.destroy$)).subscribe(() => this.updateIconDefinition()); - } - - @HostListener('click') - onClick(): void { - if (this.iconComponent) { - this.sort.sort(this.jhiSortBy); - } - } - - ngAfterContentInit(): void { - this.updateIconDefinition(); - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - private updateIconDefinition(): void { - if (this.iconComponent) { - let icon: IconDefinition = this.sortIcon; - if (this.sort.predicate === this.jhiSortBy) { - icon = this.sort.ascending ? this.sortAscIcon : this.sortDescIcon; - } - this.iconComponent.icon = icon.iconName; - this.iconComponent.render(); - } - } -} diff --git a/src/main/webapp/app/shared/sort/sort.directive.spec.ts b/src/main/webapp/app/shared/sort/sort.directive.spec.ts deleted file mode 100644 index 5dc7b8751..000000000 --- a/src/main/webapp/app/shared/sort/sort.directive.spec.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { Component, DebugElement } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; - -import SortDirective from './sort.directive'; - -@Component({ - template: ` - - - - -
- `, -}) -class TestSortDirectiveComponent { - predicate?: string; - ascending?: boolean; - transition = jest.fn(); -} - -describe('Directive: SortDirective', () => { - let component: TestSortDirectiveComponent; - let fixture: ComponentFixture; - let tableRow: DebugElement; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [SortDirective], - declarations: [TestSortDirectiveComponent], - }); - fixture = TestBed.createComponent(TestSortDirectiveComponent); - component = fixture.componentInstance; - tableRow = fixture.debugElement.query(By.directive(SortDirective)); - }); - - it('should update predicate, order and invoke sortChange function', () => { - // GIVEN - const sortDirective = tableRow.injector.get(SortDirective); - - // WHEN - fixture.detectChanges(); - sortDirective.sort('ID'); - - // THEN - expect(component.predicate).toEqual('ID'); - expect(component.ascending).toEqual(true); - expect(component.transition).toHaveBeenCalledTimes(1); - expect(component.transition).toHaveBeenCalledWith({ predicate: 'ID', ascending: true }); - }); - - it('should change sort order to descending when same field is sorted again', () => { - // GIVEN - const sortDirective = tableRow.injector.get(SortDirective); - - // WHEN - fixture.detectChanges(); - sortDirective.sort('ID'); - // sort again - sortDirective.sort('ID'); - - // THEN - expect(component.predicate).toEqual('ID'); - expect(component.ascending).toEqual(false); - expect(component.transition).toHaveBeenCalledTimes(2); - expect(component.transition).toHaveBeenNthCalledWith(1, { predicate: 'ID', ascending: true }); - expect(component.transition).toHaveBeenNthCalledWith(2, { predicate: 'ID', ascending: false }); - }); - - it('should change sort order to ascending when different field is sorted', () => { - // GIVEN - const sortDirective = tableRow.injector.get(SortDirective); - - // WHEN - fixture.detectChanges(); - sortDirective.sort('ID'); - // sort again - sortDirective.sort('NAME'); - - // THEN - expect(component.predicate).toEqual('NAME'); - expect(component.ascending).toEqual(true); - expect(component.transition).toHaveBeenCalledTimes(2); - expect(component.transition).toHaveBeenNthCalledWith(1, { predicate: 'ID', ascending: true }); - expect(component.transition).toHaveBeenNthCalledWith(2, { predicate: 'NAME', ascending: true }); - }); -}); diff --git a/src/main/webapp/app/shared/sort/sort.directive.ts b/src/main/webapp/app/shared/sort/sort.directive.ts deleted file mode 100644 index 9bc4117e2..000000000 --- a/src/main/webapp/app/shared/sort/sort.directive.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Directive, EventEmitter, Input, Output } from '@angular/core'; - -@Directive({ - standalone: true, - selector: '[jhiSort]', -}) -export default class SortDirective { - @Input() - get predicate(): T | undefined { - return this._predicate; - } - set predicate(predicate: T | undefined) { - this._predicate = predicate; - this.predicateChange.emit(predicate); - } - - @Input() - get ascending(): boolean | undefined { - return this._ascending; - } - set ascending(ascending: boolean | undefined) { - this._ascending = ascending; - this.ascendingChange.emit(ascending); - } - - @Output() predicateChange = new EventEmitter(); - @Output() ascendingChange = new EventEmitter(); - @Output() sortChange = new EventEmitter<{ predicate: T; ascending: boolean }>(); - - private _predicate?: T; - private _ascending?: boolean; - - sort(field: T): void { - this.ascending = field !== this.predicate ? true : !this.ascending; - this.predicate = field; - this.predicateChange.emit(field); - this.ascendingChange.emit(this.ascending); - this.sortChange.emit({ predicate: this.predicate, ascending: this.ascending }); - } -} diff --git a/src/main/webapp/app/shared/sort/sort.service.ts b/src/main/webapp/app/shared/sort/sort.service.ts deleted file mode 100644 index d27605992..000000000 --- a/src/main/webapp/app/shared/sort/sort.service.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Injectable } from '@angular/core'; - -@Injectable({ providedIn: 'root' }) -export class SortService { - private collator = new Intl.Collator(undefined, { - numeric: true, - sensitivity: 'base', - }); - - public startSort(property: string, order: number): (a: any, b: any) => number { - return (a: any, b: any) => this.collator.compare(a[property], b[property]) * order; - } -} diff --git a/src/main/webapp/bootstrap.ts b/src/main/webapp/bootstrap.ts deleted file mode 100644 index e5038d525..000000000 --- a/src/main/webapp/bootstrap.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { enableProdMode } from '@angular/core'; -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; - -import { DEBUG_INFO_ENABLED } from './app/app.constants'; -import { AppModule } from './app/app.module'; - -// disable debug data on prod profile to improve performance -if (!DEBUG_INFO_ENABLED) { - enableProdMode(); -} - -platformBrowserDynamic() - .bootstrapModule(AppModule, { preserveWhitespaces: true }) - // eslint-disable-next-line no-console - .then(() => console.log('Application started')) - .catch(err => console.error(err)); diff --git a/src/main/webapp/content/css/loading.css b/src/main/webapp/content/css/loading.css index 678e7b635..b2c662687 100644 --- a/src/main/webapp/content/css/loading.css +++ b/src/main/webapp/content/css/loading.css @@ -133,7 +133,7 @@ left: -8px; width: 24px; height: 10px; - background-image: url('/content/images/logo-jhipster.png'); + background-image: url('../images/logo-jhipster.png'); background-size: contain; -webkit-animation: lds-pacman-3 1s linear infinite; animation: lds-pacman-3 1.5s linear infinite; diff --git a/src/main/webapp/content/scss/_bootstrap-variables.scss b/src/main/webapp/content/scss/_bootstrap-variables.scss deleted file mode 100644 index 89712f709..000000000 --- a/src/main/webapp/content/scss/_bootstrap-variables.scss +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Bootstrap overrides https://getbootstrap.com/docs/5.1/customize/sass/ - * All values defined in bootstrap source - * https://github.com/twbs/bootstrap/blob/v5.1.3/scss/_variables.scss can be overwritten here - * Make sure not to add !default to values here - */ - -// Colors: -// Grayscale and brand colors for use across Bootstrap. - -$primary: #3e8acc; -$success: #28a745; -$info: #17a2b8; -$warning: #ffc107; -$danger: #dc3545; - -// Options: -// Quickly modify global styling by enabling or disabling optional features. -$enable-rounded: true; -$enable-shadows: false; -$enable-gradients: false; -$enable-transitions: true; -$enable-hover-media-query: false; -$enable-grid-classes: true; -$enable-print-styles: true; - -// Components: -// Define common padding and border radius sizes and more. - -$border-radius: 0.15rem; -$border-radius-lg: 0.125rem; -$border-radius-sm: 0.1rem; - -// Body: -// Settings for the `` element. - -$body-bg: #ffffff; - -// Typography: -// Font, line-height, and color for body text, headings, and more. - -$font-size-base: 1rem; - -$dropdown-link-hover-color: white; -$dropdown-link-hover-bg: #343a40; diff --git a/src/main/webapp/content/scss/global.scss b/src/main/webapp/content/scss/global.scss deleted file mode 100644 index f93917465..000000000 --- a/src/main/webapp/content/scss/global.scss +++ /dev/null @@ -1,239 +0,0 @@ -@import 'bootstrap-variables'; -@import 'bootstrap/scss/functions'; -@import 'bootstrap/scss/variables'; - -/* ============================================================== -Bootstrap tweaks -===============================================================*/ - -body, -h1, -h2, -h3, -h4 { - font-weight: 300; -} - -/* Increase contrast of links to get 100% on Lighthouse Accessability Audit. Override this color if you want to change the link color, or use a Bootswatch theme */ -a { - color: #533f03; - font-weight: bold; -} - -a:hover { - color: #533f03; -} - -/* override hover color for dropdown-item forced by bootstrap to all a:not([href]):not([tabindex]) elements in _reboot.scss */ -a:not([href]):not([tabindex]):hover.dropdown-item { - color: $dropdown-link-hover-color; -} - -/* override .dropdown-item.active background-color on hover */ -.dropdown-item.active:hover { - background-color: mix($dropdown-link-hover-bg, $dropdown-link-active-bg, 50%); -} - -a:hover { - /* make sure browsers use the pointer cursor for anchors, even with no href */ - cursor: pointer; -} - -.dropdown-item:hover { - color: $dropdown-link-hover-color; -} - -/* ========================================================================== -Browser Upgrade Prompt -========================================================================== */ -.browserupgrade { - margin: 0.2em 0; - background: #ccc; - color: #000; - padding: 0.2em 0; -} - -/* ========================================================================== -Generic styles -========================================================================== */ - -/* Error highlight on input fields */ -.ng-valid[required], -.ng-valid.required { - border-left: 5px solid green; -} - -.ng-invalid:not(form) { - border-left: 5px solid red; -} - -/* other generic styles */ - -.jh-card { - padding: 1.5%; - margin-top: 20px; - border: none; -} - -.error { - color: white; - background-color: red; -} - -.pad { - padding: 10px; -} - -.w-40 { - width: 40% !important; -} - -.w-60 { - width: 60% !important; -} - -.break { - white-space: normal; - word-break: break-all; -} - -.form-control { - background-color: #fff; -} - -.readonly { - background-color: #eee; - opacity: 1; -} - -.footer { - border-top: 1px solid rgba(0, 0, 0, 0.125); -} - -.hand, -[jhisortby] { - cursor: pointer; -} - -/* ========================================================================== -Custom alerts for notification -========================================================================== */ -.alerts { - .alert { - text-overflow: ellipsis; - pre { - background: none; - border: none; - font: inherit; - color: inherit; - padding: 0; - margin: 0; - } - .popover pre { - font-size: 10px; - } - } - .jhi-toast { - position: fixed; - width: 100%; - &.left { - left: 5px; - } - &.right { - right: 5px; - } - &.top { - top: 55px; - } - &.bottom { - bottom: 55px; - } - } -} - -@media screen and (min-width: 480px) { - .alerts .jhi-toast { - width: 50%; - } -} - -/* ========================================================================== -entity list page css -========================================================================== */ - -.table-entities thead th .d-flex > * { - margin: auto 0; -} - -/* ========================================================================== -entity detail page css -========================================================================== */ -.row-md.jh-entity-details { - display: grid; - grid-template-columns: auto 1fr; - column-gap: 10px; - line-height: 1.5; -} - -@media screen and (min-width: 768px) { - .row-md.jh-entity-details > { - dt { - float: left; - overflow: hidden; - clear: left; - text-align: right; - text-overflow: ellipsis; - white-space: nowrap; - padding: 0.5em 0; - } - dd { - border-bottom: 1px solid #eee; - padding: 0.5em 0; - margin-left: 0; - } - } -} - -/* ========================================================================== -ui bootstrap tweaks -========================================================================== */ -.nav, -.pagination, -.carousel, -.panel-title a { - cursor: pointer; -} - -.thread-dump-modal-lock { - max-width: 450px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.dropdown-menu { - padding-left: 0px; -} - -/* ========================================================================== -angular-cli removes postcss-rtl processed inline css, processed rules must be added here instead -========================================================================== */ -/* page-ribbon.component.scss */ -.ribbon { - left: -3.5em; - -moz-transform: rotate(-45deg); - -ms-transform: rotate(-45deg); - -o-transform: rotate(-45deg); - -webkit-transform: rotate(-45deg); - transform: rotate(-45deg); -} - -/* navbar.component.scss */ -.navbar { - ul.navbar-nav { - .nav-item { - margin-left: 0.5em; - } - } -} -/* jhipster-needle-scss-add-main JHipster will add new css style */ diff --git a/src/main/webapp/content/scss/vendor.scss b/src/main/webapp/content/scss/vendor.scss deleted file mode 100644 index acf2df290..000000000 --- a/src/main/webapp/content/scss/vendor.scss +++ /dev/null @@ -1,12 +0,0 @@ -/* after changing this file run 'npm run webapp:build' */ - -/*************************** -put Sass variables here: -eg $input-color: red; -****************************/ -// Override Bootstrap variables -@import 'bootstrap-variables'; -// Import Bootstrap source files from node_modules -@import 'bootstrap/scss/bootstrap'; - -/* jhipster-needle-scss-add-vendor JHipster will add new css style */ diff --git a/src/main/webapp/declarations.d.ts b/src/main/webapp/declarations.d.ts deleted file mode 100644 index 38352e9b6..000000000 --- a/src/main/webapp/declarations.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare const SERVER_API_URL: string; -declare const I18N_HASH: string; diff --git a/src/main/webapp/i18n/en/configuration.json b/src/main/webapp/i18n/en/configuration.json old mode 100644 new mode 100755 diff --git a/src/main/webapp/i18n/en/error.json b/src/main/webapp/i18n/en/error.json old mode 100644 new mode 100755 diff --git a/src/main/webapp/i18n/en/health.json b/src/main/webapp/i18n/en/health.json index cbc45bace..10f40f00a 100644 --- a/src/main/webapp/i18n/en/health.json +++ b/src/main/webapp/i18n/en/health.json @@ -25,7 +25,6 @@ "status": { "UNKNOWN": "UNKNOWN", "UP": "UP", - "OUT_OF_SERVICE": "OUT_OF_SERVICE", "DOWN": "DOWN" } } diff --git a/src/main/webapp/i18n/en/home.json b/src/main/webapp/i18n/en/home.json old mode 100644 new mode 100755 diff --git a/src/main/webapp/i18n/en/login.json b/src/main/webapp/i18n/en/login.json old mode 100644 new mode 100755 diff --git a/src/main/webapp/i18n/en/logs.json b/src/main/webapp/i18n/en/logs.json old mode 100644 new mode 100755 diff --git a/src/main/webapp/i18n/en/metrics.json b/src/main/webapp/i18n/en/metrics.json old mode 100644 new mode 100755 diff --git a/src/main/webapp/i18n/en/password.json b/src/main/webapp/i18n/en/password.json old mode 100644 new mode 100755 diff --git a/src/main/webapp/i18n/en/register.json b/src/main/webapp/i18n/en/register.json old mode 100644 new mode 100755 diff --git a/src/main/webapp/i18n/en/sessions.json b/src/main/webapp/i18n/en/sessions.json old mode 100644 new mode 100755 diff --git a/src/main/webapp/i18n/en/settings.json b/src/main/webapp/i18n/en/settings.json old mode 100644 new mode 100755 diff --git a/src/main/webapp/i18n/en/user-management.json b/src/main/webapp/i18n/en/user-management.json old mode 100644 new mode 100755 diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html index 6cf099cf0..f3397c5cc 100644 --- a/src/main/webapp/index.html +++ b/src/main/webapp/index.html @@ -8,7 +8,6 @@ - @@ -21,7 +20,7 @@ your experience.

- +
@@ -99,7 +98,7 @@

If you want to chat with contributors and other users

- +
@@ -110,18 +109,31 @@

You must enable JavaScript to view this page.

}; function showError() { var errorElm = document.getElementById('jhipster-error'); - if (errorElm?.style) { + if (errorElm && errorElm.style) { errorElm.style.display = 'block'; } } - + diff --git a/src/main/webapp/main.ts b/src/main/webapp/main.ts deleted file mode 100644 index 73c3a0e83..000000000 --- a/src/main/webapp/main.ts +++ /dev/null @@ -1 +0,0 @@ -import('./bootstrap').catch(err => console.error(err)); diff --git a/src/main/webapp/swagger-ui/index.html b/src/main/webapp/swagger-ui/index.html index a2a7a8b5e..e2ae0b687 100644 --- a/src/main/webapp/swagger-ui/index.html +++ b/src/main/webapp/swagger-ui/index.html @@ -28,7 +28,6 @@ const getBearerToken = () => { var authToken = localStorage.getItem('jhi-authenticationToken') || sessionStorage.getItem('jhi-authenticationToken'); if (authToken) { - authToken = JSON.parse(authToken); return `Bearer ${authToken}`; } return null; @@ -59,8 +58,7 @@ if (y.includes('(default)')) return 1; if (x.includes('(management)')) return -1; if (y.includes('(management)')) return 1; - if (x < y) return -1; - return x > y ? 1 : 0; + return x < y ? -1 : x > y ? 1 : 0; }); } diff --git a/src/test/gatling/user-files/simulations/BankAccountGatlingTest.scala b/src/test/gatling/user-files/simulations/BankAccountGatlingTest.scala new file mode 100644 index 000000000..7130fab78 --- /dev/null +++ b/src/test/gatling/user-files/simulations/BankAccountGatlingTest.scala @@ -0,0 +1,97 @@ +import _root_.io.gatling.core.scenario.Simulation +import ch.qos.logback.classic.{Level, LoggerContext} +import io.gatling.core.Predef._ +import io.gatling.http.Predef._ +import org.slf4j.LoggerFactory + +import scala.concurrent.duration._ + +/** + * Performance test for the BankAccount entity. + */ +class BankAccountGatlingTest extends Simulation { + + val context: LoggerContext = LoggerFactory.getILoggerFactory.asInstanceOf[LoggerContext] + // Log all HTTP requests + //context.getLogger("io.gatling.http").setLevel(Level.valueOf("TRACE")) + // Log failed HTTP requests + //context.getLogger("io.gatling.http").setLevel(Level.valueOf("DEBUG")) + + val baseURL = Option(System.getProperty("baseURL")) getOrElse """http://localhost:8080""" + + val httpConf = http + .baseUrl(baseURL) + .inferHtmlResources() + .acceptHeader("*/*") + .acceptEncodingHeader("gzip, deflate") + .acceptLanguageHeader("fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3") + .connectionHeader("keep-alive") + .userAgentHeader("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:33.0) Gecko/20100101 Firefox/33.0") + .silentResources // Silence all resources like css or css so they don't clutter the results + + val headers_http = Map( + "Accept" -> """application/json""" + ) + + val headers_http_authentication = Map( + "Content-Type" -> """application/json""", + "Accept" -> """application/json""" + ) + + val headers_http_authenticated = Map( + "Accept" -> """application/json""", + "Authorization" -> "${access_token}" + ) + + val scn = scenario("Test the BankAccount entity") + .exec(http("First unauthenticated request") + .get("/api/account") + .headers(headers_http) + .check(status.is(401)) + ).exitHereIfFailed + .pause(10) + .exec(http("Authentication") + .post("/api/authenticate") + .headers(headers_http_authentication) + .body(StringBody("""{"username":"admin", "password":"admin"}""")).asJson + .check(header("Authorization").saveAs("access_token"))).exitHereIfFailed + .pause(2) + .exec(http("Authenticated request") + .get("/api/account") + .headers(headers_http_authenticated) + .check(status.is(200))) + .pause(10) + .repeat(2) { + exec(http("Get all bankAccounts") + .get("/api/bank-accounts") + .headers(headers_http_authenticated) + .check(status.is(200))) + .pause(10 seconds, 20 seconds) + .exec(http("Create new bankAccount") + .post("/api/bank-accounts") + .headers(headers_http_authenticated) + .body(StringBody("""{ + "name":"SAMPLE_TEXT" + , "balance":"0" + }""")).asJson + .check(status.is(201)) + .check(headerRegex("Location", "(.*)").saveAs("new_bankAccount_url"))).exitHereIfFailed + .pause(10) + .repeat(5) { + exec(http("Get created bankAccount") + .get("${new_bankAccount_url}") + .headers(headers_http_authenticated)) + .pause(10) + } + .exec(http("Delete created bankAccount") + .delete("${new_bankAccount_url}") + .headers(headers_http_authenticated)) + .pause(10) + } + + val users = scenario("Users").exec(scn) + + setUp( + users.inject(rampUsers(Integer.getInteger("users", 100)) during (Integer.getInteger("ramp", 1) minutes)) + ).protocols(httpConf) +} diff --git a/src/test/gatling/user-files/simulations/LabelGatlingTest.scala b/src/test/gatling/user-files/simulations/LabelGatlingTest.scala new file mode 100644 index 000000000..c0308ce89 --- /dev/null +++ b/src/test/gatling/user-files/simulations/LabelGatlingTest.scala @@ -0,0 +1,96 @@ +import _root_.io.gatling.core.scenario.Simulation +import ch.qos.logback.classic.{Level, LoggerContext} +import io.gatling.core.Predef._ +import io.gatling.http.Predef._ +import org.slf4j.LoggerFactory + +import scala.concurrent.duration._ + +/** + * Performance test for the Label entity. + */ +class LabelGatlingTest extends Simulation { + + val context: LoggerContext = LoggerFactory.getILoggerFactory.asInstanceOf[LoggerContext] + // Log all HTTP requests + //context.getLogger("io.gatling.http").setLevel(Level.valueOf("TRACE")) + // Log failed HTTP requests + //context.getLogger("io.gatling.http").setLevel(Level.valueOf("DEBUG")) + + val baseURL = Option(System.getProperty("baseURL")) getOrElse """http://localhost:8080""" + + val httpConf = http + .baseUrl(baseURL) + .inferHtmlResources() + .acceptHeader("*/*") + .acceptEncodingHeader("gzip, deflate") + .acceptLanguageHeader("fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3") + .connectionHeader("keep-alive") + .userAgentHeader("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:33.0) Gecko/20100101 Firefox/33.0") + .silentResources // Silence all resources like css or css so they don't clutter the results + + val headers_http = Map( + "Accept" -> """application/json""" + ) + + val headers_http_authentication = Map( + "Content-Type" -> """application/json""", + "Accept" -> """application/json""" + ) + + val headers_http_authenticated = Map( + "Accept" -> """application/json""", + "Authorization" -> "${access_token}" + ) + + val scn = scenario("Test the Label entity") + .exec(http("First unauthenticated request") + .get("/api/account") + .headers(headers_http) + .check(status.is(401)) + ).exitHereIfFailed + .pause(10) + .exec(http("Authentication") + .post("/api/authenticate") + .headers(headers_http_authentication) + .body(StringBody("""{"username":"admin", "password":"admin"}""")).asJson + .check(header("Authorization").saveAs("access_token"))).exitHereIfFailed + .pause(2) + .exec(http("Authenticated request") + .get("/api/account") + .headers(headers_http_authenticated) + .check(status.is(200))) + .pause(10) + .repeat(2) { + exec(http("Get all labels") + .get("/api/labels") + .headers(headers_http_authenticated) + .check(status.is(200))) + .pause(10 seconds, 20 seconds) + .exec(http("Create new label") + .post("/api/labels") + .headers(headers_http_authenticated) + .body(StringBody("""{ + "label":"SAMPLE_TEXT" + }""")).asJson + .check(status.is(201)) + .check(headerRegex("Location", "(.*)").saveAs("new_label_url"))).exitHereIfFailed + .pause(10) + .repeat(5) { + exec(http("Get created label") + .get("${new_label_url}") + .headers(headers_http_authenticated)) + .pause(10) + } + .exec(http("Delete created label") + .delete("${new_label_url}") + .headers(headers_http_authenticated)) + .pause(10) + } + + val users = scenario("Users").exec(scn) + + setUp( + users.inject(rampUsers(Integer.getInteger("users", 100)) during (Integer.getInteger("ramp", 1) minutes)) + ).protocols(httpConf) +} diff --git a/src/test/gatling/user-files/simulations/OperationGatlingTest.scala b/src/test/gatling/user-files/simulations/OperationGatlingTest.scala new file mode 100644 index 000000000..b77c0271b --- /dev/null +++ b/src/test/gatling/user-files/simulations/OperationGatlingTest.scala @@ -0,0 +1,98 @@ +import _root_.io.gatling.core.scenario.Simulation +import ch.qos.logback.classic.{Level, LoggerContext} +import io.gatling.core.Predef._ +import io.gatling.http.Predef._ +import org.slf4j.LoggerFactory + +import scala.concurrent.duration._ + +/** + * Performance test for the Operation entity. + */ +class OperationGatlingTest extends Simulation { + + val context: LoggerContext = LoggerFactory.getILoggerFactory.asInstanceOf[LoggerContext] + // Log all HTTP requests + //context.getLogger("io.gatling.http").setLevel(Level.valueOf("TRACE")) + // Log failed HTTP requests + //context.getLogger("io.gatling.http").setLevel(Level.valueOf("DEBUG")) + + val baseURL = Option(System.getProperty("baseURL")) getOrElse """http://localhost:8080""" + + val httpConf = http + .baseUrl(baseURL) + .inferHtmlResources() + .acceptHeader("*/*") + .acceptEncodingHeader("gzip, deflate") + .acceptLanguageHeader("fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3") + .connectionHeader("keep-alive") + .userAgentHeader("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:33.0) Gecko/20100101 Firefox/33.0") + .silentResources // Silence all resources like css or css so they don't clutter the results + + val headers_http = Map( + "Accept" -> """application/json""" + ) + + val headers_http_authentication = Map( + "Content-Type" -> """application/json""", + "Accept" -> """application/json""" + ) + + val headers_http_authenticated = Map( + "Accept" -> """application/json""", + "Authorization" -> "${access_token}" + ) + + val scn = scenario("Test the Operation entity") + .exec(http("First unauthenticated request") + .get("/api/account") + .headers(headers_http) + .check(status.is(401)) + ).exitHereIfFailed + .pause(10) + .exec(http("Authentication") + .post("/api/authenticate") + .headers(headers_http_authentication) + .body(StringBody("""{"username":"admin", "password":"admin"}""")).asJson + .check(header("Authorization").saveAs("access_token"))).exitHereIfFailed + .pause(2) + .exec(http("Authenticated request") + .get("/api/account") + .headers(headers_http_authenticated) + .check(status.is(200))) + .pause(10) + .repeat(2) { + exec(http("Get all operations") + .get("/api/operations") + .headers(headers_http_authenticated) + .check(status.is(200))) + .pause(10 seconds, 20 seconds) + .exec(http("Create new operation") + .post("/api/operations") + .headers(headers_http_authenticated) + .body(StringBody("""{ + "date":"2020-01-01T00:00:00.000Z" + , "description":"SAMPLE_TEXT" + , "amount":"0" + }""")).asJson + .check(status.is(201)) + .check(headerRegex("Location", "(.*)").saveAs("new_operation_url"))).exitHereIfFailed + .pause(10) + .repeat(5) { + exec(http("Get created operation") + .get("${new_operation_url}") + .headers(headers_http_authenticated)) + .pause(10) + } + .exec(http("Delete created operation") + .delete("${new_operation_url}") + .headers(headers_http_authenticated)) + .pause(10) + } + + val users = scenario("Users").exec(scn) + + setUp( + users.inject(rampUsers(Integer.getInteger("users", 100)) during (Integer.getInteger("ramp", 1) minutes)) + ).protocols(httpConf) +} diff --git a/src/test/java/gatling/simulations/BankAccountGatlingTest.java b/src/test/java/gatling/simulations/BankAccountGatlingTest.java deleted file mode 100644 index 4a5103de2..000000000 --- a/src/test/java/gatling/simulations/BankAccountGatlingTest.java +++ /dev/null @@ -1,97 +0,0 @@ -package gatling.simulations; - -import static io.gatling.javaapi.core.CoreDsl.StringBody; -import static io.gatling.javaapi.core.CoreDsl.css; -import static io.gatling.javaapi.core.CoreDsl.exec; -import static io.gatling.javaapi.core.CoreDsl.rampUsers; -import static io.gatling.javaapi.core.CoreDsl.scenario; -import static io.gatling.javaapi.http.HttpDsl.header; -import static io.gatling.javaapi.http.HttpDsl.headerRegex; -import static io.gatling.javaapi.http.HttpDsl.http; -import static io.gatling.javaapi.http.HttpDsl.status; - -import ch.qos.logback.classic.LoggerContext; -import io.gatling.javaapi.core.ChainBuilder; -import io.gatling.javaapi.core.ScenarioBuilder; -import io.gatling.javaapi.core.Simulation; -import io.gatling.javaapi.http.HttpProtocolBuilder; -import java.time.Duration; -import java.util.Map; -import java.util.Optional; -import org.slf4j.LoggerFactory; - -/** - * Performance test for the BankAccount entity. - */ -public class BankAccountGatlingTest extends Simulation { - - LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); - - { - // Log all HTTP requests - //context.getLogger("io.gatling.http").setLevel(Level.valueOf("TRACE")); - // Log failed HTTP requests - //context.getLogger("io.gatling.http").setLevel(Level.valueOf("DEBUG")); - } - - String baseURL = Optional.ofNullable(System.getProperty("baseURL")).orElse("http://localhost:8080"); - - HttpProtocolBuilder httpConf = http - .baseUrl(baseURL) - .inferHtmlResources() - .acceptHeader("*/*") - .acceptEncodingHeader("gzip, deflate") - .acceptLanguageHeader("fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3") - .connectionHeader("keep-alive") - .userAgentHeader("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:33.0) Gecko/20100101 Firefox/33.0") - .silentResources(); // Silence all resources like css or css so they don't clutter the results - - Map headers_http = Map.of("Accept", "application/json"); - - Map headers_http_authentication = Map.of("Content-Type", "application/json", "Accept", "application/json"); - - Map headers_http_authenticated = Map.of("Accept", "application/json", "Authorization", "${access_token}"); - - ChainBuilder scn = exec(http("First unauthenticated request").get("/api/account").headers(headers_http).check(status().is(401))) - .exitHereIfFailed() - .pause(10) - .exec( - http("Authentication") - .post("/api/authenticate") - .headers(headers_http_authentication) - .body(StringBody("{\"username\":\"admin\", \"password\":\"admin\"}")) - .asJson() - .check(header("Authorization").saveAs("access_token")) - ) - .exitHereIfFailed() - .pause(2) - .exec(http("Authenticated request").get("/api/account").headers(headers_http_authenticated).check(status().is(200))) - .pause(10) - .repeat(2) - .on( - exec(http("Get all bankAccounts").get("/api/bank-accounts").headers(headers_http_authenticated).check(status().is(200))) - .pause(Duration.ofSeconds(10), Duration.ofSeconds(20)) - .exec( - http("Create new bankAccount") - .post("/api/bank-accounts") - .headers(headers_http_authenticated) - .body(StringBody("{" + "\"name\": \"SAMPLE_TEXT\"" + ", \"balance\": 0" + "}")) - .asJson() - .check(status().is(201)) - .check(headerRegex("Location", "(.*)").saveAs("new_bankAccount_url")) - ) - .exitHereIfFailed() - .pause(10) - .repeat(5) - .on(exec(http("Get created bankAccount").get("${new_bankAccount_url}").headers(headers_http_authenticated)).pause(10)) - .exec(http("Delete created bankAccount").delete("${new_bankAccount_url}").headers(headers_http_authenticated)) - .pause(10) - ); - - ScenarioBuilder users = scenario("Test the BankAccount entity").exec(scn); - - { - setUp(users.injectOpen(rampUsers(Integer.getInteger("users", 100)).during(Duration.ofMinutes(Integer.getInteger("ramp", 1))))) - .protocols(httpConf); - } -} diff --git a/src/test/java/gatling/simulations/LabelGatlingTest.java b/src/test/java/gatling/simulations/LabelGatlingTest.java deleted file mode 100644 index b1a300d0a..000000000 --- a/src/test/java/gatling/simulations/LabelGatlingTest.java +++ /dev/null @@ -1,97 +0,0 @@ -package gatling.simulations; - -import static io.gatling.javaapi.core.CoreDsl.StringBody; -import static io.gatling.javaapi.core.CoreDsl.css; -import static io.gatling.javaapi.core.CoreDsl.exec; -import static io.gatling.javaapi.core.CoreDsl.rampUsers; -import static io.gatling.javaapi.core.CoreDsl.scenario; -import static io.gatling.javaapi.http.HttpDsl.header; -import static io.gatling.javaapi.http.HttpDsl.headerRegex; -import static io.gatling.javaapi.http.HttpDsl.http; -import static io.gatling.javaapi.http.HttpDsl.status; - -import ch.qos.logback.classic.LoggerContext; -import io.gatling.javaapi.core.ChainBuilder; -import io.gatling.javaapi.core.ScenarioBuilder; -import io.gatling.javaapi.core.Simulation; -import io.gatling.javaapi.http.HttpProtocolBuilder; -import java.time.Duration; -import java.util.Map; -import java.util.Optional; -import org.slf4j.LoggerFactory; - -/** - * Performance test for the Label entity. - */ -public class LabelGatlingTest extends Simulation { - - LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); - - { - // Log all HTTP requests - //context.getLogger("io.gatling.http").setLevel(Level.valueOf("TRACE")); - // Log failed HTTP requests - //context.getLogger("io.gatling.http").setLevel(Level.valueOf("DEBUG")); - } - - String baseURL = Optional.ofNullable(System.getProperty("baseURL")).orElse("http://localhost:8080"); - - HttpProtocolBuilder httpConf = http - .baseUrl(baseURL) - .inferHtmlResources() - .acceptHeader("*/*") - .acceptEncodingHeader("gzip, deflate") - .acceptLanguageHeader("fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3") - .connectionHeader("keep-alive") - .userAgentHeader("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:33.0) Gecko/20100101 Firefox/33.0") - .silentResources(); // Silence all resources like css or css so they don't clutter the results - - Map headers_http = Map.of("Accept", "application/json"); - - Map headers_http_authentication = Map.of("Content-Type", "application/json", "Accept", "application/json"); - - Map headers_http_authenticated = Map.of("Accept", "application/json", "Authorization", "${access_token}"); - - ChainBuilder scn = exec(http("First unauthenticated request").get("/api/account").headers(headers_http).check(status().is(401))) - .exitHereIfFailed() - .pause(10) - .exec( - http("Authentication") - .post("/api/authenticate") - .headers(headers_http_authentication) - .body(StringBody("{\"username\":\"admin\", \"password\":\"admin\"}")) - .asJson() - .check(header("Authorization").saveAs("access_token")) - ) - .exitHereIfFailed() - .pause(2) - .exec(http("Authenticated request").get("/api/account").headers(headers_http_authenticated).check(status().is(200))) - .pause(10) - .repeat(2) - .on( - exec(http("Get all labels").get("/api/labels").headers(headers_http_authenticated).check(status().is(200))) - .pause(Duration.ofSeconds(10), Duration.ofSeconds(20)) - .exec( - http("Create new label") - .post("/api/labels") - .headers(headers_http_authenticated) - .body(StringBody("{" + "\"label\": \"SAMPLE_TEXT\"" + "}")) - .asJson() - .check(status().is(201)) - .check(headerRegex("Location", "(.*)").saveAs("new_label_url")) - ) - .exitHereIfFailed() - .pause(10) - .repeat(5) - .on(exec(http("Get created label").get("${new_label_url}").headers(headers_http_authenticated)).pause(10)) - .exec(http("Delete created label").delete("${new_label_url}").headers(headers_http_authenticated)) - .pause(10) - ); - - ScenarioBuilder users = scenario("Test the Label entity").exec(scn); - - { - setUp(users.injectOpen(rampUsers(Integer.getInteger("users", 100)).during(Duration.ofMinutes(Integer.getInteger("ramp", 1))))) - .protocols(httpConf); - } -} diff --git a/src/test/java/gatling/simulations/OperationGatlingTest.java b/src/test/java/gatling/simulations/OperationGatlingTest.java deleted file mode 100644 index 174a80ade..000000000 --- a/src/test/java/gatling/simulations/OperationGatlingTest.java +++ /dev/null @@ -1,105 +0,0 @@ -package gatling.simulations; - -import static io.gatling.javaapi.core.CoreDsl.StringBody; -import static io.gatling.javaapi.core.CoreDsl.css; -import static io.gatling.javaapi.core.CoreDsl.exec; -import static io.gatling.javaapi.core.CoreDsl.rampUsers; -import static io.gatling.javaapi.core.CoreDsl.scenario; -import static io.gatling.javaapi.http.HttpDsl.header; -import static io.gatling.javaapi.http.HttpDsl.headerRegex; -import static io.gatling.javaapi.http.HttpDsl.http; -import static io.gatling.javaapi.http.HttpDsl.status; - -import ch.qos.logback.classic.LoggerContext; -import io.gatling.javaapi.core.ChainBuilder; -import io.gatling.javaapi.core.ScenarioBuilder; -import io.gatling.javaapi.core.Simulation; -import io.gatling.javaapi.http.HttpProtocolBuilder; -import java.time.Duration; -import java.util.Map; -import java.util.Optional; -import org.slf4j.LoggerFactory; - -/** - * Performance test for the Operation entity. - */ -public class OperationGatlingTest extends Simulation { - - LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); - - { - // Log all HTTP requests - //context.getLogger("io.gatling.http").setLevel(Level.valueOf("TRACE")); - // Log failed HTTP requests - //context.getLogger("io.gatling.http").setLevel(Level.valueOf("DEBUG")); - } - - String baseURL = Optional.ofNullable(System.getProperty("baseURL")).orElse("http://localhost:8080"); - - HttpProtocolBuilder httpConf = http - .baseUrl(baseURL) - .inferHtmlResources() - .acceptHeader("*/*") - .acceptEncodingHeader("gzip, deflate") - .acceptLanguageHeader("fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3") - .connectionHeader("keep-alive") - .userAgentHeader("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:33.0) Gecko/20100101 Firefox/33.0") - .silentResources(); // Silence all resources like css or css so they don't clutter the results - - Map headers_http = Map.of("Accept", "application/json"); - - Map headers_http_authentication = Map.of("Content-Type", "application/json", "Accept", "application/json"); - - Map headers_http_authenticated = Map.of("Accept", "application/json", "Authorization", "${access_token}"); - - ChainBuilder scn = exec(http("First unauthenticated request").get("/api/account").headers(headers_http).check(status().is(401))) - .exitHereIfFailed() - .pause(10) - .exec( - http("Authentication") - .post("/api/authenticate") - .headers(headers_http_authentication) - .body(StringBody("{\"username\":\"admin\", \"password\":\"admin\"}")) - .asJson() - .check(header("Authorization").saveAs("access_token")) - ) - .exitHereIfFailed() - .pause(2) - .exec(http("Authenticated request").get("/api/account").headers(headers_http_authenticated).check(status().is(200))) - .pause(10) - .repeat(2) - .on( - exec(http("Get all operations").get("/api/operations").headers(headers_http_authenticated).check(status().is(200))) - .pause(Duration.ofSeconds(10), Duration.ofSeconds(20)) - .exec( - http("Create new operation") - .post("/api/operations") - .headers(headers_http_authenticated) - .body( - StringBody( - "{" + - "\"date\": \"2020-01-01T00:00:00.000Z\"" + - ", \"description\": \"SAMPLE_TEXT\"" + - ", \"amount\": 0" + - "}" - ) - ) - .asJson() - .check(status().is(201)) - .check(headerRegex("Location", "(.*)").saveAs("new_operation_url")) - ) - .exitHereIfFailed() - .pause(10) - .repeat(5) - .on(exec(http("Get created operation").get("${new_operation_url}").headers(headers_http_authenticated)).pause(10)) - .exec(http("Delete created operation").delete("${new_operation_url}").headers(headers_http_authenticated)) - .pause(10) - ); - - ScenarioBuilder users = scenario("Test the Operation entity").exec(scn); - - { - setUp(users.injectOpen(rampUsers(Integer.getInteger("users", 100)).during(Duration.ofMinutes(Integer.getInteger("ramp", 1))))) - .protocols(httpConf); - } -} diff --git a/src/test/java/io/github/jhipster/sample/TechnicalStructureTest.java b/src/test/java/io/github/jhipster/sample/TechnicalStructureTest.java index dc075792d..1480987d4 100644 --- a/src/test/java/io/github/jhipster/sample/TechnicalStructureTest.java +++ b/src/test/java/io/github/jhipster/sample/TechnicalStructureTest.java @@ -15,7 +15,6 @@ class TechnicalStructureTest { // prettier-ignore @ArchTest static final ArchRule respectsTechnicalArchitectureLayers = layeredArchitecture() - .consideringAllDependencies() .layer("Config").definedBy("..config..") .layer("Web").definedBy("..web..") .optionalLayer("Service").definedBy("..service..") diff --git a/src/test/java/io/github/jhipster/sample/config/PostgreSqlTestContainer.java b/src/test/java/io/github/jhipster/sample/config/PostgreSqlTestContainer.java index fd630bc11..532337455 100644 --- a/src/test/java/io/github/jhipster/sample/config/PostgreSqlTestContainer.java +++ b/src/test/java/io/github/jhipster/sample/config/PostgreSqlTestContainer.java @@ -24,7 +24,7 @@ public void destroy() { public void afterPropertiesSet() { if (null == postgreSQLContainer) { postgreSQLContainer = - new PostgreSQLContainer<>("postgres:15.3") + new PostgreSQLContainer<>("postgres:14.5") .withDatabaseName("jhipsterSampleApplication") .withTmpFs(Collections.singletonMap("/testtmpfs", "rw")) .withLogConsumer(new Slf4jLogConsumer(log)) diff --git a/src/test/java/io/github/jhipster/sample/config/SqlTestContainersSpringContextCustomizerFactory.java b/src/test/java/io/github/jhipster/sample/config/SqlTestContainersSpringContextCustomizerFactory.java deleted file mode 100644 index e27063f7d..000000000 --- a/src/test/java/io/github/jhipster/sample/config/SqlTestContainersSpringContextCustomizerFactory.java +++ /dev/null @@ -1,54 +0,0 @@ -package io.github.jhipster.sample.config; - -import java.util.Arrays; -import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.beans.factory.support.DefaultSingletonBeanRegistry; -import org.springframework.boot.test.util.TestPropertyValues; -import org.springframework.core.annotation.AnnotatedElementUtils; -import org.springframework.test.context.ContextConfigurationAttributes; -import org.springframework.test.context.ContextCustomizer; -import org.springframework.test.context.ContextCustomizerFactory; -import tech.jhipster.config.JHipsterConstants; - -public class SqlTestContainersSpringContextCustomizerFactory implements ContextCustomizerFactory { - - private Logger log = LoggerFactory.getLogger(SqlTestContainersSpringContextCustomizerFactory.class); - - private static SqlTestContainer prodTestContainer; - - @Override - public ContextCustomizer createContextCustomizer(Class testClass, List configAttributes) { - return (context, mergedConfig) -> { - ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); - TestPropertyValues testValues = TestPropertyValues.empty(); - EmbeddedSQL sqlAnnotation = AnnotatedElementUtils.findMergedAnnotation(testClass, EmbeddedSQL.class); - boolean usingTestProdProfile = Arrays - .asList(context.getEnvironment().getActiveProfiles()) - .contains("test" + JHipsterConstants.SPRING_PROFILE_PRODUCTION); - if (null != sqlAnnotation && usingTestProdProfile) { - log.debug("detected the EmbeddedSQL annotation on class {}", testClass.getName()); - log.info("Warming up the sql database"); - if (null == prodTestContainer) { - try { - Class containerClass = (Class) Class.forName( - this.getClass().getPackageName() + ".PostgreSqlTestContainer" - ); - prodTestContainer = beanFactory.createBean(containerClass); - beanFactory.registerSingleton(containerClass.getName(), prodTestContainer); - // ((DefaultListableBeanFactory)beanFactory).registerDisposableBean(containerClass.getName(), prodTestContainer); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } - } - testValues = testValues.and("spring.datasource.url=" + prodTestContainer.getTestContainer().getJdbcUrl() + ""); - testValues = testValues.and("spring.datasource.username=" + prodTestContainer.getTestContainer().getUsername()); - testValues = testValues.and("spring.datasource.password=" + prodTestContainer.getTestContainer().getPassword()); - } - testValues.applyTo(context); - }; - } -} diff --git a/src/test/java/io/github/jhipster/sample/config/TestContainersSpringContextCustomizerFactory.java b/src/test/java/io/github/jhipster/sample/config/TestContainersSpringContextCustomizerFactory.java new file mode 100644 index 000000000..b34736897 --- /dev/null +++ b/src/test/java/io/github/jhipster/sample/config/TestContainersSpringContextCustomizerFactory.java @@ -0,0 +1,57 @@ +package io.github.jhipster.sample.config; + +import java.util.Arrays; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.DefaultSingletonBeanRegistry; +import org.springframework.boot.test.util.TestPropertyValues; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.test.context.ContextConfigurationAttributes; +import org.springframework.test.context.ContextCustomizer; +import org.springframework.test.context.ContextCustomizerFactory; +import tech.jhipster.config.JHipsterConstants; + +public class TestContainersSpringContextCustomizerFactory implements ContextCustomizerFactory { + + private Logger log = LoggerFactory.getLogger(TestContainersSpringContextCustomizerFactory.class); + + private static SqlTestContainer prodTestContainer; + + @Override + public ContextCustomizer createContextCustomizer(Class testClass, List configAttributes) { + return (context, mergedConfig) -> { + ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); + TestPropertyValues testValues = TestPropertyValues.empty(); + EmbeddedSQL sqlAnnotation = AnnotatedElementUtils.findMergedAnnotation(testClass, EmbeddedSQL.class); + if (null != sqlAnnotation) { + log.debug("detected the EmbeddedSQL annotation on class {}", testClass.getName()); + log.info("Warming up the sql database"); + if ( + Arrays + .asList(context.getEnvironment().getActiveProfiles()) + .contains("test" + JHipsterConstants.SPRING_PROFILE_PRODUCTION) + ) { + if (null == prodTestContainer) { + try { + Class containerClass = (Class) Class.forName( + this.getClass().getPackageName() + ".PostgreSqlTestContainer" + ); + prodTestContainer = beanFactory.createBean(containerClass); + beanFactory.registerSingleton(containerClass.getName(), prodTestContainer); + // ((DefaultListableBeanFactory)beanFactory).registerDisposableBean(containerClass.getName(), prodTestContainer); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + testValues = testValues.and("spring.datasource.url=" + prodTestContainer.getTestContainer().getJdbcUrl() + ""); + testValues = testValues.and("spring.datasource.username=" + prodTestContainer.getTestContainer().getUsername()); + testValues = testValues.and("spring.datasource.password=" + prodTestContainer.getTestContainer().getPassword()); + } + } + testValues.applyTo(context); + }; + } +} diff --git a/src/test/java/io/github/jhipster/sample/config/WebConfigurerTest.java b/src/test/java/io/github/jhipster/sample/config/WebConfigurerTest.java index 9da0850ab..bf81aade2 100644 --- a/src/test/java/io/github/jhipster/sample/config/WebConfigurerTest.java +++ b/src/test/java/io/github/jhipster/sample/config/WebConfigurerTest.java @@ -10,9 +10,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import jakarta.servlet.*; import java.io.File; import java.util.*; +import javax.servlet.*; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory; diff --git a/src/test/java/io/github/jhipster/sample/repository/timezone/DateTimeWrapper.java b/src/test/java/io/github/jhipster/sample/repository/timezone/DateTimeWrapper.java index 3ef84db22..2e278e38f 100644 --- a/src/test/java/io/github/jhipster/sample/repository/timezone/DateTimeWrapper.java +++ b/src/test/java/io/github/jhipster/sample/repository/timezone/DateTimeWrapper.java @@ -1,9 +1,9 @@ package io.github.jhipster.sample.repository.timezone; -import jakarta.persistence.*; import java.io.Serializable; import java.time.*; import java.util.Objects; +import javax.persistence.*; @Entity @Table(name = "jhi_date_time_wrapper") diff --git a/src/test/java/io/github/jhipster/sample/security/jwt/AuthenticationIntegrationTest.java b/src/test/java/io/github/jhipster/sample/security/jwt/AuthenticationIntegrationTest.java deleted file mode 100644 index e9448d3ed..000000000 --- a/src/test/java/io/github/jhipster/sample/security/jwt/AuthenticationIntegrationTest.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.github.jhipster.sample.security.jwt; - -import io.github.jhipster.sample.config.SecurityConfiguration; -import io.github.jhipster.sample.config.SecurityJwtConfiguration; -import io.github.jhipster.sample.config.WebConfigurer; -import io.github.jhipster.sample.management.SecurityMetersService; -import io.github.jhipster.sample.web.rest.AuthenticateController; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.annotation.DirtiesContext; -import tech.jhipster.config.JHipsterProperties; - -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@SpringBootTest( - properties = { - "jhipster.security.authentication.jwt.base64-secret=fd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8", - "jhipster.security.authentication.jwt.token-validity-in-seconds=60000", - }, - classes = { - JHipsterProperties.class, - WebConfigurer.class, - SecurityConfiguration.class, - SecurityJwtConfiguration.class, - SecurityMetersService.class, - AuthenticateController.class, - JwtAuthenticationTestUtils.class, - } -) -@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) -public @interface AuthenticationIntegrationTest { -} diff --git a/src/test/java/io/github/jhipster/sample/security/jwt/JWTFilterTest.java b/src/test/java/io/github/jhipster/sample/security/jwt/JWTFilterTest.java new file mode 100644 index 000000000..4311b7630 --- /dev/null +++ b/src/test/java/io/github/jhipster/sample/security/jwt/JWTFilterTest.java @@ -0,0 +1,117 @@ +package io.github.jhipster.sample.security.jwt; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.github.jhipster.sample.management.SecurityMetersService; +import io.github.jhipster.sample.security.AuthoritiesConstants; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import java.util.Collections; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpStatus; +import org.springframework.mock.web.MockFilterChain; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.test.util.ReflectionTestUtils; +import tech.jhipster.config.JHipsterProperties; + +class JWTFilterTest { + + private TokenProvider tokenProvider; + + private JWTFilter jwtFilter; + + @BeforeEach + public void setup() { + JHipsterProperties jHipsterProperties = new JHipsterProperties(); + String base64Secret = "fd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8"; + jHipsterProperties.getSecurity().getAuthentication().getJwt().setBase64Secret(base64Secret); + + SecurityMetersService securityMetersService = new SecurityMetersService(new SimpleMeterRegistry()); + + tokenProvider = new TokenProvider(jHipsterProperties, securityMetersService); + ReflectionTestUtils.setField(tokenProvider, "key", Keys.hmacShaKeyFor(Decoders.BASE64.decode(base64Secret))); + + ReflectionTestUtils.setField(tokenProvider, "tokenValidityInMilliseconds", 60000); + jwtFilter = new JWTFilter(tokenProvider); + SecurityContextHolder.getContext().setAuthentication(null); + } + + @Test + void testJWTFilter() throws Exception { + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + "test-user", + "test-password", + Collections.singletonList(new SimpleGrantedAuthority(AuthoritiesConstants.USER)) + ); + String jwt = tokenProvider.createToken(authentication, false); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader(JWTFilter.AUTHORIZATION_HEADER, "Bearer " + jwt); + request.setRequestURI("/api/test"); + MockHttpServletResponse response = new MockHttpServletResponse(); + MockFilterChain filterChain = new MockFilterChain(); + jwtFilter.doFilter(request, response, filterChain); + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); + assertThat(SecurityContextHolder.getContext().getAuthentication().getName()).isEqualTo("test-user"); + assertThat(SecurityContextHolder.getContext().getAuthentication().getCredentials()).hasToString(jwt); + } + + @Test + void testJWTFilterInvalidToken() throws Exception { + String jwt = "wrong_jwt"; + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader(JWTFilter.AUTHORIZATION_HEADER, "Bearer " + jwt); + request.setRequestURI("/api/test"); + MockHttpServletResponse response = new MockHttpServletResponse(); + MockFilterChain filterChain = new MockFilterChain(); + jwtFilter.doFilter(request, response, filterChain); + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); + assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull(); + } + + @Test + void testJWTFilterMissingAuthorization() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setRequestURI("/api/test"); + MockHttpServletResponse response = new MockHttpServletResponse(); + MockFilterChain filterChain = new MockFilterChain(); + jwtFilter.doFilter(request, response, filterChain); + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); + assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull(); + } + + @Test + void testJWTFilterMissingToken() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader(JWTFilter.AUTHORIZATION_HEADER, "Bearer "); + request.setRequestURI("/api/test"); + MockHttpServletResponse response = new MockHttpServletResponse(); + MockFilterChain filterChain = new MockFilterChain(); + jwtFilter.doFilter(request, response, filterChain); + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); + assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull(); + } + + @Test + void testJWTFilterWrongScheme() throws Exception { + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + "test-user", + "test-password", + Collections.singletonList(new SimpleGrantedAuthority(AuthoritiesConstants.USER)) + ); + String jwt = tokenProvider.createToken(authentication, false); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader(JWTFilter.AUTHORIZATION_HEADER, "Basic " + jwt); + request.setRequestURI("/api/test"); + MockHttpServletResponse response = new MockHttpServletResponse(); + MockFilterChain filterChain = new MockFilterChain(); + jwtFilter.doFilter(request, response, filterChain); + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); + assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull(); + } +} diff --git a/src/test/java/io/github/jhipster/sample/security/jwt/JwtAuthenticationTestUtils.java b/src/test/java/io/github/jhipster/sample/security/jwt/JwtAuthenticationTestUtils.java deleted file mode 100644 index 6a3111de1..000000000 --- a/src/test/java/io/github/jhipster/sample/security/jwt/JwtAuthenticationTestUtils.java +++ /dev/null @@ -1,106 +0,0 @@ -package io.github.jhipster.sample.security.jwt; - -import static io.github.jhipster.sample.security.SecurityUtils.AUTHORITIES_KEY; -import static io.github.jhipster.sample.security.SecurityUtils.JWT_ALGORITHM; - -import com.nimbusds.jose.jwk.source.ImmutableSecret; -import com.nimbusds.jose.util.Base64; -import io.micrometer.core.instrument.MeterRegistry; -import io.micrometer.core.instrument.simple.SimpleMeterRegistry; -import java.time.Instant; -import java.util.Collections; -import javax.crypto.Mac; -import javax.crypto.SecretKey; -import javax.crypto.spec.SecretKeySpec; -import org.springframework.context.annotation.Bean; -import org.springframework.security.crypto.codec.Hex; -import org.springframework.security.oauth2.jwt.JwsHeader; -import org.springframework.security.oauth2.jwt.JwtClaimsSet; -import org.springframework.security.oauth2.jwt.JwtEncoder; -import org.springframework.security.oauth2.jwt.JwtEncoderParameters; -import org.springframework.security.oauth2.jwt.NimbusJwtEncoder; -import org.springframework.web.servlet.handler.HandlerMappingIntrospector; - -public class JwtAuthenticationTestUtils { - - public static final String BEARER = "Bearer "; - - @Bean - private HandlerMappingIntrospector mvcHandlerMappingIntrospector() { - return new HandlerMappingIntrospector(); - } - - @Bean - private MeterRegistry meterRegistry() { - return new SimpleMeterRegistry(); - } - - public static String createValidToken(String jwtKey) { - return createValidTokenForUser(jwtKey, "anonymous"); - } - - public static String createValidTokenForUser(String jwtKey, String user) { - JwtEncoder encoder = jwtEncoder(jwtKey); - - var now = Instant.now(); - - JwtClaimsSet claims = JwtClaimsSet - .builder() - .issuedAt(now) - .expiresAt(now.plusSeconds(60)) - .subject(user) - .claims(customClain -> customClain.put(AUTHORITIES_KEY, Collections.singletonList("ROLE_ADMIN"))) - .build(); - - JwsHeader jwsHeader = JwsHeader.with(JWT_ALGORITHM).build(); - return encoder.encode(JwtEncoderParameters.from(jwsHeader, claims)).getTokenValue(); - } - - public static String createTokenWithDifferentSignature() { - JwtEncoder encoder = jwtEncoder("Xfd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8"); - - var now = Instant.now(); - var past = now.plusSeconds(60); - - JwtClaimsSet claims = JwtClaimsSet.builder().issuedAt(now).expiresAt(past).subject("anonymous").build(); - - JwsHeader jwsHeader = JwsHeader.with(JWT_ALGORITHM).build(); - return encoder.encode(JwtEncoderParameters.from(jwsHeader, claims)).getTokenValue(); - } - - public static String createExpiredToken(String jwtKey) { - JwtEncoder encoder = jwtEncoder(jwtKey); - - var now = Instant.now(); - var past = now.minusSeconds(600); - - JwtClaimsSet claims = JwtClaimsSet.builder().issuedAt(past).expiresAt(past.plusSeconds(1)).subject("anonymous").build(); - - JwsHeader jwsHeader = JwsHeader.with(JWT_ALGORITHM).build(); - return encoder.encode(JwtEncoderParameters.from(jwsHeader, claims)).getTokenValue(); - } - - public static String createInvalidToken(String jwtKey) throws Exception { - return createValidToken(jwtKey).substring(1); - } - - public static String createSignedInvalidJwt(String jwtKey) throws Exception { - return calculateHMAC("foo", jwtKey); - } - - private static JwtEncoder jwtEncoder(String jwtKey) { - return new NimbusJwtEncoder(new ImmutableSecret<>(getSecretKey(jwtKey))); - } - - private static SecretKey getSecretKey(String jwtKey) { - byte[] keyBytes = Base64.from(jwtKey).decode(); - return new SecretKeySpec(keyBytes, 0, keyBytes.length, JWT_ALGORITHM.getName()); - } - - private static String calculateHMAC(String data, String key) throws Exception { - SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.from(key).decode(), "HmacSHA512"); - Mac mac = Mac.getInstance("HmacSHA512"); - mac.init(secretKeySpec); - return String.copyValueOf(Hex.encode(mac.doFinal(data.getBytes()))); - } -} diff --git a/src/test/java/io/github/jhipster/sample/security/jwt/TokenAuthenticationIT.java b/src/test/java/io/github/jhipster/sample/security/jwt/TokenAuthenticationIT.java deleted file mode 100644 index 77b28096b..000000000 --- a/src/test/java/io/github/jhipster/sample/security/jwt/TokenAuthenticationIT.java +++ /dev/null @@ -1,53 +0,0 @@ -package io.github.jhipster.sample.security.jwt; - -import static io.github.jhipster.sample.security.jwt.JwtAuthenticationTestUtils.*; -import static org.springframework.http.HttpHeaders.AUTHORIZATION; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; - -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; - -@AutoConfigureMockMvc -@AuthenticationIntegrationTest -class TokenAuthenticationIT { - - @Autowired - private MockMvc mvc; - - @Value("${jhipster.security.authentication.jwt.base64-secret}") - private String jwtKey; - - @Test - void testLoginWithValidToken() throws Exception { - expectOk(createValidToken(jwtKey)); - } - - @Test - void testReturnFalseWhenJWThasInvalidSignature() throws Exception { - expectUnauthorized(createTokenWithDifferentSignature()); - } - - @Test - void testReturnFalseWhenJWTisMalformed() throws Exception { - expectUnauthorized(createSignedInvalidJwt(jwtKey)); - } - - @Test - void testReturnFalseWhenJWTisExpired() throws Exception { - expectUnauthorized(createExpiredToken(jwtKey)); - } - - private void expectOk(String token) throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/authenticate").header(AUTHORIZATION, BEARER + token)).andExpect(status().isOk()); - } - - private void expectUnauthorized(String token) throws Exception { - mvc - .perform(MockMvcRequestBuilders.get("/api/authenticate").header(AUTHORIZATION, BEARER + token)) - .andExpect(status().isUnauthorized()); - } -} diff --git a/src/test/java/io/github/jhipster/sample/security/jwt/TokenAuthenticationSecurityMetersIT.java b/src/test/java/io/github/jhipster/sample/security/jwt/TokenAuthenticationSecurityMetersIT.java deleted file mode 100644 index 4be3fefb2..000000000 --- a/src/test/java/io/github/jhipster/sample/security/jwt/TokenAuthenticationSecurityMetersIT.java +++ /dev/null @@ -1,87 +0,0 @@ -package io.github.jhipster.sample.security.jwt; - -import static io.github.jhipster.sample.security.jwt.JwtAuthenticationTestUtils.*; -import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.http.HttpHeaders.AUTHORIZATION; - -import io.micrometer.core.instrument.Counter; -import io.micrometer.core.instrument.MeterRegistry; -import java.util.Collection; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; - -@AutoConfigureMockMvc -@AuthenticationIntegrationTest -class TokenAuthenticationSecurityMetersIT { - - private static final String INVALID_TOKENS_METER_EXPECTED_NAME = "security.authentication.invalid-tokens"; - - @Autowired - private MockMvc mvc; - - @Value("${jhipster.security.authentication.jwt.base64-secret}") - private String jwtKey; - - @Autowired - private MeterRegistry meterRegistry; - - @Test - void testValidTokenShouldNotCountAnything() throws Exception { - Collection counters = meterRegistry.find(INVALID_TOKENS_METER_EXPECTED_NAME).counters(); - - var count = aggregate(counters); - - tryToAuthenticate(createValidToken(jwtKey)); - - assertThat(aggregate(counters)).isEqualTo(count); - } - - @Test - void testTokenExpiredCount() throws Exception { - var count = meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "expired").counter().count(); - - tryToAuthenticate(createExpiredToken(jwtKey)); - - assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "expired").counter().count()).isEqualTo(count + 1); - } - - @Test - void testTokenSignatureInvalidCount() throws Exception { - var count = meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "invalid-signature").counter().count(); - - tryToAuthenticate(createTokenWithDifferentSignature()); - - assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "invalid-signature").counter().count()) - .isEqualTo(count + 1); - } - - @Test - void testTokenMalformedCount() throws Exception { - var count = meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "malformed").counter().count(); - - tryToAuthenticate(createSignedInvalidJwt(jwtKey)); - - assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "malformed").counter().count()).isEqualTo(count + 1); - } - - @Test - void testTokenInvalidCount() throws Exception { - var count = meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "malformed").counter().count(); - - tryToAuthenticate(createInvalidToken(jwtKey)); - - assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "malformed").counter().count()).isEqualTo(count + 1); - } - - private void tryToAuthenticate(String token) throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/authenticate").header(AUTHORIZATION, BEARER + token)); - } - - private double aggregate(Collection counters) { - return counters.stream().mapToDouble(Counter::count).sum(); - } -} diff --git a/src/test/java/io/github/jhipster/sample/security/jwt/TokenProviderSecurityMetersTests.java b/src/test/java/io/github/jhipster/sample/security/jwt/TokenProviderSecurityMetersTests.java new file mode 100644 index 000000000..ca22383dd --- /dev/null +++ b/src/test/java/io/github/jhipster/sample/security/jwt/TokenProviderSecurityMetersTests.java @@ -0,0 +1,158 @@ +package io.github.jhipster.sample.security.jwt; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.github.jhipster.sample.management.SecurityMetersService; +import io.github.jhipster.sample.security.AuthoritiesConstants; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import java.security.Key; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.test.util.ReflectionTestUtils; +import tech.jhipster.config.JHipsterProperties; + +class TokenProviderSecurityMetersTests { + + private static final long ONE_MINUTE = 60000; + private static final String INVALID_TOKENS_METER_EXPECTED_NAME = "security.authentication.invalid-tokens"; + + private MeterRegistry meterRegistry; + + private TokenProvider tokenProvider; + + @BeforeEach + public void setup() { + JHipsterProperties jHipsterProperties = new JHipsterProperties(); + String base64Secret = "fd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8"; + jHipsterProperties.getSecurity().getAuthentication().getJwt().setBase64Secret(base64Secret); + + meterRegistry = new SimpleMeterRegistry(); + + SecurityMetersService securityMetersService = new SecurityMetersService(meterRegistry); + + tokenProvider = new TokenProvider(jHipsterProperties, securityMetersService); + Key key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(base64Secret)); + + ReflectionTestUtils.setField(tokenProvider, "key", key); + ReflectionTestUtils.setField(tokenProvider, "tokenValidityInMilliseconds", ONE_MINUTE); + } + + @Test + void testValidTokenShouldNotCountAnything() { + Collection counters = meterRegistry.find(INVALID_TOKENS_METER_EXPECTED_NAME).counters(); + + assertThat(aggregate(counters)).isZero(); + + String validToken = createValidToken(); + + tokenProvider.validateToken(validToken); + + assertThat(aggregate(counters)).isZero(); + } + + @Test + void testTokenExpiredCount() { + assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "expired").counter().count()).isZero(); + + String expiredToken = createExpiredToken(); + + tokenProvider.validateToken(expiredToken); + + assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "expired").counter().count()).isEqualTo(1); + } + + @Test + void testTokenUnsupportedCount() { + assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "unsupported").counter().count()).isZero(); + + String unsupportedToken = createUnsupportedToken(); + + tokenProvider.validateToken(unsupportedToken); + + assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "unsupported").counter().count()).isEqualTo(1); + } + + @Test + void testTokenSignatureInvalidCount() { + assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "invalid-signature").counter().count()).isZero(); + + String tokenWithDifferentSignature = createTokenWithDifferentSignature(); + + tokenProvider.validateToken(tokenWithDifferentSignature); + + assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "invalid-signature").counter().count()).isEqualTo(1); + } + + @Test + void testTokenMalformedCount() { + assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "malformed").counter().count()).isZero(); + + String malformedToken = createMalformedToken(); + + tokenProvider.validateToken(malformedToken); + + assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "malformed").counter().count()).isEqualTo(1); + } + + private String createValidToken() { + Authentication authentication = createAuthentication(); + + return tokenProvider.createToken(authentication, false); + } + + private String createExpiredToken() { + ReflectionTestUtils.setField(tokenProvider, "tokenValidityInMilliseconds", -ONE_MINUTE); + + Authentication authentication = createAuthentication(); + + return tokenProvider.createToken(authentication, false); + } + + private Authentication createAuthentication() { + Collection authorities = new ArrayList<>(); + authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.ANONYMOUS)); + return new UsernamePasswordAuthenticationToken("anonymous", "anonymous", authorities); + } + + private String createUnsupportedToken() { + Key key = (Key) ReflectionTestUtils.getField(tokenProvider, "key"); + + return Jwts.builder().setPayload("payload").signWith(key, SignatureAlgorithm.HS256).compact(); + } + + private String createMalformedToken() { + String validToken = createValidToken(); + + return "X" + validToken; + } + + private String createTokenWithDifferentSignature() { + Key otherKey = Keys.hmacShaKeyFor( + Decoders.BASE64.decode("Xfd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8") + ); + + return Jwts + .builder() + .setSubject("anonymous") + .signWith(otherKey, SignatureAlgorithm.HS512) + .setExpiration(new Date(new Date().getTime() + ONE_MINUTE)) + .compact(); + } + + private double aggregate(Collection counters) { + return counters.stream().mapToDouble(Counter::count).sum(); + } +} diff --git a/src/test/java/io/github/jhipster/sample/security/jwt/TokenProviderTest.java b/src/test/java/io/github/jhipster/sample/security/jwt/TokenProviderTest.java new file mode 100644 index 000000000..c282f69b2 --- /dev/null +++ b/src/test/java/io/github/jhipster/sample/security/jwt/TokenProviderTest.java @@ -0,0 +1,141 @@ +package io.github.jhipster.sample.security.jwt; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.github.jhipster.sample.management.SecurityMetersService; +import io.github.jhipster.sample.security.AuthoritiesConstants; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import java.nio.charset.StandardCharsets; +import java.security.Key; +import java.util.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.test.util.ReflectionTestUtils; +import tech.jhipster.config.JHipsterProperties; + +class TokenProviderTest { + + private static final long ONE_MINUTE = 60000; + + private Key key; + private TokenProvider tokenProvider; + + @BeforeEach + public void setup() { + JHipsterProperties jHipsterProperties = new JHipsterProperties(); + String base64Secret = "fd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8"; + jHipsterProperties.getSecurity().getAuthentication().getJwt().setBase64Secret(base64Secret); + + SecurityMetersService securityMetersService = new SecurityMetersService(new SimpleMeterRegistry()); + + tokenProvider = new TokenProvider(jHipsterProperties, securityMetersService); + key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(base64Secret)); + + ReflectionTestUtils.setField(tokenProvider, "key", key); + ReflectionTestUtils.setField(tokenProvider, "tokenValidityInMilliseconds", ONE_MINUTE); + } + + @Test + void testReturnFalseWhenJWThasInvalidSignature() { + boolean isTokenValid = tokenProvider.validateToken(createTokenWithDifferentSignature()); + + assertThat(isTokenValid).isFalse(); + } + + @Test + void testReturnFalseWhenJWTisMalformed() { + Authentication authentication = createAuthentication(); + String token = tokenProvider.createToken(authentication, false); + String invalidToken = token.substring(1); + boolean isTokenValid = tokenProvider.validateToken(invalidToken); + + assertThat(isTokenValid).isFalse(); + } + + @Test + void testReturnFalseWhenJWTisExpired() { + ReflectionTestUtils.setField(tokenProvider, "tokenValidityInMilliseconds", -ONE_MINUTE); + + Authentication authentication = createAuthentication(); + String token = tokenProvider.createToken(authentication, false); + + boolean isTokenValid = tokenProvider.validateToken(token); + + assertThat(isTokenValid).isFalse(); + } + + @Test + void testReturnFalseWhenJWTisUnsupported() { + String unsupportedToken = createUnsupportedToken(); + + boolean isTokenValid = tokenProvider.validateToken(unsupportedToken); + + assertThat(isTokenValid).isFalse(); + } + + @Test + void testReturnFalseWhenJWTisInvalid() { + boolean isTokenValid = tokenProvider.validateToken(""); + + assertThat(isTokenValid).isFalse(); + } + + @Test + void testKeyIsSetFromSecretWhenSecretIsNotEmpty() { + final String secret = "NwskoUmKHZtzGRKJKVjsJF7BtQMMxNWi"; + JHipsterProperties jHipsterProperties = new JHipsterProperties(); + jHipsterProperties.getSecurity().getAuthentication().getJwt().setSecret(secret); + + SecurityMetersService securityMetersService = new SecurityMetersService(new SimpleMeterRegistry()); + + TokenProvider tokenProvider = new TokenProvider(jHipsterProperties, securityMetersService); + + Key key = (Key) ReflectionTestUtils.getField(tokenProvider, "key"); + assertThat(key).isNotNull().isEqualTo(Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8))); + } + + @Test + void testKeyIsSetFromBase64SecretWhenSecretIsEmpty() { + final String base64Secret = "fd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8"; + JHipsterProperties jHipsterProperties = new JHipsterProperties(); + jHipsterProperties.getSecurity().getAuthentication().getJwt().setBase64Secret(base64Secret); + + SecurityMetersService securityMetersService = new SecurityMetersService(new SimpleMeterRegistry()); + + TokenProvider tokenProvider = new TokenProvider(jHipsterProperties, securityMetersService); + + Key key = (Key) ReflectionTestUtils.getField(tokenProvider, "key"); + assertThat(key).isNotNull().isEqualTo(Keys.hmacShaKeyFor(Decoders.BASE64.decode(base64Secret))); + } + + private Authentication createAuthentication() { + Collection authorities = new ArrayList<>(); + authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.ANONYMOUS)); + return new UsernamePasswordAuthenticationToken("anonymous", "anonymous", authorities); + } + + private String createUnsupportedToken() { + return Jwts.builder().setPayload("payload").signWith(key, SignatureAlgorithm.HS512).compact(); + } + + private String createTokenWithDifferentSignature() { + Key otherKey = Keys.hmacShaKeyFor( + Decoders.BASE64.decode("Xfd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8") + ); + + return Jwts + .builder() + .setSubject("anonymous") + .signWith(otherKey, SignatureAlgorithm.HS512) + .setExpiration(new Date(new Date().getTime() + ONE_MINUTE)) + .compact(); + } +} diff --git a/src/test/java/io/github/jhipster/sample/service/MailServiceIT.java b/src/test/java/io/github/jhipster/sample/service/MailServiceIT.java index f609113aa..983188254 100644 --- a/src/test/java/io/github/jhipster/sample/service/MailServiceIT.java +++ b/src/test/java/io/github/jhipster/sample/service/MailServiceIT.java @@ -7,11 +7,6 @@ import io.github.jhipster.sample.IntegrationTest; import io.github.jhipster.sample.config.Constants; import io.github.jhipster.sample.domain.User; -import jakarta.mail.Multipart; -import jakarta.mail.Session; -import jakarta.mail.internet.MimeBodyPart; -import jakarta.mail.internet.MimeMessage; -import jakarta.mail.internet.MimeMultipart; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; @@ -22,6 +17,11 @@ import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.mail.Multipart; +import javax.mail.Session; +import javax.mail.internet.MimeBodyPart; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeMultipart; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; @@ -205,7 +205,7 @@ void testSendLocalizedEmailForAllSupportedLanguages() throws Exception { verify(javaMailSender, atLeastOnce()).send(messageCaptor.capture()); MimeMessage message = messageCaptor.getValue(); - String propertyFilePath = "i18n/messages_" + getMessageSourceSuffixForLanguage(langKey) + ".properties"; + String propertyFilePath = "i18n/messages_" + getJavaLocale(langKey) + ".properties"; URL resource = this.getClass().getClassLoader().getResource(propertyFilePath); File file = new File(new URI(resource.getFile()).getPath()); Properties properties = new Properties(); @@ -221,7 +221,7 @@ void testSendLocalizedEmailForAllSupportedLanguages() throws Exception { /** * Convert a lang key to the Java locale. */ - private String getMessageSourceSuffixForLanguage(String langKey) { + private String getJavaLocale(String langKey) { String javaLangKey = langKey; Matcher matcher2 = PATTERN_LOCALE_2.matcher(langKey); if (matcher2.matches()) { diff --git a/src/test/java/io/github/jhipster/sample/web/filter/SpaWebFilterIT.java b/src/test/java/io/github/jhipster/sample/web/filter/SpaWebFilterIT.java deleted file mode 100644 index 9e22ec459..000000000 --- a/src/test/java/io/github/jhipster/sample/web/filter/SpaWebFilterIT.java +++ /dev/null @@ -1,88 +0,0 @@ -package io.github.jhipster.sample.web.filter; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import io.github.jhipster.sample.IntegrationTest; -import io.github.jhipster.sample.security.AuthoritiesConstants; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.web.servlet.MockMvc; - -@AutoConfigureMockMvc -@WithMockUser -@IntegrationTest -class SpaWebFilterIT { - - @Autowired - private MockMvc mockMvc; - - @Test - void testFilterForwardsToIndex() throws Exception { - mockMvc.perform(get("/")).andExpect(status().isOk()).andExpect(forwardedUrl("/index.html")); - } - - @Test - void testFilterDoesNotForwardToIndexForApi() throws Exception { - mockMvc.perform(get("/api/authenticate")).andExpect(status().isOk()).andExpect(forwardedUrl(null)); - } - - @Test - @WithMockUser(authorities = AuthoritiesConstants.ADMIN) - void testFilterDoesNotForwardToIndexForV3ApiDocs() throws Exception { - mockMvc.perform(get("/v3/api-docs")).andExpect(status().isOk()).andExpect(forwardedUrl(null)); - } - - @Test - void testFilterDoesNotForwardToIndexForDotFile() throws Exception { - mockMvc.perform(get("/file.js")).andExpect(status().isNotFound()); - } - - @Test - void getBackendEndpoint() throws Exception { - mockMvc.perform(get("/test")).andExpect(status().isOk()).andExpect(forwardedUrl("/index.html")); - } - - @Test - void forwardUnmappedFirstLevelMapping() throws Exception { - mockMvc.perform(get("/first-level")).andExpect(status().isOk()).andExpect(forwardedUrl("/index.html")); - } - - @Test - void forwardUnmappedSecondLevelMapping() throws Exception { - mockMvc.perform(get("/first-level/second-level")).andExpect(status().isOk()).andExpect(forwardedUrl("/index.html")); - } - - @Test - void forwardUnmappedThirdLevelMapping() throws Exception { - mockMvc.perform(get("/first-level/second-level/third-level")).andExpect(status().isOk()).andExpect(forwardedUrl("/index.html")); - } - - @Test - void forwardUnmappedDeepMapping() throws Exception { - mockMvc.perform(get("/1/2/3/4/5/6/7/8/9/10")).andExpect(forwardedUrl("/index.html")); - } - - @Test - void getUnmappedFirstLevelFile() throws Exception { - mockMvc.perform(get("/foo.js")).andExpect(status().isNotFound()); - } - - /** - * This test verifies that any files that aren't permitted by Spring Security will be forbidden. - * If you want to change this to return isNotFound(), you need to add a request mapping that - * allows this file in SecurityConfiguration. - */ - @Test - void getUnmappedSecondLevelFile() throws Exception { - mockMvc.perform(get("/foo/bar.js")).andExpect(status().isForbidden()); - } - - @Test - void getUnmappedThirdLevelFile() throws Exception { - mockMvc.perform(get("/foo/another/bar.js")).andExpect(status().isForbidden()); - } -} diff --git a/src/test/java/io/github/jhipster/sample/web/rest/AccountResourceIT.java b/src/test/java/io/github/jhipster/sample/web/rest/AccountResourceIT.java index 6f27c6b0e..eb6813ed4 100644 --- a/src/test/java/io/github/jhipster/sample/web/rest/AccountResourceIT.java +++ b/src/test/java/io/github/jhipster/sample/web/rest/AccountResourceIT.java @@ -263,13 +263,13 @@ void testRegisterDuplicateLogin() throws Exception { Optional testUser = userRepository.findOneByEmailIgnoreCase("alice2@example.com"); assertThat(testUser).isPresent(); - testUser.orElseThrow().setActivated(true); - userRepository.save(testUser.orElseThrow()); + testUser.get().setActivated(true); + userRepository.save(testUser.get()); // Second (already activated) user restAccountMockMvc .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(secondUser))) - .andExpect(status().isCreated()); + .andExpect(status().is4xxClientError()); } @Test @@ -339,15 +339,15 @@ void testRegisterDuplicateEmail() throws Exception { Optional testUser4 = userRepository.findOneByLogin("test-register-duplicate-email-3"); assertThat(testUser4).isPresent(); - assertThat(testUser4.orElseThrow().getEmail()).isEqualTo("test-register-duplicate-email@example.com"); + assertThat(testUser4.get().getEmail()).isEqualTo("test-register-duplicate-email@example.com"); - testUser4.orElseThrow().setActivated(true); - userService.updateUser((new AdminUserDTO(testUser4.orElseThrow()))); + testUser4.get().setActivated(true); + userService.updateUser((new AdminUserDTO(testUser4.get()))); // Register 4th (already activated) user restAccountMockMvc .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(secondUser))) - .andExpect(status().isCreated()); + .andExpect(status().is4xxClientError()); } @Test @@ -370,9 +370,9 @@ void testRegisterAdminIsIgnored() throws Exception { Optional userDup = userRepository.findOneWithAuthoritiesByLogin("badguy"); assertThat(userDup).isPresent(); - assertThat(userDup.orElseThrow().getAuthorities()) + assertThat(userDup.get().getAuthorities()) .hasSize(1) - .containsExactly(authorityRepository.findById(AuthoritiesConstants.USER).orElseThrow()); + .containsExactly(authorityRepository.findById(AuthoritiesConstants.USER).get()); } @Test diff --git a/src/test/java/io/github/jhipster/sample/web/rest/BankAccountResourceIT.java b/src/test/java/io/github/jhipster/sample/web/rest/BankAccountResourceIT.java index e729898dc..4c887d4af 100644 --- a/src/test/java/io/github/jhipster/sample/web/rest/BankAccountResourceIT.java +++ b/src/test/java/io/github/jhipster/sample/web/rest/BankAccountResourceIT.java @@ -10,12 +10,12 @@ import io.github.jhipster.sample.IntegrationTest; import io.github.jhipster.sample.domain.BankAccount; import io.github.jhipster.sample.repository.BankAccountRepository; -import jakarta.persistence.EntityManager; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.concurrent.atomic.AtomicLong; +import javax.persistence.EntityManager; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -227,7 +227,7 @@ void putExistingBankAccount() throws Exception { int databaseSizeBeforeUpdate = bankAccountRepository.findAll().size(); // Update the bankAccount - BankAccount updatedBankAccount = bankAccountRepository.findById(bankAccount.getId()).orElseThrow(); + BankAccount updatedBankAccount = bankAccountRepository.findById(bankAccount.getId()).get(); // Disconnect from session so that the updates on updatedBankAccount are not directly saved in db em.detach(updatedBankAccount); updatedBankAccount.name(UPDATED_NAME).balance(UPDATED_BALANCE); @@ -316,6 +316,8 @@ void partialUpdateBankAccountWithPatch() throws Exception { BankAccount partialUpdatedBankAccount = new BankAccount(); partialUpdatedBankAccount.setId(bankAccount.getId()); + partialUpdatedBankAccount.name(UPDATED_NAME).balance(UPDATED_BALANCE); + restBankAccountMockMvc .perform( patch(ENTITY_API_URL_ID, partialUpdatedBankAccount.getId()) @@ -328,8 +330,8 @@ void partialUpdateBankAccountWithPatch() throws Exception { List bankAccountList = bankAccountRepository.findAll(); assertThat(bankAccountList).hasSize(databaseSizeBeforeUpdate); BankAccount testBankAccount = bankAccountList.get(bankAccountList.size() - 1); - assertThat(testBankAccount.getName()).isEqualTo(DEFAULT_NAME); - assertThat(testBankAccount.getBalance()).isEqualByComparingTo(DEFAULT_BALANCE); + assertThat(testBankAccount.getName()).isEqualTo(UPDATED_NAME); + assertThat(testBankAccount.getBalance()).isEqualByComparingTo(UPDATED_BALANCE); } @Test diff --git a/src/test/java/io/github/jhipster/sample/web/rest/ClientForwardControllerTest.java b/src/test/java/io/github/jhipster/sample/web/rest/ClientForwardControllerTest.java new file mode 100644 index 000000000..b5e4680e2 --- /dev/null +++ b/src/test/java/io/github/jhipster/sample/web/rest/ClientForwardControllerTest.java @@ -0,0 +1,68 @@ +package io.github.jhipster.sample.web.rest; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * Unit tests for the {@link ClientForwardController} REST controller. + */ +class ClientForwardControllerTest { + + private MockMvc restMockMvc; + + @BeforeEach + public void setup() { + ClientForwardController clientForwardController = new ClientForwardController(); + this.restMockMvc = MockMvcBuilders.standaloneSetup(clientForwardController, new TestController()).build(); + } + + @Test + void getBackendEndpoint() throws Exception { + restMockMvc + .perform(get("/test")) + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_PLAIN_VALUE)) + .andExpect(content().string("test")); + } + + @Test + void getClientEndpoint() throws Exception { + ResultActions perform = restMockMvc.perform(get("/non-existant-mapping")); + perform.andExpect(status().isOk()).andExpect(forwardedUrl("/")); + } + + @Test + void getNestedClientEndpoint() throws Exception { + restMockMvc.perform(get("/admin/user-management")).andExpect(status().isOk()).andExpect(forwardedUrl("/")); + } + + @Test + void getUnmappedDottedEndpoint() throws Exception { + restMockMvc.perform(get("/foo.js")).andExpect(status().isNotFound()); + } + + @Test + void getUnmappedNestedDottedEndpoint() throws Exception { + restMockMvc.perform(get("/foo/bar.js")).andExpect(status().isNotFound()); + } + + @RestController + public static class TestController { + + @RequestMapping(value = "/test") + public String test() { + return "test"; + } + } +} diff --git a/src/test/java/io/github/jhipster/sample/web/rest/LabelResourceIT.java b/src/test/java/io/github/jhipster/sample/web/rest/LabelResourceIT.java index 89e012be5..d32b164a0 100644 --- a/src/test/java/io/github/jhipster/sample/web/rest/LabelResourceIT.java +++ b/src/test/java/io/github/jhipster/sample/web/rest/LabelResourceIT.java @@ -8,10 +8,10 @@ import io.github.jhipster.sample.IntegrationTest; import io.github.jhipster.sample.domain.Label; import io.github.jhipster.sample.repository.LabelRepository; -import jakarta.persistence.EntityManager; import java.util.List; import java.util.Random; import java.util.concurrent.atomic.AtomicLong; +import javax.persistence.EntityManager; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -173,7 +173,7 @@ void putExistingLabel() throws Exception { int databaseSizeBeforeUpdate = labelRepository.findAll().size(); // Update the label - Label updatedLabel = labelRepository.findById(label.getId()).orElseThrow(); + Label updatedLabel = labelRepository.findById(label.getId()).get(); // Disconnect from session so that the updates on updatedLabel are not directly saved in db em.detach(updatedLabel); updatedLabel.label(UPDATED_LABEL); diff --git a/src/test/java/io/github/jhipster/sample/web/rest/OperationResourceIT.java b/src/test/java/io/github/jhipster/sample/web/rest/OperationResourceIT.java index d5ad1cc91..8561aed6b 100644 --- a/src/test/java/io/github/jhipster/sample/web/rest/OperationResourceIT.java +++ b/src/test/java/io/github/jhipster/sample/web/rest/OperationResourceIT.java @@ -10,7 +10,6 @@ import io.github.jhipster.sample.IntegrationTest; import io.github.jhipster.sample.domain.Operation; import io.github.jhipster.sample.repository.OperationRepository; -import jakarta.persistence.EntityManager; import java.math.BigDecimal; import java.time.Instant; import java.time.temporal.ChronoUnit; @@ -18,6 +17,7 @@ import java.util.List; import java.util.Random; import java.util.concurrent.atomic.AtomicLong; +import javax.persistence.EntityManager; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -235,7 +235,7 @@ void putExistingOperation() throws Exception { int databaseSizeBeforeUpdate = operationRepository.findAll().size(); // Update the operation - Operation updatedOperation = operationRepository.findById(operation.getId()).orElseThrow(); + Operation updatedOperation = operationRepository.findById(operation.getId()).get(); // Disconnect from session so that the updates on updatedOperation are not directly saved in db em.detach(updatedOperation); updatedOperation.date(UPDATED_DATE).description(UPDATED_DESCRIPTION).amount(UPDATED_AMOUNT); @@ -325,8 +325,6 @@ void partialUpdateOperationWithPatch() throws Exception { Operation partialUpdatedOperation = new Operation(); partialUpdatedOperation.setId(operation.getId()); - partialUpdatedOperation.date(UPDATED_DATE); - restOperationMockMvc .perform( patch(ENTITY_API_URL_ID, partialUpdatedOperation.getId()) @@ -339,7 +337,7 @@ void partialUpdateOperationWithPatch() throws Exception { List operationList = operationRepository.findAll(); assertThat(operationList).hasSize(databaseSizeBeforeUpdate); Operation testOperation = operationList.get(operationList.size() - 1); - assertThat(testOperation.getDate()).isEqualTo(UPDATED_DATE); + assertThat(testOperation.getDate()).isEqualTo(DEFAULT_DATE); assertThat(testOperation.getDescription()).isEqualTo(DEFAULT_DESCRIPTION); assertThat(testOperation.getAmount()).isEqualByComparingTo(DEFAULT_AMOUNT); } diff --git a/src/test/java/io/github/jhipster/sample/web/rest/PublicUserResourceIT.java b/src/test/java/io/github/jhipster/sample/web/rest/PublicUserResourceIT.java index 091fbaadb..e34e66388 100644 --- a/src/test/java/io/github/jhipster/sample/web/rest/PublicUserResourceIT.java +++ b/src/test/java/io/github/jhipster/sample/web/rest/PublicUserResourceIT.java @@ -9,7 +9,7 @@ import io.github.jhipster.sample.domain.User; import io.github.jhipster.sample.repository.UserRepository; import io.github.jhipster.sample.security.AuthoritiesConstants; -import jakarta.persistence.EntityManager; +import javax.persistence.EntityManager; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -21,7 +21,7 @@ import org.springframework.transaction.annotation.Transactional; /** - * Integration tests for the {@link PublicUserResource} REST controller. + * Integration tests for the {@link UserResource} REST controller. */ @AutoConfigureMockMvc @WithMockUser(authorities = AuthoritiesConstants.ADMIN) diff --git a/src/test/java/io/github/jhipster/sample/web/rest/TestUtil.java b/src/test/java/io/github/jhipster/sample/web/rest/TestUtil.java index c6a7b58a9..021f5c470 100644 --- a/src/test/java/io/github/jhipster/sample/web/rest/TestUtil.java +++ b/src/test/java/io/github/jhipster/sample/web/rest/TestUtil.java @@ -6,16 +6,16 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import jakarta.persistence.EntityManager; -import jakarta.persistence.TypedQuery; -import jakarta.persistence.criteria.CriteriaBuilder; -import jakarta.persistence.criteria.CriteriaQuery; -import jakarta.persistence.criteria.Root; import java.io.IOException; import java.math.BigDecimal; import java.time.ZonedDateTime; import java.time.format.DateTimeParseException; import java.util.List; +import javax.persistence.EntityManager; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; import org.hamcrest.Description; import org.hamcrest.TypeSafeDiagnosingMatcher; import org.hamcrest.TypeSafeMatcher; @@ -187,16 +187,16 @@ public static FormattingConversionService createFormattingConversionService() { } /** - * Executes a query on the EntityManager finding all stored objects. + * Makes a an executes a query to the EntityManager finding all stored objects. * @param The type of objects to be searched * @param em The instance of the EntityManager - * @param clazz The class type to be searched + * @param clss The class type to be searched * @return A list of all found objects */ - public static List findAll(EntityManager em, Class clazz) { + public static List findAll(EntityManager em, Class clss) { CriteriaBuilder cb = em.getCriteriaBuilder(); - CriteriaQuery cq = cb.createQuery(clazz); - Root rootEntry = cq.from(clazz); + CriteriaQuery cq = cb.createQuery(clss); + Root rootEntry = cq.from(clss); CriteriaQuery all = cq.select(rootEntry); TypedQuery allQuery = em.createQuery(all); return allQuery.getResultList(); diff --git a/src/test/java/io/github/jhipster/sample/web/rest/AuthenticateControllerIT.java b/src/test/java/io/github/jhipster/sample/web/rest/UserJWTControllerIT.java similarity index 97% rename from src/test/java/io/github/jhipster/sample/web/rest/AuthenticateControllerIT.java rename to src/test/java/io/github/jhipster/sample/web/rest/UserJWTControllerIT.java index 0b76c992f..e65c51990 100644 --- a/src/test/java/io/github/jhipster/sample/web/rest/AuthenticateControllerIT.java +++ b/src/test/java/io/github/jhipster/sample/web/rest/UserJWTControllerIT.java @@ -22,11 +22,11 @@ import org.springframework.transaction.annotation.Transactional; /** - * Integration tests for the {@link AuthenticateController} REST controller. + * Integration tests for the {@link UserJWTController} REST controller. */ @AutoConfigureMockMvc @IntegrationTest -class AuthenticateControllerIT { +class UserJWTControllerIT { @Autowired private UserRepository userRepository; diff --git a/src/test/java/io/github/jhipster/sample/web/rest/UserResourceIT.java b/src/test/java/io/github/jhipster/sample/web/rest/UserResourceIT.java index 560724a03..66ca5d8be 100644 --- a/src/test/java/io/github/jhipster/sample/web/rest/UserResourceIT.java +++ b/src/test/java/io/github/jhipster/sample/web/rest/UserResourceIT.java @@ -12,10 +12,11 @@ import io.github.jhipster.sample.security.AuthoritiesConstants; import io.github.jhipster.sample.service.dto.AdminUserDTO; import io.github.jhipster.sample.service.mapper.UserMapper; -import jakarta.persistence.EntityManager; +import io.github.jhipster.sample.web.rest.vm.ManagedUserVM; import java.time.Instant; import java.util.*; import java.util.function.Consumer; +import javax.persistence.EntityManager; import org.apache.commons.lang3.RandomStringUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -122,18 +123,21 @@ void createUser() throws Exception { int databaseSizeBeforeCreate = userRepository.findAll().size(); // Create the User - AdminUserDTO user = new AdminUserDTO(); - user.setLogin(DEFAULT_LOGIN); - user.setFirstName(DEFAULT_FIRSTNAME); - user.setLastName(DEFAULT_LASTNAME); - user.setEmail(DEFAULT_EMAIL); - user.setActivated(true); - user.setImageUrl(DEFAULT_IMAGEURL); - user.setLangKey(DEFAULT_LANGKEY); - user.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setLogin(DEFAULT_LOGIN); + managedUserVM.setPassword(DEFAULT_PASSWORD); + managedUserVM.setFirstName(DEFAULT_FIRSTNAME); + managedUserVM.setLastName(DEFAULT_LASTNAME); + managedUserVM.setEmail(DEFAULT_EMAIL); + managedUserVM.setActivated(true); + managedUserVM.setImageUrl(DEFAULT_IMAGEURL); + managedUserVM.setLangKey(DEFAULT_LANGKEY); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); restUserMockMvc - .perform(post("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(user))) + .perform( + post("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(managedUserVM)) + ) .andExpect(status().isCreated()); // Validate the User in the database @@ -154,20 +158,23 @@ void createUser() throws Exception { void createUserWithExistingId() throws Exception { int databaseSizeBeforeCreate = userRepository.findAll().size(); - AdminUserDTO user = new AdminUserDTO(); - user.setId(DEFAULT_ID); - user.setLogin(DEFAULT_LOGIN); - user.setFirstName(DEFAULT_FIRSTNAME); - user.setLastName(DEFAULT_LASTNAME); - user.setEmail(DEFAULT_EMAIL); - user.setActivated(true); - user.setImageUrl(DEFAULT_IMAGEURL); - user.setLangKey(DEFAULT_LANGKEY); - user.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setId(DEFAULT_ID); + managedUserVM.setLogin(DEFAULT_LOGIN); + managedUserVM.setPassword(DEFAULT_PASSWORD); + managedUserVM.setFirstName(DEFAULT_FIRSTNAME); + managedUserVM.setLastName(DEFAULT_LASTNAME); + managedUserVM.setEmail(DEFAULT_EMAIL); + managedUserVM.setActivated(true); + managedUserVM.setImageUrl(DEFAULT_IMAGEURL); + managedUserVM.setLangKey(DEFAULT_LANGKEY); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); // An entity with an existing ID cannot be created, so this API call must fail restUserMockMvc - .perform(post("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(user))) + .perform( + post("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(managedUserVM)) + ) .andExpect(status().isBadRequest()); // Validate the User in the database @@ -181,19 +188,22 @@ void createUserWithExistingLogin() throws Exception { userRepository.saveAndFlush(user); int databaseSizeBeforeCreate = userRepository.findAll().size(); - AdminUserDTO user = new AdminUserDTO(); - user.setLogin(DEFAULT_LOGIN); // this login should already be used - user.setFirstName(DEFAULT_FIRSTNAME); - user.setLastName(DEFAULT_LASTNAME); - user.setEmail("anothermail@localhost"); - user.setActivated(true); - user.setImageUrl(DEFAULT_IMAGEURL); - user.setLangKey(DEFAULT_LANGKEY); - user.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setLogin(DEFAULT_LOGIN); // this login should already be used + managedUserVM.setPassword(DEFAULT_PASSWORD); + managedUserVM.setFirstName(DEFAULT_FIRSTNAME); + managedUserVM.setLastName(DEFAULT_LASTNAME); + managedUserVM.setEmail("anothermail@localhost"); + managedUserVM.setActivated(true); + managedUserVM.setImageUrl(DEFAULT_IMAGEURL); + managedUserVM.setLangKey(DEFAULT_LANGKEY); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); // Create the User restUserMockMvc - .perform(post("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(user))) + .perform( + post("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(managedUserVM)) + ) .andExpect(status().isBadRequest()); // Validate the User in the database @@ -207,19 +217,22 @@ void createUserWithExistingEmail() throws Exception { userRepository.saveAndFlush(user); int databaseSizeBeforeCreate = userRepository.findAll().size(); - AdminUserDTO user = new AdminUserDTO(); - user.setLogin("anotherlogin"); - user.setFirstName(DEFAULT_FIRSTNAME); - user.setLastName(DEFAULT_LASTNAME); - user.setEmail(DEFAULT_EMAIL); // this email should already be used - user.setActivated(true); - user.setImageUrl(DEFAULT_IMAGEURL); - user.setLangKey(DEFAULT_LANGKEY); - user.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setLogin("anotherlogin"); + managedUserVM.setPassword(DEFAULT_PASSWORD); + managedUserVM.setFirstName(DEFAULT_FIRSTNAME); + managedUserVM.setLastName(DEFAULT_LASTNAME); + managedUserVM.setEmail(DEFAULT_EMAIL); // this email should already be used + managedUserVM.setActivated(true); + managedUserVM.setImageUrl(DEFAULT_IMAGEURL); + managedUserVM.setLangKey(DEFAULT_LANGKEY); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); // Create the User restUserMockMvc - .perform(post("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(user))) + .perform( + post("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(managedUserVM)) + ) .andExpect(status().isBadRequest()); // Validate the User in the database @@ -282,31 +295,34 @@ void updateUser() throws Exception { int databaseSizeBeforeUpdate = userRepository.findAll().size(); // Update the user - User updatedUser = userRepository.findById(user.getId()).orElseThrow(); - - AdminUserDTO user = new AdminUserDTO(); - user.setId(updatedUser.getId()); - user.setLogin(updatedUser.getLogin()); - user.setFirstName(UPDATED_FIRSTNAME); - user.setLastName(UPDATED_LASTNAME); - user.setEmail(UPDATED_EMAIL); - user.setActivated(updatedUser.isActivated()); - user.setImageUrl(UPDATED_IMAGEURL); - user.setLangKey(UPDATED_LANGKEY); - user.setCreatedBy(updatedUser.getCreatedBy()); - user.setCreatedDate(updatedUser.getCreatedDate()); - user.setLastModifiedBy(updatedUser.getLastModifiedBy()); - user.setLastModifiedDate(updatedUser.getLastModifiedDate()); - user.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + User updatedUser = userRepository.findById(user.getId()).get(); + + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setId(updatedUser.getId()); + managedUserVM.setLogin(updatedUser.getLogin()); + managedUserVM.setPassword(UPDATED_PASSWORD); + managedUserVM.setFirstName(UPDATED_FIRSTNAME); + managedUserVM.setLastName(UPDATED_LASTNAME); + managedUserVM.setEmail(UPDATED_EMAIL); + managedUserVM.setActivated(updatedUser.isActivated()); + managedUserVM.setImageUrl(UPDATED_IMAGEURL); + managedUserVM.setLangKey(UPDATED_LANGKEY); + managedUserVM.setCreatedBy(updatedUser.getCreatedBy()); + managedUserVM.setCreatedDate(updatedUser.getCreatedDate()); + managedUserVM.setLastModifiedBy(updatedUser.getLastModifiedBy()); + managedUserVM.setLastModifiedDate(updatedUser.getLastModifiedDate()); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); restUserMockMvc - .perform(put("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(user))) + .perform( + put("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(managedUserVM)) + ) .andExpect(status().isOk()); // Validate the User in the database assertPersistedUsers(users -> { assertThat(users).hasSize(databaseSizeBeforeUpdate); - User testUser = users.stream().filter(usr -> usr.getId().equals(updatedUser.getId())).findFirst().orElseThrow(); + User testUser = users.stream().filter(usr -> usr.getId().equals(updatedUser.getId())).findFirst().get(); assertThat(testUser.getFirstName()).isEqualTo(UPDATED_FIRSTNAME); assertThat(testUser.getLastName()).isEqualTo(UPDATED_LASTNAME); assertThat(testUser.getEmail()).isEqualTo(UPDATED_EMAIL); @@ -323,31 +339,34 @@ void updateUserLogin() throws Exception { int databaseSizeBeforeUpdate = userRepository.findAll().size(); // Update the user - User updatedUser = userRepository.findById(user.getId()).orElseThrow(); - - AdminUserDTO user = new AdminUserDTO(); - user.setId(updatedUser.getId()); - user.setLogin(UPDATED_LOGIN); - user.setFirstName(UPDATED_FIRSTNAME); - user.setLastName(UPDATED_LASTNAME); - user.setEmail(UPDATED_EMAIL); - user.setActivated(updatedUser.isActivated()); - user.setImageUrl(UPDATED_IMAGEURL); - user.setLangKey(UPDATED_LANGKEY); - user.setCreatedBy(updatedUser.getCreatedBy()); - user.setCreatedDate(updatedUser.getCreatedDate()); - user.setLastModifiedBy(updatedUser.getLastModifiedBy()); - user.setLastModifiedDate(updatedUser.getLastModifiedDate()); - user.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + User updatedUser = userRepository.findById(user.getId()).get(); + + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setId(updatedUser.getId()); + managedUserVM.setLogin(UPDATED_LOGIN); + managedUserVM.setPassword(UPDATED_PASSWORD); + managedUserVM.setFirstName(UPDATED_FIRSTNAME); + managedUserVM.setLastName(UPDATED_LASTNAME); + managedUserVM.setEmail(UPDATED_EMAIL); + managedUserVM.setActivated(updatedUser.isActivated()); + managedUserVM.setImageUrl(UPDATED_IMAGEURL); + managedUserVM.setLangKey(UPDATED_LANGKEY); + managedUserVM.setCreatedBy(updatedUser.getCreatedBy()); + managedUserVM.setCreatedDate(updatedUser.getCreatedDate()); + managedUserVM.setLastModifiedBy(updatedUser.getLastModifiedBy()); + managedUserVM.setLastModifiedDate(updatedUser.getLastModifiedDate()); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); restUserMockMvc - .perform(put("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(user))) + .perform( + put("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(managedUserVM)) + ) .andExpect(status().isOk()); // Validate the User in the database assertPersistedUsers(users -> { assertThat(users).hasSize(databaseSizeBeforeUpdate); - User testUser = users.stream().filter(usr -> usr.getId().equals(updatedUser.getId())).findFirst().orElseThrow(); + User testUser = users.stream().filter(usr -> usr.getId().equals(updatedUser.getId())).findFirst().get(); assertThat(testUser.getLogin()).isEqualTo(UPDATED_LOGIN); assertThat(testUser.getFirstName()).isEqualTo(UPDATED_FIRSTNAME); assertThat(testUser.getLastName()).isEqualTo(UPDATED_LASTNAME); @@ -375,25 +394,28 @@ void updateUserExistingEmail() throws Exception { userRepository.saveAndFlush(anotherUser); // Update the user - User updatedUser = userRepository.findById(user.getId()).orElseThrow(); - - AdminUserDTO user = new AdminUserDTO(); - user.setId(updatedUser.getId()); - user.setLogin(updatedUser.getLogin()); - user.setFirstName(updatedUser.getFirstName()); - user.setLastName(updatedUser.getLastName()); - user.setEmail("jhipster@localhost"); // this email should already be used by anotherUser - user.setActivated(updatedUser.isActivated()); - user.setImageUrl(updatedUser.getImageUrl()); - user.setLangKey(updatedUser.getLangKey()); - user.setCreatedBy(updatedUser.getCreatedBy()); - user.setCreatedDate(updatedUser.getCreatedDate()); - user.setLastModifiedBy(updatedUser.getLastModifiedBy()); - user.setLastModifiedDate(updatedUser.getLastModifiedDate()); - user.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + User updatedUser = userRepository.findById(user.getId()).get(); + + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setId(updatedUser.getId()); + managedUserVM.setLogin(updatedUser.getLogin()); + managedUserVM.setPassword(updatedUser.getPassword()); + managedUserVM.setFirstName(updatedUser.getFirstName()); + managedUserVM.setLastName(updatedUser.getLastName()); + managedUserVM.setEmail("jhipster@localhost"); // this email should already be used by anotherUser + managedUserVM.setActivated(updatedUser.isActivated()); + managedUserVM.setImageUrl(updatedUser.getImageUrl()); + managedUserVM.setLangKey(updatedUser.getLangKey()); + managedUserVM.setCreatedBy(updatedUser.getCreatedBy()); + managedUserVM.setCreatedDate(updatedUser.getCreatedDate()); + managedUserVM.setLastModifiedBy(updatedUser.getLastModifiedBy()); + managedUserVM.setLastModifiedDate(updatedUser.getLastModifiedDate()); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); restUserMockMvc - .perform(put("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(user))) + .perform( + put("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(managedUserVM)) + ) .andExpect(status().isBadRequest()); } @@ -415,25 +437,28 @@ void updateUserExistingLogin() throws Exception { userRepository.saveAndFlush(anotherUser); // Update the user - User updatedUser = userRepository.findById(user.getId()).orElseThrow(); - - AdminUserDTO user = new AdminUserDTO(); - user.setId(updatedUser.getId()); - user.setLogin("jhipster"); // this login should already be used by anotherUser - user.setFirstName(updatedUser.getFirstName()); - user.setLastName(updatedUser.getLastName()); - user.setEmail(updatedUser.getEmail()); - user.setActivated(updatedUser.isActivated()); - user.setImageUrl(updatedUser.getImageUrl()); - user.setLangKey(updatedUser.getLangKey()); - user.setCreatedBy(updatedUser.getCreatedBy()); - user.setCreatedDate(updatedUser.getCreatedDate()); - user.setLastModifiedBy(updatedUser.getLastModifiedBy()); - user.setLastModifiedDate(updatedUser.getLastModifiedDate()); - user.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); + User updatedUser = userRepository.findById(user.getId()).get(); + + ManagedUserVM managedUserVM = new ManagedUserVM(); + managedUserVM.setId(updatedUser.getId()); + managedUserVM.setLogin("jhipster"); // this login should already be used by anotherUser + managedUserVM.setPassword(updatedUser.getPassword()); + managedUserVM.setFirstName(updatedUser.getFirstName()); + managedUserVM.setLastName(updatedUser.getLastName()); + managedUserVM.setEmail(updatedUser.getEmail()); + managedUserVM.setActivated(updatedUser.isActivated()); + managedUserVM.setImageUrl(updatedUser.getImageUrl()); + managedUserVM.setLangKey(updatedUser.getLangKey()); + managedUserVM.setCreatedBy(updatedUser.getCreatedBy()); + managedUserVM.setCreatedDate(updatedUser.getCreatedDate()); + managedUserVM.setLastModifiedBy(updatedUser.getLastModifiedBy()); + managedUserVM.setLastModifiedDate(updatedUser.getLastModifiedDate()); + managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); restUserMockMvc - .perform(put("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(user))) + .perform( + put("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(managedUserVM)) + ) .andExpect(status().isBadRequest()); } diff --git a/src/test/java/io/github/jhipster/sample/web/rest/errors/ExceptionTranslatorIT.java b/src/test/java/io/github/jhipster/sample/web/rest/errors/ExceptionTranslatorIT.java index fc0ff77cc..ff08b20e8 100644 --- a/src/test/java/io/github/jhipster/sample/web/rest/errors/ExceptionTranslatorIT.java +++ b/src/test/java/io/github/jhipster/sample/web/rest/errors/ExceptionTranslatorIT.java @@ -93,7 +93,7 @@ void testMethodNotSupported() throws Exception { .andExpect(status().isMethodNotAllowed()) .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) .andExpect(jsonPath("$.message").value("error.http.405")) - .andExpect(jsonPath("$.detail").value("Request method 'POST' is not supported")); + .andExpect(jsonPath("$.detail").value("Request method 'POST' not supported")); } @Test diff --git a/src/test/java/io/github/jhipster/sample/web/rest/errors/ExceptionTranslatorTestController.java b/src/test/java/io/github/jhipster/sample/web/rest/errors/ExceptionTranslatorTestController.java index 29cbea8c2..78f39cabb 100644 --- a/src/test/java/io/github/jhipster/sample/web/rest/errors/ExceptionTranslatorTestController.java +++ b/src/test/java/io/github/jhipster/sample/web/rest/errors/ExceptionTranslatorTestController.java @@ -1,7 +1,7 @@ package io.github.jhipster.sample.web.rest.errors; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; import org.springframework.dao.ConcurrencyFailureException; import org.springframework.http.HttpStatus; import org.springframework.security.access.AccessDeniedException; diff --git a/src/test/javascript/cypress/e2e/account/password-page.cy.ts b/src/test/javascript/cypress/e2e/account/password-page.cy.ts index f84eee602..ed62edfa5 100644 --- a/src/test/javascript/cypress/e2e/account/password-page.cy.ts +++ b/src/test/javascript/cypress/e2e/account/password-page.cy.ts @@ -27,25 +27,20 @@ describe('/account/password', () => { }); it('requires current password', () => { - cy.get(currentPasswordSelector).should('have.class', classInvalid); - cy.get(currentPasswordSelector).type('wrong-current-password'); - cy.get(currentPasswordSelector).blur(); - cy.get(currentPasswordSelector).should('have.class', classValid); + cy.get(currentPasswordSelector) + .should('have.class', classInvalid) + .type('wrong-current-password') + .blur() + .should('have.class', classValid); }); it('requires new password', () => { - cy.get(newPasswordSelector).should('have.class', classInvalid); - cy.get(newPasswordSelector).type('jhipster'); - cy.get(newPasswordSelector).blur(); - cy.get(newPasswordSelector).should('have.class', classValid); + cy.get(newPasswordSelector).should('have.class', classInvalid).type('jhipster').blur().should('have.class', classValid); }); it('requires confirm new password', () => { cy.get(newPasswordSelector).type('jhipster'); - cy.get(confirmPasswordSelector).should('have.class', classInvalid); - cy.get(confirmPasswordSelector).type('jhipster'); - cy.get(confirmPasswordSelector).blur(); - cy.get(confirmPasswordSelector).should('have.class', classValid); + cy.get(confirmPasswordSelector).should('have.class', classInvalid).type('jhipster').blur().should('have.class', classValid); }); it('should fail to update password when using incorrect current password', () => { diff --git a/src/test/javascript/cypress/e2e/account/register-page.cy.ts b/src/test/javascript/cypress/e2e/account/register-page.cy.ts index 704d3638e..19fc45bd1 100644 --- a/src/test/javascript/cypress/e2e/account/register-page.cy.ts +++ b/src/test/javascript/cypress/e2e/account/register-page.cy.ts @@ -28,57 +28,38 @@ describe('/account/register', () => { }); it('requires username', () => { - cy.get(usernameRegisterSelector).should('have.class', classInvalid); - cy.get(usernameRegisterSelector).type('test'); - cy.get(usernameRegisterSelector).blur(); - cy.get(usernameRegisterSelector).should('have.class', classValid); + cy.get(usernameRegisterSelector).should('have.class', classInvalid).type('test').blur().should('have.class', classValid); }); it('should not accept invalid email', () => { - cy.get(emailRegisterSelector).should('have.class', classInvalid); - cy.get(emailRegisterSelector).type('testtest.fr'); - cy.get(emailRegisterSelector).blur(); - cy.get(emailRegisterSelector).should('have.class', classInvalid); + cy.get(emailRegisterSelector).should('have.class', classInvalid).type('testtest.fr').blur().should('have.class', classInvalid); }); it('requires email in correct format', () => { - cy.get(emailRegisterSelector).should('have.class', classInvalid); - cy.get(emailRegisterSelector).type('test@test.fr'); - cy.get(emailRegisterSelector).blur(); - cy.get(emailRegisterSelector).should('have.class', classValid); + cy.get(emailRegisterSelector).should('have.class', classInvalid).type('test@test.fr').blur().should('have.class', classValid); }); it('requires first password', () => { - cy.get(firstPasswordRegisterSelector).should('have.class', classInvalid); - cy.get(firstPasswordRegisterSelector).type('test@test.fr'); - cy.get(firstPasswordRegisterSelector).blur(); - cy.get(firstPasswordRegisterSelector).should('have.class', classValid); + cy.get(firstPasswordRegisterSelector).should('have.class', classInvalid).type('test@test.fr').blur().should('have.class', classValid); }); it('requires password and confirm password to be same', () => { - cy.get(firstPasswordRegisterSelector).should('have.class', classInvalid); - cy.get(firstPasswordRegisterSelector).type('test'); - cy.get(firstPasswordRegisterSelector).blur(); - cy.get(firstPasswordRegisterSelector).should('have.class', classValid); - cy.get(secondPasswordRegisterSelector).should('have.class', classInvalid); - cy.get(secondPasswordRegisterSelector).type('test'); - cy.get(secondPasswordRegisterSelector).blur(); - cy.get(secondPasswordRegisterSelector).should('have.class', classValid); + cy.get(firstPasswordRegisterSelector).should('have.class', classInvalid).type('test').blur().should('have.class', classValid); + cy.get(secondPasswordRegisterSelector).should('have.class', classInvalid).type('test').blur().should('have.class', classValid); }); it('requires password and confirm password have not the same value', () => { - cy.get(firstPasswordRegisterSelector).should('have.class', classInvalid); - cy.get(firstPasswordRegisterSelector).type('test'); - cy.get(firstPasswordRegisterSelector).blur(); - cy.get(firstPasswordRegisterSelector).should('have.class', classValid); - cy.get(secondPasswordRegisterSelector).should('have.class', classInvalid); - cy.get(secondPasswordRegisterSelector).type('otherPassword'); - cy.get(submitRegisterSelector).should('be.disabled'); + cy.get(firstPasswordRegisterSelector).should('have.class', classInvalid).type('test').blur().should('have.class', classValid); + cy.get(secondPasswordRegisterSelector) + .should('have.class', classInvalid) + .type('otherPassword') + .blur() + .should('have.class', classInvalid); }); it('register a valid user', () => { - const randomEmail = 'Mariah44@hotmail.com'; - const randomUsername = 'Arvel_Osinski55'; + const randomEmail = 'Aliza.Heaney44@hotmail.com'; + const randomUsername = 'Arvid_Balistreri64'; cy.get(usernameRegisterSelector).type(randomUsername); cy.get(emailRegisterSelector).type(randomEmail); cy.get(firstPasswordRegisterSelector).type('jondoe'); diff --git a/src/test/javascript/cypress/e2e/account/reset-password-page.cy.ts b/src/test/javascript/cypress/e2e/account/reset-password-page.cy.ts index dbe3ef2e5..ee64cb245 100644 --- a/src/test/javascript/cypress/e2e/account/reset-password-page.cy.ts +++ b/src/test/javascript/cypress/e2e/account/reset-password-page.cy.ts @@ -22,8 +22,7 @@ describe('forgot your password', () => { }); it('requires email', () => { - cy.get(emailResetPasswordSelector).should('have.class', classInvalid); - cy.get(emailResetPasswordSelector).type('user@gmail.com'); + cy.get(emailResetPasswordSelector).should('have.class', classInvalid).type('user@gmail.com'); cy.get(emailResetPasswordSelector).should('have.class', classValid); }); diff --git a/src/test/javascript/cypress/e2e/account/settings-page.cy.ts b/src/test/javascript/cypress/e2e/account/settings-page.cy.ts index 45edf7d92..c41e16f26 100644 --- a/src/test/javascript/cypress/e2e/account/settings-page.cy.ts +++ b/src/test/javascript/cypress/e2e/account/settings-page.cy.ts @@ -1,5 +1,4 @@ import { firstNameSettingsSelector, lastNameSettingsSelector, submitSettingsSelector, emailSettingsSelector } from '../../support/commands'; -import type { Account } from '../../support/account'; describe('/account/settings', () => { const adminUsername = Cypress.env('E2E_USERNAME') ?? 'admin'; @@ -7,38 +6,13 @@ describe('/account/settings', () => { const username = Cypress.env('E2E_USERNAME') ?? 'user'; const password = Cypress.env('E2E_PASSWORD') ?? 'user'; - const testUserEmail = 'user@localhost.fr'; - let originalUserAccount: Account; - let testUserAccount: Account; - - before(() => { - cy.login(username, password); - - cy.getAccount().then(account => { - originalUserAccount = account; - testUserAccount = { ...account, email: testUserEmail }; - - // need to modify email because default email does not match regex in some frameworks - cy.saveAccount(testUserAccount).its('status').should('eq', 200); - }); - }); - beforeEach(() => { cy.login(username, password); cy.visit('/account/settings'); - cy.get(emailSettingsSelector).should('have.value', testUserEmail); - - cy.intercept('POST', '/api/account').as('settingsSave'); }); - afterEach(() => { - cy.login(username, password); - cy.saveAccount(testUserAccount).its('status').should('eq', 200); - }); - - after(() => { - cy.login(username, password); - cy.saveAccount(originalUserAccount).its('status').should('eq', 200); + beforeEach(() => { + cy.intercept('POST', '/api/account').as('settingsSave'); }); it('should be accessible through menu', () => { @@ -48,52 +22,45 @@ describe('/account/settings', () => { }); it("should be able to change 'user' firstname settings", () => { - cy.get(firstNameSettingsSelector).clear(); - cy.get(firstNameSettingsSelector).type('jhipster'); + cy.get(firstNameSettingsSelector).clear().type('jhipster'); + // need to modify email because default email does not match regex in vue + cy.get(emailSettingsSelector).clear().type('user@localhost.fr'); cy.get(submitSettingsSelector).click(); - cy.wait('@settingsSave').then(({ response }) => expect(response?.statusCode).to.equal(200)); + cy.wait('@settingsSave').then(({ response }) => expect(response.statusCode).to.equal(200)); }); it("should be able to change 'user' lastname settings", () => { - cy.get(lastNameSettingsSelector).clear(); - cy.get(lastNameSettingsSelector).type('retspihj'); + cy.get(lastNameSettingsSelector).clear().type('retspihj'); + // need to modify email because default email does not match regex in vue + cy.get(emailSettingsSelector).clear().type('user@localhost.fr'); cy.get(submitSettingsSelector).click(); - cy.wait('@settingsSave').then(({ response }) => expect(response?.statusCode).to.equal(200)); + cy.wait('@settingsSave').then(({ response }) => expect(response.statusCode).to.equal(200)); }); it("should be able to change 'user' email settings", () => { - cy.get(emailSettingsSelector).clear(); - cy.get(emailSettingsSelector).type('user@localhost.fr'); + cy.get(emailSettingsSelector).clear().type('user@localhost.fr'); cy.get(submitSettingsSelector).click(); - cy.wait('@settingsSave').then(({ response }) => expect(response?.statusCode).to.equal(200)); + cy.wait('@settingsSave').then(({ response }) => expect(response.statusCode).to.equal(200)); }); describe('if there is another user with an email', () => { - let originalAdminAccount: Account; - const testAdminEmail = 'admin@localhost.fr'; - before(() => { cy.login(adminUsername, adminPassword); - cy.getAccount().then(account => { - originalAdminAccount = account; - - // need to modify email because default email does not match regex in some frameworks - cy.saveAccount({ ...account, email: testAdminEmail }) - .its('status') - .should('eq', 200); - }); - }); - - after(() => { - cy.login(adminUsername, adminPassword); - cy.saveAccount(originalAdminAccount).its('status').should('eq', 200); + cy.visit('/account/settings'); + cy.get(emailSettingsSelector).clear().type('admin@localhost.fr'); + cy.intercept({ + method: 'POST', + url: '/api/account', + times: 1, + }).as('settingsSave'); + cy.get(submitSettingsSelector).click(); + cy.wait('@settingsSave'); }); it("should not be able to change 'user' email to same value", () => { - cy.get(emailSettingsSelector).clear(); - cy.get(emailSettingsSelector).type(testAdminEmail); + cy.get(emailSettingsSelector).clear().type('admin@localhost.fr'); cy.get(submitSettingsSelector).click(); - cy.wait('@settingsSave').then(({ response }) => expect(response?.statusCode).to.equal(400)); + cy.wait('@settingsSave').then(({ response }) => expect(response.statusCode).to.equal(400)); }); }); }); diff --git a/src/test/javascript/cypress/e2e/entity/bank-account.cy.ts b/src/test/javascript/cypress/e2e/entity/bank-account.cy.ts index bd86d5e3d..8ec50f943 100644 --- a/src/test/javascript/cypress/e2e/entity/bank-account.cy.ts +++ b/src/test/javascript/cypress/e2e/entity/bank-account.cy.ts @@ -15,7 +15,7 @@ describe('BankAccount e2e test', () => { const bankAccountPageUrlPattern = new RegExp('/bank-account(\\?.*)?$'); const username = Cypress.env('E2E_USERNAME') ?? 'user'; const password = Cypress.env('E2E_PASSWORD') ?? 'user'; - const bankAccountSample = { name: 'modi', balance: 18773 }; + const bankAccountSample = { name: 'Refined Visionary', balance: 14517 }; let bankAccount; @@ -157,11 +157,9 @@ describe('BankAccount e2e test', () => { }); it('should create an instance of BankAccount', () => { - cy.get(`[data-cy="name"]`).type('deposit olive protocol'); - cy.get(`[data-cy="name"]`).should('have.value', 'deposit olive protocol'); + cy.get(`[data-cy="name"]`).type('experiences withdrawal').should('have.value', 'experiences withdrawal'); - cy.get(`[data-cy="balance"]`).type('9469'); - cy.get(`[data-cy="balance"]`).should('have.value', '9469'); + cy.get(`[data-cy="balance"]`).type('93119').should('have.value', '93119'); cy.get(entityCreateSaveButtonSelector).click(); diff --git a/src/test/javascript/cypress/e2e/entity/label.cy.ts b/src/test/javascript/cypress/e2e/entity/label.cy.ts index bde5f0548..7a3c24198 100644 --- a/src/test/javascript/cypress/e2e/entity/label.cy.ts +++ b/src/test/javascript/cypress/e2e/entity/label.cy.ts @@ -15,7 +15,7 @@ describe('Label e2e test', () => { const labelPageUrlPattern = new RegExp('/label(\\?.*)?$'); const username = Cypress.env('E2E_USERNAME') ?? 'user'; const password = Cypress.env('E2E_PASSWORD') ?? 'user'; - const labelSample = { label: 'Nevada male Berkshire' }; + const labelSample = { label: 'input bypass' }; let label; @@ -157,8 +157,7 @@ describe('Label e2e test', () => { }); it('should create an instance of Label', () => { - cy.get(`[data-cy="label"]`).type('Branding wrapping'); - cy.get(`[data-cy="label"]`).should('have.value', 'Branding wrapping'); + cy.get(`[data-cy="label"]`).type('Synergized').should('have.value', 'Synergized'); cy.get(entityCreateSaveButtonSelector).click(); diff --git a/src/test/javascript/cypress/e2e/entity/operation.cy.ts b/src/test/javascript/cypress/e2e/entity/operation.cy.ts index dd4890afb..6280e8b74 100644 --- a/src/test/javascript/cypress/e2e/entity/operation.cy.ts +++ b/src/test/javascript/cypress/e2e/entity/operation.cy.ts @@ -15,7 +15,7 @@ describe('Operation e2e test', () => { const operationPageUrlPattern = new RegExp('/operation(\\?.*)?$'); const username = Cypress.env('E2E_USERNAME') ?? 'user'; const password = Cypress.env('E2E_PASSWORD') ?? 'user'; - const operationSample = { date: '2015-08-05T05:24:11.952Z', amount: 20913 }; + const operationSample = { date: '2015-08-04T18:04:46.481Z', amount: 40149 }; let operation; @@ -160,15 +160,11 @@ describe('Operation e2e test', () => { }); it('should create an instance of Operation', () => { - cy.get(`[data-cy="date"]`).type('2015-08-04T22:14'); - cy.get(`[data-cy="date"]`).blur(); - cy.get(`[data-cy="date"]`).should('have.value', '2015-08-04T22:14'); + cy.get(`[data-cy="date"]`).type('2015-08-05T09:35').blur().should('have.value', '2015-08-05T09:35'); - cy.get(`[data-cy="description"]`).type('Soap wireless Peso'); - cy.get(`[data-cy="description"]`).should('have.value', 'Soap wireless Peso'); + cy.get(`[data-cy="description"]`).type('back-end iterate').should('have.value', 'back-end iterate'); - cy.get(`[data-cy="amount"]`).type('31059'); - cy.get(`[data-cy="amount"]`).should('have.value', '31059'); + cy.get(`[data-cy="amount"]`).type('10331').should('have.value', '10331'); cy.get(entityCreateSaveButtonSelector).click(); diff --git a/src/test/javascript/cypress/fixtures/integration-test.png b/src/test/javascript/cypress/fixtures/integration-test.png old mode 100644 new mode 100755 diff --git a/src/test/javascript/cypress/plugins/index.ts b/src/test/javascript/cypress/plugins/index.ts index b88c9928b..b0f502018 100644 --- a/src/test/javascript/cypress/plugins/index.ts +++ b/src/test/javascript/cypress/plugins/index.ts @@ -12,6 +12,7 @@ // the project's config changing) import { existsSync, mkdirSync, writeFileSync } from 'fs'; import { lighthouse, pa11y, prepareAudit } from 'cypress-audit'; +import ReportGenerator from 'lighthouse/report/generator/report-generator'; export default async (on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions) => { on('before:browser:launch', (browser, launchOptions) => { @@ -22,22 +23,9 @@ export default async (on: Cypress.PluginEvents, config: Cypress.PluginConfigOpti } }); - // Allows logging with cy.task('log', 'message') or cy.task('table', object) on('task', { - log(message) { - console.log(message); - return null; - }, - table(message) { - console.table(message); - return null; - }, - }); - - on('task', { - lighthouse: lighthouse(async lighthouseReport => { - const { default: ReportGenerator } = await import('lighthouse/report/generator/report-generator'); - !existsSync('target/cypress/') && mkdirSync('target/cypress/', { recursive: true }); + lighthouse: lighthouse(lighthouseReport => { + !existsSync('target/cypress') && mkdirSync('target/cypress', { recursive: true }); writeFileSync('target/cypress/lhreport.html', ReportGenerator.generateReport(lighthouseReport.lhr, 'html')); }), pa11y: pa11y(), diff --git a/src/test/javascript/cypress/support/account.ts b/src/test/javascript/cypress/support/account.ts deleted file mode 100644 index da5d3682b..000000000 --- a/src/test/javascript/cypress/support/account.ts +++ /dev/null @@ -1,27 +0,0 @@ -export type Account = Record; - -Cypress.Commands.add('getAccount', () => { - return cy - .authenticatedRequest({ - method: 'GET', - url: '/api/account', - }) - .then(response => response.body as Account); -}); - -Cypress.Commands.add('saveAccount', (account: Account) => { - return cy.authenticatedRequest({ - method: 'POST', - url: '/api/account', - body: account, - }); -}); - -declare global { - namespace Cypress { - interface Chainable { - getAccount(): Cypress.Chainable; - saveAccount(account: Account): Cypress.Chainable>; - } - } -} diff --git a/src/test/javascript/cypress/support/commands.ts b/src/test/javascript/cypress/support/commands.ts index 96a3fdbcc..3a540af23 100644 --- a/src/test/javascript/cypress/support/commands.ts +++ b/src/test/javascript/cypress/support/commands.ts @@ -74,22 +74,16 @@ export const configurationPageHeadingSelector = '[data-cy="configurationPageHead // End Specific Selector Attributes for Cypress // *********************************************** -export const classInvalid = 'ng-invalid'; - -export const classValid = 'ng-valid'; - +export const classInvalid = 'invalid'; +export const classValid = 'valid'; Cypress.Commands.add('authenticatedRequest', data => { - const jwtToken = sessionStorage.getItem(Cypress.env('jwtStorageName')); - const bearerToken = jwtToken && JSON.parse(jwtToken); - if (bearerToken) { - return cy.request({ - ...data, - auth: { - bearer: bearerToken, - }, - }); - } - return cy.request(data); + const bearerToken = sessionStorage.getItem(Cypress.env('jwtStorageName')); + return cy.request({ + ...data, + auth: { + bearer: bearerToken, + }, + }); }); Cypress.Commands.add('login', (username: string, password: string) => { diff --git a/src/test/javascript/cypress/support/entity.ts b/src/test/javascript/cypress/support/entity.ts index 904458425..e944772dd 100644 --- a/src/test/javascript/cypress/support/entity.ts +++ b/src/test/javascript/cypress/support/entity.ts @@ -62,8 +62,7 @@ Cypress.Commands.add('setFieldSelectToLastOfEntity', (fieldName: string) => { return cy.get(`[data-cy="${fieldName}"] option`).then((options: JQuery) => { const elements = [...options].map((o: HTMLElement) => (o as HTMLOptionElement).label); const lastElement = elements.length - 1; - cy.get(`[data-cy="${fieldName}"]`).select(lastElement); - cy.get(`[data-cy="${fieldName}"]`).type('{downarrow}'); + cy.get(`[data-cy="${fieldName}"]`).select(lastElement).type('{downarrow}'); }); } else { return cy.get(`[data-cy="${fieldName}"]`).type('{downarrow}'); diff --git a/src/test/javascript/cypress/support/index.ts b/src/test/javascript/cypress/support/index.ts index 96bd01cc2..1a4430051 100644 --- a/src/test/javascript/cypress/support/index.ts +++ b/src/test/javascript/cypress/support/index.ts @@ -13,7 +13,6 @@ // https://on.cypress.io/configuration // *********************************************************** -import './account'; import './commands'; import './navbar'; import './entity'; diff --git a/src/test/javascript/cypress/support/navbar.ts b/src/test/javascript/cypress/support/navbar.ts index 8a06068e8..6c1b656db 100644 --- a/src/test/javascript/cypress/support/navbar.ts +++ b/src/test/javascript/cypress/support/navbar.ts @@ -14,38 +14,31 @@ import { } from './commands'; Cypress.Commands.add('clickOnLoginItem', () => { - cy.get(navbarSelector).get(accountMenuSelector).click(); - return cy.get(navbarSelector).get(accountMenuSelector).get(loginItemSelector).click(); + return cy.get(navbarSelector).get(accountMenuSelector).click().get(loginItemSelector).click(); }); Cypress.Commands.add('clickOnLogoutItem', () => { - cy.get(navbarSelector).get(accountMenuSelector).click(); - return cy.get(navbarSelector).get(accountMenuSelector).get(logoutItemSelector).click(); + return cy.get(navbarSelector).get(accountMenuSelector).click().get(logoutItemSelector).click(); }); Cypress.Commands.add('clickOnRegisterItem', () => { - cy.get(navbarSelector).get(accountMenuSelector).click(); - return cy.get(navbarSelector).get(accountMenuSelector).get(registerItemSelector).click(); + return cy.get(navbarSelector).get(accountMenuSelector).click().get(registerItemSelector).click(); }); Cypress.Commands.add('clickOnSettingsItem', () => { - cy.get(navbarSelector).get(accountMenuSelector).click(); - return cy.get(navbarSelector).get(accountMenuSelector).get(settingsItemSelector).click(); + return cy.get(navbarSelector).get(accountMenuSelector).click().get(settingsItemSelector).click(); }); Cypress.Commands.add('clickOnPasswordItem', () => { - cy.get(navbarSelector).get(accountMenuSelector).click(); - return cy.get(navbarSelector).get(accountMenuSelector).get(passwordItemSelector).click(); + return cy.get(navbarSelector).get(accountMenuSelector).click().get(passwordItemSelector).click(); }); Cypress.Commands.add('clickOnAdminMenuItem', (item: string) => { - cy.get(navbarSelector).get(adminMenuSelector).click(); - return cy.get(navbarSelector).get(adminMenuSelector).get(`.dropdown-item[href="/admin/${item}"]`).click(); + return cy.get(navbarSelector).get(adminMenuSelector).click().get(`.dropdown-item[href="/admin/${item}"]`).click(); }); Cypress.Commands.add('clickOnEntityMenuItem', (entityName: string) => { - cy.get(navbarSelector).get(entityItemSelector).click(); - return cy.get(navbarSelector).get(entityItemSelector).get(`.dropdown-item[href="/${entityName}"]`).click({ force: true }); + return cy.get(navbarSelector).get(entityItemSelector).click().get(`.dropdown-item[href="/${entityName}"]`).click(); }); declare global { diff --git a/src/test/javascript/cypress/tsconfig.json b/src/test/javascript/cypress/tsconfig.json index bf2d9fa84..c0f1ddc11 100644 --- a/src/test/javascript/cypress/tsconfig.json +++ b/src/test/javascript/cypress/tsconfig.json @@ -2,8 +2,7 @@ "extends": "../../../../tsconfig.json", "compilerOptions": { "baseUrl": "./", - "sourceMap": false, - "outDir": "../../../../target/cypress/out-tsc", + "outDir": "../../../../target/out-tsc/cypress", "target": "es2018", "types": ["cypress", "node"] }, diff --git a/src/test/resources/META-INF/spring.factories b/src/test/resources/META-INF/spring.factories index d23f3042e..a2d487413 100644 --- a/src/test/resources/META-INF/spring.factories +++ b/src/test/resources/META-INF/spring.factories @@ -1,2 +1 @@ -org.springframework.test.context.ContextCustomizerFactory = io.github.jhipster.\ - sample.config.SqlTestContainersSpringContextCustomizerFactory \ No newline at end of file +org.springframework.test.context.ContextCustomizerFactory = io.github.jhipster.sample.config.TestContainersSpringContextCustomizerFactory diff --git a/src/test/resources/config/application-testdev.yml b/src/test/resources/config/application-testdev.yml index 0093a1457..98d28d0f2 100644 --- a/src/test/resources/config/application-testdev.yml +++ b/src/test/resources/config/application-testdev.yml @@ -11,9 +11,6 @@ spring: datasource: type: com.zaxxer.hikari.HikariDataSource - url: jdbc:h2:mem:jhipstersampleapplication:12344;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE - username: jhipsterSampleApplication - password: hikari: auto-commit: false jpa: @@ -21,7 +18,7 @@ spring: hibernate: ddl-auto: none naming: - physical-strategy: org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy + physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy properties: hibernate.id.new_generator_mappings: true @@ -29,7 +26,6 @@ spring: hibernate.cache.use_second_level_cache: false hibernate.cache.use_query_cache: false hibernate.generate_statistics: false - hibernate.hbm2ddl.auto: none #TODO: temp relief for integration tests, revisit required - hibernate.type.preferred_instant_jdbc_type: TIMESTAMP + hibernate.hbm2ddl.auto: validate hibernate.jdbc.time_zone: UTC hibernate.query.fail_on_pagination_over_collection_fetch: true diff --git a/src/test/resources/config/application-testprod.yml b/src/test/resources/config/application-testprod.yml index 3b823807f..484eda81f 100644 --- a/src/test/resources/config/application-testprod.yml +++ b/src/test/resources/config/application-testprod.yml @@ -16,11 +16,12 @@ spring: auto-commit: false maximum-pool-size: 1 jpa: + database-platform: tech.jhipster.domain.util.FixedPostgreSQL10Dialect open-in-view: false hibernate: ddl-auto: none naming: - physical-strategy: org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy + physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy properties: hibernate.id.new_generator_mappings: true @@ -28,7 +29,6 @@ spring: hibernate.cache.use_second_level_cache: false hibernate.cache.use_query_cache: false hibernate.generate_statistics: false - hibernate.hbm2ddl.auto: none #TODO: temp relief for integration tests, revisit required - hibernate.type.preferred_instant_jdbc_type: TIMESTAMP + hibernate.hbm2ddl.auto: validate hibernate.jdbc.time_zone: UTC hibernate.query.fail_on_pagination_over_collection_fetch: true diff --git a/src/test/resources/config/application.yml b/src/test/resources/config/application.yml index df98fc359..826d3c687 100644 --- a/src/test/resources/config/application.yml +++ b/src/test/resources/config/application.yml @@ -26,6 +26,9 @@ spring: host: localhost main: allow-bean-definition-overriding: true + mvc: + pathmatch: + matching-strategy: ant_path_matcher messages: basename: i18n/messages task: @@ -64,7 +67,7 @@ jhipster: enabled: false host: localhost port: 5000 - ring-buffer-size: 512 + queue-size: 512 security: authentication: jwt: @@ -72,7 +75,6 @@ jhipster: base64-secret: bXktc2VjcmV0LWtleS13aGljaC1zaG91bGQtYmUtY2hhbmdlZC1pbi1wcm9kdWN0aW9uLWFuZC1iZS1iYXNlNjQtZW5jb2RlZAo= # Token is valid 24 hours token-validity-in-seconds: 86400 - token-validity-in-seconds-for-remember-me: 86400 # =================================================================== # Application specific properties diff --git a/src/test/resources/logback.xml b/src/test/resources/logback.xml index 90e8e4d86..948a5c356 100644 --- a/src/test/resources/logback.xml +++ b/src/test/resources/logback.xml @@ -12,9 +12,9 @@ - - - + + + @@ -38,10 +38,14 @@ - - - + + + + + WARN + + diff --git a/src/test/resources/testcontainers.properties b/src/test/resources/testcontainers.properties new file mode 100644 index 000000000..f0e6e42c2 --- /dev/null +++ b/src/test/resources/testcontainers.properties @@ -0,0 +1 @@ +testcontainers.reuse.enable=true diff --git a/tsconfig.app.json b/tsconfig.app.json deleted file mode 100644 index 85b73341c..000000000 --- a/tsconfig.app.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./target/classes/static/app", - "types": ["@angular/localize"] - }, - "files": ["src/main/webapp/main.ts"], - "include": ["src/main/webapp/**/*.d.ts"] -} diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index b12774a0a..000000000 --- a/tsconfig.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "compilerOptions": { - "baseUrl": "src/main/webapp/", - "outDir": "./target/classes/static/", - "forceConsistentCasingInFileNames": true, - "strict": true, - "strictNullChecks": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "sourceMap": true, - "declaration": false, - "downlevelIteration": true, - "experimentalDecorators": true, - "moduleResolution": "node", - "importHelpers": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "useDefineForClassFields": false, - "target": "es2022", - "module": "es2020", - "types": [], - "lib": ["es2018", "dom"] - }, - "references": [ - { - "path": "tsconfig.spec.json" - } - ], - "angularCompilerOptions": { - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true, - "preserveWhitespaces": true - } -} diff --git a/tsconfig.spec.json b/tsconfig.spec.json deleted file mode 100644 index d00c68763..000000000 --- a/tsconfig.spec.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "./tsconfig.json", - "include": ["src/main/webapp/**/*.ts"], - "compilerOptions": { - "composite": true, - "outDir": "target/out-tsc/spec", - "types": ["jest", "node"] - } -}