TODO#129597,建立後臺Spring boot專案
¤ñ¹ï·sÀÉ®× |
| | |
| | | # EditorConfig helps developers define and maintain consistent |
| | | # coding styles between different editors and IDEs |
| | | # editorconfig.org |
| | | |
| | | root = true |
| | | |
| | | [*] |
| | | |
| | | # We recommend you to keep these unchanged |
| | | end_of_line = lf |
| | | charset = utf-8 |
| | | trim_trailing_whitespace = true |
| | | insert_final_newline = true |
| | | |
| | | # Change these settings to your own preference |
| | | indent_style = space |
| | | indent_size = 4 |
| | | |
| | | [*.{ts,tsx,js,jsx,json,css,scss,yml,html,vue}] |
| | | indent_size = 2 |
| | | |
| | | [*.md] |
| | | trim_trailing_whitespace = false |
¤ñ¹ï·sÀÉ®× |
| | |
| | | # This file is inspired by https://github.com/alexkaratarakis/gitattributes |
| | | # |
| | | # Auto detect text files and perform LF normalization |
| | | # http://davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/ |
| | | * text=auto |
| | | |
| | | # The above will handle all files NOT found below |
| | | # These files are text and should be normalized (Convert crlf => lf) |
| | | |
| | | *.bat text eol=crlf |
| | | *.cmd text eol=crlf |
| | | *.ps1 text eol=crlf |
| | | *.coffee text |
| | | *.css text |
| | | *.cql text |
| | | *.df text |
| | | *.ejs text |
| | | *.html text |
| | | *.java text |
| | | *.js text |
| | | *.json text |
| | | *.less text |
| | | *.properties text |
| | | *.sass text |
| | | *.scss text |
| | | *.sh text eol=lf |
| | | *.sql text |
| | | *.txt text |
| | | *.ts text |
| | | *.xml text |
| | | *.yaml text |
| | | *.yml text |
| | | |
| | | # Documents |
| | | *.doc diff=astextplain |
| | | *.DOC diff=astextplain |
| | | *.docx diff=astextplain |
| | | *.DOCX diff=astextplain |
| | | *.dot diff=astextplain |
| | | *.DOT diff=astextplain |
| | | *.pdf diff=astextplain |
| | | *.PDF diff=astextplain |
| | | *.rtf diff=astextplain |
| | | *.RTF diff=astextplain |
| | | *.markdown text |
| | | *.md text |
| | | *.adoc text |
| | | *.textile text |
| | | *.mustache text |
| | | *.csv text |
| | | *.tab text |
| | | *.tsv text |
| | | *.txt text |
| | | AUTHORS text |
| | | CHANGELOG text |
| | | CHANGES text |
| | | CONTRIBUTING text |
| | | COPYING text |
| | | copyright text |
| | | *COPYRIGHT* text |
| | | INSTALL text |
| | | license text |
| | | LICENSE text |
| | | NEWS text |
| | | readme text |
| | | *README* text |
| | | TODO text |
| | | |
| | | # Graphics |
| | | *.png binary |
| | | *.jpg binary |
| | | *.jpeg binary |
| | | *.gif binary |
| | | *.tif binary |
| | | *.tiff binary |
| | | *.ico binary |
| | | # SVG treated as an asset (binary) by default. If you want to treat it as text, |
| | | # comment-out the following line and uncomment the line after. |
| | | *.svg binary |
| | | #*.svg text |
| | | *.eps binary |
| | | |
| | | # These files are binary and should be left untouched |
| | | # (binary is a macro for -text -diff) |
| | | *.class binary |
| | | *.jar binary |
| | | *.war binary |
| | | |
| | | ## LINTERS |
| | | .csslintrc text |
| | | .eslintrc text |
| | | .jscsrc text |
| | | .jshintrc text |
| | | .jshintignore text |
| | | .stylelintrc text |
| | | |
| | | ## CONFIGS |
| | | *.conf text |
| | | *.config text |
| | | .editorconfig text |
| | | .gitattributes text |
| | | .gitconfig text |
| | | .gitignore text |
| | | .htaccess text |
| | | *.npmignore text |
| | | |
| | | ## HEROKU |
| | | Procfile text |
| | | .slugignore text |
| | | |
| | | ## AUDIO |
| | | *.kar binary |
| | | *.m4a binary |
| | | *.mid binary |
| | | *.midi binary |
| | | *.mp3 binary |
| | | *.ogg binary |
| | | *.ra binary |
| | | |
| | | ## VIDEO |
| | | *.3gpp binary |
| | | *.3gp binary |
| | | *.as binary |
| | | *.asf binary |
| | | *.asx binary |
| | | *.fla binary |
| | | *.flv binary |
| | | *.m4v binary |
| | | *.mng binary |
| | | *.mov binary |
| | | *.mp4 binary |
| | | *.mpeg binary |
| | | *.mpg binary |
| | | *.swc binary |
| | | *.swf binary |
| | | *.webm binary |
| | | |
| | | ## ARCHIVES |
| | | *.7z binary |
| | | *.gz binary |
| | | *.rar binary |
| | | *.tar binary |
| | | *.zip binary |
| | | |
| | | ## FONTS |
| | | *.ttf binary |
| | | *.eot binary |
| | | *.otf binary |
| | | *.woff binary |
| | | *.woff2 binary |
¤ñ¹ï·sÀÉ®× |
| | |
| | | ###################### |
| | | # Project Specific |
| | | ###################### |
| | | /target/classes/static/** |
| | | /src/test/javascript/coverage/ |
| | | |
| | | ###################### |
| | | # Node |
| | | ###################### |
| | | /node/ |
| | | node_tmp/ |
| | | node_modules/ |
| | | npm-debug.log.* |
| | | /.awcache/* |
| | | /.cache-loader/* |
| | | |
| | | ###################### |
| | | # SASS |
| | | ###################### |
| | | .sass-cache/ |
| | | |
| | | ###################### |
| | | # Eclipse |
| | | ###################### |
| | | *.pydevproject |
| | | .project |
| | | .metadata |
| | | tmp/ |
| | | tmp/**/* |
| | | *.tmp |
| | | *.bak |
| | | *.swp |
| | | *~.nib |
| | | local.properties |
| | | .classpath |
| | | .settings/ |
| | | .loadpath |
| | | .factorypath |
| | | /src/main/resources/rebel.xml |
| | | |
| | | # External tool builders |
| | | .externalToolBuilders/** |
| | | |
| | | # Locally stored "Eclipse launch configurations" |
| | | *.launch |
| | | |
| | | # CDT-specific |
| | | .cproject |
| | | |
| | | # PDT-specific |
| | | .buildpath |
| | | |
| | | # STS-specific |
| | | /.sts4-cache/* |
| | | |
| | | ###################### |
| | | # IntelliJ |
| | | ###################### |
| | | .idea/ |
| | | *.iml |
| | | *.iws |
| | | *.ipr |
| | | *.ids |
| | | *.orig |
| | | classes/ |
| | | out/ |
| | | |
| | | ###################### |
| | | # Visual Studio Code |
| | | ###################### |
| | | .vscode/* |
| | | !.vscode/settings.json |
| | | !.vscode/tasks.json |
| | | !.vscode/launch.json |
| | | !.vscode/extensions.json |
| | | *.code-workspace |
| | | |
| | | ###################### |
| | | # Maven |
| | | ###################### |
| | | /log/ |
| | | /target/ |
| | | |
| | | ###################### |
| | | # Gradle |
| | | ###################### |
| | | .gradle/ |
| | | /build/ |
| | | |
| | | ###################### |
| | | # Package Files |
| | | ###################### |
| | | *.jar |
| | | *.war |
| | | *.ear |
| | | *.db |
| | | |
| | | ###################### |
| | | # Windows |
| | | ###################### |
| | | # Windows image file caches |
| | | Thumbs.db |
| | | |
| | | # Folder config file |
| | | Desktop.ini |
| | | |
| | | ###################### |
| | | # Mac OSX |
| | | ###################### |
| | | .DS_Store |
| | | .svn |
| | | |
| | | # Thumbnails |
| | | ._* |
| | | |
| | | # Files that might appear on external disk |
| | | .Spotlight-V100 |
| | | .Trashes |
| | | |
| | | ###################### |
| | | # Directories |
| | | ###################### |
| | | /bin/ |
| | | /deploy/ |
| | | |
| | | ###################### |
| | | # Logs |
| | | ###################### |
| | | *.log* |
| | | |
| | | ###################### |
| | | # Others |
| | | ###################### |
| | | *.class |
| | | *.*~ |
| | | *~ |
| | | .merge_file* |
| | | |
| | | ###################### |
| | | # Gradle Wrapper |
| | | ###################### |
| | | !gradle/wrapper/gradle-wrapper.jar |
| | | |
| | | ###################### |
| | | # Maven Wrapper |
| | | ###################### |
| | | !.mvn/wrapper/maven-wrapper.jar |
| | | |
| | | ###################### |
| | | # ESLint |
| | | ###################### |
| | | .eslintcache |
| | | |
| | | ###################### |
| | | # Code coverage |
| | | ###################### |
| | | /coverage/ |
| | | /.nyc_output/ |
¤ñ¹ï·sÀÉ®× |
| | |
| | | /* |
| | | * Copyright 2007-present the original author or authors. |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * 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 "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | import java.net.*; |
| | | import java.io.*; |
| | | import java.nio.channels.*; |
| | | import java.util.Properties; |
| | | |
| | | public class MavenWrapperDownloader { |
| | | |
| | | private static final String WRAPPER_VERSION = "0.5.6"; |
| | | /** |
| | | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. |
| | | */ |
| | | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" |
| | | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; |
| | | |
| | | /** |
| | | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to |
| | | * use instead of the default one. |
| | | */ |
| | | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = |
| | | ".mvn/wrapper/maven-wrapper.properties"; |
| | | |
| | | /** |
| | | * Path where the maven-wrapper.jar will be saved to. |
| | | */ |
| | | private static final String MAVEN_WRAPPER_JAR_PATH = |
| | | ".mvn/wrapper/maven-wrapper.jar"; |
| | | |
| | | /** |
| | | * Name of the property which should be used to override the default download url for the wrapper. |
| | | */ |
| | | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; |
| | | |
| | | public static void main(String args[]) { |
| | | System.out.println("- Downloader started"); |
| | | File baseDirectory = new File(args[0]); |
| | | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); |
| | | |
| | | // If the maven-wrapper.properties exists, read it and check if it contains a custom |
| | | // wrapperUrl parameter. |
| | | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); |
| | | String url = DEFAULT_DOWNLOAD_URL; |
| | | if(mavenWrapperPropertyFile.exists()) { |
| | | FileInputStream mavenWrapperPropertyFileInputStream = null; |
| | | try { |
| | | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); |
| | | Properties mavenWrapperProperties = new Properties(); |
| | | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); |
| | | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); |
| | | } catch (IOException e) { |
| | | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); |
| | | } finally { |
| | | try { |
| | | if(mavenWrapperPropertyFileInputStream != null) { |
| | | mavenWrapperPropertyFileInputStream.close(); |
| | | } |
| | | } catch (IOException e) { |
| | | // Ignore ... |
| | | } |
| | | } |
| | | } |
| | | System.out.println("- Downloading from: " + url); |
| | | |
| | | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); |
| | | if(!outputFile.getParentFile().exists()) { |
| | | if(!outputFile.getParentFile().mkdirs()) { |
| | | System.out.println( |
| | | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); |
| | | } |
| | | } |
| | | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); |
| | | try { |
| | | downloadFileFromURL(url, outputFile); |
| | | System.out.println("Done"); |
| | | System.exit(0); |
| | | } catch (Throwable e) { |
| | | System.out.println("- Error downloading"); |
| | | e.printStackTrace(); |
| | | System.exit(1); |
| | | } |
| | | } |
| | | |
| | | private static void downloadFileFromURL(String urlString, File destination) throws Exception { |
| | | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { |
| | | String username = System.getenv("MVNW_USERNAME"); |
| | | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); |
| | | Authenticator.setDefault(new Authenticator() { |
| | | @Override |
| | | protected PasswordAuthentication getPasswordAuthentication() { |
| | | return new PasswordAuthentication(username, password); |
| | | } |
| | | }); |
| | | } |
| | | URL website = new URL(urlString); |
| | | ReadableByteChannel rbc; |
| | | rbc = Channels.newChannel(website.openStream()); |
| | | FileOutputStream fos = new FileOutputStream(destination); |
| | | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); |
| | | fos.close(); |
| | | rbc.close(); |
| | | } |
| | | |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.3/apache-maven-3.8.3-bin.zip |
| | | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar |
¤ñ¹ï·sÀÉ®× |
| | |
| | | node_modules |
| | | target |
| | | build |
| | | package-lock.json |
| | | .git |
| | | .mvn |
| | | gradle |
| | | .gradle |
¤ñ¹ï·sÀÉ®× |
| | |
| | | # Prettier configuration |
| | | |
| | | printWidth: 140 |
| | | singleQuote: true |
| | | tabWidth: 2 |
| | | useTabs: false |
| | | |
| | | # js and ts rules: |
| | | arrowParens: avoid |
| | | |
| | | # jsx and tsx rules: |
| | | jsxBracketSameLine: false |
| | | |
| | | # java rules: |
| | | overrides: |
| | | - files: "*.java" |
| | | options: |
| | | tabWidth: 4 |
¤ñ¹ï·sÀÉ®× |
| | |
| | | { |
| | | "generator-jhipster:7.3.0": { |
| | | "promptValues": { |
| | | "packageName": "com.pollex.pam", |
| | | "nativeLanguage": "zh-tw" |
| | | } |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | { |
| | | "generator-jhipster": { |
| | | "skipClient": true, |
| | | "applicationType": "monolith", |
| | | "baseName": "pamapi", |
| | | "jhipsterVersion": "7.3.0", |
| | | "skipServer": false, |
| | | "skipUserManagement": false, |
| | | "skipCheckLengthOfIdentifier": false, |
| | | "skipFakeData": false, |
| | | "jhiPrefix": "jhi", |
| | | "entitySuffix": "", |
| | | "dtoSuffix": "DTO", |
| | | "testFrameworks": [], |
| | | "blueprints": [], |
| | | "otherModules": [], |
| | | "pages": [], |
| | | "creationTimestamp": 1635842756094, |
| | | "serviceDiscoveryType": "no", |
| | | "reactive": false, |
| | | "authenticationType": "jwt", |
| | | "packageName": "com.pollex.pam", |
| | | "serverPort": "8080", |
| | | "cacheProvider": "ehcache", |
| | | "enableHibernateCache": true, |
| | | "databaseType": "sql", |
| | | "devDatabaseType": "postgresql", |
| | | "prodDatabaseType": "postgresql", |
| | | "buildTool": "maven", |
| | | "serverSideOptions": ["websocket:spring-websocket"], |
| | | "websocket": "spring-websocket", |
| | | "searchEngine": false, |
| | | "messageBroker": false, |
| | | "enableSwaggerCodegen": false, |
| | | "enableTranslation": true, |
| | | "nativeLanguage": "zh-tw", |
| | | "monorepository": true, |
| | | "skipCommitHook": true, |
| | | "jwtSecretKey": "MjI3YWRiMzg1ZTY3ZmZkZDgxZmI5Yjc5YjVkOTIzMzc4MmI2OWM3NWVkZjFiOTNmNjg0YWFjZWQ4YzhlOTUzYzk3MGUzMzM5Y2U5MDdkZTMyN2Q0N2E0M2ZmM2FhYzkyNDY4MjBkYTY5OGM4YmIzMmYxODJhNWFkMmVhNmVhNTM=", |
| | | "languages": ["zh-tw", "en"], |
| | | "enableGradleEnterprise": false, |
| | | "clientFramework": "angularX", |
| | | "clientPackageManager": "npm", |
| | | "clientTheme": "none", |
| | | "clientThemeVariant": "", |
| | | "withAdminUi": true |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | # pamapi |
| | | |
| | | This application was generated using JHipster 7.3.0, you can find documentation and help at [https://www.jhipster.tech/documentation-archive/v7.3.0](https://www.jhipster.tech/documentation-archive/v7.3.0). |
| | | |
| | | ## Development |
| | | |
| | | To start your application in the dev profile, run: |
| | | |
| | | ``` |
| | | ./mvnw |
| | | ``` |
| | | |
| | | For further instructions on how to develop with JHipster, have a look at [Using JHipster in development][]. |
| | | |
| | | ### 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 |
| | | ``` |
| | | |
| | | ## Building for production |
| | | |
| | | ### Packaging as jar |
| | | |
| | | To build the final jar and optimize the pamapi application for production, run: |
| | | |
| | | ``` |
| | | ./mvnw -Pprod clean verify |
| | | ``` |
| | | |
| | | To ensure everything worked, run: |
| | | |
| | | ``` |
| | | java -jar target/*.jar |
| | | ``` |
| | | |
| | | Refer to [Using JHipster in production][] for more details. |
| | | |
| | | ### Packaging as war |
| | | |
| | | To package your application as a war in order to deploy it to an application server, run: |
| | | |
| | | ``` |
| | | ./mvnw -Pprod,war clean verify |
| | | ``` |
| | | |
| | | ## Testing |
| | | |
| | | To launch your application's tests, run: |
| | | |
| | | ``` |
| | | ./mvnw verify |
| | | ``` |
| | | |
| | | For more information, refer to the [Running tests page][]. |
| | | |
| | | ### Code quality |
| | | |
| | | 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 |
| | | ``` |
| | | |
| | | 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 |
| | | ``` |
| | | |
| | | 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 |
| | | ``` |
| | | |
| | | For more information, refer to the [Code quality page][]. |
| | | |
| | | ## Using Docker to simplify development (optional) |
| | | |
| | | You can use Docker to improve your JHipster development experience. A number of docker-compose configuration are available in the [src/main/docker](src/main/docker) folder to launch required third party services. |
| | | |
| | | For example, to start a postgresql database in a docker container, run: |
| | | |
| | | ``` |
| | | 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 |
| | | ``` |
| | | |
| | | You can also fully dockerize your application and all the services that it depends on. |
| | | To achieve this, first build a docker image of your app by running: |
| | | |
| | | ``` |
| | | ./mvnw -Pprod verify jib:dockerBuild |
| | | ``` |
| | | |
| | | Then run: |
| | | |
| | | ``` |
| | | docker-compose -f src/main/docker/app.yml up -d |
| | | ``` |
| | | |
| | | For more information refer to [Using Docker and Docker-Compose][], this page also contains information on the docker-compose sub-generator (`jhipster docker-compose`), which is able to generate docker configurations for one or several JHipster applications. |
| | | |
| | | ## Continuous Integration (optional) |
| | | |
| | | 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.3.0 archive]: https://www.jhipster.tech/documentation-archive/v7.3.0 |
| | | [using jhipster in development]: https://www.jhipster.tech/documentation-archive/v7.3.0/development/ |
| | | [using docker and docker-compose]: https://www.jhipster.tech/documentation-archive/v7.3.0/docker-compose |
| | | [using jhipster in production]: https://www.jhipster.tech/documentation-archive/v7.3.0/production/ |
| | | [running tests page]: https://www.jhipster.tech/documentation-archive/v7.3.0/running-tests/ |
| | | [code quality page]: https://www.jhipster.tech/documentation-archive/v7.3.0/code-quality/ |
| | | [setting up continuous integration]: https://www.jhipster.tech/documentation-archive/v7.3.0/setting-up-ci/ |
| | | [node.js]: https://nodejs.org/ |
| | | [npm]: https://www.npmjs.com/ |
¤ñ¹ï·sÀÉ®× |
| | |
| | | <?xml version="1.0"?> |
| | | <!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" |
| | | "https://checkstyle.org/dtds/configuration_1_3.dtd"> |
| | | <module name="Checker"> |
| | | |
| | | <!-- Configure checker to use UTF-8 encoding --> |
| | | <property name="charset" value="UTF-8"/> |
| | | <!-- Configure checker to run on files with these extensions --> |
| | | <property name="fileExtensions" value=""/> |
| | | <!-- For detailed checkstyle configuration, see https://github.com/spring-io/nohttp/tree/master/nohttp-checkstyle --> |
| | | <module name="io.spring.nohttp.checkstyle.check.NoHttpCheck"> |
| | | <property name="allowlist" value="^\Qhttp://maven.apache.org/POM/4.0.0 ^\Qhttp://www.w3.org/2001/XMLSchema-instance"/> |
| | | </module> |
| | | <!-- Allow suppression with comments |
| | | // CHECKSTYLE:OFF |
| | | ... ignored content ... |
| | | // CHECKSTYLE:ON |
| | | --> |
| | | <module name="SuppressWithPlainTextCommentFilter"/> |
| | | </module> |
¤ñ¹ï·sÀÉ®× |
| | |
| | | #!/bin/sh |
| | | # ---------------------------------------------------------------------------- |
| | | # Licensed to the Apache Software Foundation (ASF) under one |
| | | # or more contributor license agreements. See the NOTICE file |
| | | # distributed with this work for additional information |
| | | # regarding copyright ownership. The ASF licenses this file |
| | | # to you under the Apache License, Version 2.0 (the |
| | | # "License"); you may not use this file except in compliance |
| | | # with the License. You may obtain a copy of the License at |
| | | # |
| | | # 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 |
| | | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| | | # KIND, either express or implied. See the License for the |
| | | # specific language governing permissions and limitations |
| | | # under the License. |
| | | # ---------------------------------------------------------------------------- |
| | | |
| | | # ---------------------------------------------------------------------------- |
| | | # Maven Start Up Batch script |
| | | # |
| | | # Required ENV vars: |
| | | # ------------------ |
| | | # JAVA_HOME - location of a JDK home dir |
| | | # |
| | | # 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 |
| | | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files |
| | | # ---------------------------------------------------------------------------- |
| | | |
| | | if [ -z "$MAVEN_SKIP_RC" ] ; then |
| | | |
| | | if [ -f /etc/mavenrc ] ; then |
| | | . /etc/mavenrc |
| | | fi |
| | | |
| | | if [ -f "$HOME/.mavenrc" ] ; then |
| | | . "$HOME/.mavenrc" |
| | | fi |
| | | |
| | | fi |
| | | |
| | | # OS specific support. $var _must_ be set to either true or false. |
| | | cygwin=false; |
| | | darwin=false; |
| | | mingw=false |
| | | case "`uname`" in |
| | | CYGWIN*) cygwin=true ;; |
| | | MINGW*) mingw=true;; |
| | | Darwin*) darwin=true |
| | | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home |
| | | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html |
| | | if [ -z "$JAVA_HOME" ]; then |
| | | if [ -x "/usr/libexec/java_home" ]; then |
| | | export JAVA_HOME="`/usr/libexec/java_home`" |
| | | else |
| | | export JAVA_HOME="/Library/Java/Home" |
| | | fi |
| | | fi |
| | | ;; |
| | | esac |
| | | |
| | | if [ -z "$JAVA_HOME" ] ; then |
| | | if [ -r /etc/gentoo-release ] ; then |
| | | 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"` |
| | | [ -n "$CLASSPATH" ] && |
| | | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` |
| | | fi |
| | | |
| | | # For Mingw, ensure paths are in UNIX format before anything is touched |
| | | if $mingw ; then |
| | | [ -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 |
| | | # readlink(1) is not available as standard on Solaris 10. |
| | | readLink=`which readlink` |
| | | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then |
| | | if $darwin ; then |
| | | javaHome="`dirname \"$javaExecutable\"`" |
| | | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" |
| | | else |
| | | javaExecutable="`readlink -f \"$javaExecutable\"`" |
| | | fi |
| | | javaHome="`dirname \"$javaExecutable\"`" |
| | | javaHome=`expr "$javaHome" : '\(.*\)/bin'` |
| | | JAVA_HOME="$javaHome" |
| | | export JAVA_HOME |
| | | fi |
| | | fi |
| | | fi |
| | | |
| | | if [ -z "$JAVACMD" ] ; then |
| | | if [ -n "$JAVA_HOME" ] ; then |
| | | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then |
| | | # IBM's JDK on AIX uses strange locations for the executables |
| | | JAVACMD="$JAVA_HOME/jre/sh/java" |
| | | else |
| | | JAVACMD="$JAVA_HOME/bin/java" |
| | | fi |
| | | else |
| | | JAVACMD="`which java`" |
| | | fi |
| | | fi |
| | | |
| | | if [ ! -x "$JAVACMD" ] ; then |
| | | echo "Error: JAVA_HOME is not defined correctly." >&2 |
| | | echo " We cannot execute $JAVACMD" >&2 |
| | | exit 1 |
| | | fi |
| | | |
| | | 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" |
| | | return 1 |
| | | fi |
| | | |
| | | basedir="$1" |
| | | wdir="$1" |
| | | while [ "$wdir" != '/' ] ; do |
| | | if [ -d "$wdir"/.mvn ] ; then |
| | | basedir=$wdir |
| | | break |
| | | fi |
| | | # workaround for JBEAP-8937 (on Solaris 10/Sparc) |
| | | if [ -d "${wdir}" ]; then |
| | | wdir=`cd "$wdir/.."; pwd` |
| | | fi |
| | | # end of workaround |
| | | done |
| | | echo "${basedir}" |
| | | } |
| | | |
| | | # concatenates all lines of a file |
| | | concat_lines() { |
| | | if [ -f "$1" ]; then |
| | | echo "$(tr -s '\n' ' ' < "$1")" |
| | | fi |
| | | } |
| | | |
| | | BASE_DIR=`find_maven_basedir "$(pwd)"` |
| | | if [ -z "$BASE_DIR" ]; then |
| | | exit 1; |
| | | fi |
| | | |
| | | ########################################################################################## |
| | | # 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. |
| | | ########################################################################################## |
| | | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then |
| | | if [ "$MVNW_VERBOSE" = true ]; then |
| | | echo "Found .mvn/wrapper/maven-wrapper.jar" |
| | | fi |
| | | else |
| | | if [ "$MVNW_VERBOSE" = true ]; then |
| | | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." |
| | | fi |
| | | if [ -n "$MVNW_REPOURL" ]; then |
| | | jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" |
| | | else |
| | | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" |
| | | fi |
| | | while IFS="=" read key value; do |
| | | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; |
| | | esac |
| | | 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"` |
| | | fi |
| | | |
| | | if command -v wget > /dev/null; then |
| | | if [ "$MVNW_VERBOSE" = true ]; then |
| | | echo "Found wget ... using wget" |
| | | fi |
| | | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then |
| | | wget "$jarUrl" -O "$wrapperJarPath" |
| | | else |
| | | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" |
| | | fi |
| | | elif command -v curl > /dev/null; then |
| | | if [ "$MVNW_VERBOSE" = true ]; then |
| | | echo "Found curl ... using curl" |
| | | fi |
| | | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then |
| | | curl -o "$wrapperJarPath" "$jarUrl" -f |
| | | else |
| | | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f |
| | | fi |
| | | |
| | | else |
| | | 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 |
| | | javaClass=`cygpath --path --windows "$javaClass"` |
| | | fi |
| | | 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 "$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 |
| | | fi |
| | | ########################################################################################## |
| | | # End of extension |
| | | ########################################################################################## |
| | | |
| | | 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"` |
| | | [ -n "$CLASSPATH" ] && |
| | | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` |
| | | [ -n "$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 $@" |
| | | export MAVEN_CMD_LINE_ARGS |
| | | |
| | | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain |
| | | |
| | | exec "$JAVACMD" \ |
| | | $MAVEN_OPTS \ |
| | | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ |
| | | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ |
| | | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" |
¤ñ¹ï·sÀÉ®× |
| | |
| | | @REM ---------------------------------------------------------------------------- |
| | | @REM Licensed to the Apache Software Foundation (ASF) under one |
| | | @REM or more contributor license agreements. See the NOTICE file |
| | | @REM distributed with this work for additional information |
| | | @REM regarding copyright ownership. The ASF licenses this file |
| | | @REM to you under the Apache License, Version 2.0 (the |
| | | @REM "License"); you may not use this file except in compliance |
| | | @REM with the License. You may obtain a copy of the License at |
| | | @REM |
| | | @REM https://www.apache.org/licenses/LICENSE-2.0 |
| | | @REM |
| | | @REM Unless required by applicable law or agreed to in writing, |
| | | @REM software distributed under the License is distributed on an |
| | | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| | | @REM KIND, either express or implied. See the License for the |
| | | @REM specific language governing permissions and limitations |
| | | @REM under the License. |
| | | @REM ---------------------------------------------------------------------------- |
| | | |
| | | @REM ---------------------------------------------------------------------------- |
| | | @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 |
| | | @REM e.g. to debug Maven itself, use |
| | | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 |
| | | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files |
| | | @REM ---------------------------------------------------------------------------- |
| | | |
| | | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' |
| | | @echo off |
| | | @REM set title of command window |
| | | title %0 |
| | | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' |
| | | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% |
| | | |
| | | @REM set %HOME% to equivalent of $HOME |
| | | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") |
| | | |
| | | @REM Execute a user defined script before this one |
| | | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre |
| | | @REM check for pre script, once with legacy .bat ending and once with .cmd ending |
| | | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" |
| | | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" |
| | | :skipRcPre |
| | | |
| | | @setlocal |
| | | |
| | | set ERROR_CODE=0 |
| | | |
| | | @REM To isolate internal variables from possible post scripts, we use another setlocal |
| | | @setlocal |
| | | |
| | | @REM ==== START VALIDATION ==== |
| | | if not "%JAVA_HOME%" == "" goto OkJHome |
| | | |
| | | echo. |
| | | echo Error: JAVA_HOME not found in your environment. >&2 |
| | | echo Please set the JAVA_HOME variable in your environment to match the >&2 |
| | | echo location of your Java installation. >&2 |
| | | echo. |
| | | goto error |
| | | |
| | | :OkJHome |
| | | if exist "%JAVA_HOME%\bin\java.exe" goto init |
| | | |
| | | echo. |
| | | echo Error: JAVA_HOME is set to an invalid directory. >&2 |
| | | echo JAVA_HOME = "%JAVA_HOME%" >&2 |
| | | echo Please set the JAVA_HOME variable in your environment to match the >&2 |
| | | echo location of your Java installation. >&2 |
| | | echo. |
| | | goto error |
| | | |
| | | @REM ==== END VALIDATION ==== |
| | | |
| | | :init |
| | | |
| | | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". |
| | | @REM Fallback to current working directory if not found. |
| | | |
| | | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% |
| | | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir |
| | | |
| | | set EXEC_DIR=%CD% |
| | | set WDIR=%EXEC_DIR% |
| | | :findBaseDir |
| | | IF EXIST "%WDIR%"\.mvn goto baseDirFound |
| | | cd .. |
| | | IF "%WDIR%"=="%CD%" goto baseDirNotFound |
| | | set WDIR=%CD% |
| | | goto findBaseDir |
| | | |
| | | :baseDirFound |
| | | set MAVEN_PROJECTBASEDIR=%WDIR% |
| | | cd "%EXEC_DIR%" |
| | | goto endDetectBaseDir |
| | | |
| | | :baseDirNotFound |
| | | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% |
| | | cd "%EXEC_DIR%" |
| | | |
| | | :endDetectBaseDir |
| | | |
| | | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig |
| | | |
| | | @setlocal EnableExtensions EnableDelayedExpansion |
| | | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a |
| | | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% |
| | | |
| | | :endReadAdditionalConfig |
| | | |
| | | 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 DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" |
| | | |
| | | FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( |
| | | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B |
| | | ) |
| | | |
| | | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central |
| | | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. |
| | | if exist %WRAPPER_JAR% ( |
| | | if "%MVNW_VERBOSE%" == "true" ( |
| | | echo Found %WRAPPER_JAR% |
| | | ) |
| | | ) else ( |
| | | if not "%MVNW_REPOURL%" == "" ( |
| | | SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" |
| | | ) |
| | | if "%MVNW_VERBOSE%" == "true" ( |
| | | echo Couldn't find %WRAPPER_JAR%, downloading it ... |
| | | echo Downloading from: %DOWNLOAD_URL% |
| | | ) |
| | | |
| | | powershell -Command "&{"^ |
| | | "$webclient = new-object System.Net.WebClient;"^ |
| | | "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('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ |
| | | "}" |
| | | if "%MVNW_VERBOSE%" == "true" ( |
| | | echo Finished downloading %WRAPPER_JAR% |
| | | ) |
| | | ) |
| | | @REM End of extension |
| | | |
| | | @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=%* |
| | | |
| | | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* |
| | | if ERRORLEVEL 1 goto error |
| | | goto end |
| | | |
| | | :error |
| | | set ERROR_CODE=1 |
| | | |
| | | :end |
| | | @endlocal & set ERROR_CODE=%ERROR_CODE% |
| | | |
| | | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost |
| | | @REM check for post script, once with legacy .bat ending and once with .cmd ending |
| | | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" |
| | | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" |
| | | :skipRcPost |
| | | |
| | | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' |
| | | if "%MAVEN_BATCH_PAUSE%" == "on" pause |
| | | |
| | | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% |
| | | |
| | | exit /B %ERROR_CODE% |
¤ñ¹ï·sÀÉ®× |
| | |
| | | #!/bin/sh |
| | | |
| | | basedir=`dirname "$0"` |
| | | |
| | | if [ -f "$basedir/mvnw" ]; then |
| | | builddir="target/node" |
| | | installCommand="$basedir/mvnw frontend:install-node-and-npm@install-node-and-npm" |
| | | else |
| | | builddir=".gradle/npm" |
| | | installCommand="$basedir/gradlew npmSetup" |
| | | fi |
| | | |
| | | NPM_EXE="$basedir/$builddir/npm" |
| | | |
| | | if ! [ -x "$NPM_EXE" ]; then |
| | | $installCommand || true |
| | | fi |
| | | |
| | | if ! [ -x "$NPM_EXE" ]; then |
| | | echo "Using npm installed globally" |
| | | npm "$@" |
| | | else |
| | | echo "Using npm installed locally $($NPM_EXE --version)" |
| | | $NPM_EXE "$@" |
| | | fi |
¤ñ¹ï·sÀÉ®× |
| | |
| | | @echo off |
| | | |
| | | @setlocal |
| | | |
| | | set NPMW_DIR=%~dp0 |
| | | |
| | | if exist "%NPMW_DIR%\mvnw.cmd" ( |
| | | set NPM_EXE=%NPMW_DIR%\target\node\npm.cmd |
| | | set INSTALL_NPM_COMMAND=%NPMW_DIR%\mvnw.cmd frontend:install-node-and-npm@install-node-and-npm |
| | | ) else ( |
| | | set NPM_EXE=%NPMW_DIR%\.gradle\npm\npm.cmd |
| | | set INSTALL_NPM_COMMAND=%NPMW_DIR%\gradlew.bat npmSetup |
| | | ) |
| | | |
| | | if not exist %NPM_EXE% ( |
| | | call %INSTALL_NPM_COMMAND% |
| | | ) |
| | | |
| | | if not exist %NPM_EXE% goto globalNpm |
| | | |
| | | %NPM_EXE% %* |
| | | |
| | | :globalNpm |
| | | npm %* |
¤ñ¹ï·sÀÉ®× |
| | |
| | | { |
| | | "name": "pamapi", |
| | | "version": "0.0.0", |
| | | "private": true, |
| | | "description": "Description for pamapi", |
| | | "license": "UNLICENSED", |
| | | "scripts": { |
| | | "app:start": "./mvnw", |
| | | "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 -P-webapp", |
| | | "backend:unit:test": "./mvnw -ntp -P-webapp verify --batch-mode -Dlogging.level.ROOT=OFF -Dlogging.level.org.zalando=OFF -Dlogging.level.tech.jhipster=OFF -Dlogging.level.com.pollex.pam=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", |
| | | "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 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=$npm_package_config_default_environment -Dlogging.level.ROOT=OFF -Dlogging.level.org.zalando=OFF -Dlogging.level.tech.jhipster=OFF -Dlogging.level.com.pollex.pam=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:server:package": "npm run java:$npm_package_config_packaging:$npm_package_config_default_environment", |
| | | "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 --remove-orphans", |
| | | "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": "", |
| | | "java:docker": "./mvnw -ntp verify -DskipTests jib:dockerBuild", |
| | | "java:docker:arm64": "npm run java:docker -- -Djib-maven-plugin.architecture=arm64", |
| | | "java:docker:dev": "npm run java:docker -- -Pdev,webapp", |
| | | "java:docker:prod": "npm run java:docker -- -Pprod", |
| | | "java:jar": "./mvnw -ntp verify -DskipTests --batch-mode", |
| | | "java:jar:dev": "npm run java:jar -- -Pdev,webapp", |
| | | "java:jar:prod": "npm run java:jar -- -Pprod", |
| | | "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", |
| | | "prettier:check": "prettier --check \"{,src/**/}*.{md,json,yml,html,java}\"", |
| | | "prettier:format": "prettier --write \"{,src/**/}*.{md,json,yml,html,java}\"" |
| | | }, |
| | | "config": { |
| | | "backend_port": "8080", |
| | | "default_environment": "prod", |
| | | "packaging": "jar" |
| | | }, |
| | | "devDependencies": { |
| | | "generator-jhipster": "7.3.0", |
| | | "prettier": "2.4.1", |
| | | "prettier-plugin-java": "1.4.0", |
| | | "prettier-plugin-packagejson": "2.2.13" |
| | | }, |
| | | "engines": { |
| | | "node": ">=14.17.6" |
| | | }, |
| | | "cacheDirectories": [ |
| | | "node_modules" |
| | | ] |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <project xmlns="http://maven.apache.org/POM/4.0.0" |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 |
| | | https://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <modelVersion>4.0.0</modelVersion> |
| | | |
| | | <groupId>com.pollex.pam</groupId> |
| | | <artifactId>pamapi</artifactId> |
| | | <version>0.0.1-SNAPSHOT</version> |
| | | <packaging>jar</packaging> |
| | | <name>Pamapi</name> |
| | | <description>Description for pamapi</description> |
| | | |
| | | <repositories> |
| | | <!-- jhipster-needle-maven-repository --> |
| | | </repositories> |
| | | |
| | | <pluginRepositories> |
| | | <!-- jhipster-needle-maven-plugin-repository --> |
| | | </pluginRepositories> |
| | | |
| | | <!-- jhipster-needle-distribution-management --> |
| | | |
| | | <properties> |
| | | <!-- Build properties --> |
| | | <maven.version>3.3.9</maven.version> |
| | | <java.version>11</java.version> |
| | | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
| | | <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> |
| | | <maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format> |
| | | <maven.compiler.source>${java.version}</maven.compiler.source> |
| | | <maven.compiler.target>${java.version}</maven.compiler.target> |
| | | <start-class>com.pollex.pam.PamapiApp</start-class> |
| | | <argLine>-Djava.security.egd=file:/dev/./urandom -Xmx256m</argLine> |
| | | <m2e.apt.activation>jdt_apt</m2e.apt.activation> |
| | | <run.addResources>false</run.addResources> |
| | | <!-- These remain empty unless the corresponding profile is active --> |
| | | <profile.no-liquibase /> |
| | | <profile.api-docs /> |
| | | <profile.tls /> |
| | | |
| | | <!-- Dependency versions --> |
| | | <jhipster-dependencies.version>7.3.0</jhipster-dependencies.version> |
| | | <!-- The spring-boot version should match the one managed by |
| | | https://mvnrepository.com/artifact/tech.jhipster/jhipster-dependencies/${jhipster-dependencies.version} --> |
| | | <spring-boot.version>2.5.5</spring-boot.version> |
| | | <!-- The hibernate version should match the one managed by |
| | | https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-dependencies/${spring-boot.version} --> |
| | | <hibernate.version>5.4.32.Final</hibernate.version> |
| | | <!-- The javassist version should match the one managed by |
| | | https://mvnrepository.com/artifact/org.hibernate/hibernate-core/${hibernate.version} --> |
| | | <javassist.version>3.27.0-GA</javassist.version> |
| | | <!-- The liquibase version should match the one managed by |
| | | https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-dependencies/${spring-boot.version} --> |
| | | <liquibase.version>4.5.0</liquibase.version> |
| | | <liquibase-hibernate5.version>4.5.0</liquibase-hibernate5.version> |
| | | <validation-api.version>2.0.1.Final</validation-api.version> |
| | | <jaxb-runtime.version>2.3.3</jaxb-runtime.version> |
| | | <archunit-junit5.version>0.21.0</archunit-junit5.version> |
| | | <mapstruct.version>1.4.2.Final</mapstruct.version> |
| | | <!-- Plugin versions --> |
| | | <maven-clean-plugin.version>3.1.0</maven-clean-plugin.version> |
| | | <maven-site-plugin.version>3.9.1</maven-site-plugin.version> |
| | | <maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version> |
| | | <maven-javadoc-plugin.version>3.3.1</maven-javadoc-plugin.version> |
| | | <maven-eclipse-plugin.version>2.10</maven-eclipse-plugin.version> |
| | | <maven-enforcer-plugin.version>3.0.0</maven-enforcer-plugin.version> |
| | | <maven-failsafe-plugin.version>3.0.0-M5</maven-failsafe-plugin.version> |
| | | <maven-idea-plugin.version>2.2.1</maven-idea-plugin.version> |
| | | <maven-resources-plugin.version>3.2.0</maven-resources-plugin.version> |
| | | <maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version> |
| | | <maven-war-plugin.version>3.3.1</maven-war-plugin.version> |
| | | <maven-checkstyle-plugin.version>3.1.2</maven-checkstyle-plugin.version> |
| | | <checkstyle.version>9.0</checkstyle.version> |
| | | <nohttp-checkstyle.version>0.0.9</nohttp-checkstyle.version> |
| | | <git-commit-id-plugin.version>5.0.0</git-commit-id-plugin.version> |
| | | <modernizer-maven-plugin.version>2.3.0</modernizer-maven-plugin.version> |
| | | <jacoco-maven-plugin.version>0.8.7</jacoco-maven-plugin.version> |
| | | <jib-maven-plugin.version>3.1.4</jib-maven-plugin.version> |
| | | <jib-maven-plugin.image>eclipse-temurin:11-jre-focal</jib-maven-plugin.image> |
| | | <jib-maven-plugin.architecture>amd64</jib-maven-plugin.architecture> |
| | | <lifecycle-mapping.version>1.0.0</lifecycle-mapping.version> |
| | | <properties-maven-plugin.version>1.0.0</properties-maven-plugin.version> |
| | | <sonar-maven-plugin.version>3.9.0.2155</sonar-maven-plugin.version> |
| | | <!-- jhipster-needle-maven-property --> |
| | | </properties> |
| | | |
| | | <dependencyManagement> |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>tech.jhipster</groupId> |
| | | <artifactId>jhipster-dependencies</artifactId> |
| | | <version>${jhipster-dependencies.version}</version> |
| | | <type>pom</type> |
| | | <scope>import</scope> |
| | | </dependency> |
| | | <!-- jhipster-needle-maven-add-dependency-management --> |
| | | </dependencies> |
| | | </dependencyManagement> |
| | | |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>tech.jhipster</groupId> |
| | | <artifactId>jhipster-framework</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>javax.annotation</groupId> |
| | | <artifactId>javax.annotation-api</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-cache</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.fasterxml.jackson.module</groupId> |
| | | <artifactId>jackson-module-jaxb-annotations</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.fasterxml.jackson.datatype</groupId> |
| | | <artifactId>jackson-datatype-hibernate5</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.fasterxml.jackson.datatype</groupId> |
| | | <artifactId>jackson-datatype-hppc</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.fasterxml.jackson.datatype</groupId> |
| | | <artifactId>jackson-datatype-jsr310</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.h2database</groupId> |
| | | <artifactId>h2</artifactId> |
| | | <scope>test</scope> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>io.springfox</groupId> |
| | | <artifactId>springfox-oas</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>io.springfox</groupId> |
| | | <artifactId>springfox-swagger2</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>io.springfox</groupId> |
| | | <artifactId>springfox-bean-validators</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.zaxxer</groupId> |
| | | <artifactId>HikariCP</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.apache.commons</groupId> |
| | | <artifactId>commons-lang3</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.testcontainers</groupId> |
| | | <artifactId>postgresql</artifactId> |
| | | <scope>test</scope> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>javax.cache</groupId> |
| | | <artifactId>cache-api</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.ehcache</groupId> |
| | | <artifactId>ehcache</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.hibernate</groupId> |
| | | <artifactId>hibernate-jcache</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.hibernate</groupId> |
| | | <artifactId>hibernate-jpamodelgen</artifactId> |
| | | <scope>provided</scope> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.hibernate</groupId> |
| | | <artifactId>hibernate-core</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.hibernate.validator</groupId> |
| | | <artifactId>hibernate-validator</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.liquibase</groupId> |
| | | <artifactId>liquibase-core</artifactId> |
| | | <!-- Inherited version from Spring Boot can't be used because of regressions --> |
| | | <version>${liquibase.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.postgresql</groupId> |
| | | <artifactId>postgresql</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.mapstruct</groupId> |
| | | <artifactId>mapstruct</artifactId> |
| | | <version>${mapstruct.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.mapstruct</groupId> |
| | | <artifactId>mapstruct-processor</artifactId> |
| | | <version>${mapstruct.version}</version> |
| | | <scope>provided</scope> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-configuration-processor</artifactId> |
| | | <scope>provided</scope> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-loader-tools</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-actuator</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-data-jpa</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-logging</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-mail</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-security</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-thymeleaf</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-web</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-test</artifactId> |
| | | <scope>test</scope> |
| | | <exclusions> |
| | | <exclusion> |
| | | <groupId>org.junit.vintage</groupId> |
| | | <artifactId>junit-vintage-engine</artifactId> |
| | | </exclusion> |
| | | </exclusions> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-test</artifactId> |
| | | <scope>test</scope> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.security</groupId> |
| | | <artifactId>spring-security-test</artifactId> |
| | | <scope>test</scope> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.tngtech.archunit</groupId> |
| | | <artifactId>archunit-junit5-api</artifactId> |
| | | <version>${archunit-junit5.version}</version> |
| | | <scope>test</scope> |
| | | </dependency> |
| | | <!-- Adding the engine dependency to the surefire-plugin unfortunately does not work in the current version. --> |
| | | <!-- https://www.archunit.org/userguide/html/000_Index.html#_junit_5 --> |
| | | <dependency> |
| | | <groupId>com.tngtech.archunit</groupId> |
| | | <artifactId>archunit-junit5-engine</artifactId> |
| | | <version>${archunit-junit5.version}</version> |
| | | <scope>test</scope> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.zalando</groupId> |
| | | <artifactId>problem-spring-web</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-websocket</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>io.jsonwebtoken</groupId> |
| | | <artifactId>jjwt-api</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>io.jsonwebtoken</groupId> |
| | | <artifactId>jjwt-impl</artifactId> |
| | | <scope>runtime</scope> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>io.jsonwebtoken</groupId> |
| | | <artifactId>jjwt-jackson</artifactId> |
| | | <scope>runtime</scope> |
| | | </dependency> |
| | | <!-- Spring Cloud --> |
| | | <dependency> |
| | | <groupId>org.springframework.cloud</groupId> |
| | | <artifactId>spring-cloud-starter-bootstrap</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>org.springframework.security</groupId> |
| | | <artifactId>spring-security-data</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>io.micrometer</groupId> |
| | | <artifactId>micrometer-registry-prometheus</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>io.dropwizard.metrics</groupId> |
| | | <artifactId>metrics-core</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.security</groupId> |
| | | <artifactId>spring-security-messaging</artifactId> |
| | | </dependency> |
| | | <!-- jhipster-needle-maven-add-dependency --> |
| | | </dependencies> |
| | | |
| | | <build> |
| | | <defaultGoal>spring-boot:run</defaultGoal> |
| | | <plugins> |
| | | <plugin> |
| | | <groupId>org.apache.maven.plugins</groupId> |
| | | <artifactId>maven-compiler-plugin</artifactId> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.apache.maven.plugins</groupId> |
| | | <artifactId>maven-checkstyle-plugin</artifactId> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.apache.maven.plugins</groupId> |
| | | <artifactId>maven-javadoc-plugin</artifactId> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.apache.maven.plugins</groupId> |
| | | <artifactId>maven-eclipse-plugin</artifactId> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.apache.maven.plugins</groupId> |
| | | <artifactId>maven-enforcer-plugin</artifactId> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.apache.maven.plugins</groupId> |
| | | <artifactId>maven-failsafe-plugin</artifactId> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.apache.maven.plugins</groupId> |
| | | <artifactId>maven-idea-plugin</artifactId> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.apache.maven.plugins</groupId> |
| | | <artifactId>maven-resources-plugin</artifactId> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.apache.maven.plugins</groupId> |
| | | <artifactId>maven-surefire-plugin</artifactId> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.jacoco</groupId> |
| | | <artifactId>jacoco-maven-plugin</artifactId> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.sonarsource.scanner.maven</groupId> |
| | | <artifactId>sonar-maven-plugin</artifactId> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.liquibase</groupId> |
| | | <artifactId>liquibase-maven-plugin</artifactId> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-maven-plugin</artifactId> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>com.google.cloud.tools</groupId> |
| | | <artifactId>jib-maven-plugin</artifactId> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.codehaus.mojo</groupId> |
| | | <artifactId>properties-maven-plugin</artifactId> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.gaul</groupId> |
| | | <artifactId>modernizer-maven-plugin</artifactId> |
| | | </plugin> |
| | | <!-- jhipster-needle-maven-add-plugin --> |
| | | </plugins> |
| | | <pluginManagement> |
| | | <plugins> |
| | | <plugin> |
| | | <groupId>org.apache.maven.plugins</groupId> |
| | | <artifactId>maven-checkstyle-plugin</artifactId> |
| | | <version>${maven-checkstyle-plugin.version}</version> |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>com.puppycrawl.tools</groupId> |
| | | <artifactId>checkstyle</artifactId> |
| | | <version>${checkstyle.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>io.spring.nohttp</groupId> |
| | | <artifactId>nohttp-checkstyle</artifactId> |
| | | <version>${nohttp-checkstyle.version}</version> |
| | | </dependency> |
| | | </dependencies> |
| | | <configuration> |
| | | <configLocation>checkstyle.xml</configLocation> |
| | | <includes>pom.xml,README.md</includes> |
| | | <excludes>.git/**/*,target/**/*,node_modules/**/*,node/**/*</excludes> |
| | | <sourceDirectories>./</sourceDirectories> |
| | | </configuration> |
| | | <executions> |
| | | <execution> |
| | | <goals> |
| | | <goal>check</goal> |
| | | </goals> |
| | | </execution> |
| | | </executions> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.apache.maven.plugins</groupId> |
| | | <artifactId>maven-compiler-plugin</artifactId> |
| | | <version>${maven-compiler-plugin.version}</version> |
| | | <configuration> |
| | | <source>${java.version}</source> |
| | | <target>${java.version}</target> |
| | | <annotationProcessorPaths> |
| | | <path> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-configuration-processor</artifactId> |
| | | <version>${spring-boot.version}</version> |
| | | </path> |
| | | <path> |
| | | <groupId>org.mapstruct</groupId> |
| | | <artifactId>mapstruct-processor</artifactId> |
| | | <version>${mapstruct.version}</version> |
| | | </path> |
| | | <!-- For JPA static metamodel generation --> |
| | | <path> |
| | | <groupId>org.hibernate</groupId> |
| | | <artifactId>hibernate-jpamodelgen</artifactId> |
| | | <version>${hibernate.version}</version> |
| | | </path> |
| | | <path> |
| | | <groupId>org.glassfish.jaxb</groupId> |
| | | <artifactId>jaxb-runtime</artifactId> |
| | | <version>${jaxb-runtime.version}</version> |
| | | </path> |
| | | <!-- jhipster-needle-maven-add-annotation-processor --> |
| | | </annotationProcessorPaths> |
| | | </configuration> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.apache.maven.plugins</groupId> |
| | | <artifactId>maven-javadoc-plugin</artifactId> |
| | | <version>${maven-javadoc-plugin.version}</version> |
| | | <configuration> |
| | | <source>${maven.compiler.source}</source> |
| | | </configuration> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.apache.maven.plugins</groupId> |
| | | <artifactId>maven-war-plugin</artifactId> |
| | | <version>${maven-war-plugin.version}</version> |
| | | <executions> |
| | | <execution> |
| | | <id>default-war</id> |
| | | <goals> |
| | | <goal>war</goal> |
| | | </goals> |
| | | <phase>package</phase> |
| | | </execution> |
| | | </executions> |
| | | <configuration> |
| | | <warSourceIncludes>WEB-INF/**,META-INF/**</warSourceIncludes> |
| | | <failOnMissingWebXml>false</failOnMissingWebXml> |
| | | </configuration> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.codehaus.mojo</groupId> |
| | | <artifactId>properties-maven-plugin</artifactId> |
| | | <version>${properties-maven-plugin.version}</version> |
| | | <executions> |
| | | <execution> |
| | | <phase>initialize</phase> |
| | | <goals> |
| | | <goal>read-project-properties</goal> |
| | | </goals> |
| | | <configuration> |
| | | <files> |
| | | <file>sonar-project.properties</file> |
| | | </files> |
| | | </configuration> |
| | | </execution> |
| | | </executions> |
| | | </plugin> |
| | | |
| | | <plugin> |
| | | <groupId>io.github.git-commit-id</groupId> |
| | | <artifactId>git-commit-id-maven-plugin</artifactId> |
| | | <version>${git-commit-id-plugin.version}</version> |
| | | <executions> |
| | | <execution> |
| | | <goals> |
| | | <goal>revision</goal> |
| | | </goals> |
| | | </execution> |
| | | </executions> |
| | | <configuration> |
| | | <failOnNoGitDirectory>false</failOnNoGitDirectory> |
| | | <failOnUnableToExtractRepoInfo>false</failOnUnableToExtractRepoInfo> |
| | | <generateGitPropertiesFile>true</generateGitPropertiesFile> |
| | | <includeOnlyProperties> |
| | | <includeOnlyProperty>^git.commit.id.abbrev$</includeOnlyProperty> |
| | | <includeOnlyProperty>^git.commit.id.describe$</includeOnlyProperty> |
| | | <includeOnlyProperty>^git.branch$</includeOnlyProperty> |
| | | </includeOnlyProperties> |
| | | </configuration> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.gaul</groupId> |
| | | <artifactId>modernizer-maven-plugin</artifactId> |
| | | <version>${modernizer-maven-plugin.version}</version> |
| | | <executions> |
| | | <execution> |
| | | <id>modernizer</id> |
| | | <phase>package</phase> |
| | | <goals> |
| | | <goal>modernizer</goal> |
| | | </goals> |
| | | </execution> |
| | | </executions> |
| | | <configuration> |
| | | <javaVersion>${java.version}</javaVersion> |
| | | </configuration> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.jacoco</groupId> |
| | | <artifactId>jacoco-maven-plugin</artifactId> |
| | | <version>${jacoco-maven-plugin.version}</version> |
| | | <executions> |
| | | <execution> |
| | | <id>pre-unit-tests</id> |
| | | <goals> |
| | | <goal>prepare-agent</goal> |
| | | </goals> |
| | | </execution> |
| | | <!-- Ensures that the code coverage report for unit tests is created after unit tests have been run --> |
| | | <execution> |
| | | <id>post-unit-test</id> |
| | | <phase>test</phase> |
| | | <goals> |
| | | <goal>report</goal> |
| | | </goals> |
| | | </execution> |
| | | <execution> |
| | | <id>pre-integration-tests</id> |
| | | <goals> |
| | | <goal>prepare-agent-integration</goal> |
| | | </goals> |
| | | </execution> |
| | | <!-- Ensures that the code coverage report for integration tests is created after integration tests have been run --> |
| | | <execution> |
| | | <id>post-integration-tests</id> |
| | | <phase>post-integration-test</phase> |
| | | <goals> |
| | | <goal>report-integration</goal> |
| | | </goals> |
| | | </execution> |
| | | </executions> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>com.google.cloud.tools</groupId> |
| | | <artifactId>jib-maven-plugin</artifactId> |
| | | <version>${jib-maven-plugin.version}</version> |
| | | <configuration> |
| | | <from> |
| | | <image>${jib-maven-plugin.image}</image> |
| | | <platforms> |
| | | <platform> |
| | | <architecture>${jib-maven-plugin.architecture}</architecture> |
| | | <os>linux</os> |
| | | </platform> |
| | | </platforms> |
| | | </from> |
| | | <to> |
| | | <image>pamapi:latest</image> |
| | | </to> |
| | | <container> |
| | | <entrypoint> |
| | | <shell>bash</shell> |
| | | <option>-c</option> |
| | | <arg>/entrypoint.sh</arg> |
| | | </entrypoint> |
| | | <ports> |
| | | <port>8080</port> |
| | | </ports> |
| | | <environment> |
| | | <SPRING_OUTPUT_ANSI_ENABLED>ALWAYS</SPRING_OUTPUT_ANSI_ENABLED> |
| | | <JHIPSTER_SLEEP>0</JHIPSTER_SLEEP> |
| | | </environment> |
| | | <creationTime>USE_CURRENT_TIMESTAMP</creationTime> |
| | | <user>1000</user> |
| | | </container> |
| | | <extraDirectories> |
| | | <paths>src/main/docker/jib</paths> |
| | | <permissions> |
| | | <permission> |
| | | <file>/entrypoint.sh</file> |
| | | <mode>755</mode> |
| | | </permission> |
| | | </permissions> |
| | | </extraDirectories> |
| | | </configuration> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.liquibase</groupId> |
| | | <artifactId>liquibase-maven-plugin</artifactId> |
| | | <version>${liquibase.version}</version> |
| | | <configuration> |
| | | <changeLogFile>${project.basedir}/src/main/resources/config/liquibase/master.xml</changeLogFile> |
| | | <diffChangeLogFile>${project.basedir}/src/main/resources/config/liquibase/changelog/${maven.build.timestamp}_changelog.xml</diffChangeLogFile> |
| | | <driver>org.postgresql.Driver</driver> |
| | | <url>jdbc:postgresql://localhost:5432/pamapi</url> |
| | | <defaultSchemaName></defaultSchemaName> |
| | | <username>pamapi</username> |
| | | <password></password> |
| | | <referenceUrl>hibernate:spring:com.pollex.pam.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</referenceUrl> |
| | | <verbose>true</verbose> |
| | | <logging>debug</logging> |
| | | <contexts>!test</contexts> |
| | | </configuration> |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>org.liquibase</groupId> |
| | | <artifactId>liquibase-core</artifactId> |
| | | <version>${liquibase.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.liquibase.ext</groupId> |
| | | <artifactId>liquibase-hibernate5</artifactId> |
| | | <version>${liquibase-hibernate5.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-data-jpa</artifactId> |
| | | <version>${spring-boot.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>javax.validation</groupId> |
| | | <artifactId>validation-api</artifactId> |
| | | <version>${validation-api.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.javassist</groupId> |
| | | <artifactId>javassist</artifactId> |
| | | <version>${javassist.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>tech.jhipster</groupId> |
| | | <artifactId>jhipster-framework</artifactId> |
| | | <version>${jhipster-dependencies.version}</version> |
| | | </dependency> |
| | | </dependencies> |
| | | </plugin> |
| | | <plugin> |
| | | <artifactId>maven-clean-plugin</artifactId> |
| | | <version>${maven-clean-plugin.version}</version> |
| | | </plugin> |
| | | <plugin> |
| | | <artifactId>maven-site-plugin</artifactId> |
| | | <version>${maven-site-plugin.version}</version> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.apache.maven.plugins</groupId> |
| | | <artifactId>maven-eclipse-plugin</artifactId> |
| | | <version>${maven-eclipse-plugin.version}</version> |
| | | <configuration> |
| | | <downloadSources>true</downloadSources> |
| | | <downloadJavadocs>true</downloadJavadocs> |
| | | </configuration> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.apache.maven.plugins</groupId> |
| | | <artifactId>maven-enforcer-plugin</artifactId> |
| | | <version>${maven-enforcer-plugin.version}</version> |
| | | <executions> |
| | | <execution> |
| | | <id>enforce-versions</id> |
| | | <goals> |
| | | <goal>enforce</goal> |
| | | </goals> |
| | | </execution> |
| | | <execution> |
| | | <id>enforce-dependencyConvergence</id> |
| | | <configuration> |
| | | <rules> |
| | | <DependencyConvergence /> |
| | | </rules> |
| | | <fail>false</fail> |
| | | </configuration> |
| | | <goals> |
| | | <goal>enforce</goal> |
| | | </goals> |
| | | </execution> |
| | | </executions> |
| | | <configuration> |
| | | <rules> |
| | | <requireMavenVersion> |
| | | <message>You are running an older version of Maven. JHipster requires at least Maven ${maven.version}</message> |
| | | <version>[${maven.version},)</version> |
| | | </requireMavenVersion> |
| | | <requireJavaVersion> |
| | | <message>You are running an incompatible version of Java. JHipster supports JDK 8 to 17.</message> |
| | | <version>[1.8,18)</version> |
| | | </requireJavaVersion> |
| | | </rules> |
| | | </configuration> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.apache.maven.plugins</groupId> |
| | | <artifactId>maven-idea-plugin</artifactId> |
| | | <version>${maven-idea-plugin.version}</version> |
| | | <configuration> |
| | | <exclude>node_modules</exclude> |
| | | </configuration> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.apache.maven.plugins</groupId> |
| | | <artifactId>maven-resources-plugin</artifactId> |
| | | <version>${maven-resources-plugin.version}</version> |
| | | <executions> |
| | | <execution> |
| | | <id>default-resources</id> |
| | | <phase>validate</phase> |
| | | <goals> |
| | | <goal>copy-resources</goal> |
| | | </goals> |
| | | <configuration> |
| | | <outputDirectory>${project.build.directory}/classes</outputDirectory> |
| | | <useDefaultDelimiters>false</useDefaultDelimiters> |
| | | <delimiters> |
| | | <delimiter>#</delimiter> |
| | | </delimiters> |
| | | <resources> |
| | | <resource> |
| | | <directory>src/main/resources/</directory> |
| | | <filtering>true</filtering> |
| | | <includes> |
| | | <include>config/*.yml</include> |
| | | </includes> |
| | | </resource> |
| | | <resource> |
| | | <directory>src/main/resources/</directory> |
| | | <filtering>false</filtering> |
| | | <excludes> |
| | | <exclude>config/*.yml</exclude> |
| | | </excludes> |
| | | </resource> |
| | | </resources> |
| | | </configuration> |
| | | </execution> |
| | | </executions> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.apache.maven.plugins</groupId> |
| | | <artifactId>maven-surefire-plugin</artifactId> |
| | | <version>${maven-surefire-plugin.version}</version> |
| | | <configuration> |
| | | <!-- Force alphabetical order to have a reproducible build --> |
| | | <runOrder>alphabetical</runOrder> |
| | | <excludes> |
| | | <exclude>**/*IT*</exclude> |
| | | <exclude>**/*IntTest*</exclude> |
| | | </excludes> |
| | | </configuration> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.apache.maven.plugins</groupId> |
| | | <artifactId>maven-failsafe-plugin</artifactId> |
| | | <version>${maven-failsafe-plugin.version}</version> |
| | | <configuration> |
| | | <!-- Due to spring-boot repackage, without adding this property test classes are not found |
| | | See https://github.com/spring-projects/spring-boot/issues/6254 --> |
| | | <classesDirectory>${project.build.outputDirectory}</classesDirectory> |
| | | <!-- Force alphabetical order to have a reproducible build --> |
| | | <runOrder>alphabetical</runOrder> |
| | | <includes> |
| | | <include>**/*IT*</include> |
| | | <include>**/*IntTest*</include> |
| | | </includes> |
| | | </configuration> |
| | | <executions> |
| | | <execution> |
| | | <id>integration-test</id> |
| | | <goals> |
| | | <goal>integration-test</goal> |
| | | </goals> |
| | | </execution> |
| | | <execution> |
| | | <id>verify</id> |
| | | <goals> |
| | | <goal>verify</goal> |
| | | </goals> |
| | | </execution> |
| | | </executions> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.sonarsource.scanner.maven</groupId> |
| | | <artifactId>sonar-maven-plugin</artifactId> |
| | | <version>${sonar-maven-plugin.version}</version> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-maven-plugin</artifactId> |
| | | <version>${spring-boot.version}</version> |
| | | <executions> |
| | | <execution> |
| | | <goals> |
| | | <goal>repackage</goal> |
| | | </goals> |
| | | </execution> |
| | | </executions> |
| | | <configuration> |
| | | <mainClass>${start-class}</mainClass> |
| | | <fork>true</fork> |
| | | <!-- |
| | | Enable the line below to have remote debugging of your application on port 5005 |
| | | <jvmArguments>-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005</jvmArguments> |
| | | --> |
| | | </configuration> |
| | | |
| | | </plugin> |
| | | <!-- jhipster-needle-maven-add-plugin-management --> |
| | | </plugins> |
| | | </pluginManagement> |
| | | </build> |
| | | <profiles> |
| | | <profile> |
| | | <id>no-liquibase</id> |
| | | <properties> |
| | | <profile.no-liquibase>,no-liquibase</profile.no-liquibase> |
| | | </properties> |
| | | </profile> |
| | | <profile> |
| | | <id>api-docs</id> |
| | | <properties> |
| | | <profile.api-docs>,api-docs</profile.api-docs> |
| | | </properties> |
| | | </profile> |
| | | <profile> |
| | | <id>tls</id> |
| | | <properties> |
| | | <profile.tls>,tls</profile.tls> |
| | | </properties> |
| | | </profile> |
| | | <profile> |
| | | <id>dev</id> |
| | | <activation> |
| | | <activeByDefault>true</activeByDefault> |
| | | </activation> |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-undertow</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-devtools</artifactId> |
| | | <optional>true</optional> |
| | | </dependency> |
| | | </dependencies> |
| | | <properties> |
| | | <!-- default Spring profiles --> |
| | | <spring.profiles.active>dev${profile.tls}${profile.no-liquibase}</spring.profiles.active> |
| | | </properties> |
| | | </profile> |
| | | <profile> |
| | | <id>prod</id> |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-undertow</artifactId> |
| | | </dependency> |
| | | </dependencies> |
| | | <build> |
| | | <plugins> |
| | | <plugin> |
| | | <artifactId>maven-clean-plugin</artifactId> |
| | | <configuration> |
| | | <filesets> |
| | | <fileset> |
| | | <directory>target/classes/static/</directory> |
| | | </fileset> |
| | | </filesets> |
| | | </configuration> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-maven-plugin</artifactId> |
| | | <executions> |
| | | <execution> |
| | | <goals> |
| | | <goal>build-info</goal> |
| | | </goals> |
| | | </execution> |
| | | </executions> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>io.github.git-commit-id</groupId> |
| | | <artifactId>git-commit-id-maven-plugin</artifactId> |
| | | </plugin> |
| | | </plugins> |
| | | </build> |
| | | <properties> |
| | | <!-- default Spring profiles --> |
| | | <spring.profiles.active>prod${profile.api-docs}${profile.tls}${profile.no-liquibase}</spring.profiles.active> |
| | | </properties> |
| | | </profile> |
| | | <profile> |
| | | <id>war</id> |
| | | <build> |
| | | <plugins> |
| | | <plugin> |
| | | <groupId>org.apache.maven.plugins</groupId> |
| | | <artifactId>maven-war-plugin</artifactId> |
| | | </plugin> |
| | | </plugins> |
| | | </build> |
| | | </profile> |
| | | <profile> |
| | | <!-- |
| | | Profile for tracing requests with Zipkin. |
| | | --> |
| | | <id>zipkin</id> |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>org.springframework.cloud</groupId> |
| | | <artifactId>spring-cloud-starter-zipkin</artifactId> |
| | | </dependency> |
| | | </dependencies> |
| | | </profile> |
| | | <profile> |
| | | <!-- |
| | | Profile for applying IDE-specific configuration. |
| | | At the moment it configures MapStruct and Hibernate JPA Metamodel Generator, which you need when working |
| | | with DTOs and entity filtering. |
| | | --> |
| | | <id>IDE</id> |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>org.mapstruct</groupId> |
| | | <artifactId>mapstruct-processor</artifactId> |
| | | <version>${mapstruct.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.hibernate</groupId> |
| | | <artifactId>hibernate-jpamodelgen</artifactId> |
| | | </dependency> |
| | | </dependencies> |
| | | </profile> |
| | | <profile> |
| | | <!-- This is automatically activated when working in Eclipse --> |
| | | <id>eclipse</id> |
| | | <activation> |
| | | <property> |
| | | <name>m2e.version</name> |
| | | </property> |
| | | </activation> |
| | | <dependencies> |
| | | <!-- The following dependency is added due to issue #9175--> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-undertow</artifactId> |
| | | </dependency> |
| | | </dependencies> |
| | | <build> |
| | | <pluginManagement> |
| | | <plugins> |
| | | <!-- |
| | | This plugin's configuration is used to store Eclipse m2e settings only. |
| | | It has no influence on the Maven build itself. |
| | | Remove when the m2e plugin can correctly bind to Maven lifecycle |
| | | --> |
| | | <plugin> |
| | | <groupId>org.eclipse.m2e</groupId> |
| | | <artifactId>lifecycle-mapping</artifactId> |
| | | <version>${lifecycle-mapping.version}</version> |
| | | <configuration> |
| | | <lifecycleMappingMetadata> |
| | | <pluginExecutions> |
| | | <pluginExecution> |
| | | <pluginExecutionFilter> |
| | | <groupId>org.jacoco</groupId> |
| | | <artifactId> |
| | | jacoco-maven-plugin |
| | | </artifactId> |
| | | <versionRange> |
| | | ${jacoco-maven-plugin.version} |
| | | </versionRange> |
| | | <goals> |
| | | <goal>prepare-agent</goal> |
| | | </goals> |
| | | </pluginExecutionFilter> |
| | | <action> |
| | | <ignore/> |
| | | </action> |
| | | </pluginExecution> |
| | | </pluginExecutions> |
| | | </lifecycleMappingMetadata> |
| | | </configuration> |
| | | </plugin> |
| | | </plugins> |
| | | </pluginManagement> |
| | | </build> |
| | | </profile> |
| | | <!-- jhipster-needle-maven-add-profile --> |
| | | </profiles> |
| | | </project> |
¤ñ¹ï·sÀÉ®× |
| | |
| | | sonar.projectKey=pamapi |
| | | sonar.projectName=pamapi generated by jhipster |
| | | sonar.projectVersion=1.0 |
| | | |
| | | sonar.sources=src/main/ |
| | | sonar.host.url=http://localhost:9001 |
| | | |
| | | sonar.tests=src/test/ |
| | | sonar.coverage.jacoco.xmlReportPaths=target/site/**/jacoco*.xml |
| | | sonar.java.codeCoveragePlugin=jacoco |
| | | sonar.junit.reportPaths=target/surefire-reports,target/failsafe-reports |
| | | |
| | | sonar.sourceEncoding=UTF-8 |
| | | sonar.exclusions=src/main/webapp/content/**/*.*, src/main/webapp/i18n/*.js, target/classes/static/**/*.* |
| | | |
| | | sonar.issue.ignore.multicriteria=S3437,S4502,S4684,UndocumentedApi |
| | | # Rule https://rules.sonarsource.com/java/RSPEC-3437 is ignored, as a JPA-managed field cannot be transient |
| | | sonar.issue.ignore.multicriteria.S3437.resourceKey=src/main/java/**/* |
| | | sonar.issue.ignore.multicriteria.S3437.ruleKey=squid:S3437 |
| | | # Rule https://rules.sonarsource.com/java/RSPEC-1176 is ignored, as we want to follow "clean code" guidelines and classes, methods and arguments names should be self-explanatory |
| | | sonar.issue.ignore.multicriteria.UndocumentedApi.resourceKey=src/main/java/**/* |
| | | sonar.issue.ignore.multicriteria.UndocumentedApi.ruleKey=squid:UndocumentedApi |
| | | # Rule https://rules.sonarsource.com/java/RSPEC-4502 is ignored, as for JWT tokens we are not subject to CSRF attack |
| | | sonar.issue.ignore.multicriteria.S4502.resourceKey=src/main/java/**/* |
| | | sonar.issue.ignore.multicriteria.S4502.ruleKey=squid:S4502 |
| | | # Rule https://rules.sonarsource.com/java/RSPEC-4684 |
| | | sonar.issue.ignore.multicriteria.S4684.resourceKey=src/main/java/**/* |
| | | sonar.issue.ignore.multicriteria.S4684.ruleKey=java:S4684 |
¤ñ¹ï·sÀÉ®× |
| | |
| | | # This configuration is intended for development purpose, it's **your** responsibility to harden it for production |
| | | version: '3.8' |
| | | services: |
| | | pamapi-app: |
| | | image: pamapi |
| | | environment: |
| | | - _JAVA_OPTIONS=-Xmx512m -Xms256m |
| | | - SPRING_PROFILES_ACTIVE=prod,api-docs |
| | | - MANAGEMENT_METRICS_EXPORT_PROMETHEUS_ENABLED=true |
| | | - SPRING_DATASOURCE_URL=jdbc:postgresql://pamapi-postgresql:5432/pamapi |
| | | - SPRING_LIQUIBASE_URL=jdbc:postgresql://pamapi-postgresql:5432/pamapi |
| | | - 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 |
| | | pamapi-postgresql: |
| | | image: postgres:13.4 |
| | | # volumes: |
| | | # - ~/volumes/jhipster/pamapi/postgresql/:/var/lib/postgresql/data/ |
| | | environment: |
| | | - POSTGRES_USER=pamapi |
| | | - 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 |
¤ñ¹ï·sÀÉ®× |
| | |
| | | # Central configuration sources details |
¤ñ¹ï·sÀÉ®× |
| | |
| | | { |
| | | "annotations": { |
| | | "list": [ |
| | | { |
| | | "builtIn": 1, |
| | | "datasource": "-- Grafana --", |
| | | "enable": true, |
| | | "hide": true, |
| | | "iconColor": "rgba(0, 211, 255, 1)", |
| | | "limit": 100, |
| | | "name": "Annotations & Alerts", |
| | | "showIn": 0, |
| | | "type": "dashboard" |
| | | }, |
| | | { |
| | | "datasource": "Prometheus", |
| | | "enable": true, |
| | | "expr": "resets(process_uptime_seconds{application=\"$application\", instance=\"$instance\"}[1m]) > 0", |
| | | "iconColor": "rgba(255, 96, 96, 1)", |
| | | "name": "Restart Detection", |
| | | "showIn": 0, |
| | | "step": "1m", |
| | | "tagKeys": "restart-tag", |
| | | "textFormat": "uptime reset", |
| | | "titleFormat": "Restart" |
| | | } |
| | | ] |
| | | }, |
| | | "description": "Dashboard for Micrometer instrumented applications (Java, Spring Boot, Micronaut)", |
| | | "editable": true, |
| | | "gnetId": 4701, |
| | | "graphTooltip": 1, |
| | | "iteration": 1553765841423, |
| | | "links": [], |
| | | "panels": [ |
| | | { |
| | | "content": "\n# Acknowledgments\n\nThank you to [Michael Weirauch](https://twitter.com/emwexx) for creating this dashboard: see original JVM (Micrometer) dashboard at [https://grafana.com/dashboards/4701](https://grafana.com/dashboards/4701)\n\n\n\n", |
| | | "gridPos": { |
| | | "h": 3, |
| | | "w": 24, |
| | | "x": 0, |
| | | "y": 0 |
| | | }, |
| | | "id": 141, |
| | | "links": [], |
| | | "mode": "markdown", |
| | | "timeFrom": null, |
| | | "timeShift": null, |
| | | "title": "Acknowledgments", |
| | | "type": "text" |
| | | }, |
| | | { |
| | | "collapsed": false, |
| | | "gridPos": { |
| | | "h": 1, |
| | | "w": 24, |
| | | "x": 0, |
| | | "y": 3 |
| | | }, |
| | | "id": 125, |
| | | "panels": [], |
| | | "repeat": null, |
| | | "title": "Quick Facts", |
| | | "type": "row" |
| | | }, |
| | | { |
| | | "cacheTimeout": null, |
| | | "colorBackground": false, |
| | | "colorValue": true, |
| | | "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], |
| | | "datasource": "Prometheus", |
| | | "decimals": 1, |
| | | "editable": true, |
| | | "error": false, |
| | | "format": "s", |
| | | "gauge": { |
| | | "maxValue": 100, |
| | | "minValue": 0, |
| | | "show": false, |
| | | "thresholdLabels": false, |
| | | "thresholdMarkers": true |
| | | }, |
| | | "gridPos": { |
| | | "h": 3, |
| | | "w": 6, |
| | | "x": 0, |
| | | "y": 4 |
| | | }, |
| | | "height": "", |
| | | "id": 63, |
| | | "interval": null, |
| | | "links": [], |
| | | "mappingType": 1, |
| | | "mappingTypes": [ |
| | | { |
| | | "name": "value to text", |
| | | "value": 1 |
| | | }, |
| | | { |
| | | "name": "range to text", |
| | | "value": 2 |
| | | } |
| | | ], |
| | | "maxDataPoints": 100, |
| | | "nullPointMode": "connected", |
| | | "nullText": null, |
| | | "postfix": "", |
| | | "postfixFontSize": "50%", |
| | | "prefix": "", |
| | | "prefixFontSize": "70%", |
| | | "rangeMaps": [ |
| | | { |
| | | "from": "null", |
| | | "text": "N/A", |
| | | "to": "null" |
| | | } |
| | | ], |
| | | "sparkline": { |
| | | "fillColor": "rgba(31, 118, 189, 0.18)", |
| | | "full": false, |
| | | "lineColor": "rgb(31, 120, 193)", |
| | | "show": false |
| | | }, |
| | | "tableColumn": "", |
| | | "targets": [ |
| | | { |
| | | "expr": "process_uptime_seconds{application=\"$application\", instance=\"$instance\"}", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "", |
| | | "metric": "", |
| | | "refId": "A", |
| | | "step": 14400 |
| | | } |
| | | ], |
| | | "thresholds": "", |
| | | "title": "Uptime", |
| | | "type": "singlestat", |
| | | "valueFontSize": "80%", |
| | | "valueMaps": [ |
| | | { |
| | | "op": "=", |
| | | "text": "N/A", |
| | | "value": "null" |
| | | } |
| | | ], |
| | | "valueName": "current" |
| | | }, |
| | | { |
| | | "cacheTimeout": null, |
| | | "colorBackground": false, |
| | | "colorValue": true, |
| | | "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], |
| | | "datasource": "Prometheus", |
| | | "decimals": null, |
| | | "editable": true, |
| | | "error": false, |
| | | "format": "dateTimeAsIso", |
| | | "gauge": { |
| | | "maxValue": 100, |
| | | "minValue": 0, |
| | | "show": false, |
| | | "thresholdLabels": false, |
| | | "thresholdMarkers": true |
| | | }, |
| | | "gridPos": { |
| | | "h": 3, |
| | | "w": 6, |
| | | "x": 6, |
| | | "y": 4 |
| | | }, |
| | | "height": "", |
| | | "id": 92, |
| | | "interval": null, |
| | | "links": [], |
| | | "mappingType": 1, |
| | | "mappingTypes": [ |
| | | { |
| | | "name": "value to text", |
| | | "value": 1 |
| | | }, |
| | | { |
| | | "name": "range to text", |
| | | "value": 2 |
| | | } |
| | | ], |
| | | "maxDataPoints": 100, |
| | | "nullPointMode": "connected", |
| | | "nullText": null, |
| | | "postfix": "", |
| | | "postfixFontSize": "50%", |
| | | "prefix": "", |
| | | "prefixFontSize": "70%", |
| | | "rangeMaps": [ |
| | | { |
| | | "from": "null", |
| | | "text": "N/A", |
| | | "to": "null" |
| | | } |
| | | ], |
| | | "sparkline": { |
| | | "fillColor": "rgba(31, 118, 189, 0.18)", |
| | | "full": false, |
| | | "lineColor": "rgb(31, 120, 193)", |
| | | "show": false |
| | | }, |
| | | "tableColumn": "", |
| | | "targets": [ |
| | | { |
| | | "expr": "process_start_time_seconds{application=\"$application\", instance=\"$instance\"}*1000", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "", |
| | | "metric": "", |
| | | "refId": "A", |
| | | "step": 14400 |
| | | } |
| | | ], |
| | | "thresholds": "", |
| | | "title": "Start time", |
| | | "type": "singlestat", |
| | | "valueFontSize": "70%", |
| | | "valueMaps": [ |
| | | { |
| | | "op": "=", |
| | | "text": "N/A", |
| | | "value": "null" |
| | | } |
| | | ], |
| | | "valueName": "current" |
| | | }, |
| | | { |
| | | "cacheTimeout": null, |
| | | "colorBackground": false, |
| | | "colorValue": true, |
| | | "colors": ["rgba(50, 172, 45, 0.97)", "rgba(237, 129, 40, 0.89)", "rgba(245, 54, 54, 0.9)"], |
| | | "datasource": "Prometheus", |
| | | "decimals": 2, |
| | | "editable": true, |
| | | "error": false, |
| | | "format": "percent", |
| | | "gauge": { |
| | | "maxValue": 100, |
| | | "minValue": 0, |
| | | "show": false, |
| | | "thresholdLabels": false, |
| | | "thresholdMarkers": true |
| | | }, |
| | | "gridPos": { |
| | | "h": 3, |
| | | "w": 6, |
| | | "x": 12, |
| | | "y": 4 |
| | | }, |
| | | "id": 65, |
| | | "interval": null, |
| | | "links": [], |
| | | "mappingType": 1, |
| | | "mappingTypes": [ |
| | | { |
| | | "name": "value to text", |
| | | "value": 1 |
| | | }, |
| | | { |
| | | "name": "range to text", |
| | | "value": 2 |
| | | } |
| | | ], |
| | | "maxDataPoints": 100, |
| | | "nullPointMode": "connected", |
| | | "nullText": null, |
| | | "postfix": "", |
| | | "postfixFontSize": "50%", |
| | | "prefix": "", |
| | | "prefixFontSize": "70%", |
| | | "rangeMaps": [ |
| | | { |
| | | "from": "null", |
| | | "text": "N/A", |
| | | "to": "null" |
| | | } |
| | | ], |
| | | "sparkline": { |
| | | "fillColor": "rgba(31, 118, 189, 0.18)", |
| | | "full": false, |
| | | "lineColor": "rgb(31, 120, 193)", |
| | | "show": false |
| | | }, |
| | | "tableColumn": "", |
| | | "targets": [ |
| | | { |
| | | "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"heap\"})*100/sum(jvm_memory_max_bytes{application=\"$application\",instance=\"$instance\", area=\"heap\"})", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "", |
| | | "refId": "A", |
| | | "step": 14400 |
| | | } |
| | | ], |
| | | "thresholds": "70,90", |
| | | "title": "Heap used", |
| | | "type": "singlestat", |
| | | "valueFontSize": "80%", |
| | | "valueMaps": [ |
| | | { |
| | | "op": "=", |
| | | "text": "N/A", |
| | | "value": "null" |
| | | } |
| | | ], |
| | | "valueName": "current" |
| | | }, |
| | | { |
| | | "cacheTimeout": null, |
| | | "colorBackground": false, |
| | | "colorValue": true, |
| | | "colors": ["rgba(50, 172, 45, 0.97)", "rgba(237, 129, 40, 0.89)", "rgba(245, 54, 54, 0.9)"], |
| | | "datasource": "Prometheus", |
| | | "decimals": 2, |
| | | "editable": true, |
| | | "error": false, |
| | | "format": "percent", |
| | | "gauge": { |
| | | "maxValue": 100, |
| | | "minValue": 0, |
| | | "show": false, |
| | | "thresholdLabels": false, |
| | | "thresholdMarkers": true |
| | | }, |
| | | "gridPos": { |
| | | "h": 3, |
| | | "w": 6, |
| | | "x": 18, |
| | | "y": 4 |
| | | }, |
| | | "id": 75, |
| | | "interval": null, |
| | | "links": [], |
| | | "mappingType": 2, |
| | | "mappingTypes": [ |
| | | { |
| | | "name": "value to text", |
| | | "value": 1 |
| | | }, |
| | | { |
| | | "name": "range to text", |
| | | "value": 2 |
| | | } |
| | | ], |
| | | "maxDataPoints": 100, |
| | | "nullPointMode": "connected", |
| | | "nullText": null, |
| | | "postfix": "", |
| | | "postfixFontSize": "50%", |
| | | "prefix": "", |
| | | "prefixFontSize": "70%", |
| | | "rangeMaps": [ |
| | | { |
| | | "from": "null", |
| | | "text": "N/A", |
| | | "to": "null" |
| | | }, |
| | | { |
| | | "from": "-99999999999999999999999999999999", |
| | | "text": "N/A", |
| | | "to": "0" |
| | | } |
| | | ], |
| | | "sparkline": { |
| | | "fillColor": "rgba(31, 118, 189, 0.18)", |
| | | "full": false, |
| | | "lineColor": "rgb(31, 120, 193)", |
| | | "show": false |
| | | }, |
| | | "tableColumn": "", |
| | | "targets": [ |
| | | { |
| | | "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"nonheap\"})*100/sum(jvm_memory_max_bytes{application=\"$application\",instance=\"$instance\", area=\"nonheap\"})", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "", |
| | | "refId": "A", |
| | | "step": 14400 |
| | | } |
| | | ], |
| | | "thresholds": "70,90", |
| | | "title": "Non-Heap used", |
| | | "type": "singlestat", |
| | | "valueFontSize": "80%", |
| | | "valueMaps": [ |
| | | { |
| | | "op": "=", |
| | | "text": "N/A", |
| | | "value": "null" |
| | | }, |
| | | { |
| | | "op": "=", |
| | | "text": "x", |
| | | "value": "" |
| | | } |
| | | ], |
| | | "valueName": "current" |
| | | }, |
| | | { |
| | | "collapsed": false, |
| | | "gridPos": { |
| | | "h": 1, |
| | | "w": 24, |
| | | "x": 0, |
| | | "y": 7 |
| | | }, |
| | | "id": 126, |
| | | "panels": [], |
| | | "repeat": null, |
| | | "title": "I/O Overview", |
| | | "type": "row" |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "fill": 1, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 8, |
| | | "x": 0, |
| | | "y": 8 |
| | | }, |
| | | "id": 111, |
| | | "legend": { |
| | | "avg": false, |
| | | "current": true, |
| | | "max": false, |
| | | "min": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": true |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "sum(rate(http_server_requests_seconds_count{application=\"$application\", instance=\"$instance\"}[1m]))", |
| | | "format": "time_series", |
| | | "intervalFactor": 1, |
| | | "legendFormat": "HTTP", |
| | | "refId": "A" |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "Rate", |
| | | "tooltip": { |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "individual" |
| | | }, |
| | | "type": "graph", |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "yaxes": [ |
| | | { |
| | | "decimals": null, |
| | | "format": "ops", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": "0", |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "aliasColors": { |
| | | "HTTP": "#890f02", |
| | | "HTTP - 5xx": "#bf1b00" |
| | | }, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "fill": 1, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 8, |
| | | "x": 8, |
| | | "y": 8 |
| | | }, |
| | | "id": 112, |
| | | "legend": { |
| | | "avg": false, |
| | | "current": true, |
| | | "max": false, |
| | | "min": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": true |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "sum(rate(http_server_requests_seconds_count{application=\"$application\", instance=\"$instance\", status=~\"5..\"}[1m]))", |
| | | "format": "time_series", |
| | | "intervalFactor": 1, |
| | | "legendFormat": "HTTP - 5xx", |
| | | "refId": "A" |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "Errors", |
| | | "tooltip": { |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "individual" |
| | | }, |
| | | "type": "graph", |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "yaxes": [ |
| | | { |
| | | "decimals": null, |
| | | "format": "ops", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": "0", |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "fill": 1, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 8, |
| | | "x": 16, |
| | | "y": 8 |
| | | }, |
| | | "id": 113, |
| | | "legend": { |
| | | "avg": false, |
| | | "current": true, |
| | | "max": false, |
| | | "min": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": true |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "sum(rate(http_server_requests_seconds_sum{application=\"$application\", instance=\"$instance\", status!~\"5..\"}[1m]))/sum(rate(http_server_requests_seconds_count{application=\"$application\", instance=\"$instance\", status!~\"5..\"}[1m]))", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "intervalFactor": 1, |
| | | "legendFormat": "HTTP - AVG", |
| | | "refId": "A" |
| | | }, |
| | | { |
| | | "expr": "max(http_server_requests_seconds_max{application=\"$application\", instance=\"$instance\", status!~\"5..\"})", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "intervalFactor": 1, |
| | | "legendFormat": "HTTP - MAX", |
| | | "refId": "B" |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "Duration", |
| | | "tooltip": { |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "individual" |
| | | }, |
| | | "type": "graph", |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "yaxes": [ |
| | | { |
| | | "format": "s", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": "0", |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "collapsed": false, |
| | | "gridPos": { |
| | | "h": 1, |
| | | "w": 24, |
| | | "x": 0, |
| | | "y": 15 |
| | | }, |
| | | "id": 127, |
| | | "panels": [], |
| | | "repeat": null, |
| | | "title": "JVM Memory", |
| | | "type": "row" |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "editable": true, |
| | | "error": false, |
| | | "fill": 1, |
| | | "grid": { |
| | | "leftLogBase": 1, |
| | | "leftMax": null, |
| | | "leftMin": null, |
| | | "rightLogBase": 1, |
| | | "rightMax": null, |
| | | "rightMin": null |
| | | }, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 8, |
| | | "x": 0, |
| | | "y": 16 |
| | | }, |
| | | "id": 24, |
| | | "legend": { |
| | | "avg": false, |
| | | "current": true, |
| | | "max": true, |
| | | "min": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": true |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"heap\"})", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "used", |
| | | "metric": "", |
| | | "refId": "A", |
| | | "step": 2400 |
| | | }, |
| | | { |
| | | "expr": "sum(jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\", area=\"heap\"})", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "committed", |
| | | "refId": "B", |
| | | "step": 2400 |
| | | }, |
| | | { |
| | | "expr": "sum(jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\", area=\"heap\"})", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "max", |
| | | "refId": "C", |
| | | "step": 2400 |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "JVM Heap", |
| | | "tooltip": { |
| | | "msResolution": false, |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "cumulative" |
| | | }, |
| | | "type": "graph", |
| | | "x-axis": true, |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "y-axis": true, |
| | | "y_formats": ["mbytes", "short"], |
| | | "yaxes": [ |
| | | { |
| | | "format": "bytes", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": 0, |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "editable": true, |
| | | "error": false, |
| | | "fill": 1, |
| | | "grid": { |
| | | "leftLogBase": 1, |
| | | "leftMax": null, |
| | | "leftMin": null, |
| | | "rightLogBase": 1, |
| | | "rightMax": null, |
| | | "rightMin": null |
| | | }, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 8, |
| | | "x": 8, |
| | | "y": 16 |
| | | }, |
| | | "id": 25, |
| | | "legend": { |
| | | "avg": false, |
| | | "current": true, |
| | | "max": true, |
| | | "min": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": true |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"nonheap\"})", |
| | | "format": "time_series", |
| | | "interval": "", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "used", |
| | | "metric": "", |
| | | "refId": "A", |
| | | "step": 2400 |
| | | }, |
| | | { |
| | | "expr": "sum(jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\", area=\"nonheap\"})", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "committed", |
| | | "refId": "B", |
| | | "step": 2400 |
| | | }, |
| | | { |
| | | "expr": "sum(jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\", area=\"nonheap\"})", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "max", |
| | | "refId": "C", |
| | | "step": 2400 |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "JVM Non-Heap", |
| | | "tooltip": { |
| | | "msResolution": false, |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "cumulative" |
| | | }, |
| | | "type": "graph", |
| | | "x-axis": true, |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "y-axis": true, |
| | | "y_formats": ["mbytes", "short"], |
| | | "yaxes": [ |
| | | { |
| | | "format": "bytes", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": 0, |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "editable": true, |
| | | "error": false, |
| | | "fill": 1, |
| | | "grid": { |
| | | "leftLogBase": 1, |
| | | "leftMax": null, |
| | | "leftMin": null, |
| | | "rightLogBase": 1, |
| | | "rightMax": null, |
| | | "rightMin": null |
| | | }, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 8, |
| | | "x": 16, |
| | | "y": 16 |
| | | }, |
| | | "id": 26, |
| | | "legend": { |
| | | "alignAsTable": false, |
| | | "avg": false, |
| | | "current": true, |
| | | "max": true, |
| | | "min": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": true |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\"})", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "used", |
| | | "metric": "", |
| | | "refId": "A", |
| | | "step": 2400 |
| | | }, |
| | | { |
| | | "expr": "sum(jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\"})", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "committed", |
| | | "refId": "B", |
| | | "step": 2400 |
| | | }, |
| | | { |
| | | "expr": "sum(jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\"})", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "max", |
| | | "refId": "C", |
| | | "step": 2400 |
| | | }, |
| | | { |
| | | "expr": "process_memory_vss_bytes{application=\"$application\", instance=\"$instance\"}", |
| | | "format": "time_series", |
| | | "hide": true, |
| | | "intervalFactor": 2, |
| | | "legendFormat": "vss", |
| | | "metric": "", |
| | | "refId": "D", |
| | | "step": 2400 |
| | | }, |
| | | { |
| | | "expr": "process_memory_rss_bytes{application=\"$application\", instance=\"$instance\"}", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "rss", |
| | | "refId": "E", |
| | | "step": 2400 |
| | | }, |
| | | { |
| | | "expr": "process_memory_pss_bytes{application=\"$application\", instance=\"$instance\"}", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "pss", |
| | | "refId": "F", |
| | | "step": 2400 |
| | | }, |
| | | { |
| | | "expr": "process_memory_swap_bytes{application=\"$application\", instance=\"$instance\"}", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "swap", |
| | | "refId": "G", |
| | | "step": 2400 |
| | | }, |
| | | { |
| | | "expr": "process_memory_swappss_bytes{application=\"$application\", instance=\"$instance\"}", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "swappss", |
| | | "refId": "H", |
| | | "step": 2400 |
| | | }, |
| | | { |
| | | "expr": "process_memory_pss_bytes{application=\"$application\", instance=\"$instance\"} + process_memory_swap_bytes{application=\"$application\", instance=\"$instance\"}", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "phys (pss+swap)", |
| | | "refId": "I", |
| | | "step": 2400 |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "JVM Total", |
| | | "tooltip": { |
| | | "msResolution": false, |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "cumulative" |
| | | }, |
| | | "type": "graph", |
| | | "x-axis": true, |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "y-axis": true, |
| | | "y_formats": ["mbytes", "short"], |
| | | "yaxes": [ |
| | | { |
| | | "format": "bytes", |
| | | "label": "", |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": 0, |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "collapsed": false, |
| | | "gridPos": { |
| | | "h": 1, |
| | | "w": 24, |
| | | "x": 0, |
| | | "y": 23 |
| | | }, |
| | | "id": 128, |
| | | "panels": [], |
| | | "repeat": null, |
| | | "title": "JVM Misc", |
| | | "type": "row" |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "editable": true, |
| | | "error": false, |
| | | "fill": 1, |
| | | "grid": { |
| | | "leftLogBase": 1, |
| | | "leftMax": null, |
| | | "leftMin": null, |
| | | "rightLogBase": 1, |
| | | "rightMax": null, |
| | | "rightMin": null |
| | | }, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 6, |
| | | "x": 0, |
| | | "y": 24 |
| | | }, |
| | | "id": 106, |
| | | "legend": { |
| | | "avg": false, |
| | | "current": true, |
| | | "max": true, |
| | | "min": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": true |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "system_cpu_usage{application=\"$application\", instance=\"$instance\"}", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "intervalFactor": 1, |
| | | "legendFormat": "system", |
| | | "metric": "", |
| | | "refId": "A", |
| | | "step": 2400 |
| | | }, |
| | | { |
| | | "expr": "process_cpu_usage{application=\"$application\", instance=\"$instance\"}", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "intervalFactor": 1, |
| | | "legendFormat": "process", |
| | | "refId": "B" |
| | | }, |
| | | { |
| | | "expr": "avg_over_time(process_cpu_usage{application=\"$application\", instance=\"$instance\"}[1h])", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "intervalFactor": 1, |
| | | "legendFormat": "process-1h", |
| | | "refId": "C" |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "CPU", |
| | | "tooltip": { |
| | | "msResolution": false, |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "cumulative" |
| | | }, |
| | | "type": "graph", |
| | | "x-axis": true, |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "y-axis": true, |
| | | "y_formats": ["short", "short"], |
| | | "yaxes": [ |
| | | { |
| | | "decimals": 1, |
| | | "format": "percentunit", |
| | | "label": "", |
| | | "logBase": 1, |
| | | "max": "1", |
| | | "min": 0, |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "editable": true, |
| | | "error": false, |
| | | "fill": 1, |
| | | "grid": { |
| | | "leftLogBase": 1, |
| | | "leftMax": null, |
| | | "leftMin": null, |
| | | "rightLogBase": 1, |
| | | "rightMax": null, |
| | | "rightMin": null |
| | | }, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 6, |
| | | "x": 6, |
| | | "y": 24 |
| | | }, |
| | | "id": 93, |
| | | "legend": { |
| | | "avg": false, |
| | | "current": true, |
| | | "max": true, |
| | | "min": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": true |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "system_load_average_1m{application=\"$application\", instance=\"$instance\"}", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "system-1m", |
| | | "metric": "", |
| | | "refId": "A", |
| | | "step": 2400 |
| | | }, |
| | | { |
| | | "expr": "", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "refId": "B" |
| | | }, |
| | | { |
| | | "expr": "system_cpu_count{application=\"$application\", instance=\"$instance\"}", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "cpu", |
| | | "refId": "C" |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "Load", |
| | | "tooltip": { |
| | | "msResolution": false, |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "cumulative" |
| | | }, |
| | | "type": "graph", |
| | | "x-axis": true, |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "y-axis": true, |
| | | "y_formats": ["short", "short"], |
| | | "yaxes": [ |
| | | { |
| | | "decimals": 1, |
| | | "format": "short", |
| | | "label": "", |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": 0, |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "editable": true, |
| | | "error": false, |
| | | "fill": 1, |
| | | "grid": { |
| | | "leftLogBase": 1, |
| | | "leftMax": null, |
| | | "leftMin": null, |
| | | "rightLogBase": 1, |
| | | "rightMax": null, |
| | | "rightMin": null |
| | | }, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 6, |
| | | "x": 12, |
| | | "y": 24 |
| | | }, |
| | | "id": 32, |
| | | "legend": { |
| | | "avg": false, |
| | | "current": true, |
| | | "max": true, |
| | | "min": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": true |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "jvm_threads_live{application=\"$application\", instance=\"$instance\"} or jvm_threads_live_threads{application=\"$application\", instance=\"$instance\"}", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "live", |
| | | "metric": "", |
| | | "refId": "A", |
| | | "step": 2400 |
| | | }, |
| | | { |
| | | "expr": "jvm_threads_daemon{application=\"$application\", instance=\"$instance\"} or jvm_threads_daemon_threads{application=\"$application\", instance=\"$instance\"}", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "daemon", |
| | | "metric": "", |
| | | "refId": "B", |
| | | "step": 2400 |
| | | }, |
| | | { |
| | | "expr": "jvm_threads_peak{application=\"$application\", instance=\"$instance\"} or jvm_threads_peak_threads{application=\"$application\", instance=\"$instance\"}", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "peak", |
| | | "refId": "C", |
| | | "step": 2400 |
| | | }, |
| | | { |
| | | "expr": "process_threads{application=\"$application\", instance=\"$instance\"}", |
| | | "format": "time_series", |
| | | "interval": "", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "process", |
| | | "refId": "D", |
| | | "step": 2400 |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "Threads", |
| | | "tooltip": { |
| | | "msResolution": false, |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "cumulative" |
| | | }, |
| | | "type": "graph", |
| | | "x-axis": true, |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "y-axis": true, |
| | | "y_formats": ["short", "short"], |
| | | "yaxes": [ |
| | | { |
| | | "decimals": 0, |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": 0, |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "aliasColors": { |
| | | "blocked": "#bf1b00", |
| | | "new": "#fce2de", |
| | | "runnable": "#7eb26d", |
| | | "terminated": "#511749", |
| | | "timed-waiting": "#c15c17", |
| | | "waiting": "#eab839" |
| | | }, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "fill": 1, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 6, |
| | | "x": 18, |
| | | "y": 24 |
| | | }, |
| | | "id": 124, |
| | | "legend": { |
| | | "alignAsTable": false, |
| | | "avg": false, |
| | | "current": true, |
| | | "max": true, |
| | | "min": false, |
| | | "rightSide": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": true |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "jvm_threads_states_threads{application=\"$application\", instance=\"$instance\"}", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "{{state}}", |
| | | "refId": "A" |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "Thread States", |
| | | "tooltip": { |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "individual" |
| | | }, |
| | | "type": "graph", |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "yaxes": [ |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "aliasColors": { |
| | | "debug": "#1F78C1", |
| | | "error": "#BF1B00", |
| | | "info": "#508642", |
| | | "trace": "#6ED0E0", |
| | | "warn": "#EAB839" |
| | | }, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "editable": true, |
| | | "error": false, |
| | | "fill": 1, |
| | | "grid": { |
| | | "leftLogBase": 1, |
| | | "leftMax": null, |
| | | "leftMin": null, |
| | | "rightLogBase": 1, |
| | | "rightMax": null, |
| | | "rightMin": null |
| | | }, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 18, |
| | | "x": 0, |
| | | "y": 31 |
| | | }, |
| | | "height": "", |
| | | "id": 91, |
| | | "legend": { |
| | | "alignAsTable": false, |
| | | "avg": false, |
| | | "current": true, |
| | | "hideEmpty": false, |
| | | "hideZero": false, |
| | | "max": true, |
| | | "min": false, |
| | | "rightSide": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": true |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": true, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "seriesOverrides": [ |
| | | { |
| | | "alias": "error", |
| | | "yaxis": 1 |
| | | }, |
| | | { |
| | | "alias": "warn", |
| | | "yaxis": 1 |
| | | } |
| | | ], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "increase(logback_events_total{application=\"$application\", instance=\"$instance\"}[1m])", |
| | | "format": "time_series", |
| | | "interval": "", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "{{level}}", |
| | | "metric": "", |
| | | "refId": "A", |
| | | "step": 1200 |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "Log Events (1m)", |
| | | "tooltip": { |
| | | "msResolution": false, |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "individual" |
| | | }, |
| | | "type": "graph", |
| | | "x-axis": true, |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "y-axis": true, |
| | | "y_formats": ["short", "short"], |
| | | "yaxes": [ |
| | | { |
| | | "decimals": 0, |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": "0", |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "editable": true, |
| | | "error": false, |
| | | "fill": 1, |
| | | "grid": { |
| | | "leftLogBase": 1, |
| | | "leftMax": null, |
| | | "leftMin": null, |
| | | "rightLogBase": 1, |
| | | "rightMax": null, |
| | | "rightMin": null |
| | | }, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 6, |
| | | "x": 18, |
| | | "y": 31 |
| | | }, |
| | | "id": 61, |
| | | "legend": { |
| | | "avg": false, |
| | | "current": true, |
| | | "max": true, |
| | | "min": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": true |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "process_open_fds{application=\"$application\", instance=\"$instance\"}", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "intervalFactor": 2, |
| | | "legendFormat": "open", |
| | | "metric": "", |
| | | "refId": "A", |
| | | "step": 2400 |
| | | }, |
| | | { |
| | | "expr": "process_max_fds{application=\"$application\", instance=\"$instance\"}", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "intervalFactor": 2, |
| | | "legendFormat": "max", |
| | | "metric": "", |
| | | "refId": "B", |
| | | "step": 2400 |
| | | }, |
| | | { |
| | | "expr": "process_files_open{application=\"$application\", instance=\"$instance\"} or process_files_open_files{application=\"$application\", instance=\"$instance\"}", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "open", |
| | | "refId": "C" |
| | | }, |
| | | { |
| | | "expr": "process_files_max{application=\"$application\", instance=\"$instance\"} or process_files_max_files{application=\"$application\", instance=\"$instance\"}", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "max", |
| | | "refId": "D" |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "File Descriptors", |
| | | "tooltip": { |
| | | "msResolution": false, |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "cumulative" |
| | | }, |
| | | "type": "graph", |
| | | "x-axis": true, |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "y-axis": true, |
| | | "y_formats": ["short", "short"], |
| | | "yaxes": [ |
| | | { |
| | | "decimals": 0, |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 10, |
| | | "max": null, |
| | | "min": 0, |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "collapsed": false, |
| | | "gridPos": { |
| | | "h": 1, |
| | | "w": 24, |
| | | "x": 0, |
| | | "y": 38 |
| | | }, |
| | | "id": 129, |
| | | "panels": [], |
| | | "repeat": "persistence_counts", |
| | | "title": "JVM Memory Pools (Heap)", |
| | | "type": "row" |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "editable": true, |
| | | "error": false, |
| | | "fill": 1, |
| | | "grid": { |
| | | "leftLogBase": 1, |
| | | "leftMax": null, |
| | | "leftMin": null, |
| | | "rightLogBase": 1, |
| | | "rightMax": null, |
| | | "rightMin": null |
| | | }, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 8, |
| | | "x": 0, |
| | | "y": 39 |
| | | }, |
| | | "id": 3, |
| | | "legend": { |
| | | "alignAsTable": false, |
| | | "avg": false, |
| | | "current": true, |
| | | "max": true, |
| | | "min": false, |
| | | "rightSide": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": true |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "maxPerRow": 3, |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "repeat": "jvm_memory_pool_heap", |
| | | "scopedVars": { |
| | | "jvm_memory_pool_heap": { |
| | | "selected": false, |
| | | "text": "PS Eden Space", |
| | | "value": "PS Eden Space" |
| | | } |
| | | }, |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", id=\"$jvm_memory_pool_heap\"}", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "interval": "", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "used", |
| | | "metric": "", |
| | | "refId": "A", |
| | | "step": 1800 |
| | | }, |
| | | { |
| | | "expr": "jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\", id=\"$jvm_memory_pool_heap\"}", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "interval": "", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "commited", |
| | | "metric": "", |
| | | "refId": "B", |
| | | "step": 1800 |
| | | }, |
| | | { |
| | | "expr": "jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\", id=\"$jvm_memory_pool_heap\"}", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "interval": "", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "max", |
| | | "metric": "", |
| | | "refId": "C", |
| | | "step": 1800 |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "$jvm_memory_pool_heap", |
| | | "tooltip": { |
| | | "msResolution": false, |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "cumulative" |
| | | }, |
| | | "type": "graph", |
| | | "x-axis": true, |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "y-axis": true, |
| | | "y_formats": ["mbytes", "short"], |
| | | "yaxes": [ |
| | | { |
| | | "format": "bytes", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": 0, |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "editable": true, |
| | | "error": false, |
| | | "fill": 1, |
| | | "grid": { |
| | | "leftLogBase": 1, |
| | | "leftMax": null, |
| | | "leftMin": null, |
| | | "rightLogBase": 1, |
| | | "rightMax": null, |
| | | "rightMin": null |
| | | }, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 8, |
| | | "x": 8, |
| | | "y": 39 |
| | | }, |
| | | "id": 134, |
| | | "legend": { |
| | | "alignAsTable": false, |
| | | "avg": false, |
| | | "current": true, |
| | | "max": true, |
| | | "min": false, |
| | | "rightSide": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": true |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "maxPerRow": 3, |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "repeat": null, |
| | | "repeatIteration": 1553765841423, |
| | | "repeatPanelId": 3, |
| | | "scopedVars": { |
| | | "jvm_memory_pool_heap": { |
| | | "selected": false, |
| | | "text": "PS Old Gen", |
| | | "value": "PS Old Gen" |
| | | } |
| | | }, |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", id=\"$jvm_memory_pool_heap\"}", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "interval": "", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "used", |
| | | "metric": "", |
| | | "refId": "A", |
| | | "step": 1800 |
| | | }, |
| | | { |
| | | "expr": "jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\", id=\"$jvm_memory_pool_heap\"}", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "interval": "", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "commited", |
| | | "metric": "", |
| | | "refId": "B", |
| | | "step": 1800 |
| | | }, |
| | | { |
| | | "expr": "jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\", id=\"$jvm_memory_pool_heap\"}", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "interval": "", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "max", |
| | | "metric": "", |
| | | "refId": "C", |
| | | "step": 1800 |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "$jvm_memory_pool_heap", |
| | | "tooltip": { |
| | | "msResolution": false, |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "cumulative" |
| | | }, |
| | | "type": "graph", |
| | | "x-axis": true, |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "y-axis": true, |
| | | "y_formats": ["mbytes", "short"], |
| | | "yaxes": [ |
| | | { |
| | | "format": "bytes", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": 0, |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "editable": true, |
| | | "error": false, |
| | | "fill": 1, |
| | | "grid": { |
| | | "leftLogBase": 1, |
| | | "leftMax": null, |
| | | "leftMin": null, |
| | | "rightLogBase": 1, |
| | | "rightMax": null, |
| | | "rightMin": null |
| | | }, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 8, |
| | | "x": 16, |
| | | "y": 39 |
| | | }, |
| | | "id": 135, |
| | | "legend": { |
| | | "alignAsTable": false, |
| | | "avg": false, |
| | | "current": true, |
| | | "max": true, |
| | | "min": false, |
| | | "rightSide": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": true |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "maxPerRow": 3, |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "repeat": null, |
| | | "repeatIteration": 1553765841423, |
| | | "repeatPanelId": 3, |
| | | "scopedVars": { |
| | | "jvm_memory_pool_heap": { |
| | | "selected": false, |
| | | "text": "PS Survivor Space", |
| | | "value": "PS Survivor Space" |
| | | } |
| | | }, |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", id=\"$jvm_memory_pool_heap\"}", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "interval": "", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "used", |
| | | "metric": "", |
| | | "refId": "A", |
| | | "step": 1800 |
| | | }, |
| | | { |
| | | "expr": "jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\", id=\"$jvm_memory_pool_heap\"}", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "interval": "", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "commited", |
| | | "metric": "", |
| | | "refId": "B", |
| | | "step": 1800 |
| | | }, |
| | | { |
| | | "expr": "jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\", id=\"$jvm_memory_pool_heap\"}", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "interval": "", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "max", |
| | | "metric": "", |
| | | "refId": "C", |
| | | "step": 1800 |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "$jvm_memory_pool_heap", |
| | | "tooltip": { |
| | | "msResolution": false, |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "cumulative" |
| | | }, |
| | | "type": "graph", |
| | | "x-axis": true, |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "y-axis": true, |
| | | "y_formats": ["mbytes", "short"], |
| | | "yaxes": [ |
| | | { |
| | | "format": "bytes", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": 0, |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "collapsed": false, |
| | | "gridPos": { |
| | | "h": 1, |
| | | "w": 24, |
| | | "x": 0, |
| | | "y": 46 |
| | | }, |
| | | "id": 130, |
| | | "panels": [], |
| | | "repeat": null, |
| | | "title": "JVM Memory Pools (Non-Heap)", |
| | | "type": "row" |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "editable": true, |
| | | "error": false, |
| | | "fill": 1, |
| | | "grid": { |
| | | "leftLogBase": 1, |
| | | "leftMax": null, |
| | | "leftMin": null, |
| | | "rightLogBase": 1, |
| | | "rightMax": null, |
| | | "rightMin": null |
| | | }, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 8, |
| | | "x": 0, |
| | | "y": 47 |
| | | }, |
| | | "id": 78, |
| | | "legend": { |
| | | "alignAsTable": false, |
| | | "avg": false, |
| | | "current": true, |
| | | "max": true, |
| | | "min": false, |
| | | "rightSide": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": true |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "maxPerRow": 3, |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "repeat": "jvm_memory_pool_nonheap", |
| | | "scopedVars": { |
| | | "jvm_memory_pool_nonheap": { |
| | | "selected": false, |
| | | "text": "Metaspace", |
| | | "value": "Metaspace" |
| | | } |
| | | }, |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", id=\"$jvm_memory_pool_nonheap\"}", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "interval": "", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "used", |
| | | "metric": "", |
| | | "refId": "A", |
| | | "step": 1800 |
| | | }, |
| | | { |
| | | "expr": "jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\", id=\"$jvm_memory_pool_nonheap\"}", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "interval": "", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "commited", |
| | | "metric": "", |
| | | "refId": "B", |
| | | "step": 1800 |
| | | }, |
| | | { |
| | | "expr": "jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\", id=\"$jvm_memory_pool_nonheap\"}", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "interval": "", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "max", |
| | | "metric": "", |
| | | "refId": "C", |
| | | "step": 1800 |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "$jvm_memory_pool_nonheap", |
| | | "tooltip": { |
| | | "msResolution": false, |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "cumulative" |
| | | }, |
| | | "type": "graph", |
| | | "x-axis": true, |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "y-axis": true, |
| | | "y_formats": ["mbytes", "short"], |
| | | "yaxes": [ |
| | | { |
| | | "format": "bytes", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": 0, |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "editable": true, |
| | | "error": false, |
| | | "fill": 1, |
| | | "grid": { |
| | | "leftLogBase": 1, |
| | | "leftMax": null, |
| | | "leftMin": null, |
| | | "rightLogBase": 1, |
| | | "rightMax": null, |
| | | "rightMin": null |
| | | }, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 8, |
| | | "x": 8, |
| | | "y": 47 |
| | | }, |
| | | "id": 136, |
| | | "legend": { |
| | | "alignAsTable": false, |
| | | "avg": false, |
| | | "current": true, |
| | | "max": true, |
| | | "min": false, |
| | | "rightSide": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": true |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "maxPerRow": 3, |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "repeat": null, |
| | | "repeatIteration": 1553765841423, |
| | | "repeatPanelId": 78, |
| | | "scopedVars": { |
| | | "jvm_memory_pool_nonheap": { |
| | | "selected": false, |
| | | "text": "Compressed Class Space", |
| | | "value": "Compressed Class Space" |
| | | } |
| | | }, |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", id=\"$jvm_memory_pool_nonheap\"}", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "interval": "", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "used", |
| | | "metric": "", |
| | | "refId": "A", |
| | | "step": 1800 |
| | | }, |
| | | { |
| | | "expr": "jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\", id=\"$jvm_memory_pool_nonheap\"}", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "interval": "", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "commited", |
| | | "metric": "", |
| | | "refId": "B", |
| | | "step": 1800 |
| | | }, |
| | | { |
| | | "expr": "jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\", id=\"$jvm_memory_pool_nonheap\"}", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "interval": "", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "max", |
| | | "metric": "", |
| | | "refId": "C", |
| | | "step": 1800 |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "$jvm_memory_pool_nonheap", |
| | | "tooltip": { |
| | | "msResolution": false, |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "cumulative" |
| | | }, |
| | | "type": "graph", |
| | | "x-axis": true, |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "y-axis": true, |
| | | "y_formats": ["mbytes", "short"], |
| | | "yaxes": [ |
| | | { |
| | | "format": "bytes", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": 0, |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "editable": true, |
| | | "error": false, |
| | | "fill": 1, |
| | | "grid": { |
| | | "leftLogBase": 1, |
| | | "leftMax": null, |
| | | "leftMin": null, |
| | | "rightLogBase": 1, |
| | | "rightMax": null, |
| | | "rightMin": null |
| | | }, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 8, |
| | | "x": 16, |
| | | "y": 47 |
| | | }, |
| | | "id": 137, |
| | | "legend": { |
| | | "alignAsTable": false, |
| | | "avg": false, |
| | | "current": true, |
| | | "max": true, |
| | | "min": false, |
| | | "rightSide": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": true |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "maxPerRow": 3, |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "repeat": null, |
| | | "repeatIteration": 1553765841423, |
| | | "repeatPanelId": 78, |
| | | "scopedVars": { |
| | | "jvm_memory_pool_nonheap": { |
| | | "selected": false, |
| | | "text": "Code Cache", |
| | | "value": "Code Cache" |
| | | } |
| | | }, |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", id=\"$jvm_memory_pool_nonheap\"}", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "interval": "", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "used", |
| | | "metric": "", |
| | | "refId": "A", |
| | | "step": 1800 |
| | | }, |
| | | { |
| | | "expr": "jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\", id=\"$jvm_memory_pool_nonheap\"}", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "interval": "", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "commited", |
| | | "metric": "", |
| | | "refId": "B", |
| | | "step": 1800 |
| | | }, |
| | | { |
| | | "expr": "jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\", id=\"$jvm_memory_pool_nonheap\"}", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "interval": "", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "max", |
| | | "metric": "", |
| | | "refId": "C", |
| | | "step": 1800 |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "$jvm_memory_pool_nonheap", |
| | | "tooltip": { |
| | | "msResolution": false, |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "cumulative" |
| | | }, |
| | | "type": "graph", |
| | | "x-axis": true, |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "y-axis": true, |
| | | "y_formats": ["mbytes", "short"], |
| | | "yaxes": [ |
| | | { |
| | | "format": "bytes", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": 0, |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "collapsed": false, |
| | | "gridPos": { |
| | | "h": 1, |
| | | "w": 24, |
| | | "x": 0, |
| | | "y": 54 |
| | | }, |
| | | "id": 131, |
| | | "panels": [], |
| | | "repeat": null, |
| | | "title": "Garbage Collection", |
| | | "type": "row" |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "fill": 1, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 8, |
| | | "x": 0, |
| | | "y": 55 |
| | | }, |
| | | "id": 98, |
| | | "legend": { |
| | | "avg": false, |
| | | "current": false, |
| | | "max": false, |
| | | "min": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": false |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "rate(jvm_gc_pause_seconds_count{application=\"$application\", instance=\"$instance\"}[1m])", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "intervalFactor": 2, |
| | | "legendFormat": "{{action}} ({{cause}})", |
| | | "refId": "A" |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "Collections", |
| | | "tooltip": { |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "individual" |
| | | }, |
| | | "type": "graph", |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "yaxes": [ |
| | | { |
| | | "format": "ops", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": "0", |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": "", |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "fill": 1, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 8, |
| | | "x": 8, |
| | | "y": 55 |
| | | }, |
| | | "id": 101, |
| | | "legend": { |
| | | "avg": false, |
| | | "current": false, |
| | | "max": false, |
| | | "min": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": false |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "rate(jvm_gc_pause_seconds_sum{application=\"$application\", instance=\"$instance\"}[1m])/rate(jvm_gc_pause_seconds_count{application=\"$application\", instance=\"$instance\"}[1m])", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "instant": false, |
| | | "intervalFactor": 1, |
| | | "legendFormat": "avg {{action}} ({{cause}})", |
| | | "refId": "A" |
| | | }, |
| | | { |
| | | "expr": "jvm_gc_pause_seconds_max{application=\"$application\", instance=\"$instance\"}", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "instant": false, |
| | | "intervalFactor": 1, |
| | | "legendFormat": "max {{action}} ({{cause}})", |
| | | "refId": "B" |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "Pause Durations", |
| | | "tooltip": { |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "individual" |
| | | }, |
| | | "type": "graph", |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "yaxes": [ |
| | | { |
| | | "format": "s", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": "0", |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": "", |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "fill": 1, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 8, |
| | | "x": 16, |
| | | "y": 55 |
| | | }, |
| | | "id": 99, |
| | | "legend": { |
| | | "avg": false, |
| | | "current": false, |
| | | "max": false, |
| | | "min": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": false |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "rate(jvm_gc_memory_allocated_bytes_total{application=\"$application\", instance=\"$instance\"}[1m])", |
| | | "format": "time_series", |
| | | "interval": "", |
| | | "intervalFactor": 1, |
| | | "legendFormat": "allocated", |
| | | "refId": "A" |
| | | }, |
| | | { |
| | | "expr": "rate(jvm_gc_memory_promoted_bytes_total{application=\"$application\", instance=\"$instance\"}[1m])", |
| | | "format": "time_series", |
| | | "interval": "", |
| | | "intervalFactor": 1, |
| | | "legendFormat": "promoted", |
| | | "refId": "B" |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "Allocated/Promoted", |
| | | "tooltip": { |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "individual" |
| | | }, |
| | | "type": "graph", |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "yaxes": [ |
| | | { |
| | | "format": "bytes", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": "0", |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "collapsed": false, |
| | | "gridPos": { |
| | | "h": 1, |
| | | "w": 24, |
| | | "x": 0, |
| | | "y": 62 |
| | | }, |
| | | "id": 132, |
| | | "panels": [], |
| | | "repeat": null, |
| | | "title": "Classloading", |
| | | "type": "row" |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "editable": true, |
| | | "error": false, |
| | | "fill": 1, |
| | | "grid": { |
| | | "leftLogBase": 1, |
| | | "leftMax": null, |
| | | "leftMin": null, |
| | | "rightLogBase": 1, |
| | | "rightMax": null, |
| | | "rightMin": null |
| | | }, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 12, |
| | | "x": 0, |
| | | "y": 63 |
| | | }, |
| | | "id": 37, |
| | | "legend": { |
| | | "avg": false, |
| | | "current": false, |
| | | "max": false, |
| | | "min": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": false |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "jvm_classes_loaded{application=\"$application\", instance=\"$instance\"} or jvm_classes_loaded_classes{application=\"$application\", instance=\"$instance\"}", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "loaded", |
| | | "metric": "", |
| | | "refId": "A", |
| | | "step": 1200 |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "Classes loaded", |
| | | "tooltip": { |
| | | "msResolution": false, |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "cumulative" |
| | | }, |
| | | "type": "graph", |
| | | "x-axis": true, |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "y-axis": true, |
| | | "y_formats": ["short", "short"], |
| | | "yaxes": [ |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": 0, |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "editable": true, |
| | | "error": false, |
| | | "fill": 1, |
| | | "grid": { |
| | | "leftLogBase": 1, |
| | | "leftMax": null, |
| | | "leftMin": null, |
| | | "rightLogBase": 1, |
| | | "rightMax": null, |
| | | "rightMin": null |
| | | }, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 12, |
| | | "x": 12, |
| | | "y": 63 |
| | | }, |
| | | "id": 38, |
| | | "legend": { |
| | | "avg": false, |
| | | "current": false, |
| | | "max": false, |
| | | "min": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": false |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "delta(jvm_classes_loaded{application=\"$application\",instance=\"$instance\"}[5m]) or delta(jvm_classes_loaded_classes{application=\"$application\",instance=\"$instance\"}[5m])", |
| | | "format": "time_series", |
| | | "hide": false, |
| | | "interval": "", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "delta", |
| | | "metric": "", |
| | | "refId": "A", |
| | | "step": 1200 |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "Class delta (5m)", |
| | | "tooltip": { |
| | | "msResolution": false, |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "cumulative" |
| | | }, |
| | | "type": "graph", |
| | | "x-axis": true, |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "y-axis": true, |
| | | "y_formats": ["ops", "short"], |
| | | "yaxes": [ |
| | | { |
| | | "decimals": null, |
| | | "format": "short", |
| | | "label": "", |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "collapsed": false, |
| | | "gridPos": { |
| | | "h": 1, |
| | | "w": 24, |
| | | "x": 0, |
| | | "y": 70 |
| | | }, |
| | | "id": 133, |
| | | "panels": [], |
| | | "repeat": null, |
| | | "title": "Buffer Pools", |
| | | "type": "row" |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "editable": true, |
| | | "error": false, |
| | | "fill": 1, |
| | | "grid": { |
| | | "leftLogBase": 1, |
| | | "leftMax": null, |
| | | "leftMin": null, |
| | | "rightLogBase": 1, |
| | | "rightMax": null, |
| | | "rightMin": null |
| | | }, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 6, |
| | | "x": 0, |
| | | "y": 71 |
| | | }, |
| | | "id": 33, |
| | | "legend": { |
| | | "avg": false, |
| | | "current": false, |
| | | "max": false, |
| | | "min": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": false |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "jvm_buffer_memory_used_bytes{application=\"$application\", instance=\"$instance\", id=\"direct\"}", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "used", |
| | | "metric": "", |
| | | "refId": "A", |
| | | "step": 2400 |
| | | }, |
| | | { |
| | | "expr": "jvm_buffer_total_capacity_bytes{application=\"$application\", instance=\"$instance\", id=\"direct\"}", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "capacity", |
| | | "metric": "", |
| | | "refId": "B", |
| | | "step": 2400 |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "Direct Buffers", |
| | | "tooltip": { |
| | | "msResolution": false, |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "cumulative" |
| | | }, |
| | | "type": "graph", |
| | | "x-axis": true, |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "y-axis": true, |
| | | "y_formats": ["short", "short"], |
| | | "yaxes": [ |
| | | { |
| | | "format": "bytes", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": 0, |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "editable": true, |
| | | "error": false, |
| | | "fill": 1, |
| | | "grid": { |
| | | "leftLogBase": 1, |
| | | "leftMax": null, |
| | | "leftMin": null, |
| | | "rightLogBase": 1, |
| | | "rightMax": null, |
| | | "rightMin": null |
| | | }, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 6, |
| | | "x": 6, |
| | | "y": 71 |
| | | }, |
| | | "id": 83, |
| | | "legend": { |
| | | "avg": false, |
| | | "current": false, |
| | | "max": false, |
| | | "min": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": false |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "jvm_buffer_count{application=\"$application\", instance=\"$instance\", id=\"direct\"} or jvm_buffer_count_buffers{application=\"$application\", instance=\"$instance\", id=\"direct\"}", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "count", |
| | | "metric": "", |
| | | "refId": "A", |
| | | "step": 2400 |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "Direct Buffers", |
| | | "tooltip": { |
| | | "msResolution": false, |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "cumulative" |
| | | }, |
| | | "type": "graph", |
| | | "x-axis": true, |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "y-axis": true, |
| | | "y_formats": ["short", "short"], |
| | | "yaxes": [ |
| | | { |
| | | "decimals": 0, |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": 0, |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "editable": true, |
| | | "error": false, |
| | | "fill": 1, |
| | | "grid": { |
| | | "leftLogBase": 1, |
| | | "leftMax": null, |
| | | "leftMin": null, |
| | | "rightLogBase": 1, |
| | | "rightMax": null, |
| | | "rightMin": null |
| | | }, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 6, |
| | | "x": 12, |
| | | "y": 71 |
| | | }, |
| | | "id": 85, |
| | | "legend": { |
| | | "avg": false, |
| | | "current": false, |
| | | "max": false, |
| | | "min": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": false |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "jvm_buffer_memory_used_bytes{application=\"$application\", instance=\"$instance\", id=\"mapped\"}", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "used", |
| | | "metric": "", |
| | | "refId": "A", |
| | | "step": 2400 |
| | | }, |
| | | { |
| | | "expr": "jvm_buffer_total_capacity_bytes{application=\"$application\", instance=\"$instance\", id=\"mapped\"}", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "capacity", |
| | | "metric": "", |
| | | "refId": "B", |
| | | "step": 2400 |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "Mapped Buffers", |
| | | "tooltip": { |
| | | "msResolution": false, |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "cumulative" |
| | | }, |
| | | "type": "graph", |
| | | "x-axis": true, |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "y-axis": true, |
| | | "y_formats": ["short", "short"], |
| | | "yaxes": [ |
| | | { |
| | | "format": "bytes", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": 0, |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | }, |
| | | { |
| | | "aliasColors": {}, |
| | | "bars": false, |
| | | "dashLength": 10, |
| | | "dashes": false, |
| | | "datasource": "Prometheus", |
| | | "editable": true, |
| | | "error": false, |
| | | "fill": 1, |
| | | "grid": { |
| | | "leftLogBase": 1, |
| | | "leftMax": null, |
| | | "leftMin": null, |
| | | "rightLogBase": 1, |
| | | "rightMax": null, |
| | | "rightMin": null |
| | | }, |
| | | "gridPos": { |
| | | "h": 7, |
| | | "w": 6, |
| | | "x": 18, |
| | | "y": 71 |
| | | }, |
| | | "id": 84, |
| | | "legend": { |
| | | "avg": false, |
| | | "current": false, |
| | | "max": false, |
| | | "min": false, |
| | | "show": true, |
| | | "total": false, |
| | | "values": false |
| | | }, |
| | | "lines": true, |
| | | "linewidth": 1, |
| | | "links": [], |
| | | "nullPointMode": "null", |
| | | "paceLength": 10, |
| | | "percentage": false, |
| | | "pointradius": 5, |
| | | "points": false, |
| | | "renderer": "flot", |
| | | "seriesOverrides": [], |
| | | "spaceLength": 10, |
| | | "stack": false, |
| | | "steppedLine": false, |
| | | "targets": [ |
| | | { |
| | | "expr": "jvm_buffer_count{application=\"$application\", instance=\"$instance\", id=\"mapped\"} or jvm_buffer_count_buffers{application=\"$application\", instance=\"$instance\", id=\"mapped\"}", |
| | | "format": "time_series", |
| | | "intervalFactor": 2, |
| | | "legendFormat": "count", |
| | | "metric": "", |
| | | "refId": "A", |
| | | "step": 2400 |
| | | } |
| | | ], |
| | | "thresholds": [], |
| | | "timeFrom": null, |
| | | "timeRegions": [], |
| | | "timeShift": null, |
| | | "title": "Mapped Buffers", |
| | | "tooltip": { |
| | | "msResolution": false, |
| | | "shared": true, |
| | | "sort": 0, |
| | | "value_type": "cumulative" |
| | | }, |
| | | "type": "graph", |
| | | "x-axis": true, |
| | | "xaxis": { |
| | | "buckets": null, |
| | | "mode": "time", |
| | | "name": null, |
| | | "show": true, |
| | | "values": [] |
| | | }, |
| | | "y-axis": true, |
| | | "y_formats": ["short", "short"], |
| | | "yaxes": [ |
| | | { |
| | | "decimals": 0, |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": 0, |
| | | "show": true |
| | | }, |
| | | { |
| | | "format": "short", |
| | | "label": null, |
| | | "logBase": 1, |
| | | "max": null, |
| | | "min": null, |
| | | "show": true |
| | | } |
| | | ], |
| | | "yaxis": { |
| | | "align": false, |
| | | "alignLevel": null |
| | | } |
| | | } |
| | | ], |
| | | "refresh": "10s", |
| | | "schemaVersion": 18, |
| | | "style": "dark", |
| | | "tags": [], |
| | | "templating": { |
| | | "list": [ |
| | | { |
| | | "allValue": null, |
| | | "current": { |
| | | "text": "test", |
| | | "value": "test" |
| | | }, |
| | | "datasource": "Prometheus", |
| | | "definition": "", |
| | | "hide": 0, |
| | | "includeAll": false, |
| | | "label": "Application", |
| | | "multi": false, |
| | | "name": "application", |
| | | "options": [], |
| | | "query": "label_values(application)", |
| | | "refresh": 2, |
| | | "regex": "", |
| | | "skipUrlSync": false, |
| | | "sort": 0, |
| | | "tagValuesQuery": "", |
| | | "tags": [], |
| | | "tagsQuery": "", |
| | | "type": "query", |
| | | "useTags": false |
| | | }, |
| | | { |
| | | "allFormat": "glob", |
| | | "allValue": null, |
| | | "current": { |
| | | "text": "localhost:8080", |
| | | "value": "localhost:8080" |
| | | }, |
| | | "datasource": "Prometheus", |
| | | "definition": "", |
| | | "hide": 0, |
| | | "includeAll": false, |
| | | "label": "Instance", |
| | | "multi": false, |
| | | "multiFormat": "glob", |
| | | "name": "instance", |
| | | "options": [], |
| | | "query": "label_values(jvm_memory_used_bytes{application=\"$application\"}, instance)", |
| | | "refresh": 2, |
| | | "regex": "", |
| | | "skipUrlSync": false, |
| | | "sort": 0, |
| | | "tagValuesQuery": "", |
| | | "tags": [], |
| | | "tagsQuery": "", |
| | | "type": "query", |
| | | "useTags": false |
| | | }, |
| | | { |
| | | "allFormat": "glob", |
| | | "allValue": null, |
| | | "current": { |
| | | "text": "All", |
| | | "value": "$__all" |
| | | }, |
| | | "datasource": "Prometheus", |
| | | "definition": "", |
| | | "hide": 0, |
| | | "includeAll": true, |
| | | "label": "JVM Memory Pools Heap", |
| | | "multi": false, |
| | | "multiFormat": "glob", |
| | | "name": "jvm_memory_pool_heap", |
| | | "options": [], |
| | | "query": "label_values(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"heap\"},id)", |
| | | "refresh": 1, |
| | | "regex": "", |
| | | "skipUrlSync": false, |
| | | "sort": 1, |
| | | "tagValuesQuery": "", |
| | | "tags": [], |
| | | "tagsQuery": "", |
| | | "type": "query", |
| | | "useTags": false |
| | | }, |
| | | { |
| | | "allFormat": "glob", |
| | | "allValue": null, |
| | | "current": { |
| | | "text": "All", |
| | | "value": "$__all" |
| | | }, |
| | | "datasource": "Prometheus", |
| | | "definition": "", |
| | | "hide": 0, |
| | | "includeAll": true, |
| | | "label": "JVM Memory Pools Non-Heap", |
| | | "multi": false, |
| | | "multiFormat": "glob", |
| | | "name": "jvm_memory_pool_nonheap", |
| | | "options": [], |
| | | "query": "label_values(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"nonheap\"},id)", |
| | | "refresh": 1, |
| | | "regex": "", |
| | | "skipUrlSync": false, |
| | | "sort": 2, |
| | | "tagValuesQuery": "", |
| | | "tags": [], |
| | | "tagsQuery": "", |
| | | "type": "query", |
| | | "useTags": false |
| | | } |
| | | ] |
| | | }, |
| | | "time": { |
| | | "from": "now-30m", |
| | | "to": "now" |
| | | }, |
| | | "timepicker": { |
| | | "now": true, |
| | | "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], |
| | | "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] |
| | | }, |
| | | "timezone": "browser", |
| | | "title": "JVM (Micrometer)", |
| | | "uid": "Ud1CFe3iz", |
| | | "version": 1 |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | apiVersion: 1 |
| | | |
| | | providers: |
| | | - name: 'Prometheus' |
| | | orgId: 1 |
| | | folder: '' |
| | | type: file |
| | | disableDeletion: false |
| | | editable: true |
| | | options: |
| | | path: /etc/grafana/provisioning/dashboards |
¤ñ¹ï·sÀÉ®× |
| | |
| | | apiVersion: 1 |
| | | |
| | | # list of datasources that should be deleted from the database |
| | | deleteDatasources: |
| | | - name: Prometheus |
| | | orgId: 1 |
| | | |
| | | # list of datasources to insert/update depending |
| | | # whats available in the database |
| | | datasources: |
| | | # <string, required> name of the datasource. Required |
| | | - name: Prometheus |
| | | # <string, required> datasource type. Required |
| | | type: prometheus |
| | | # <string, required> access mode. direct or proxy. Required |
| | | access: proxy |
| | | # <int> org id. will default to orgId 1 if not specified |
| | | orgId: 1 |
| | | # <string> url |
| | | # On MacOS, replace localhost by host.docker.internal |
| | | url: http://localhost:9090 |
| | | # <string> database password, if used |
| | | password: |
| | | # <string> database user, if used |
| | | user: |
| | | # <string> database name, if used |
| | | database: |
| | | # <bool> enable/disable basic auth |
| | | basicAuth: false |
| | | # <string> basic auth username |
| | | basicAuthUser: admin |
| | | # <string> basic auth password |
| | | basicAuthPassword: admin |
| | | # <bool> enable/disable with credentials headers |
| | | withCredentials: |
| | | # <bool> mark as default datasource. Max one per org |
| | | isDefault: true |
| | | # <map> fields that will be converted to json and stored in json_data |
| | | jsonData: |
| | | graphiteVersion: '1.1' |
| | | tlsAuth: false |
| | | tlsAuthWithCACert: false |
| | | # <string> json object of data that will be encrypted. |
| | | secureJsonData: |
| | | tlsCACert: '...' |
| | | tlsClientCert: '...' |
| | | tlsClientKey: '...' |
| | | version: 1 |
| | | # <bool> allow users to edit datasources from the UI. |
| | | editable: true |
¤ñ¹ï·sÀÉ®× |
| | |
| | | ## How to use JHCC docker compose |
| | | # To allow JHCC to reach JHipster application from a docker container note that we set the host as host.docker.internal |
| | | # To reach the application from a browser, you need to add '127.0.0.1 host.docker.internal' to your hosts file. |
| | | ### Discovery mode |
| | | # JHCC support 3 kinds of discovery mode: Consul, Eureka and static |
| | | # In order to use one, please set SPRING_PROFILES_ACTIVE to one (and only one) of this values: consul,eureka,static |
| | | ### Discovery properties |
| | | # According to the discovery mode choose as Spring profile, you have to set the right properties |
| | | # please note that current properties are set to run JHCC with default values, personalize them if needed |
| | | # and remove those from other modes. You can only have one mode active. |
| | | #### Eureka |
| | | # - EUREKA_CLIENT_SERVICE_URL_DEFAULTZONE=http://admin:admin@host.docker.internal:8761/eureka/ |
| | | #### Consul |
| | | # - SPRING_CLOUD_CONSUL_HOST=host.docker.internal |
| | | # - SPRING_CLOUD_CONSUL_PORT=8500 |
| | | #### Static |
| | | # Add instances to "MyApp" |
| | | # - SPRING_CLOUD_DISCOVERY_CLIENT_SIMPLE_INSTANCES_MYAPP_0_URI=http://host.docker.internal:8081 |
| | | # - SPRING_CLOUD_DISCOVERY_CLIENT_SIMPLE_INSTANCES_MYAPP_1_URI=http://host.docker.internal:8082 |
| | | # Or add a new application named MyNewApp |
| | | # - SPRING_CLOUD_DISCOVERY_CLIENT_SIMPLE_INSTANCES_MYNEWAPP_0_URI=http://host.docker.internal:8080 |
| | | # This configuration is intended for development purpose, it's **your** responsibility to harden it for production |
| | | |
| | | #### IMPORTANT |
| | | # If you choose Consul or Eureka mode: |
| | | # Do not forget to remove the prefix "127.0.0.1" in front of their port in order to expose them. |
| | | # This is required because JHCC need to communicate with Consul or Eureka. |
| | | # - In Consul mode, the ports are in the consul.yml file. |
| | | # - In Eureka mode, the ports are in the jhipster-registry.yml file. |
| | | |
| | | version: '3.8' |
| | | services: |
| | | jhipster-control-center: |
| | | image: 'jhipster/jhipster-control-center:v0.5.0' |
| | | command: |
| | | - /bin/sh |
| | | - -c |
| | | # Patch /etc/hosts to support resolving host.docker.internal to the internal IP address used by the host in all OSes |
| | | - echo "`ip route | grep default | cut -d ' ' -f3` host.docker.internal" | tee -a /etc/hosts > /dev/null && java -jar /jhipster-control-center.jar |
| | | environment: |
| | | - _JAVA_OPTIONS=-Xmx512m -Xms256m |
| | | - SPRING_PROFILES_ACTIVE=prod,api-docs,no |
| | | - 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=MjI3YWRiMzg1ZTY3ZmZkZDgxZmI5Yjc5YjVkOTIzMzc4MmI2OWM3NWVkZjFiOTNmNjg0YWFjZWQ4YzhlOTUzYzk3MGUzMzM5Y2U5MDdkZTMyN2Q0N2E0M2ZmM2FhYzkyNDY4MjBkYTY5OGM4YmIzMmYxODJhNWFkMmVhNmVhNTM= |
| | | - SPRING_CLOUD_DISCOVERY_CLIENT_SIMPLE_INSTANCES_PAMAPI_0_URI=http://host.docker.internal:8080 |
| | | - LOGGING_FILE_NAME=/tmp/jhipster-control-center.log |
| | | # If you want to expose these ports outside your dev PC, |
| | | # remove the "127.0.0.1:" prefix |
| | | ports: |
| | | - 127.0.0.1:7419:7419 |
¤ñ¹ï·sÀÉ®× |
| | |
| | | #!/bin/sh |
| | | |
| | | echo "The application will start in ${JHIPSTER_SLEEP}s..." && sleep ${JHIPSTER_SLEEP} |
| | | exec java ${JAVA_OPTS} -noverify -XX:+AlwaysPreTouch -Djava.security.egd=file:/dev/./urandom -cp /app/resources/:/app/classes/:/app/libs/* "com.pollex.pam.PamapiApp" "$@" |
¤ñ¹ï·sÀÉ®× |
| | |
| | | # This configuration is intended for development purpose, it's **your** responsibility to harden it for production |
| | | version: '3.8' |
| | | services: |
| | | pamapi-prometheus: |
| | | image: prom/prometheus:v2.29.2 |
| | | volumes: |
| | | - ./prometheus/:/etc/prometheus/ |
| | | command: |
| | | - '--config.file=/etc/prometheus/prometheus.yml' |
| | | # If you want to expose these ports outside your dev PC, |
| | | # remove the "127.0.0.1:" prefix |
| | | ports: |
| | | - 127.0.0.1:9090:9090 |
| | | # 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 |
| | | pamapi-grafana: |
| | | image: grafana/grafana:8.1.3 |
| | | volumes: |
| | | - ./grafana/provisioning/:/etc/grafana/provisioning/ |
| | | environment: |
| | | - GF_SECURITY_ADMIN_PASSWORD=admin |
| | | - GF_USERS_ALLOW_SIGN_UP=false |
| | | - GF_INSTALL_PLUGINS=grafana-piechart-panel |
| | | # If you want to expose these ports outside your dev PC, |
| | | # remove the "127.0.0.1:" prefix |
| | | ports: |
| | | - 127.0.0.1:3000:3000 |
| | | # 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 |
¤ñ¹ï·sÀÉ®× |
| | |
| | | # This configuration is intended for development purpose, it's **your** responsibility to harden it for production |
| | | version: '3.8' |
| | | services: |
| | | pamapi-postgresql: |
| | | image: postgres:13.4 |
| | | # volumes: |
| | | # - ~/volumes/jhipster/pamapi/postgresql/:/var/lib/postgresql/data/ |
| | | environment: |
| | | - POSTGRES_USER=pamapi |
| | | - 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 |
¤ñ¹ï·sÀÉ®× |
| | |
| | | # Sample global config for monitoring JHipster applications |
| | | global: |
| | | scrape_interval: 15s # By default, scrape targets every 15 seconds. |
| | | evaluation_interval: 15s # By default, scrape targets every 15 seconds. |
| | | # scrape_timeout is set to the global default (10s). |
| | | |
| | | # Attach these labels to any time series or alerts when communicating with |
| | | # external systems (federation, remote storage, Alertmanager). |
| | | external_labels: |
| | | monitor: 'jhipster' |
| | | |
| | | # A scrape configuration containing exactly one endpoint to scrape: |
| | | # Here it's Prometheus itself. |
| | | scrape_configs: |
| | | # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config. |
| | | - job_name: 'prometheus' |
| | | |
| | | # Override the global default and scrape targets from this job every 5 seconds. |
| | | scrape_interval: 5s |
| | | |
| | | # scheme defaults to 'http' enable https in case your application is server via https |
| | | #scheme: https |
| | | # basic auth is not needed by default. See https://www.jhipster.tech/monitoring/#configuring-metrics-forwarding for details |
| | | #basic_auth: |
| | | # username: admin |
| | | # password: admin |
| | | metrics_path: /management/prometheus |
| | | static_configs: |
| | | - targets: |
| | | # On MacOS, replace localhost by host.docker.internal |
| | | - localhost:8080 |
¤ñ¹ï·sÀÉ®× |
| | |
| | | # This configuration is intended for development purpose, it's **your** responsibility to harden it for production |
| | | version: '3.8' |
| | | services: |
| | | pamapi-sonar: |
| | | image: sonarqube:8.9.2-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 |
| | | # 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 |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam; |
| | | |
| | | import org.springframework.boot.builder.SpringApplicationBuilder; |
| | | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; |
| | | import tech.jhipster.config.DefaultProfileUtil; |
| | | |
| | | /** |
| | | * This is a helper Java class that provides an alternative to creating a {@code web.xml}. |
| | | * This will be invoked only when the application is deployed to a Servlet container like Tomcat, JBoss etc. |
| | | */ |
| | | public class ApplicationWebXml extends SpringBootServletInitializer { |
| | | |
| | | @Override |
| | | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { |
| | | // set a default to use when no profile is configured. |
| | | DefaultProfileUtil.addDefaultProfile(application.application()); |
| | | return application.sources(PamapiApp.class); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam; |
| | | |
| | | 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.3.0") |
| | | @Retention(RetentionPolicy.SOURCE) |
| | | @Target({ ElementType.TYPE }) |
| | | public @interface GeneratedByJHipster { |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam; |
| | | |
| | | import com.pollex.pam.config.ApplicationProperties; |
| | | 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; |
| | | import org.springframework.boot.SpringApplication; |
| | | import org.springframework.boot.autoconfigure.SpringBootApplication; |
| | | import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties; |
| | | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| | | import org.springframework.core.env.Environment; |
| | | import tech.jhipster.config.DefaultProfileUtil; |
| | | import tech.jhipster.config.JHipsterConstants; |
| | | |
| | | @SpringBootApplication |
| | | @EnableConfigurationProperties({ LiquibaseProperties.class, ApplicationProperties.class }) |
| | | public class PamapiApp { |
| | | |
| | | private static final Logger log = LoggerFactory.getLogger(PamapiApp.class); |
| | | |
| | | private final Environment env; |
| | | |
| | | public PamapiApp(Environment env) { |
| | | this.env = env; |
| | | } |
| | | |
| | | /** |
| | | * Initializes pamapi. |
| | | * <p> |
| | | * Spring profiles can be configured with a program argument --spring.profiles.active=your-active-profile |
| | | * <p> |
| | | * You can find more information on how profiles work with JHipster on <a href="https://www.jhipster.tech/profiles/">https://www.jhipster.tech/profiles/</a>. |
| | | */ |
| | | @PostConstruct |
| | | public void initApplication() { |
| | | Collection<String> activeProfiles = Arrays.asList(env.getActiveProfiles()); |
| | | if ( |
| | | activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) && |
| | | activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_PRODUCTION) |
| | | ) { |
| | | log.error( |
| | | "You have misconfigured your application! It should not run " + "with both the 'dev' and 'prod' profiles at the same time." |
| | | ); |
| | | } |
| | | if ( |
| | | activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) && |
| | | activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_CLOUD) |
| | | ) { |
| | | log.error( |
| | | "You have misconfigured your application! It should not " + "run with both the 'dev' and 'cloud' profiles at the same time." |
| | | ); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Main method, used to run the application. |
| | | * |
| | | * @param args the command line arguments. |
| | | */ |
| | | public static void main(String[] args) { |
| | | SpringApplication app = new SpringApplication(PamapiApp.class); |
| | | DefaultProfileUtil.addDefaultProfile(app); |
| | | Environment env = app.run(args).getEnvironment(); |
| | | logApplicationStartup(env); |
| | | } |
| | | |
| | | private static void logApplicationStartup(Environment env) { |
| | | String protocol = Optional.ofNullable(env.getProperty("server.ssl.key-store")).map(key -> "https").orElse("http"); |
| | | String serverPort = env.getProperty("server.port"); |
| | | String contextPath = Optional |
| | | .ofNullable(env.getProperty("server.servlet.context-path")) |
| | | .filter(StringUtils::isNotBlank) |
| | | .orElse("/"); |
| | | String hostAddress = "localhost"; |
| | | try { |
| | | hostAddress = InetAddress.getLocalHost().getHostAddress(); |
| | | } catch (UnknownHostException e) { |
| | | log.warn("The host name could not be determined, using `localhost` as fallback"); |
| | | } |
| | | log.info( |
| | | "\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, |
| | | contextPath, |
| | | protocol, |
| | | hostAddress, |
| | | serverPort, |
| | | contextPath, |
| | | env.getActiveProfiles().length == 0 ? env.getDefaultProfiles() : env.getActiveProfiles() |
| | | ); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.aop.logging; |
| | | |
| | | import java.util.Arrays; |
| | | import org.aspectj.lang.JoinPoint; |
| | | import org.aspectj.lang.ProceedingJoinPoint; |
| | | import org.aspectj.lang.annotation.AfterThrowing; |
| | | import org.aspectj.lang.annotation.Around; |
| | | import org.aspectj.lang.annotation.Aspect; |
| | | import org.aspectj.lang.annotation.Pointcut; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.core.env.Environment; |
| | | import org.springframework.core.env.Profiles; |
| | | import tech.jhipster.config.JHipsterConstants; |
| | | |
| | | /** |
| | | * Aspect for logging execution of service and repository Spring components. |
| | | * |
| | | * By default, it only runs with the "dev" profile. |
| | | */ |
| | | @Aspect |
| | | public class LoggingAspect { |
| | | |
| | | private final Environment env; |
| | | |
| | | public LoggingAspect(Environment env) { |
| | | this.env = env; |
| | | } |
| | | |
| | | /** |
| | | * Pointcut that matches all repositories, services and Web REST endpoints. |
| | | */ |
| | | @Pointcut( |
| | | "within(@org.springframework.stereotype.Repository *)" + |
| | | " || within(@org.springframework.stereotype.Service *)" + |
| | | " || within(@org.springframework.web.bind.annotation.RestController *)" |
| | | ) |
| | | public void springBeanPointcut() { |
| | | // Method is empty as this is just a Pointcut, the implementations are in the advices. |
| | | } |
| | | |
| | | /** |
| | | * Pointcut that matches all Spring beans in the application's main packages. |
| | | */ |
| | | @Pointcut("within(com.pollex.pam.repository..*)" + " || within(com.pollex.pam.service..*)" + " || within(com.pollex.pam.web.rest..*)") |
| | | public void applicationPackagePointcut() { |
| | | // Method is empty as this is just a Pointcut, the implementations are in the advices. |
| | | } |
| | | |
| | | /** |
| | | * Retrieves the {@link Logger} associated to the given {@link JoinPoint}. |
| | | * |
| | | * @param joinPoint join point we want the logger for. |
| | | * @return {@link Logger} associated to the given {@link JoinPoint}. |
| | | */ |
| | | private Logger logger(JoinPoint joinPoint) { |
| | | return LoggerFactory.getLogger(joinPoint.getSignature().getDeclaringTypeName()); |
| | | } |
| | | |
| | | /** |
| | | * Advice that logs methods throwing exceptions. |
| | | * |
| | | * @param joinPoint join point for advice. |
| | | * @param e exception. |
| | | */ |
| | | @AfterThrowing(pointcut = "applicationPackagePointcut() && springBeanPointcut()", throwing = "e") |
| | | public void logAfterThrowing(JoinPoint joinPoint, Throwable e) { |
| | | if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT))) { |
| | | logger(joinPoint) |
| | | .error( |
| | | "Exception in {}() with cause = '{}' and exception = '{}'", |
| | | joinPoint.getSignature().getName(), |
| | | e.getCause() != null ? e.getCause() : "NULL", |
| | | e.getMessage(), |
| | | e |
| | | ); |
| | | } else { |
| | | logger(joinPoint) |
| | | .error( |
| | | "Exception in {}() with cause = {}", |
| | | joinPoint.getSignature().getName(), |
| | | e.getCause() != null ? e.getCause() : "NULL" |
| | | ); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Advice that logs when a method is entered and exited. |
| | | * |
| | | * @param joinPoint join point for advice. |
| | | * @return result. |
| | | * @throws Throwable throws {@link IllegalArgumentException}. |
| | | */ |
| | | @Around("applicationPackagePointcut() && springBeanPointcut()") |
| | | public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { |
| | | Logger log = logger(joinPoint); |
| | | if (log.isDebugEnabled()) { |
| | | log.debug("Enter: {}() with argument[s] = {}", joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs())); |
| | | } |
| | | try { |
| | | Object result = joinPoint.proceed(); |
| | | if (log.isDebugEnabled()) { |
| | | log.debug("Exit: {}() with result = {}", joinPoint.getSignature().getName(), result); |
| | | } |
| | | return result; |
| | | } catch (IllegalArgumentException e) { |
| | | log.error("Illegal argument: {} in {}()", Arrays.toString(joinPoint.getArgs()), joinPoint.getSignature().getName()); |
| | | throw e; |
| | | } |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.config; |
| | | |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | |
| | | /** |
| | | * Properties specific to Pamapi. |
| | | * <p> |
| | | * Properties are configured in the {@code application.yml} file. |
| | | * See {@link tech.jhipster.config.JHipsterProperties} for a good example. |
| | | */ |
| | | @ConfigurationProperties(prefix = "application", ignoreUnknownFields = false) |
| | | public class ApplicationProperties {} |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.config; |
| | | |
| | | import java.util.concurrent.Executor; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; |
| | | import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler; |
| | | import org.springframework.boot.autoconfigure.task.TaskExecutionProperties; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.scheduling.annotation.AsyncConfigurer; |
| | | import org.springframework.scheduling.annotation.EnableAsync; |
| | | import org.springframework.scheduling.annotation.EnableScheduling; |
| | | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; |
| | | import tech.jhipster.async.ExceptionHandlingAsyncTaskExecutor; |
| | | |
| | | @Configuration |
| | | @EnableAsync |
| | | @EnableScheduling |
| | | public class AsyncConfiguration implements AsyncConfigurer { |
| | | |
| | | private final Logger log = LoggerFactory.getLogger(AsyncConfiguration.class); |
| | | |
| | | private final TaskExecutionProperties taskExecutionProperties; |
| | | |
| | | public AsyncConfiguration(TaskExecutionProperties taskExecutionProperties) { |
| | | this.taskExecutionProperties = taskExecutionProperties; |
| | | } |
| | | |
| | | @Override |
| | | @Bean(name = "taskExecutor") |
| | | public Executor getAsyncExecutor() { |
| | | log.debug("Creating Async Task Executor"); |
| | | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); |
| | | executor.setCorePoolSize(taskExecutionProperties.getPool().getCoreSize()); |
| | | executor.setMaxPoolSize(taskExecutionProperties.getPool().getMaxSize()); |
| | | executor.setQueueCapacity(taskExecutionProperties.getPool().getQueueCapacity()); |
| | | executor.setThreadNamePrefix(taskExecutionProperties.getThreadNamePrefix()); |
| | | return new ExceptionHandlingAsyncTaskExecutor(executor); |
| | | } |
| | | |
| | | @Override |
| | | public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { |
| | | return new SimpleAsyncUncaughtExceptionHandler(); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.config; |
| | | |
| | | import java.time.Duration; |
| | | import org.ehcache.config.builders.*; |
| | | import org.ehcache.jsr107.Eh107Configuration; |
| | | import org.hibernate.cache.jcache.ConfigSettings; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer; |
| | | import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer; |
| | | import org.springframework.boot.info.BuildProperties; |
| | | import org.springframework.boot.info.GitProperties; |
| | | import org.springframework.cache.annotation.EnableCaching; |
| | | import org.springframework.cache.interceptor.KeyGenerator; |
| | | import org.springframework.context.annotation.*; |
| | | import tech.jhipster.config.JHipsterProperties; |
| | | import tech.jhipster.config.cache.PrefixedKeyGenerator; |
| | | |
| | | @Configuration |
| | | @EnableCaching |
| | | public class CacheConfiguration { |
| | | |
| | | private GitProperties gitProperties; |
| | | private BuildProperties buildProperties; |
| | | private final javax.cache.configuration.Configuration<Object, Object> jcacheConfiguration; |
| | | |
| | | public CacheConfiguration(JHipsterProperties jHipsterProperties) { |
| | | JHipsterProperties.Cache.Ehcache ehcache = jHipsterProperties.getCache().getEhcache(); |
| | | |
| | | jcacheConfiguration = |
| | | Eh107Configuration.fromEhcacheCacheConfiguration( |
| | | CacheConfigurationBuilder |
| | | .newCacheConfigurationBuilder(Object.class, Object.class, ResourcePoolsBuilder.heap(ehcache.getMaxEntries())) |
| | | .withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(ehcache.getTimeToLiveSeconds()))) |
| | | .build() |
| | | ); |
| | | } |
| | | |
| | | @Bean |
| | | public HibernatePropertiesCustomizer hibernatePropertiesCustomizer(javax.cache.CacheManager cacheManager) { |
| | | return hibernateProperties -> hibernateProperties.put(ConfigSettings.CACHE_MANAGER, cacheManager); |
| | | } |
| | | |
| | | @Bean |
| | | public JCacheManagerCustomizer cacheManagerCustomizer() { |
| | | return cm -> { |
| | | createCache(cm, com.pollex.pam.repository.UserRepository.USERS_BY_LOGIN_CACHE); |
| | | createCache(cm, com.pollex.pam.repository.UserRepository.USERS_BY_EMAIL_CACHE); |
| | | createCache(cm, com.pollex.pam.domain.User.class.getName()); |
| | | createCache(cm, com.pollex.pam.domain.Authority.class.getName()); |
| | | createCache(cm, com.pollex.pam.domain.User.class.getName() + ".authorities"); |
| | | // jhipster-needle-ehcache-add-entry |
| | | }; |
| | | } |
| | | |
| | | private void createCache(javax.cache.CacheManager cm, String cacheName) { |
| | | javax.cache.Cache<Object, Object> cache = cm.getCache(cacheName); |
| | | if (cache != null) { |
| | | cache.clear(); |
| | | } else { |
| | | cm.createCache(cacheName, jcacheConfiguration); |
| | | } |
| | | } |
| | | |
| | | @Autowired(required = false) |
| | | public void setGitProperties(GitProperties gitProperties) { |
| | | this.gitProperties = gitProperties; |
| | | } |
| | | |
| | | @Autowired(required = false) |
| | | public void setBuildProperties(BuildProperties buildProperties) { |
| | | this.buildProperties = buildProperties; |
| | | } |
| | | |
| | | @Bean |
| | | public KeyGenerator keyGenerator() { |
| | | return new PrefixedKeyGenerator(this.gitProperties, this.buildProperties); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.config; |
| | | |
| | | /** |
| | | * Application constants. |
| | | */ |
| | | public final class Constants { |
| | | |
| | | // Regex for acceptable logins |
| | | public static final String LOGIN_REGEX = "^(?>[a-zA-Z0-9!$&*+=?^_`{|}~.-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*)|(?>[_.@A-Za-z0-9-]+)$"; |
| | | |
| | | public static final String SYSTEM = "system"; |
| | | public static final String DEFAULT_LANGUAGE = "zh-tw"; |
| | | |
| | | private Constants() {} |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.config; |
| | | |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.data.jpa.repository.config.EnableJpaAuditing; |
| | | import org.springframework.data.jpa.repository.config.EnableJpaRepositories; |
| | | import org.springframework.transaction.annotation.EnableTransactionManagement; |
| | | import tech.jhipster.config.JHipsterConstants; |
| | | |
| | | @Configuration |
| | | @EnableJpaRepositories({ "com.pollex.pam.repository" }) |
| | | @EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware") |
| | | @EnableTransactionManagement |
| | | public class DatabaseConfiguration {} |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.config; |
| | | |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.format.FormatterRegistry; |
| | | import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar; |
| | | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; |
| | | |
| | | /** |
| | | * Configure the converters to use the ISO format for dates by default. |
| | | */ |
| | | @Configuration |
| | | public class DateTimeFormatConfiguration implements WebMvcConfigurer { |
| | | |
| | | @Override |
| | | public void addFormatters(FormatterRegistry registry) { |
| | | DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar(); |
| | | registrar.setUseIsoFormat(true); |
| | | registrar.registerFormatters(registry); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.config; |
| | | |
| | | 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 { |
| | | |
| | | /** |
| | | * Support for Java date and time API. |
| | | * @return the corresponding Jackson module. |
| | | */ |
| | | @Bean |
| | | public JavaTimeModule javaTimeModule() { |
| | | return new JavaTimeModule(); |
| | | } |
| | | |
| | | @Bean |
| | | public Jdk8Module jdk8TimeModule() { |
| | | return new Jdk8Module(); |
| | | } |
| | | |
| | | /* |
| | | * Support for Hibernate types in Jackson. |
| | | */ |
| | | @Bean |
| | | 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(); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.config; |
| | | |
| | | import java.util.concurrent.Executor; |
| | | import javax.sql.DataSource; |
| | | import liquibase.integration.spring.SpringLiquibase; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.ObjectProvider; |
| | | import org.springframework.beans.factory.annotation.Qualifier; |
| | | import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; |
| | | import org.springframework.boot.autoconfigure.liquibase.LiquibaseDataSource; |
| | | import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.core.env.Environment; |
| | | import org.springframework.core.env.Profiles; |
| | | import tech.jhipster.config.JHipsterConstants; |
| | | import tech.jhipster.config.liquibase.SpringLiquibaseUtil; |
| | | |
| | | @Configuration |
| | | public class LiquibaseConfiguration { |
| | | |
| | | private final Logger log = LoggerFactory.getLogger(LiquibaseConfiguration.class); |
| | | |
| | | private final Environment env; |
| | | |
| | | public LiquibaseConfiguration(Environment env) { |
| | | this.env = env; |
| | | } |
| | | |
| | | @Bean |
| | | public SpringLiquibase liquibase( |
| | | @Qualifier("taskExecutor") Executor executor, |
| | | @LiquibaseDataSource ObjectProvider<DataSource> liquibaseDataSource, |
| | | LiquibaseProperties liquibaseProperties, |
| | | ObjectProvider<DataSource> dataSource, |
| | | DataSourceProperties dataSourceProperties |
| | | ) { |
| | | // If you don't want Liquibase to start asynchronously, substitute by this: |
| | | // SpringLiquibase liquibase = SpringLiquibaseUtil.createSpringLiquibase(liquibaseDataSource.getIfAvailable(), liquibaseProperties, dataSource.getIfUnique(), dataSourceProperties); |
| | | SpringLiquibase liquibase = SpringLiquibaseUtil.createAsyncSpringLiquibase( |
| | | this.env, |
| | | executor, |
| | | liquibaseDataSource.getIfAvailable(), |
| | | liquibaseProperties, |
| | | dataSource.getIfUnique(), |
| | | dataSourceProperties |
| | | ); |
| | | liquibase.setChangeLog("classpath:config/liquibase/master.xml"); |
| | | liquibase.setContexts(liquibaseProperties.getContexts()); |
| | | liquibase.setDefaultSchema(liquibaseProperties.getDefaultSchema()); |
| | | liquibase.setLiquibaseSchema(liquibaseProperties.getLiquibaseSchema()); |
| | | liquibase.setLiquibaseTablespace(liquibaseProperties.getLiquibaseTablespace()); |
| | | liquibase.setDatabaseChangeLogLockTable(liquibaseProperties.getDatabaseChangeLogLockTable()); |
| | | liquibase.setDatabaseChangeLogTable(liquibaseProperties.getDatabaseChangeLogTable()); |
| | | liquibase.setDropFirst(liquibaseProperties.isDropFirst()); |
| | | liquibase.setLabels(liquibaseProperties.getLabels()); |
| | | liquibase.setChangeLogParameters(liquibaseProperties.getParameters()); |
| | | liquibase.setRollbackFile(liquibaseProperties.getRollbackFile()); |
| | | liquibase.setTestRollbackOnUpdate(liquibaseProperties.isTestRollbackOnUpdate()); |
| | | if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_NO_LIQUIBASE))) { |
| | | liquibase.setShouldRun(false); |
| | | } else { |
| | | liquibase.setShouldRun(liquibaseProperties.isEnabled()); |
| | | log.debug("Configuring Liquibase"); |
| | | } |
| | | return liquibase; |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.config; |
| | | |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.web.servlet.LocaleResolver; |
| | | import org.springframework.web.servlet.config.annotation.*; |
| | | import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; |
| | | import tech.jhipster.config.locale.AngularCookieLocaleResolver; |
| | | |
| | | @Configuration |
| | | public class LocaleConfiguration implements WebMvcConfigurer { |
| | | |
| | | @Bean |
| | | public LocaleResolver localeResolver() { |
| | | AngularCookieLocaleResolver cookieLocaleResolver = new AngularCookieLocaleResolver(); |
| | | cookieLocaleResolver.setCookieName("NG_TRANSLATE_LANG_KEY"); |
| | | return cookieLocaleResolver; |
| | | } |
| | | |
| | | @Override |
| | | public void addInterceptors(InterceptorRegistry registry) { |
| | | LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor(); |
| | | localeChangeInterceptor.setParamName("language"); |
| | | registry.addInterceptor(localeChangeInterceptor); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.config; |
| | | |
| | | import com.pollex.pam.aop.logging.LoggingAspect; |
| | | import org.springframework.context.annotation.*; |
| | | import org.springframework.core.env.Environment; |
| | | import tech.jhipster.config.JHipsterConstants; |
| | | |
| | | @Configuration |
| | | @EnableAspectJAutoProxy |
| | | public class LoggingAspectConfiguration { |
| | | |
| | | @Bean |
| | | @Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) |
| | | public LoggingAspect loggingAspect(Environment env) { |
| | | return new LoggingAspect(env); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.config; |
| | | |
| | | import static tech.jhipster.config.logging.LoggingUtils.*; |
| | | |
| | | import ch.qos.logback.classic.LoggerContext; |
| | | import com.fasterxml.jackson.core.JsonProcessingException; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import tech.jhipster.config.JHipsterProperties; |
| | | |
| | | /* |
| | | * Configures the console and Logstash log appenders from the app properties |
| | | */ |
| | | @Configuration |
| | | public class LoggingConfiguration { |
| | | |
| | | public LoggingConfiguration( |
| | | @Value("${spring.application.name}") String appName, |
| | | @Value("${server.port}") String serverPort, |
| | | JHipsterProperties jHipsterProperties, |
| | | ObjectMapper mapper |
| | | ) throws JsonProcessingException { |
| | | LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); |
| | | |
| | | Map<String, String> map = new HashMap<>(); |
| | | map.put("app_name", appName); |
| | | map.put("app_port", serverPort); |
| | | String customFields = mapper.writeValueAsString(map); |
| | | |
| | | JHipsterProperties.Logging loggingProperties = jHipsterProperties.getLogging(); |
| | | JHipsterProperties.Logging.Logstash logstashProperties = loggingProperties.getLogstash(); |
| | | |
| | | if (loggingProperties.isUseJsonFormat()) { |
| | | addJsonConsoleAppender(context, customFields); |
| | | } |
| | | if (logstashProperties.isEnabled()) { |
| | | addLogstashTcpSocketAppender(context, customFields, logstashProperties); |
| | | } |
| | | if (loggingProperties.isUseJsonFormat() || logstashProperties.isEnabled()) { |
| | | addContextListener(context, customFields, loggingProperties); |
| | | } |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.config; |
| | | |
| | | import com.pollex.pam.security.*; |
| | | import com.pollex.pam.security.jwt.*; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Import; |
| | | import org.springframework.http.HttpMethod; |
| | | 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.builders.WebSecurity; |
| | | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; |
| | | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; |
| | | 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.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; |
| | | |
| | | @EnableWebSecurity |
| | | @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) |
| | | @Import(SecurityProblemSupport.class) |
| | | public class SecurityConfiguration extends WebSecurityConfigurerAdapter { |
| | | |
| | | private final 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; |
| | | } |
| | | |
| | | @Bean |
| | | public PasswordEncoder passwordEncoder() { |
| | | return new BCryptPasswordEncoder(); |
| | | } |
| | | |
| | | @Override |
| | | public void configure(WebSecurity web) { |
| | | web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**").antMatchers("/swagger-ui/**").antMatchers("/test/**"); |
| | | } |
| | | |
| | | @Override |
| | | public void configure(HttpSecurity http) throws Exception { |
| | | // @formatter:off |
| | | http |
| | | .csrf() |
| | | .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() |
| | | .deny() |
| | | .and() |
| | | .sessionManagement() |
| | | .sessionCreationPolicy(SessionCreationPolicy.STATELESS) |
| | | .and() |
| | | .authorizeRequests() |
| | | .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("/websocket/**").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()); |
| | | // @formatter:on |
| | | } |
| | | |
| | | private JWTConfigurer securityConfigurerAdapter() { |
| | | return new JWTConfigurer(tokenProvider); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.config; |
| | | |
| | | import javax.servlet.*; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.boot.web.server.*; |
| | | import org.springframework.boot.web.servlet.ServletContextInitializer; |
| | | import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.core.env.Environment; |
| | | import org.springframework.core.env.Profiles; |
| | | import org.springframework.util.CollectionUtils; |
| | | import org.springframework.web.cors.CorsConfiguration; |
| | | import org.springframework.web.cors.UrlBasedCorsConfigurationSource; |
| | | import org.springframework.web.filter.CorsFilter; |
| | | import tech.jhipster.config.JHipsterProperties; |
| | | |
| | | /** |
| | | * Configuration of web application with Servlet 3.0 APIs. |
| | | */ |
| | | @Configuration |
| | | public class WebConfigurer implements ServletContextInitializer { |
| | | |
| | | private final Logger log = LoggerFactory.getLogger(WebConfigurer.class); |
| | | |
| | | private final Environment env; |
| | | |
| | | private final JHipsterProperties jHipsterProperties; |
| | | |
| | | public WebConfigurer(Environment env, JHipsterProperties jHipsterProperties) { |
| | | this.env = env; |
| | | this.jHipsterProperties = jHipsterProperties; |
| | | } |
| | | |
| | | @Override |
| | | public void onStartup(ServletContext servletContext) throws ServletException { |
| | | if (env.getActiveProfiles().length != 0) { |
| | | log.info("Web application configuration, using profiles: {}", (Object[]) env.getActiveProfiles()); |
| | | } |
| | | |
| | | log.info("Web application fully configured"); |
| | | } |
| | | |
| | | @Bean |
| | | public CorsFilter corsFilter() { |
| | | UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); |
| | | CorsConfiguration config = jHipsterProperties.getCors(); |
| | | if (!CollectionUtils.isEmpty(config.getAllowedOrigins()) || !CollectionUtils.isEmpty(config.getAllowedOriginPatterns())) { |
| | | log.debug("Registering CORS filter"); |
| | | source.registerCorsConfiguration("/api/**", config); |
| | | source.registerCorsConfiguration("/management/**", config); |
| | | source.registerCorsConfiguration("/v2/api-docs", config); |
| | | source.registerCorsConfiguration("/v3/api-docs", config); |
| | | source.registerCorsConfiguration("/swagger-resources", config); |
| | | source.registerCorsConfiguration("/swagger-ui/**", config); |
| | | } |
| | | return new CorsFilter(source); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.config; |
| | | |
| | | import com.pollex.pam.security.AuthoritiesConstants; |
| | | import java.security.Principal; |
| | | import java.util.*; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.http.server.*; |
| | | import org.springframework.messaging.simp.config.MessageBrokerRegistry; |
| | | import org.springframework.security.authentication.AnonymousAuthenticationToken; |
| | | import org.springframework.security.core.authority.SimpleGrantedAuthority; |
| | | import org.springframework.web.socket.WebSocketHandler; |
| | | import org.springframework.web.socket.config.annotation.*; |
| | | import org.springframework.web.socket.server.HandshakeInterceptor; |
| | | import org.springframework.web.socket.server.support.DefaultHandshakeHandler; |
| | | import tech.jhipster.config.JHipsterProperties; |
| | | |
| | | @Configuration |
| | | @EnableWebSocketMessageBroker |
| | | public class WebsocketConfiguration implements WebSocketMessageBrokerConfigurer { |
| | | |
| | | public static final String IP_ADDRESS = "IP_ADDRESS"; |
| | | |
| | | private final JHipsterProperties jHipsterProperties; |
| | | |
| | | public WebsocketConfiguration(JHipsterProperties jHipsterProperties) { |
| | | this.jHipsterProperties = jHipsterProperties; |
| | | } |
| | | |
| | | @Override |
| | | public void configureMessageBroker(MessageBrokerRegistry config) { |
| | | config.enableSimpleBroker("/topic"); |
| | | } |
| | | |
| | | @Override |
| | | public void registerStompEndpoints(StompEndpointRegistry registry) { |
| | | String[] allowedOrigins = Optional |
| | | .ofNullable(jHipsterProperties.getCors().getAllowedOrigins()) |
| | | .map(origins -> origins.toArray(new String[0])) |
| | | .orElse(new String[0]); |
| | | registry |
| | | .addEndpoint("/websocket/tracker") |
| | | .setHandshakeHandler(defaultHandshakeHandler()) |
| | | .setAllowedOrigins(allowedOrigins) |
| | | .withSockJS() |
| | | .setInterceptors(httpSessionHandshakeInterceptor()); |
| | | } |
| | | |
| | | @Bean |
| | | public HandshakeInterceptor httpSessionHandshakeInterceptor() { |
| | | return new HandshakeInterceptor() { |
| | | @Override |
| | | public boolean beforeHandshake( |
| | | ServerHttpRequest request, |
| | | ServerHttpResponse response, |
| | | WebSocketHandler wsHandler, |
| | | Map<String, Object> attributes |
| | | ) throws Exception { |
| | | if (request instanceof ServletServerHttpRequest) { |
| | | ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request; |
| | | attributes.put(IP_ADDRESS, servletRequest.getRemoteAddress()); |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public void afterHandshake( |
| | | ServerHttpRequest request, |
| | | ServerHttpResponse response, |
| | | WebSocketHandler wsHandler, |
| | | Exception exception |
| | | ) {} |
| | | }; |
| | | } |
| | | |
| | | private DefaultHandshakeHandler defaultHandshakeHandler() { |
| | | return new DefaultHandshakeHandler() { |
| | | @Override |
| | | protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) { |
| | | Principal principal = request.getPrincipal(); |
| | | if (principal == null) { |
| | | Collection<SimpleGrantedAuthority> authorities = new ArrayList<>(); |
| | | authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.ANONYMOUS)); |
| | | principal = new AnonymousAuthenticationToken("WebsocketConfiguration", "anonymous", authorities); |
| | | } |
| | | return principal; |
| | | } |
| | | }; |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.config; |
| | | |
| | | import com.pollex.pam.security.AuthoritiesConstants; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.messaging.simp.SimpMessageType; |
| | | import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry; |
| | | import org.springframework.security.config.annotation.web.socket.AbstractSecurityWebSocketMessageBrokerConfigurer; |
| | | |
| | | @Configuration |
| | | public class WebsocketSecurityConfiguration extends AbstractSecurityWebSocketMessageBrokerConfigurer { |
| | | |
| | | @Override |
| | | protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { |
| | | messages |
| | | .nullDestMatcher() |
| | | .authenticated() |
| | | .simpDestMatchers("/topic/tracker") |
| | | .hasAuthority(AuthoritiesConstants.ADMIN) |
| | | // matches any destination that starts with /topic/ |
| | | // (i.e. cannot send messages directly to /topic/) |
| | | // (i.e. cannot subscribe to /topic/messages/* to get messages sent to |
| | | // /topic/messages-user<id>) |
| | | .simpDestMatchers("/topic/**") |
| | | .authenticated() |
| | | // message types other than MESSAGE and SUBSCRIBE |
| | | .simpTypeMatchers(SimpMessageType.MESSAGE, SimpMessageType.SUBSCRIBE) |
| | | .denyAll() |
| | | // catch all |
| | | .anyMessage() |
| | | .denyAll(); |
| | | } |
| | | |
| | | /** |
| | | * Disables CSRF for Websockets. |
| | | */ |
| | | @Override |
| | | protected boolean sameOriginDisabled() { |
| | | return true; |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | /** |
| | | * Spring Framework configuration files. |
| | | */ |
| | | package com.pollex.pam.config; |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.domain; |
| | | |
| | | import com.fasterxml.jackson.annotation.JsonIgnore; |
| | | 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; |
| | | import org.springframework.data.annotation.LastModifiedDate; |
| | | import org.springframework.data.jpa.domain.support.AuditingEntityListener; |
| | | |
| | | /** |
| | | * Base abstract class for entities which will hold definitions for created, last modified, created by, |
| | | * last modified by attributes. |
| | | */ |
| | | @MappedSuperclass |
| | | @EntityListeners(AuditingEntityListener.class) |
| | | public abstract class AbstractAuditingEntity implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @CreatedBy |
| | | @Column(name = "created_by", nullable = false, length = 50, updatable = false) |
| | | @JsonIgnore |
| | | private String createdBy; |
| | | |
| | | @CreatedDate |
| | | @Column(name = "created_date", updatable = false) |
| | | @JsonIgnore |
| | | private Instant createdDate = Instant.now(); |
| | | |
| | | @LastModifiedBy |
| | | @Column(name = "last_modified_by", length = 50) |
| | | @JsonIgnore |
| | | private String lastModifiedBy; |
| | | |
| | | @LastModifiedDate |
| | | @Column(name = "last_modified_date") |
| | | @JsonIgnore |
| | | private Instant lastModifiedDate = Instant.now(); |
| | | |
| | | public String getCreatedBy() { |
| | | return createdBy; |
| | | } |
| | | |
| | | public void setCreatedBy(String createdBy) { |
| | | this.createdBy = createdBy; |
| | | } |
| | | |
| | | public Instant getCreatedDate() { |
| | | return createdDate; |
| | | } |
| | | |
| | | public void setCreatedDate(Instant createdDate) { |
| | | this.createdDate = createdDate; |
| | | } |
| | | |
| | | public String getLastModifiedBy() { |
| | | return lastModifiedBy; |
| | | } |
| | | |
| | | public void setLastModifiedBy(String lastModifiedBy) { |
| | | this.lastModifiedBy = lastModifiedBy; |
| | | } |
| | | |
| | | public Instant getLastModifiedDate() { |
| | | return lastModifiedDate; |
| | | } |
| | | |
| | | public void setLastModifiedDate(Instant lastModifiedDate) { |
| | | this.lastModifiedDate = lastModifiedDate; |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.domain; |
| | | |
| | | 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; |
| | | |
| | | /** |
| | | * An authority (a security role) used by Spring Security. |
| | | */ |
| | | @Entity |
| | | @Table(name = "jhi_authority") |
| | | @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) |
| | | public class Authority implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @NotNull |
| | | @Size(max = 50) |
| | | @Id |
| | | @Column(length = 50) |
| | | private String name; |
| | | |
| | | public String getName() { |
| | | return name; |
| | | } |
| | | |
| | | public void setName(String name) { |
| | | this.name = name; |
| | | } |
| | | |
| | | @Override |
| | | public boolean equals(Object o) { |
| | | if (this == o) { |
| | | return true; |
| | | } |
| | | if (!(o instanceof Authority)) { |
| | | return false; |
| | | } |
| | | return Objects.equals(name, ((Authority) o).name); |
| | | } |
| | | |
| | | @Override |
| | | public int hashCode() { |
| | | return Objects.hashCode(name); |
| | | } |
| | | |
| | | // prettier-ignore |
| | | @Override |
| | | public String toString() { |
| | | return "Authority{" + |
| | | "name='" + name + '\'' + |
| | | "}"; |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.domain; |
| | | |
| | | import com.fasterxml.jackson.annotation.JsonIgnore; |
| | | import com.pollex.pam.config.Constants; |
| | | 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; |
| | | import org.hibernate.annotations.CacheConcurrencyStrategy; |
| | | |
| | | /** |
| | | * A user. |
| | | */ |
| | | @Entity |
| | | @Table(name = "jhi_user") |
| | | @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) |
| | | public class User extends AbstractAuditingEntity implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @Id |
| | | @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") |
| | | @SequenceGenerator(name = "sequenceGenerator") |
| | | private Long id; |
| | | |
| | | @NotNull |
| | | @Pattern(regexp = Constants.LOGIN_REGEX) |
| | | @Size(min = 1, max = 50) |
| | | @Column(length = 50, unique = true, nullable = false) |
| | | private String login; |
| | | |
| | | @JsonIgnore |
| | | @NotNull |
| | | @Size(min = 60, max = 60) |
| | | @Column(name = "password_hash", length = 60, nullable = false) |
| | | private String password; |
| | | |
| | | @Size(max = 50) |
| | | @Column(name = "first_name", length = 50) |
| | | private String firstName; |
| | | |
| | | @Size(max = 50) |
| | | @Column(name = "last_name", length = 50) |
| | | private String lastName; |
| | | |
| | | @Email |
| | | @Size(min = 5, max = 254) |
| | | @Column(length = 254, unique = true) |
| | | private String email; |
| | | |
| | | @NotNull |
| | | @Column(nullable = false) |
| | | private boolean activated = false; |
| | | |
| | | @Size(min = 2, max = 10) |
| | | @Column(name = "lang_key", length = 10) |
| | | private String langKey; |
| | | |
| | | @Size(max = 256) |
| | | @Column(name = "image_url", length = 256) |
| | | private String imageUrl; |
| | | |
| | | @Size(max = 20) |
| | | @Column(name = "activation_key", length = 20) |
| | | @JsonIgnore |
| | | private String activationKey; |
| | | |
| | | @Size(max = 20) |
| | | @Column(name = "reset_key", length = 20) |
| | | @JsonIgnore |
| | | private String resetKey; |
| | | |
| | | @Column(name = "reset_date") |
| | | private Instant resetDate = null; |
| | | |
| | | @JsonIgnore |
| | | @ManyToMany |
| | | @JoinTable( |
| | | name = "jhi_user_authority", |
| | | joinColumns = { @JoinColumn(name = "user_id", referencedColumnName = "id") }, |
| | | inverseJoinColumns = { @JoinColumn(name = "authority_name", referencedColumnName = "name") } |
| | | ) |
| | | @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) |
| | | @BatchSize(size = 20) |
| | | private Set<Authority> authorities = new HashSet<>(); |
| | | |
| | | public Long getId() { |
| | | return id; |
| | | } |
| | | |
| | | public void setId(Long id) { |
| | | this.id = id; |
| | | } |
| | | |
| | | public String getLogin() { |
| | | return login; |
| | | } |
| | | |
| | | // Lowercase the login before saving it in database |
| | | public void setLogin(String login) { |
| | | this.login = StringUtils.lowerCase(login, Locale.ENGLISH); |
| | | } |
| | | |
| | | public String getPassword() { |
| | | return password; |
| | | } |
| | | |
| | | public void setPassword(String password) { |
| | | this.password = password; |
| | | } |
| | | |
| | | public String getFirstName() { |
| | | return firstName; |
| | | } |
| | | |
| | | public void setFirstName(String firstName) { |
| | | this.firstName = firstName; |
| | | } |
| | | |
| | | public String getLastName() { |
| | | return lastName; |
| | | } |
| | | |
| | | public void setLastName(String lastName) { |
| | | this.lastName = lastName; |
| | | } |
| | | |
| | | public String getEmail() { |
| | | return email; |
| | | } |
| | | |
| | | public void setEmail(String email) { |
| | | this.email = email; |
| | | } |
| | | |
| | | public String getImageUrl() { |
| | | return imageUrl; |
| | | } |
| | | |
| | | public void setImageUrl(String imageUrl) { |
| | | this.imageUrl = imageUrl; |
| | | } |
| | | |
| | | public boolean isActivated() { |
| | | return activated; |
| | | } |
| | | |
| | | public void setActivated(boolean activated) { |
| | | this.activated = activated; |
| | | } |
| | | |
| | | public String getActivationKey() { |
| | | return activationKey; |
| | | } |
| | | |
| | | public void setActivationKey(String activationKey) { |
| | | this.activationKey = activationKey; |
| | | } |
| | | |
| | | public String getResetKey() { |
| | | return resetKey; |
| | | } |
| | | |
| | | public void setResetKey(String resetKey) { |
| | | this.resetKey = resetKey; |
| | | } |
| | | |
| | | public Instant getResetDate() { |
| | | return resetDate; |
| | | } |
| | | |
| | | public void setResetDate(Instant resetDate) { |
| | | this.resetDate = resetDate; |
| | | } |
| | | |
| | | public String getLangKey() { |
| | | return langKey; |
| | | } |
| | | |
| | | public void setLangKey(String langKey) { |
| | | this.langKey = langKey; |
| | | } |
| | | |
| | | public Set<Authority> getAuthorities() { |
| | | return authorities; |
| | | } |
| | | |
| | | public void setAuthorities(Set<Authority> authorities) { |
| | | this.authorities = authorities; |
| | | } |
| | | |
| | | @Override |
| | | public boolean equals(Object o) { |
| | | if (this == o) { |
| | | return true; |
| | | } |
| | | if (!(o instanceof User)) { |
| | | return false; |
| | | } |
| | | return id != null && id.equals(((User) o).id); |
| | | } |
| | | |
| | | @Override |
| | | public int hashCode() { |
| | | // see https://vladmihalcea.com/how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier/ |
| | | return getClass().hashCode(); |
| | | } |
| | | |
| | | // prettier-ignore |
| | | @Override |
| | | public String toString() { |
| | | return "User{" + |
| | | "login='" + login + '\'' + |
| | | ", firstName='" + firstName + '\'' + |
| | | ", lastName='" + lastName + '\'' + |
| | | ", email='" + email + '\'' + |
| | | ", imageUrl='" + imageUrl + '\'' + |
| | | ", activated='" + activated + '\'' + |
| | | ", langKey='" + langKey + '\'' + |
| | | ", activationKey='" + activationKey + '\'' + |
| | | "}"; |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | /** |
| | | * JPA domain objects. |
| | | */ |
| | | package com.pollex.pam.domain; |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.repository; |
| | | |
| | | import com.pollex.pam.domain.Authority; |
| | | import org.springframework.data.jpa.repository.JpaRepository; |
| | | |
| | | /** |
| | | * Spring Data JPA repository for the {@link Authority} entity. |
| | | */ |
| | | public interface AuthorityRepository extends JpaRepository<Authority, String> {} |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.repository; |
| | | |
| | | import com.pollex.pam.domain.User; |
| | | import java.time.Instant; |
| | | import java.util.List; |
| | | import java.util.Optional; |
| | | import org.springframework.cache.annotation.Cacheable; |
| | | import org.springframework.data.domain.Page; |
| | | import org.springframework.data.domain.Pageable; |
| | | import org.springframework.data.jpa.repository.EntityGraph; |
| | | import org.springframework.data.jpa.repository.JpaRepository; |
| | | import org.springframework.stereotype.Repository; |
| | | |
| | | /** |
| | | * Spring Data JPA repository for the {@link User} entity. |
| | | */ |
| | | @Repository |
| | | public interface UserRepository extends JpaRepository<User, Long> { |
| | | String USERS_BY_LOGIN_CACHE = "usersByLogin"; |
| | | |
| | | String USERS_BY_EMAIL_CACHE = "usersByEmail"; |
| | | |
| | | Optional<User> findOneByActivationKey(String activationKey); |
| | | |
| | | List<User> findAllByActivatedIsFalseAndActivationKeyIsNotNullAndCreatedDateBefore(Instant dateTime); |
| | | |
| | | Optional<User> findOneByResetKey(String resetKey); |
| | | |
| | | Optional<User> findOneByEmailIgnoreCase(String email); |
| | | |
| | | Optional<User> findOneByLogin(String login); |
| | | |
| | | @EntityGraph(attributePaths = "authorities") |
| | | @Cacheable(cacheNames = USERS_BY_LOGIN_CACHE) |
| | | Optional<User> findOneWithAuthoritiesByLogin(String login); |
| | | |
| | | @EntityGraph(attributePaths = "authorities") |
| | | @Cacheable(cacheNames = USERS_BY_EMAIL_CACHE) |
| | | Optional<User> findOneWithAuthoritiesByEmailIgnoreCase(String email); |
| | | |
| | | Page<User> findAllByIdNotNullAndActivatedIsTrue(Pageable pageable); |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | /** |
| | | * Spring Data JPA repositories. |
| | | */ |
| | | package com.pollex.pam.repository; |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.security; |
| | | |
| | | /** |
| | | * Constants for Spring Security authorities. |
| | | */ |
| | | public final class AuthoritiesConstants { |
| | | |
| | | public static final String ADMIN = "ROLE_ADMIN"; |
| | | |
| | | public static final String USER = "ROLE_USER"; |
| | | |
| | | public static final String ANONYMOUS = "ROLE_ANONYMOUS"; |
| | | |
| | | private AuthoritiesConstants() {} |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.security; |
| | | |
| | | import com.pollex.pam.domain.User; |
| | | import com.pollex.pam.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; |
| | | import org.springframework.security.core.userdetails.UsernameNotFoundException; |
| | | import org.springframework.stereotype.Component; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | /** |
| | | * Authenticate a user from the database. |
| | | */ |
| | | @Component("userDetailsService") |
| | | public class DomainUserDetailsService implements UserDetailsService { |
| | | |
| | | private final Logger log = LoggerFactory.getLogger(DomainUserDetailsService.class); |
| | | |
| | | private final UserRepository userRepository; |
| | | |
| | | public DomainUserDetailsService(UserRepository userRepository) { |
| | | this.userRepository = userRepository; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional |
| | | public UserDetails loadUserByUsername(final String login) { |
| | | log.debug("Authenticating {}", login); |
| | | |
| | | if (new EmailValidator().isValid(login, null)) { |
| | | return userRepository |
| | | .findOneWithAuthoritiesByEmailIgnoreCase(login) |
| | | .map(user -> createSpringSecurityUser(login, user)) |
| | | .orElseThrow(() -> new UsernameNotFoundException("User with email " + login + " was not found in the database")); |
| | | } |
| | | |
| | | String lowercaseLogin = login.toLowerCase(Locale.ENGLISH); |
| | | return userRepository |
| | | .findOneWithAuthoritiesByLogin(lowercaseLogin) |
| | | .map(user -> createSpringSecurityUser(lowercaseLogin, user)) |
| | | .orElseThrow(() -> new UsernameNotFoundException("User " + lowercaseLogin + " was not found in the database")); |
| | | } |
| | | |
| | | private org.springframework.security.core.userdetails.User createSpringSecurityUser(String lowercaseLogin, User user) { |
| | | if (!user.isActivated()) { |
| | | throw new UserNotActivatedException("User " + lowercaseLogin + " was not activated"); |
| | | } |
| | | List<GrantedAuthority> grantedAuthorities = user |
| | | .getAuthorities() |
| | | .stream() |
| | | .map(authority -> new SimpleGrantedAuthority(authority.getName())) |
| | | .collect(Collectors.toList()); |
| | | return new org.springframework.security.core.userdetails.User(user.getLogin(), user.getPassword(), grantedAuthorities); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.security; |
| | | |
| | | import java.util.Arrays; |
| | | import java.util.Optional; |
| | | import java.util.stream.Stream; |
| | | import org.springframework.security.core.Authentication; |
| | | import org.springframework.security.core.GrantedAuthority; |
| | | import org.springframework.security.core.context.SecurityContext; |
| | | import org.springframework.security.core.context.SecurityContextHolder; |
| | | import org.springframework.security.core.userdetails.UserDetails; |
| | | |
| | | /** |
| | | * Utility class for Spring Security. |
| | | */ |
| | | public final class SecurityUtils { |
| | | |
| | | private SecurityUtils() {} |
| | | |
| | | /** |
| | | * Get the login of the current user. |
| | | * |
| | | * @return the login of the current user. |
| | | */ |
| | | public static Optional<String> getCurrentUserLogin() { |
| | | SecurityContext securityContext = SecurityContextHolder.getContext(); |
| | | return Optional.ofNullable(extractPrincipal(securityContext.getAuthentication())); |
| | | } |
| | | |
| | | private static String extractPrincipal(Authentication authentication) { |
| | | if (authentication == null) { |
| | | return null; |
| | | } else if (authentication.getPrincipal() instanceof UserDetails) { |
| | | UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal(); |
| | | return springSecurityUser.getUsername(); |
| | | } else if (authentication.getPrincipal() instanceof String) { |
| | | return (String) authentication.getPrincipal(); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * Get the JWT of the current user. |
| | | * |
| | | * @return the JWT of the current user. |
| | | */ |
| | | public static Optional<String> getCurrentUserJWT() { |
| | | SecurityContext securityContext = SecurityContextHolder.getContext(); |
| | | return Optional |
| | | .ofNullable(securityContext.getAuthentication()) |
| | | .filter(authentication -> authentication.getCredentials() instanceof String) |
| | | .map(authentication -> (String) authentication.getCredentials()); |
| | | } |
| | | |
| | | /** |
| | | * Check if a user is authenticated. |
| | | * |
| | | * @return true if the user is authenticated, false otherwise. |
| | | */ |
| | | public static boolean isAuthenticated() { |
| | | Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); |
| | | return authentication != null && getAuthorities(authentication).noneMatch(AuthoritiesConstants.ANONYMOUS::equals); |
| | | } |
| | | |
| | | /** |
| | | * Checks if the current user has any of the authorities. |
| | | * |
| | | * @param authorities the authorities to check. |
| | | * @return true if the current user has any of the authorities, false otherwise. |
| | | */ |
| | | public static boolean hasCurrentUserAnyOfAuthorities(String... authorities) { |
| | | Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); |
| | | return ( |
| | | authentication != null && getAuthorities(authentication).anyMatch(authority -> Arrays.asList(authorities).contains(authority)) |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * Checks if the current user has none of the authorities. |
| | | * |
| | | * @param authorities the authorities to check. |
| | | * @return true if the current user has none of the authorities, false otherwise. |
| | | */ |
| | | public static boolean hasCurrentUserNoneOfAuthorities(String... authorities) { |
| | | return !hasCurrentUserAnyOfAuthorities(authorities); |
| | | } |
| | | |
| | | /** |
| | | * Checks if the current user has a specific authority. |
| | | * |
| | | * @param authority the authority to check. |
| | | * @return true if the current user has the authority, false otherwise. |
| | | */ |
| | | public static boolean hasCurrentUserThisAuthority(String authority) { |
| | | return hasCurrentUserAnyOfAuthorities(authority); |
| | | } |
| | | |
| | | private static Stream<String> getAuthorities(Authentication authentication) { |
| | | return authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.security; |
| | | |
| | | import com.pollex.pam.config.Constants; |
| | | import java.util.Optional; |
| | | import org.springframework.data.domain.AuditorAware; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | /** |
| | | * Implementation of {@link AuditorAware} based on Spring Security. |
| | | */ |
| | | @Component |
| | | public class SpringSecurityAuditorAware implements AuditorAware<String> { |
| | | |
| | | @Override |
| | | public Optional<String> getCurrentAuditor() { |
| | | return Optional.of(SecurityUtils.getCurrentUserLogin().orElse(Constants.SYSTEM)); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.security; |
| | | |
| | | import org.springframework.security.core.AuthenticationException; |
| | | |
| | | /** |
| | | * This exception is thrown in case of a not activated user trying to authenticate. |
| | | */ |
| | | public class UserNotActivatedException extends AuthenticationException { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | public UserNotActivatedException(String message) { |
| | | super(message); |
| | | } |
| | | |
| | | public UserNotActivatedException(String message, Throwable t) { |
| | | super(message, t); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.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<DefaultSecurityFilterChain, HttpSecurity> { |
| | | |
| | | 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); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.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"; |
| | | |
| | | public static final String AUTHORIZATION_TOKEN = "access_token"; |
| | | |
| | | 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); |
| | | } |
| | | String jwt = request.getParameter(AUTHORIZATION_TOKEN); |
| | | if (StringUtils.hasText(jwt)) { |
| | | return jwt; |
| | | } |
| | | return null; |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.security.jwt; |
| | | |
| | | import io.jsonwebtoken.*; |
| | | import io.jsonwebtoken.io.Decoders; |
| | | import io.jsonwebtoken.security.Keys; |
| | | 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 final Key key; |
| | | |
| | | private final JwtParser jwtParser; |
| | | |
| | | private final long tokenValidityInMilliseconds; |
| | | |
| | | private final long tokenValidityInMillisecondsForRememberMe; |
| | | |
| | | public TokenProvider(JHipsterProperties jHipsterProperties) { |
| | | 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(); |
| | | } |
| | | |
| | | 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<? extends GrantedAuthority> 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 (JwtException | IllegalArgumentException e) { |
| | | log.info("Invalid JWT token."); |
| | | log.trace("Invalid JWT token trace.", e); |
| | | } |
| | | return false; |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | /** |
| | | * Spring Security configuration. |
| | | */ |
| | | package com.pollex.pam.security; |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.service; |
| | | |
| | | public class EmailAlreadyUsedException extends RuntimeException { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | public EmailAlreadyUsedException() { |
| | | super("Email is already in use!"); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.service; |
| | | |
| | | public class InvalidPasswordException extends RuntimeException { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | public InvalidPasswordException() { |
| | | super("Incorrect password"); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.service; |
| | | |
| | | import com.pollex.pam.domain.User; |
| | | 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; |
| | | import org.springframework.mail.MailException; |
| | | import org.springframework.mail.javamail.JavaMailSender; |
| | | import org.springframework.mail.javamail.MimeMessageHelper; |
| | | import org.springframework.scheduling.annotation.Async; |
| | | import org.springframework.stereotype.Service; |
| | | import org.thymeleaf.context.Context; |
| | | import org.thymeleaf.spring5.SpringTemplateEngine; |
| | | import tech.jhipster.config.JHipsterProperties; |
| | | |
| | | /** |
| | | * Service for sending emails. |
| | | * <p> |
| | | * We use the {@link Async} annotation to send emails asynchronously. |
| | | */ |
| | | @Service |
| | | public class MailService { |
| | | |
| | | private final Logger log = LoggerFactory.getLogger(MailService.class); |
| | | |
| | | private static final String USER = "user"; |
| | | |
| | | private static final String BASE_URL = "baseUrl"; |
| | | |
| | | private final JHipsterProperties jHipsterProperties; |
| | | |
| | | private final JavaMailSender javaMailSender; |
| | | |
| | | private final MessageSource messageSource; |
| | | |
| | | private final SpringTemplateEngine templateEngine; |
| | | |
| | | public MailService( |
| | | JHipsterProperties jHipsterProperties, |
| | | JavaMailSender javaMailSender, |
| | | MessageSource messageSource, |
| | | SpringTemplateEngine templateEngine |
| | | ) { |
| | | this.jHipsterProperties = jHipsterProperties; |
| | | this.javaMailSender = javaMailSender; |
| | | this.messageSource = messageSource; |
| | | this.templateEngine = templateEngine; |
| | | } |
| | | |
| | | @Async |
| | | public void sendEmail(String to, String subject, String content, boolean isMultipart, boolean isHtml) { |
| | | log.debug( |
| | | "Send email[multipart '{}' and html '{}'] to '{}' with subject '{}' and content={}", |
| | | isMultipart, |
| | | isHtml, |
| | | to, |
| | | subject, |
| | | content |
| | | ); |
| | | |
| | | // Prepare message using a Spring helper |
| | | MimeMessage mimeMessage = javaMailSender.createMimeMessage(); |
| | | try { |
| | | MimeMessageHelper message = new MimeMessageHelper(mimeMessage, isMultipart, StandardCharsets.UTF_8.name()); |
| | | message.setTo(to); |
| | | message.setFrom(jHipsterProperties.getMail().getFrom()); |
| | | message.setSubject(subject); |
| | | message.setText(content, isHtml); |
| | | javaMailSender.send(mimeMessage); |
| | | log.debug("Sent email to User '{}'", to); |
| | | } catch (MailException | MessagingException e) { |
| | | log.warn("Email could not be sent to user '{}'", to, e); |
| | | } |
| | | } |
| | | |
| | | @Async |
| | | public void sendEmailFromTemplate(User user, String templateName, String titleKey) { |
| | | if (user.getEmail() == null) { |
| | | log.debug("Email doesn't exist for user '{}'", user.getLogin()); |
| | | return; |
| | | } |
| | | Locale locale = Locale.forLanguageTag(user.getLangKey()); |
| | | Context context = new Context(locale); |
| | | context.setVariable(USER, user); |
| | | context.setVariable(BASE_URL, jHipsterProperties.getMail().getBaseUrl()); |
| | | String content = templateEngine.process(templateName, context); |
| | | String subject = messageSource.getMessage(titleKey, null, locale); |
| | | sendEmail(user.getEmail(), subject, content, false, true); |
| | | } |
| | | |
| | | @Async |
| | | public void sendActivationEmail(User user) { |
| | | log.debug("Sending activation email to '{}'", user.getEmail()); |
| | | sendEmailFromTemplate(user, "mail/activationEmail", "email.activation.title"); |
| | | } |
| | | |
| | | @Async |
| | | public void sendCreationEmail(User user) { |
| | | log.debug("Sending creation email to '{}'", user.getEmail()); |
| | | sendEmailFromTemplate(user, "mail/creationEmail", "email.activation.title"); |
| | | } |
| | | |
| | | @Async |
| | | public void sendPasswordResetMail(User user) { |
| | | log.debug("Sending password reset email to '{}'", user.getEmail()); |
| | | sendEmailFromTemplate(user, "mail/passwordResetEmail", "email.reset.title"); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.service; |
| | | |
| | | import com.pollex.pam.config.Constants; |
| | | import com.pollex.pam.domain.Authority; |
| | | import com.pollex.pam.domain.User; |
| | | import com.pollex.pam.repository.AuthorityRepository; |
| | | import com.pollex.pam.repository.UserRepository; |
| | | import com.pollex.pam.security.AuthoritiesConstants; |
| | | import com.pollex.pam.security.SecurityUtils; |
| | | import com.pollex.pam.service.dto.AdminUserDTO; |
| | | import com.pollex.pam.service.dto.UserDTO; |
| | | import java.time.Instant; |
| | | import java.time.temporal.ChronoUnit; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.cache.CacheManager; |
| | | import org.springframework.data.domain.Page; |
| | | import org.springframework.data.domain.Pageable; |
| | | import org.springframework.scheduling.annotation.Scheduled; |
| | | import org.springframework.security.crypto.password.PasswordEncoder; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import tech.jhipster.security.RandomUtil; |
| | | |
| | | /** |
| | | * Service class for managing users. |
| | | */ |
| | | @Service |
| | | @Transactional |
| | | public class UserService { |
| | | |
| | | private final Logger log = LoggerFactory.getLogger(UserService.class); |
| | | |
| | | private final UserRepository userRepository; |
| | | |
| | | private final PasswordEncoder passwordEncoder; |
| | | |
| | | private final AuthorityRepository authorityRepository; |
| | | |
| | | private final CacheManager cacheManager; |
| | | |
| | | public UserService( |
| | | UserRepository userRepository, |
| | | PasswordEncoder passwordEncoder, |
| | | AuthorityRepository authorityRepository, |
| | | CacheManager cacheManager |
| | | ) { |
| | | this.userRepository = userRepository; |
| | | this.passwordEncoder = passwordEncoder; |
| | | this.authorityRepository = authorityRepository; |
| | | this.cacheManager = cacheManager; |
| | | } |
| | | |
| | | public Optional<User> activateRegistration(String key) { |
| | | log.debug("Activating user for activation key {}", key); |
| | | return userRepository |
| | | .findOneByActivationKey(key) |
| | | .map(user -> { |
| | | // activate given user for the registration key. |
| | | user.setActivated(true); |
| | | user.setActivationKey(null); |
| | | this.clearUserCaches(user); |
| | | log.debug("Activated user: {}", user); |
| | | return user; |
| | | }); |
| | | } |
| | | |
| | | public Optional<User> completePasswordReset(String newPassword, String key) { |
| | | log.debug("Reset user password for reset key {}", key); |
| | | return userRepository |
| | | .findOneByResetKey(key) |
| | | .filter(user -> user.getResetDate().isAfter(Instant.now().minus(1, ChronoUnit.DAYS))) |
| | | .map(user -> { |
| | | user.setPassword(passwordEncoder.encode(newPassword)); |
| | | user.setResetKey(null); |
| | | user.setResetDate(null); |
| | | this.clearUserCaches(user); |
| | | return user; |
| | | }); |
| | | } |
| | | |
| | | public Optional<User> requestPasswordReset(String mail) { |
| | | return userRepository |
| | | .findOneByEmailIgnoreCase(mail) |
| | | .filter(User::isActivated) |
| | | .map(user -> { |
| | | user.setResetKey(RandomUtil.generateResetKey()); |
| | | user.setResetDate(Instant.now()); |
| | | this.clearUserCaches(user); |
| | | return user; |
| | | }); |
| | | } |
| | | |
| | | public User registerUser(AdminUserDTO userDTO, String password) { |
| | | userRepository |
| | | .findOneByLogin(userDTO.getLogin().toLowerCase()) |
| | | .ifPresent(existingUser -> { |
| | | boolean removed = removeNonActivatedUser(existingUser); |
| | | if (!removed) { |
| | | throw new UsernameAlreadyUsedException(); |
| | | } |
| | | }); |
| | | userRepository |
| | | .findOneByEmailIgnoreCase(userDTO.getEmail()) |
| | | .ifPresent(existingUser -> { |
| | | boolean removed = removeNonActivatedUser(existingUser); |
| | | if (!removed) { |
| | | throw new EmailAlreadyUsedException(); |
| | | } |
| | | }); |
| | | User newUser = new User(); |
| | | String encryptedPassword = passwordEncoder.encode(password); |
| | | newUser.setLogin(userDTO.getLogin().toLowerCase()); |
| | | // new user gets initially a generated password |
| | | newUser.setPassword(encryptedPassword); |
| | | newUser.setFirstName(userDTO.getFirstName()); |
| | | newUser.setLastName(userDTO.getLastName()); |
| | | if (userDTO.getEmail() != null) { |
| | | newUser.setEmail(userDTO.getEmail().toLowerCase()); |
| | | } |
| | | newUser.setImageUrl(userDTO.getImageUrl()); |
| | | newUser.setLangKey(userDTO.getLangKey()); |
| | | // new user is not active |
| | | newUser.setActivated(false); |
| | | // new user gets registration key |
| | | newUser.setActivationKey(RandomUtil.generateActivationKey()); |
| | | Set<Authority> authorities = new HashSet<>(); |
| | | authorityRepository.findById(AuthoritiesConstants.USER).ifPresent(authorities::add); |
| | | newUser.setAuthorities(authorities); |
| | | userRepository.save(newUser); |
| | | this.clearUserCaches(newUser); |
| | | log.debug("Created Information for User: {}", newUser); |
| | | return newUser; |
| | | } |
| | | |
| | | private boolean removeNonActivatedUser(User existingUser) { |
| | | if (existingUser.isActivated()) { |
| | | return false; |
| | | } |
| | | userRepository.delete(existingUser); |
| | | userRepository.flush(); |
| | | this.clearUserCaches(existingUser); |
| | | return true; |
| | | } |
| | | |
| | | public User createUser(AdminUserDTO userDTO) { |
| | | User user = new User(); |
| | | user.setLogin(userDTO.getLogin().toLowerCase()); |
| | | user.setFirstName(userDTO.getFirstName()); |
| | | user.setLastName(userDTO.getLastName()); |
| | | if (userDTO.getEmail() != null) { |
| | | user.setEmail(userDTO.getEmail().toLowerCase()); |
| | | } |
| | | user.setImageUrl(userDTO.getImageUrl()); |
| | | if (userDTO.getLangKey() == null) { |
| | | user.setLangKey(Constants.DEFAULT_LANGUAGE); // default language |
| | | } else { |
| | | user.setLangKey(userDTO.getLangKey()); |
| | | } |
| | | String encryptedPassword = passwordEncoder.encode(RandomUtil.generatePassword()); |
| | | user.setPassword(encryptedPassword); |
| | | user.setResetKey(RandomUtil.generateResetKey()); |
| | | user.setResetDate(Instant.now()); |
| | | user.setActivated(true); |
| | | if (userDTO.getAuthorities() != null) { |
| | | Set<Authority> authorities = userDTO |
| | | .getAuthorities() |
| | | .stream() |
| | | .map(authorityRepository::findById) |
| | | .filter(Optional::isPresent) |
| | | .map(Optional::get) |
| | | .collect(Collectors.toSet()); |
| | | user.setAuthorities(authorities); |
| | | } |
| | | userRepository.save(user); |
| | | this.clearUserCaches(user); |
| | | log.debug("Created Information for User: {}", user); |
| | | return user; |
| | | } |
| | | |
| | | /** |
| | | * Update all information for a specific user, and return the modified user. |
| | | * |
| | | * @param userDTO user to update. |
| | | * @return updated user. |
| | | */ |
| | | public Optional<AdminUserDTO> updateUser(AdminUserDTO userDTO) { |
| | | return Optional |
| | | .of(userRepository.findById(userDTO.getId())) |
| | | .filter(Optional::isPresent) |
| | | .map(Optional::get) |
| | | .map(user -> { |
| | | this.clearUserCaches(user); |
| | | user.setLogin(userDTO.getLogin().toLowerCase()); |
| | | user.setFirstName(userDTO.getFirstName()); |
| | | user.setLastName(userDTO.getLastName()); |
| | | if (userDTO.getEmail() != null) { |
| | | user.setEmail(userDTO.getEmail().toLowerCase()); |
| | | } |
| | | user.setImageUrl(userDTO.getImageUrl()); |
| | | user.setActivated(userDTO.isActivated()); |
| | | user.setLangKey(userDTO.getLangKey()); |
| | | Set<Authority> managedAuthorities = user.getAuthorities(); |
| | | managedAuthorities.clear(); |
| | | userDTO |
| | | .getAuthorities() |
| | | .stream() |
| | | .map(authorityRepository::findById) |
| | | .filter(Optional::isPresent) |
| | | .map(Optional::get) |
| | | .forEach(managedAuthorities::add); |
| | | this.clearUserCaches(user); |
| | | log.debug("Changed Information for User: {}", user); |
| | | return user; |
| | | }) |
| | | .map(AdminUserDTO::new); |
| | | } |
| | | |
| | | public void deleteUser(String login) { |
| | | userRepository |
| | | .findOneByLogin(login) |
| | | .ifPresent(user -> { |
| | | userRepository.delete(user); |
| | | this.clearUserCaches(user); |
| | | log.debug("Deleted User: {}", user); |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * Update basic information (first name, last name, email, language) for the current user. |
| | | * |
| | | * @param firstName first name of user. |
| | | * @param lastName last name of user. |
| | | * @param email email id of user. |
| | | * @param langKey language key. |
| | | * @param imageUrl image URL of user. |
| | | */ |
| | | public void updateUser(String firstName, String lastName, String email, String langKey, String imageUrl) { |
| | | SecurityUtils |
| | | .getCurrentUserLogin() |
| | | .flatMap(userRepository::findOneByLogin) |
| | | .ifPresent(user -> { |
| | | user.setFirstName(firstName); |
| | | user.setLastName(lastName); |
| | | if (email != null) { |
| | | user.setEmail(email.toLowerCase()); |
| | | } |
| | | user.setLangKey(langKey); |
| | | user.setImageUrl(imageUrl); |
| | | this.clearUserCaches(user); |
| | | log.debug("Changed Information for User: {}", user); |
| | | }); |
| | | } |
| | | |
| | | @Transactional |
| | | public void changePassword(String currentClearTextPassword, String newPassword) { |
| | | SecurityUtils |
| | | .getCurrentUserLogin() |
| | | .flatMap(userRepository::findOneByLogin) |
| | | .ifPresent(user -> { |
| | | String currentEncryptedPassword = user.getPassword(); |
| | | if (!passwordEncoder.matches(currentClearTextPassword, currentEncryptedPassword)) { |
| | | throw new InvalidPasswordException(); |
| | | } |
| | | String encryptedPassword = passwordEncoder.encode(newPassword); |
| | | user.setPassword(encryptedPassword); |
| | | this.clearUserCaches(user); |
| | | log.debug("Changed password for User: {}", user); |
| | | }); |
| | | } |
| | | |
| | | @Transactional(readOnly = true) |
| | | public Page<AdminUserDTO> getAllManagedUsers(Pageable pageable) { |
| | | return userRepository.findAll(pageable).map(AdminUserDTO::new); |
| | | } |
| | | |
| | | @Transactional(readOnly = true) |
| | | public Page<UserDTO> getAllPublicUsers(Pageable pageable) { |
| | | return userRepository.findAllByIdNotNullAndActivatedIsTrue(pageable).map(UserDTO::new); |
| | | } |
| | | |
| | | @Transactional(readOnly = true) |
| | | public Optional<User> getUserWithAuthoritiesByLogin(String login) { |
| | | return userRepository.findOneWithAuthoritiesByLogin(login); |
| | | } |
| | | |
| | | @Transactional(readOnly = true) |
| | | public Optional<User> getUserWithAuthorities() { |
| | | return SecurityUtils.getCurrentUserLogin().flatMap(userRepository::findOneWithAuthoritiesByLogin); |
| | | } |
| | | |
| | | /** |
| | | * Not activated users should be automatically deleted after 3 days. |
| | | * <p> |
| | | * This is scheduled to get fired everyday, at 01:00 (am). |
| | | */ |
| | | @Scheduled(cron = "0 0 1 * * ?") |
| | | public void removeNotActivatedUsers() { |
| | | userRepository |
| | | .findAllByActivatedIsFalseAndActivationKeyIsNotNullAndCreatedDateBefore(Instant.now().minus(3, ChronoUnit.DAYS)) |
| | | .forEach(user -> { |
| | | log.debug("Deleting not activated user {}", user.getLogin()); |
| | | userRepository.delete(user); |
| | | this.clearUserCaches(user); |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * Gets a list of all the authorities. |
| | | * @return a list of all the authorities. |
| | | */ |
| | | @Transactional(readOnly = true) |
| | | public List<String> getAuthorities() { |
| | | return authorityRepository.findAll().stream().map(Authority::getName).collect(Collectors.toList()); |
| | | } |
| | | |
| | | private void clearUserCaches(User user) { |
| | | Objects.requireNonNull(cacheManager.getCache(UserRepository.USERS_BY_LOGIN_CACHE)).evict(user.getLogin()); |
| | | if (user.getEmail() != null) { |
| | | Objects.requireNonNull(cacheManager.getCache(UserRepository.USERS_BY_EMAIL_CACHE)).evict(user.getEmail()); |
| | | } |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.service; |
| | | |
| | | public class UsernameAlreadyUsedException extends RuntimeException { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | public UsernameAlreadyUsedException() { |
| | | super("Login name already used!"); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.service.dto; |
| | | |
| | | import com.pollex.pam.config.Constants; |
| | | import com.pollex.pam.domain.Authority; |
| | | import com.pollex.pam.domain.User; |
| | | 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. |
| | | */ |
| | | public class AdminUserDTO { |
| | | |
| | | private Long id; |
| | | |
| | | @NotBlank |
| | | @Pattern(regexp = Constants.LOGIN_REGEX) |
| | | @Size(min = 1, max = 50) |
| | | private String login; |
| | | |
| | | @Size(max = 50) |
| | | private String firstName; |
| | | |
| | | @Size(max = 50) |
| | | private String lastName; |
| | | |
| | | @Email |
| | | @Size(min = 5, max = 254) |
| | | private String email; |
| | | |
| | | @Size(max = 256) |
| | | private String imageUrl; |
| | | |
| | | private boolean activated = false; |
| | | |
| | | @Size(min = 2, max = 10) |
| | | private String langKey; |
| | | |
| | | private String createdBy; |
| | | |
| | | private Instant createdDate; |
| | | |
| | | private String lastModifiedBy; |
| | | |
| | | private Instant lastModifiedDate; |
| | | |
| | | private Set<String> authorities; |
| | | |
| | | public AdminUserDTO() { |
| | | // Empty constructor needed for Jackson. |
| | | } |
| | | |
| | | public AdminUserDTO(User user) { |
| | | this.id = user.getId(); |
| | | this.login = user.getLogin(); |
| | | this.firstName = user.getFirstName(); |
| | | this.lastName = user.getLastName(); |
| | | this.email = user.getEmail(); |
| | | this.activated = user.isActivated(); |
| | | this.imageUrl = user.getImageUrl(); |
| | | this.langKey = user.getLangKey(); |
| | | this.createdBy = user.getCreatedBy(); |
| | | this.createdDate = user.getCreatedDate(); |
| | | this.lastModifiedBy = user.getLastModifiedBy(); |
| | | this.lastModifiedDate = user.getLastModifiedDate(); |
| | | this.authorities = user.getAuthorities().stream().map(Authority::getName).collect(Collectors.toSet()); |
| | | } |
| | | |
| | | public Long getId() { |
| | | return id; |
| | | } |
| | | |
| | | public void setId(Long id) { |
| | | this.id = id; |
| | | } |
| | | |
| | | public String getLogin() { |
| | | return login; |
| | | } |
| | | |
| | | public void setLogin(String login) { |
| | | this.login = login; |
| | | } |
| | | |
| | | public String getFirstName() { |
| | | return firstName; |
| | | } |
| | | |
| | | public void setFirstName(String firstName) { |
| | | this.firstName = firstName; |
| | | } |
| | | |
| | | public String getLastName() { |
| | | return lastName; |
| | | } |
| | | |
| | | public void setLastName(String lastName) { |
| | | this.lastName = lastName; |
| | | } |
| | | |
| | | public String getEmail() { |
| | | return email; |
| | | } |
| | | |
| | | public void setEmail(String email) { |
| | | this.email = email; |
| | | } |
| | | |
| | | public String getImageUrl() { |
| | | return imageUrl; |
| | | } |
| | | |
| | | public void setImageUrl(String imageUrl) { |
| | | this.imageUrl = imageUrl; |
| | | } |
| | | |
| | | public boolean isActivated() { |
| | | return activated; |
| | | } |
| | | |
| | | public void setActivated(boolean activated) { |
| | | this.activated = activated; |
| | | } |
| | | |
| | | public String getLangKey() { |
| | | return langKey; |
| | | } |
| | | |
| | | public void setLangKey(String langKey) { |
| | | this.langKey = langKey; |
| | | } |
| | | |
| | | public String getCreatedBy() { |
| | | return createdBy; |
| | | } |
| | | |
| | | public void setCreatedBy(String createdBy) { |
| | | this.createdBy = createdBy; |
| | | } |
| | | |
| | | public Instant getCreatedDate() { |
| | | return createdDate; |
| | | } |
| | | |
| | | public void setCreatedDate(Instant createdDate) { |
| | | this.createdDate = createdDate; |
| | | } |
| | | |
| | | public String getLastModifiedBy() { |
| | | return lastModifiedBy; |
| | | } |
| | | |
| | | public void setLastModifiedBy(String lastModifiedBy) { |
| | | this.lastModifiedBy = lastModifiedBy; |
| | | } |
| | | |
| | | public Instant getLastModifiedDate() { |
| | | return lastModifiedDate; |
| | | } |
| | | |
| | | public void setLastModifiedDate(Instant lastModifiedDate) { |
| | | this.lastModifiedDate = lastModifiedDate; |
| | | } |
| | | |
| | | public Set<String> getAuthorities() { |
| | | return authorities; |
| | | } |
| | | |
| | | public void setAuthorities(Set<String> authorities) { |
| | | this.authorities = authorities; |
| | | } |
| | | |
| | | // prettier-ignore |
| | | @Override |
| | | public String toString() { |
| | | return "AdminUserDTO{" + |
| | | "login='" + login + '\'' + |
| | | ", firstName='" + firstName + '\'' + |
| | | ", lastName='" + lastName + '\'' + |
| | | ", email='" + email + '\'' + |
| | | ", imageUrl='" + imageUrl + '\'' + |
| | | ", activated=" + activated + |
| | | ", langKey='" + langKey + '\'' + |
| | | ", createdBy=" + createdBy + |
| | | ", createdDate=" + createdDate + |
| | | ", lastModifiedBy='" + lastModifiedBy + '\'' + |
| | | ", lastModifiedDate=" + lastModifiedDate + |
| | | ", authorities=" + authorities + |
| | | "}"; |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.service.dto; |
| | | |
| | | /** |
| | | * A DTO representing a password change required data - current and new password. |
| | | */ |
| | | public class PasswordChangeDTO { |
| | | |
| | | private String currentPassword; |
| | | private String newPassword; |
| | | |
| | | public PasswordChangeDTO() { |
| | | // Empty constructor needed for Jackson. |
| | | } |
| | | |
| | | public PasswordChangeDTO(String currentPassword, String newPassword) { |
| | | this.currentPassword = currentPassword; |
| | | this.newPassword = newPassword; |
| | | } |
| | | |
| | | public String getCurrentPassword() { |
| | | return currentPassword; |
| | | } |
| | | |
| | | public void setCurrentPassword(String currentPassword) { |
| | | this.currentPassword = currentPassword; |
| | | } |
| | | |
| | | public String getNewPassword() { |
| | | return newPassword; |
| | | } |
| | | |
| | | public void setNewPassword(String newPassword) { |
| | | this.newPassword = newPassword; |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.service.dto; |
| | | |
| | | import com.pollex.pam.domain.User; |
| | | |
| | | /** |
| | | * A DTO representing a user, with only the public attributes. |
| | | */ |
| | | public class UserDTO { |
| | | |
| | | private Long id; |
| | | |
| | | private String login; |
| | | |
| | | public UserDTO() { |
| | | // Empty constructor needed for Jackson. |
| | | } |
| | | |
| | | public UserDTO(User user) { |
| | | this.id = user.getId(); |
| | | // Customize it here if you need, or not, firstName/lastName/etc |
| | | this.login = user.getLogin(); |
| | | } |
| | | |
| | | public Long getId() { |
| | | return id; |
| | | } |
| | | |
| | | public void setId(Long id) { |
| | | this.id = id; |
| | | } |
| | | |
| | | public String getLogin() { |
| | | return login; |
| | | } |
| | | |
| | | public void setLogin(String login) { |
| | | this.login = login; |
| | | } |
| | | |
| | | // prettier-ignore |
| | | @Override |
| | | public String toString() { |
| | | return "UserDTO{" + |
| | | "id='" + id + '\'' + |
| | | ", login='" + login + '\'' + |
| | | "}"; |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | /** |
| | | * Data Transfer Objects. |
| | | */ |
| | | package com.pollex.pam.service.dto; |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.service.mapper; |
| | | |
| | | import com.pollex.pam.domain.Authority; |
| | | import com.pollex.pam.domain.User; |
| | | import com.pollex.pam.service.dto.AdminUserDTO; |
| | | import com.pollex.pam.service.dto.UserDTO; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | import org.mapstruct.BeanMapping; |
| | | import org.mapstruct.Mapping; |
| | | import org.mapstruct.Named; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | /** |
| | | * Mapper for the entity {@link User} and its DTO called {@link UserDTO}. |
| | | * |
| | | * Normal mappers are generated using MapStruct, this one is hand-coded as MapStruct |
| | | * support is still in beta, and requires a manual step with an IDE. |
| | | */ |
| | | @Service |
| | | public class UserMapper { |
| | | |
| | | public List<UserDTO> usersToUserDTOs(List<User> users) { |
| | | return users.stream().filter(Objects::nonNull).map(this::userToUserDTO).collect(Collectors.toList()); |
| | | } |
| | | |
| | | public UserDTO userToUserDTO(User user) { |
| | | return new UserDTO(user); |
| | | } |
| | | |
| | | public List<AdminUserDTO> usersToAdminUserDTOs(List<User> users) { |
| | | return users.stream().filter(Objects::nonNull).map(this::userToAdminUserDTO).collect(Collectors.toList()); |
| | | } |
| | | |
| | | public AdminUserDTO userToAdminUserDTO(User user) { |
| | | return new AdminUserDTO(user); |
| | | } |
| | | |
| | | public List<User> userDTOsToUsers(List<AdminUserDTO> userDTOs) { |
| | | return userDTOs.stream().filter(Objects::nonNull).map(this::userDTOToUser).collect(Collectors.toList()); |
| | | } |
| | | |
| | | public User userDTOToUser(AdminUserDTO userDTO) { |
| | | if (userDTO == null) { |
| | | return null; |
| | | } else { |
| | | User user = new User(); |
| | | user.setId(userDTO.getId()); |
| | | user.setLogin(userDTO.getLogin()); |
| | | user.setFirstName(userDTO.getFirstName()); |
| | | user.setLastName(userDTO.getLastName()); |
| | | user.setEmail(userDTO.getEmail()); |
| | | user.setImageUrl(userDTO.getImageUrl()); |
| | | user.setActivated(userDTO.isActivated()); |
| | | user.setLangKey(userDTO.getLangKey()); |
| | | Set<Authority> authorities = this.authoritiesFromStrings(userDTO.getAuthorities()); |
| | | user.setAuthorities(authorities); |
| | | return user; |
| | | } |
| | | } |
| | | |
| | | private Set<Authority> authoritiesFromStrings(Set<String> authoritiesAsString) { |
| | | Set<Authority> authorities = new HashSet<>(); |
| | | |
| | | if (authoritiesAsString != null) { |
| | | authorities = |
| | | authoritiesAsString |
| | | .stream() |
| | | .map(string -> { |
| | | Authority auth = new Authority(); |
| | | auth.setName(string); |
| | | return auth; |
| | | }) |
| | | .collect(Collectors.toSet()); |
| | | } |
| | | |
| | | return authorities; |
| | | } |
| | | |
| | | public User userFromId(Long id) { |
| | | if (id == null) { |
| | | return null; |
| | | } |
| | | User user = new User(); |
| | | user.setId(id); |
| | | return user; |
| | | } |
| | | |
| | | @Named("id") |
| | | @BeanMapping(ignoreByDefault = true) |
| | | @Mapping(target = "id", source = "id") |
| | | public UserDTO toDtoId(User user) { |
| | | if (user == null) { |
| | | return null; |
| | | } |
| | | UserDTO userDto = new UserDTO(); |
| | | userDto.setId(user.getId()); |
| | | return userDto; |
| | | } |
| | | |
| | | @Named("idSet") |
| | | @BeanMapping(ignoreByDefault = true) |
| | | @Mapping(target = "id", source = "id") |
| | | public Set<UserDTO> toDtoIdSet(Set<User> users) { |
| | | if (users == null) { |
| | | return Collections.emptySet(); |
| | | } |
| | | |
| | | Set<UserDTO> userSet = new HashSet<>(); |
| | | for (User userEntity : users) { |
| | | userSet.add(this.toDtoId(userEntity)); |
| | | } |
| | | |
| | | return userSet; |
| | | } |
| | | |
| | | @Named("login") |
| | | @BeanMapping(ignoreByDefault = true) |
| | | @Mapping(target = "id", source = "id") |
| | | @Mapping(target = "login", source = "login") |
| | | public UserDTO toDtoLogin(User user) { |
| | | if (user == null) { |
| | | return null; |
| | | } |
| | | UserDTO userDto = new UserDTO(); |
| | | userDto.setId(user.getId()); |
| | | userDto.setLogin(user.getLogin()); |
| | | return userDto; |
| | | } |
| | | |
| | | @Named("loginSet") |
| | | @BeanMapping(ignoreByDefault = true) |
| | | @Mapping(target = "id", source = "id") |
| | | @Mapping(target = "login", source = "login") |
| | | public Set<UserDTO> toDtoLoginSet(Set<User> users) { |
| | | if (users == null) { |
| | | return Collections.emptySet(); |
| | | } |
| | | |
| | | Set<UserDTO> userSet = new HashSet<>(); |
| | | for (User userEntity : users) { |
| | | userSet.add(this.toDtoLogin(userEntity)); |
| | | } |
| | | |
| | | return userSet; |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | /** |
| | | * MapStruct mappers for mapping domain objects and Data Transfer Objects. |
| | | */ |
| | | package com.pollex.pam.service.mapper; |
¤ñ¹ï·sÀÉ®× |
| | |
| | | /** |
| | | * Service layer beans. |
| | | */ |
| | | package com.pollex.pam.service; |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.rest; |
| | | |
| | | import com.pollex.pam.domain.User; |
| | | import com.pollex.pam.repository.UserRepository; |
| | | import com.pollex.pam.security.SecurityUtils; |
| | | import com.pollex.pam.service.MailService; |
| | | import com.pollex.pam.service.UserService; |
| | | import com.pollex.pam.service.dto.AdminUserDTO; |
| | | import com.pollex.pam.service.dto.PasswordChangeDTO; |
| | | import com.pollex.pam.web.rest.errors.*; |
| | | import com.pollex.pam.web.rest.vm.KeyAndPasswordVM; |
| | | import com.pollex.pam.web.rest.vm.ManagedUserVM; |
| | | 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; |
| | | import org.springframework.http.HttpStatus; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | /** |
| | | * REST controller for managing the current user's account. |
| | | */ |
| | | @RestController |
| | | @RequestMapping("/api") |
| | | public class AccountResource { |
| | | |
| | | private static class AccountResourceException extends RuntimeException { |
| | | |
| | | private AccountResourceException(String message) { |
| | | super(message); |
| | | } |
| | | } |
| | | |
| | | private final Logger log = LoggerFactory.getLogger(AccountResource.class); |
| | | |
| | | private final UserRepository userRepository; |
| | | |
| | | private final UserService userService; |
| | | |
| | | private final MailService mailService; |
| | | |
| | | public AccountResource(UserRepository userRepository, UserService userService, MailService mailService) { |
| | | this.userRepository = userRepository; |
| | | this.userService = userService; |
| | | this.mailService = mailService; |
| | | } |
| | | |
| | | /** |
| | | * {@code POST /register} : register the user. |
| | | * |
| | | * @param managedUserVM the managed user View Model. |
| | | * @throws InvalidPasswordException {@code 400 (Bad Request)} if the password is incorrect. |
| | | * @throws EmailAlreadyUsedException {@code 400 (Bad Request)} if the email is already used. |
| | | * @throws LoginAlreadyUsedException {@code 400 (Bad Request)} if the login is already used. |
| | | */ |
| | | @PostMapping("/register") |
| | | @ResponseStatus(HttpStatus.CREATED) |
| | | public void registerAccount(@Valid @RequestBody ManagedUserVM managedUserVM) { |
| | | if (isPasswordLengthInvalid(managedUserVM.getPassword())) { |
| | | throw new InvalidPasswordException(); |
| | | } |
| | | User user = userService.registerUser(managedUserVM, managedUserVM.getPassword()); |
| | | mailService.sendActivationEmail(user); |
| | | } |
| | | |
| | | /** |
| | | * {@code GET /activate} : activate the registered user. |
| | | * |
| | | * @param key the activation key. |
| | | * @throws RuntimeException {@code 500 (Internal Server Error)} if the user couldn't be activated. |
| | | */ |
| | | @GetMapping("/activate") |
| | | public void activateAccount(@RequestParam(value = "key") String key) { |
| | | Optional<User> user = userService.activateRegistration(key); |
| | | if (!user.isPresent()) { |
| | | throw new AccountResourceException("No user was found for this activation 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. |
| | | * |
| | | * @return the current user. |
| | | * @throws RuntimeException {@code 500 (Internal Server Error)} if the user couldn't be returned. |
| | | */ |
| | | @GetMapping("/account") |
| | | public AdminUserDTO getAccount() { |
| | | return userService |
| | | .getUserWithAuthorities() |
| | | .map(AdminUserDTO::new) |
| | | .orElseThrow(() -> new AccountResourceException("User could not be found")); |
| | | } |
| | | |
| | | /** |
| | | * {@code POST /account} : update the current user information. |
| | | * |
| | | * @param userDTO the current user information. |
| | | * @throws EmailAlreadyUsedException {@code 400 (Bad Request)} if the email is already used. |
| | | * @throws RuntimeException {@code 500 (Internal Server Error)} if the user login wasn't found. |
| | | */ |
| | | @PostMapping("/account") |
| | | public void saveAccount(@Valid @RequestBody AdminUserDTO userDTO) { |
| | | String userLogin = SecurityUtils |
| | | .getCurrentUserLogin() |
| | | .orElseThrow(() -> new AccountResourceException("Current user login not found")); |
| | | Optional<User> existingUser = userRepository.findOneByEmailIgnoreCase(userDTO.getEmail()); |
| | | if (existingUser.isPresent() && (!existingUser.get().getLogin().equalsIgnoreCase(userLogin))) { |
| | | throw new EmailAlreadyUsedException(); |
| | | } |
| | | Optional<User> user = userRepository.findOneByLogin(userLogin); |
| | | if (!user.isPresent()) { |
| | | throw new AccountResourceException("User could not be found"); |
| | | } |
| | | userService.updateUser( |
| | | userDTO.getFirstName(), |
| | | userDTO.getLastName(), |
| | | userDTO.getEmail(), |
| | | userDTO.getLangKey(), |
| | | userDTO.getImageUrl() |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * {@code POST /account/change-password} : changes the current user's password. |
| | | * |
| | | * @param passwordChangeDto current and new password. |
| | | * @throws InvalidPasswordException {@code 400 (Bad Request)} if the new password is incorrect. |
| | | */ |
| | | @PostMapping(path = "/account/change-password") |
| | | public void changePassword(@RequestBody PasswordChangeDTO passwordChangeDto) { |
| | | if (isPasswordLengthInvalid(passwordChangeDto.getNewPassword())) { |
| | | throw new InvalidPasswordException(); |
| | | } |
| | | userService.changePassword(passwordChangeDto.getCurrentPassword(), passwordChangeDto.getNewPassword()); |
| | | } |
| | | |
| | | /** |
| | | * {@code POST /account/reset-password/init} : Send an email to reset the password of the user. |
| | | * |
| | | * @param mail the mail of the user. |
| | | */ |
| | | @PostMapping(path = "/account/reset-password/init") |
| | | public void requestPasswordReset(@RequestBody String mail) { |
| | | Optional<User> user = userService.requestPasswordReset(mail); |
| | | if (user.isPresent()) { |
| | | 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 |
| | | log.warn("Password reset requested for non existing mail"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@code POST /account/reset-password/finish} : Finish to reset the password of the user. |
| | | * |
| | | * @param keyAndPassword the generated key and the new password. |
| | | * @throws InvalidPasswordException {@code 400 (Bad Request)} if the password is incorrect. |
| | | * @throws RuntimeException {@code 500 (Internal Server Error)} if the password could not be reset. |
| | | */ |
| | | @PostMapping(path = "/account/reset-password/finish") |
| | | public void finishPasswordReset(@RequestBody KeyAndPasswordVM keyAndPassword) { |
| | | if (isPasswordLengthInvalid(keyAndPassword.getNewPassword())) { |
| | | throw new InvalidPasswordException(); |
| | | } |
| | | Optional<User> user = userService.completePasswordReset(keyAndPassword.getNewPassword(), keyAndPassword.getKey()); |
| | | |
| | | if (!user.isPresent()) { |
| | | throw new AccountResourceException("No user was found for this reset key"); |
| | | } |
| | | } |
| | | |
| | | private static boolean isPasswordLengthInvalid(String password) { |
| | | return ( |
| | | StringUtils.isEmpty(password) || |
| | | password.length() < ManagedUserVM.PASSWORD_MIN_LENGTH || |
| | | password.length() > ManagedUserVM.PASSWORD_MAX_LENGTH |
| | | ); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.rest; |
| | | |
| | | import com.pollex.pam.service.UserService; |
| | | import com.pollex.pam.service.dto.UserDTO; |
| | | import java.util.*; |
| | | import java.util.Collections; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.data.domain.Page; |
| | | import org.springframework.data.domain.Pageable; |
| | | import org.springframework.data.domain.Sort; |
| | | import org.springframework.http.HttpHeaders; |
| | | import org.springframework.http.HttpStatus; |
| | | import org.springframework.http.ResponseEntity; |
| | | import org.springframework.web.bind.annotation.*; |
| | | import org.springframework.web.servlet.support.ServletUriComponentsBuilder; |
| | | import tech.jhipster.web.util.PaginationUtil; |
| | | |
| | | @RestController |
| | | @RequestMapping("/api") |
| | | public class PublicUserResource { |
| | | |
| | | private static final List<String> ALLOWED_ORDERED_PROPERTIES = Collections.unmodifiableList( |
| | | Arrays.asList("id", "login", "firstName", "lastName", "email", "activated", "langKey") |
| | | ); |
| | | |
| | | private final Logger log = LoggerFactory.getLogger(PublicUserResource.class); |
| | | |
| | | private final UserService userService; |
| | | |
| | | public PublicUserResource(UserService userService) { |
| | | this.userService = userService; |
| | | } |
| | | |
| | | /** |
| | | * {@code GET /users} : get all users with only the public informations - calling this are allowed for anyone. |
| | | * |
| | | * @param pageable the pagination information. |
| | | * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body all users. |
| | | */ |
| | | @GetMapping("/users") |
| | | public ResponseEntity<List<UserDTO>> getAllPublicUsers(Pageable pageable) { |
| | | log.debug("REST request to get all public User names"); |
| | | if (!onlyContainsAllowedProperties(pageable)) { |
| | | return ResponseEntity.badRequest().build(); |
| | | } |
| | | |
| | | final Page<UserDTO> page = userService.getAllPublicUsers(pageable); |
| | | HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(ServletUriComponentsBuilder.fromCurrentRequest(), page); |
| | | return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); |
| | | } |
| | | |
| | | private boolean onlyContainsAllowedProperties(Pageable pageable) { |
| | | return pageable.getSort().stream().map(Sort.Order::getProperty).allMatch(ALLOWED_ORDERED_PROPERTIES::contains); |
| | | } |
| | | |
| | | /** |
| | | * Gets a list of all roles. |
| | | * @return a string list of all roles. |
| | | */ |
| | | @GetMapping("/authorities") |
| | | public List<String> getAuthorities() { |
| | | return userService.getAuthorities(); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.rest; |
| | | |
| | | import com.fasterxml.jackson.annotation.JsonProperty; |
| | | import com.pollex.pam.security.jwt.JWTFilter; |
| | | import com.pollex.pam.security.jwt.TokenProvider; |
| | | import com.pollex.pam.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<JWTToken> 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; |
| | | } |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.rest; |
| | | |
| | | import com.pollex.pam.config.Constants; |
| | | import com.pollex.pam.domain.User; |
| | | import com.pollex.pam.repository.UserRepository; |
| | | import com.pollex.pam.security.AuthoritiesConstants; |
| | | import com.pollex.pam.service.MailService; |
| | | import com.pollex.pam.service.UserService; |
| | | import com.pollex.pam.service.dto.AdminUserDTO; |
| | | import com.pollex.pam.web.rest.errors.BadRequestAlertException; |
| | | import com.pollex.pam.web.rest.errors.EmailAlreadyUsedException; |
| | | import com.pollex.pam.web.rest.errors.LoginAlreadyUsedException; |
| | | 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; |
| | | import org.springframework.data.domain.Page; |
| | | import org.springframework.data.domain.Pageable; |
| | | import org.springframework.data.domain.Sort; |
| | | import org.springframework.http.HttpHeaders; |
| | | import org.springframework.http.HttpStatus; |
| | | import org.springframework.http.ResponseEntity; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.web.bind.annotation.*; |
| | | import org.springframework.web.servlet.support.ServletUriComponentsBuilder; |
| | | import tech.jhipster.web.util.HeaderUtil; |
| | | import tech.jhipster.web.util.PaginationUtil; |
| | | import tech.jhipster.web.util.ResponseUtil; |
| | | |
| | | /** |
| | | * REST controller for managing users. |
| | | * <p> |
| | | * This class accesses the {@link User} entity, and needs to fetch its collection of authorities. |
| | | * <p> |
| | | * For a normal use-case, it would be better to have an eager relationship between User and Authority, |
| | | * and send everything to the client side: there would be no View Model and DTO, a lot less code, and an outer-join |
| | | * which would be good for performance. |
| | | * <p> |
| | | * We use a View Model and a DTO for 3 reasons: |
| | | * <ul> |
| | | * <li>We want to keep a lazy association between the user and the authorities, because people will |
| | | * quite often do relationships with the user, and we don't want them to get the authorities all |
| | | * the time for nothing (for performance reasons). This is the #1 goal: we should not impact our users' |
| | | * application because of this use-case.</li> |
| | | * <li> Not having an outer join causes n+1 requests to the database. This is not a real issue as |
| | | * we have by default a second-level cache. This means on the first HTTP call we do the n+1 requests, |
| | | * but then all authorities come from the cache, so in fact it's much better than doing an outer join |
| | | * (which will get lots of data from the database, for each HTTP call).</li> |
| | | * <li> As this manages users, for security reasons, we'd rather have a DTO layer.</li> |
| | | * </ul> |
| | | * <p> |
| | | * Another option would be to have a specific JPA entity graph to handle this case. |
| | | */ |
| | | @RestController |
| | | @RequestMapping("/api/admin") |
| | | public class UserResource { |
| | | |
| | | private static final List<String> ALLOWED_ORDERED_PROPERTIES = Collections.unmodifiableList( |
| | | Arrays.asList( |
| | | "id", |
| | | "login", |
| | | "firstName", |
| | | "lastName", |
| | | "email", |
| | | "activated", |
| | | "langKey", |
| | | "createdBy", |
| | | "createdDate", |
| | | "lastModifiedBy", |
| | | "lastModifiedDate" |
| | | ) |
| | | ); |
| | | |
| | | private final Logger log = LoggerFactory.getLogger(UserResource.class); |
| | | |
| | | @Value("${jhipster.clientApp.name}") |
| | | private String applicationName; |
| | | |
| | | private final UserService userService; |
| | | |
| | | private final UserRepository userRepository; |
| | | |
| | | private final MailService mailService; |
| | | |
| | | public UserResource(UserService userService, UserRepository userRepository, MailService mailService) { |
| | | this.userService = userService; |
| | | this.userRepository = userRepository; |
| | | this.mailService = mailService; |
| | | } |
| | | |
| | | /** |
| | | * {@code POST /admin/users} : Creates a new user. |
| | | * <p> |
| | | * Creates a new user if the login and email are not already used, and sends an |
| | | * mail with an activation link. |
| | | * The user needs to be activated on creation. |
| | | * |
| | | * @param userDTO the user to create. |
| | | * @return the {@link ResponseEntity} with status {@code 201 (Created)} and with body the new user, or with status {@code 400 (Bad Request)} if the login or email is already in use. |
| | | * @throws URISyntaxException if the Location URI syntax is incorrect. |
| | | * @throws BadRequestAlertException {@code 400 (Bad Request)} if the login or email is already in use. |
| | | */ |
| | | @PostMapping("/users") |
| | | @PreAuthorize("hasAuthority(\"" + AuthoritiesConstants.ADMIN + "\")") |
| | | public ResponseEntity<User> createUser(@Valid @RequestBody AdminUserDTO userDTO) throws URISyntaxException { |
| | | log.debug("REST request to save User : {}", userDTO); |
| | | |
| | | if (userDTO.getId() != null) { |
| | | throw new BadRequestAlertException("A new user cannot already have an ID", "userManagement", "idexists"); |
| | | // Lowercase the user login before comparing with database |
| | | } else if (userRepository.findOneByLogin(userDTO.getLogin().toLowerCase()).isPresent()) { |
| | | throw new LoginAlreadyUsedException(); |
| | | } else if (userRepository.findOneByEmailIgnoreCase(userDTO.getEmail()).isPresent()) { |
| | | throw new EmailAlreadyUsedException(); |
| | | } else { |
| | | User newUser = userService.createUser(userDTO); |
| | | mailService.sendCreationEmail(newUser); |
| | | return ResponseEntity |
| | | .created(new URI("/api/admin/users/" + newUser.getLogin())) |
| | | .headers(HeaderUtil.createAlert(applicationName, "userManagement.created", newUser.getLogin())) |
| | | .body(newUser); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@code PUT /admin/users} : Updates an existing User. |
| | | * |
| | | * @param userDTO the user to update. |
| | | * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the updated user. |
| | | * @throws EmailAlreadyUsedException {@code 400 (Bad Request)} if the email is already in use. |
| | | * @throws LoginAlreadyUsedException {@code 400 (Bad Request)} if the login is already in use. |
| | | */ |
| | | @PutMapping("/users") |
| | | @PreAuthorize("hasAuthority(\"" + AuthoritiesConstants.ADMIN + "\")") |
| | | public ResponseEntity<AdminUserDTO> updateUser(@Valid @RequestBody AdminUserDTO userDTO) { |
| | | log.debug("REST request to update User : {}", userDTO); |
| | | Optional<User> existingUser = userRepository.findOneByEmailIgnoreCase(userDTO.getEmail()); |
| | | if (existingUser.isPresent() && (!existingUser.get().getId().equals(userDTO.getId()))) { |
| | | throw new EmailAlreadyUsedException(); |
| | | } |
| | | existingUser = userRepository.findOneByLogin(userDTO.getLogin().toLowerCase()); |
| | | if (existingUser.isPresent() && (!existingUser.get().getId().equals(userDTO.getId()))) { |
| | | throw new LoginAlreadyUsedException(); |
| | | } |
| | | Optional<AdminUserDTO> updatedUser = userService.updateUser(userDTO); |
| | | |
| | | return ResponseUtil.wrapOrNotFound( |
| | | updatedUser, |
| | | HeaderUtil.createAlert(applicationName, "userManagement.updated", userDTO.getLogin()) |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * {@code GET /admin/users} : get all users with all the details - calling this are only allowed for the administrators. |
| | | * |
| | | * @param pageable the pagination information. |
| | | * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body all users. |
| | | */ |
| | | @GetMapping("/users") |
| | | @PreAuthorize("hasAuthority(\"" + AuthoritiesConstants.ADMIN + "\")") |
| | | public ResponseEntity<List<AdminUserDTO>> getAllUsers(Pageable pageable) { |
| | | log.debug("REST request to get all User for an admin"); |
| | | if (!onlyContainsAllowedProperties(pageable)) { |
| | | return ResponseEntity.badRequest().build(); |
| | | } |
| | | |
| | | final Page<AdminUserDTO> page = userService.getAllManagedUsers(pageable); |
| | | HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(ServletUriComponentsBuilder.fromCurrentRequest(), page); |
| | | return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); |
| | | } |
| | | |
| | | private boolean onlyContainsAllowedProperties(Pageable pageable) { |
| | | return pageable.getSort().stream().map(Sort.Order::getProperty).allMatch(ALLOWED_ORDERED_PROPERTIES::contains); |
| | | } |
| | | |
| | | /** |
| | | * {@code GET /admin/users/:login} : get the "login" user. |
| | | * |
| | | * @param login the login of the user to find. |
| | | * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the "login" user, or with status {@code 404 (Not Found)}. |
| | | */ |
| | | @GetMapping("/users/{login}") |
| | | @PreAuthorize("hasAuthority(\"" + AuthoritiesConstants.ADMIN + "\")") |
| | | public ResponseEntity<AdminUserDTO> getUser(@PathVariable @Pattern(regexp = Constants.LOGIN_REGEX) String login) { |
| | | log.debug("REST request to get User : {}", login); |
| | | return ResponseUtil.wrapOrNotFound(userService.getUserWithAuthoritiesByLogin(login).map(AdminUserDTO::new)); |
| | | } |
| | | |
| | | /** |
| | | * {@code DELETE /admin/users/:login} : delete the "login" User. |
| | | * |
| | | * @param login the login of the user to delete. |
| | | * @return the {@link ResponseEntity} with status {@code 204 (NO_CONTENT)}. |
| | | */ |
| | | @DeleteMapping("/users/{login}") |
| | | @PreAuthorize("hasAuthority(\"" + AuthoritiesConstants.ADMIN + "\")") |
| | | public ResponseEntity<Void> deleteUser(@PathVariable @Pattern(regexp = Constants.LOGIN_REGEX) String login) { |
| | | log.debug("REST request to delete User: {}", login); |
| | | userService.deleteUser(login); |
| | | return ResponseEntity.noContent().headers(HeaderUtil.createAlert(applicationName, "userManagement.deleted", login)).build(); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.rest.errors; |
| | | |
| | | import java.net.URI; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | import org.zalando.problem.AbstractThrowableProblem; |
| | | import org.zalando.problem.Status; |
| | | |
| | | public class BadRequestAlertException extends AbstractThrowableProblem { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private final String entityName; |
| | | |
| | | private final String errorKey; |
| | | |
| | | public BadRequestAlertException(String defaultMessage, String entityName, String errorKey) { |
| | | this(ErrorConstants.DEFAULT_TYPE, defaultMessage, entityName, errorKey); |
| | | } |
| | | |
| | | public BadRequestAlertException(URI type, String defaultMessage, String entityName, String errorKey) { |
| | | super(type, defaultMessage, Status.BAD_REQUEST, null, null, null, getAlertParameters(entityName, errorKey)); |
| | | this.entityName = entityName; |
| | | this.errorKey = errorKey; |
| | | } |
| | | |
| | | public String getEntityName() { |
| | | return entityName; |
| | | } |
| | | |
| | | public String getErrorKey() { |
| | | return errorKey; |
| | | } |
| | | |
| | | private static Map<String, Object> getAlertParameters(String entityName, String errorKey) { |
| | | Map<String, Object> parameters = new HashMap<>(); |
| | | parameters.put("message", "error." + errorKey); |
| | | parameters.put("params", entityName); |
| | | return parameters; |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.rest.errors; |
| | | |
| | | public class EmailAlreadyUsedException extends BadRequestAlertException { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | public EmailAlreadyUsedException() { |
| | | super(ErrorConstants.EMAIL_ALREADY_USED_TYPE, "Email is already in use!", "userManagement", "emailexists"); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.rest.errors; |
| | | |
| | | import java.net.URI; |
| | | |
| | | public final class ErrorConstants { |
| | | |
| | | public static final String ERR_CONCURRENCY_FAILURE = "error.concurrencyFailure"; |
| | | public static final String ERR_VALIDATION = "error.validation"; |
| | | public static final String PROBLEM_BASE_URL = "https://www.jhipster.tech/problem"; |
| | | public static final URI DEFAULT_TYPE = URI.create(PROBLEM_BASE_URL + "/problem-with-message"); |
| | | public static final URI CONSTRAINT_VIOLATION_TYPE = URI.create(PROBLEM_BASE_URL + "/constraint-violation"); |
| | | public static final URI INVALID_PASSWORD_TYPE = URI.create(PROBLEM_BASE_URL + "/invalid-password"); |
| | | public static final URI EMAIL_ALREADY_USED_TYPE = URI.create(PROBLEM_BASE_URL + "/email-already-used"); |
| | | public static final URI LOGIN_ALREADY_USED_TYPE = URI.create(PROBLEM_BASE_URL + "/login-already-used"); |
| | | |
| | | private ErrorConstants() {} |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.rest.errors; |
| | | |
| | | import java.net.URI; |
| | | import java.util.Arrays; |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | 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.ResponseEntity; |
| | | import org.springframework.http.converter.HttpMessageConversionException; |
| | | 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.context.request.NativeWebRequest; |
| | | 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.util.HeaderUtil; |
| | | |
| | | /** |
| | | * Controller advice to translate the server side exceptions to client-friendly json structures. |
| | | * The error response follows RFC7807 - Problem Details for HTTP APIs (https://tools.ietf.org/html/rfc7807). |
| | | */ |
| | | @ControllerAdvice |
| | | 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 String VIOLATIONS_KEY = "violations"; |
| | | |
| | | @Value("${jhipster.clientApp.name}") |
| | | private String applicationName; |
| | | |
| | | private final Environment env; |
| | | |
| | | public ExceptionTranslator(Environment env) { |
| | | this.env = env; |
| | | } |
| | | |
| | | /** |
| | | * Post-process the Problem payload to add the message key for the front-end if needed. |
| | | */ |
| | | @Override |
| | | public ResponseEntity<Problem> process(@Nullable ResponseEntity<Problem> entity, NativeWebRequest request) { |
| | | if (entity == null) { |
| | | return null; |
| | | } |
| | | Problem problem = entity.getBody(); |
| | | if (!(problem instanceof ConstraintViolationProblem || problem instanceof DefaultProblem)) { |
| | | return entity; |
| | | } |
| | | |
| | | 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()); |
| | | } |
| | | } |
| | | return new ResponseEntity<>(builder.build(), entity.getHeaders(), entity.getStatusCode()); |
| | | } |
| | | |
| | | @Override |
| | | public ResponseEntity<Problem> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, @Nonnull NativeWebRequest request) { |
| | | BindingResult result = ex.getBindingResult(); |
| | | List<FieldErrorVM> fieldErrors = result |
| | | .getFieldErrors() |
| | | .stream() |
| | | .map(f -> |
| | | new FieldErrorVM( |
| | | f.getObjectName().replaceFirst("DTO$", ""), |
| | | f.getField(), |
| | | StringUtils.isNotBlank(f.getDefaultMessage()) ? f.getDefaultMessage() : f.getCode() |
| | | ) |
| | | ) |
| | | .collect(Collectors.toList()); |
| | | |
| | | 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); |
| | | } |
| | | |
| | | @ExceptionHandler |
| | | public ResponseEntity<Problem> handleEmailAlreadyUsedException( |
| | | com.pollex.pam.service.EmailAlreadyUsedException ex, |
| | | NativeWebRequest request |
| | | ) { |
| | | EmailAlreadyUsedException problem = new EmailAlreadyUsedException(); |
| | | return create( |
| | | problem, |
| | | request, |
| | | HeaderUtil.createFailureAlert(applicationName, true, problem.getEntityName(), problem.getErrorKey(), problem.getMessage()) |
| | | ); |
| | | } |
| | | |
| | | @ExceptionHandler |
| | | public ResponseEntity<Problem> handleUsernameAlreadyUsedException( |
| | | com.pollex.pam.service.UsernameAlreadyUsedException ex, |
| | | NativeWebRequest request |
| | | ) { |
| | | LoginAlreadyUsedException problem = new LoginAlreadyUsedException(); |
| | | return create( |
| | | problem, |
| | | request, |
| | | HeaderUtil.createFailureAlert(applicationName, true, problem.getEntityName(), problem.getErrorKey(), problem.getMessage()) |
| | | ); |
| | | } |
| | | |
| | | @ExceptionHandler |
| | | public ResponseEntity<Problem> handleInvalidPasswordException( |
| | | com.pollex.pam.service.InvalidPasswordException ex, |
| | | NativeWebRequest request |
| | | ) { |
| | | return create(new InvalidPasswordException(), request); |
| | | } |
| | | |
| | | @ExceptionHandler |
| | | public ResponseEntity<Problem> handleBadRequestAlertException(BadRequestAlertException ex, NativeWebRequest request) { |
| | | return create( |
| | | ex, |
| | | request, |
| | | HeaderUtil.createFailureAlert(applicationName, true, ex.getEntityName(), ex.getErrorKey(), ex.getMessage()) |
| | | ); |
| | | } |
| | | |
| | | @ExceptionHandler |
| | | public ResponseEntity<Problem> 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); |
| | | } |
| | | |
| | | @Override |
| | | public ProblemBuilder prepare(final Throwable throwable, final StatusType status, final URI type) { |
| | | Collection<String> activeProfiles = Arrays.asList(env.getActiveProfiles()); |
| | | |
| | | 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 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.", "javax.", "com.", "io.", "de.", "com.pollex.pam"); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.rest.errors; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | public class FieldErrorVM implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private final String objectName; |
| | | |
| | | private final String field; |
| | | |
| | | private final String message; |
| | | |
| | | public FieldErrorVM(String dto, String field, String message) { |
| | | this.objectName = dto; |
| | | this.field = field; |
| | | this.message = message; |
| | | } |
| | | |
| | | public String getObjectName() { |
| | | return objectName; |
| | | } |
| | | |
| | | public String getField() { |
| | | return field; |
| | | } |
| | | |
| | | public String getMessage() { |
| | | return message; |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.rest.errors; |
| | | |
| | | import org.zalando.problem.AbstractThrowableProblem; |
| | | import org.zalando.problem.Status; |
| | | |
| | | public class InvalidPasswordException extends AbstractThrowableProblem { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | public InvalidPasswordException() { |
| | | super(ErrorConstants.INVALID_PASSWORD_TYPE, "Incorrect password", Status.BAD_REQUEST); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.rest.errors; |
| | | |
| | | public class LoginAlreadyUsedException extends BadRequestAlertException { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | public LoginAlreadyUsedException() { |
| | | super(ErrorConstants.LOGIN_ALREADY_USED_TYPE, "Login name already used!", "userManagement", "userexists"); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | /** |
| | | * Specific errors used with Zalando's "problem-spring-web" library. |
| | | * |
| | | * More information on https://github.com/zalando/problem-spring-web |
| | | */ |
| | | package com.pollex.pam.web.rest.errors; |
¤ñ¹ï·sÀÉ®× |
| | |
| | | /** |
| | | * Spring MVC REST controllers. |
| | | */ |
| | | package com.pollex.pam.web.rest; |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.rest.vm; |
| | | |
| | | /** |
| | | * View Model object for storing the user's key and password. |
| | | */ |
| | | public class KeyAndPasswordVM { |
| | | |
| | | private String key; |
| | | |
| | | private String newPassword; |
| | | |
| | | public String getKey() { |
| | | return key; |
| | | } |
| | | |
| | | public void setKey(String key) { |
| | | this.key = key; |
| | | } |
| | | |
| | | public String getNewPassword() { |
| | | return newPassword; |
| | | } |
| | | |
| | | public void setNewPassword(String newPassword) { |
| | | this.newPassword = newPassword; |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.rest.vm; |
| | | |
| | | import javax.validation.constraints.NotNull; |
| | | import javax.validation.constraints.Size; |
| | | |
| | | /** |
| | | * View Model object for storing a user's credentials. |
| | | */ |
| | | public class LoginVM { |
| | | |
| | | @NotNull |
| | | @Size(min = 1, max = 50) |
| | | private String username; |
| | | |
| | | @NotNull |
| | | @Size(min = 4, max = 100) |
| | | private String password; |
| | | |
| | | private boolean rememberMe; |
| | | |
| | | public String getUsername() { |
| | | return username; |
| | | } |
| | | |
| | | public void setUsername(String username) { |
| | | this.username = username; |
| | | } |
| | | |
| | | public String getPassword() { |
| | | return password; |
| | | } |
| | | |
| | | public void setPassword(String password) { |
| | | this.password = password; |
| | | } |
| | | |
| | | public boolean isRememberMe() { |
| | | return rememberMe; |
| | | } |
| | | |
| | | public void setRememberMe(boolean rememberMe) { |
| | | this.rememberMe = rememberMe; |
| | | } |
| | | |
| | | // prettier-ignore |
| | | @Override |
| | | public String toString() { |
| | | return "LoginVM{" + |
| | | "username='" + username + '\'' + |
| | | ", rememberMe=" + rememberMe + |
| | | '}'; |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.rest.vm; |
| | | |
| | | import com.pollex.pam.service.dto.AdminUserDTO; |
| | | import javax.validation.constraints.Size; |
| | | |
| | | /** |
| | | * View Model extending the AdminUserDTO, which is meant to be used in the user management UI. |
| | | */ |
| | | public class ManagedUserVM extends AdminUserDTO { |
| | | |
| | | public static final int PASSWORD_MIN_LENGTH = 4; |
| | | |
| | | public static final int PASSWORD_MAX_LENGTH = 100; |
| | | |
| | | @Size(min = PASSWORD_MIN_LENGTH, max = PASSWORD_MAX_LENGTH) |
| | | private String password; |
| | | |
| | | public ManagedUserVM() { |
| | | // Empty constructor needed for Jackson. |
| | | } |
| | | |
| | | public String getPassword() { |
| | | return password; |
| | | } |
| | | |
| | | public void setPassword(String password) { |
| | | this.password = password; |
| | | } |
| | | |
| | | // prettier-ignore |
| | | @Override |
| | | public String toString() { |
| | | return "ManagedUserVM{" + super.toString() + "} "; |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | /** |
| | | * View Models used by Spring MVC REST controllers. |
| | | */ |
| | | package com.pollex.pam.web.rest.vm; |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.websocket; |
| | | |
| | | import static com.pollex.pam.config.WebsocketConfiguration.IP_ADDRESS; |
| | | |
| | | import com.pollex.pam.web.websocket.dto.ActivityDTO; |
| | | import java.security.Principal; |
| | | import java.time.Instant; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.context.ApplicationListener; |
| | | import org.springframework.messaging.handler.annotation.*; |
| | | import org.springframework.messaging.simp.SimpMessageSendingOperations; |
| | | import org.springframework.messaging.simp.stomp.StompHeaderAccessor; |
| | | import org.springframework.stereotype.Controller; |
| | | import org.springframework.web.socket.messaging.SessionDisconnectEvent; |
| | | |
| | | @Controller |
| | | public class ActivityService implements ApplicationListener<SessionDisconnectEvent> { |
| | | |
| | | private static final Logger log = LoggerFactory.getLogger(ActivityService.class); |
| | | |
| | | private final SimpMessageSendingOperations messagingTemplate; |
| | | |
| | | public ActivityService(SimpMessageSendingOperations messagingTemplate) { |
| | | this.messagingTemplate = messagingTemplate; |
| | | } |
| | | |
| | | @MessageMapping("/topic/activity") |
| | | @SendTo("/topic/tracker") |
| | | public ActivityDTO sendActivity(@Payload ActivityDTO activityDTO, StompHeaderAccessor stompHeaderAccessor, Principal principal) { |
| | | activityDTO.setUserLogin(principal.getName()); |
| | | activityDTO.setSessionId(stompHeaderAccessor.getSessionId()); |
| | | activityDTO.setIpAddress(stompHeaderAccessor.getSessionAttributes().get(IP_ADDRESS).toString()); |
| | | activityDTO.setTime(Instant.now()); |
| | | log.debug("Sending user tracking data {}", activityDTO); |
| | | return activityDTO; |
| | | } |
| | | |
| | | @Override |
| | | public void onApplicationEvent(SessionDisconnectEvent event) { |
| | | ActivityDTO activityDTO = new ActivityDTO(); |
| | | activityDTO.setSessionId(event.getSessionId()); |
| | | activityDTO.setPage("logout"); |
| | | messagingTemplate.convertAndSend("/topic/tracker", activityDTO); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.websocket.dto; |
| | | |
| | | import java.time.Instant; |
| | | |
| | | /** |
| | | * DTO for storing a user's activity. |
| | | */ |
| | | public class ActivityDTO { |
| | | |
| | | private String sessionId; |
| | | |
| | | private String userLogin; |
| | | |
| | | private String ipAddress; |
| | | |
| | | private String page; |
| | | |
| | | private Instant time; |
| | | |
| | | public String getSessionId() { |
| | | return sessionId; |
| | | } |
| | | |
| | | public void setSessionId(String sessionId) { |
| | | this.sessionId = sessionId; |
| | | } |
| | | |
| | | public String getUserLogin() { |
| | | return userLogin; |
| | | } |
| | | |
| | | public void setUserLogin(String userLogin) { |
| | | this.userLogin = userLogin; |
| | | } |
| | | |
| | | public String getIpAddress() { |
| | | return ipAddress; |
| | | } |
| | | |
| | | public void setIpAddress(String ipAddress) { |
| | | this.ipAddress = ipAddress; |
| | | } |
| | | |
| | | public String getPage() { |
| | | return page; |
| | | } |
| | | |
| | | public void setPage(String page) { |
| | | this.page = page; |
| | | } |
| | | |
| | | public Instant getTime() { |
| | | return time; |
| | | } |
| | | |
| | | public void setTime(Instant time) { |
| | | this.time = time; |
| | | } |
| | | |
| | | // prettier-ignore |
| | | @Override |
| | | public String toString() { |
| | | return "ActivityDTO{" + |
| | | "sessionId='" + sessionId + '\'' + |
| | | ", userLogin='" + userLogin + '\'' + |
| | | ", ipAddress='" + ipAddress + '\'' + |
| | | ", page='" + page + '\'' + |
| | | ", time='" + time + '\'' + |
| | | '}'; |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | /** |
| | | * Data Access Objects used by WebSocket services. |
| | | */ |
| | | package com.pollex.pam.web.websocket.dto; |
¤ñ¹ï·sÀÉ®× |
| | |
| | | /** |
| | | * WebSocket services, using Spring Websocket. |
| | | */ |
| | | package com.pollex.pam.web.websocket; |
¤ñ¹ï·sÀÉ®× |
| | |
| | | |
| | | ${AnsiColor.GREEN} âââ${AnsiColor.RED} âââ âââ âââââââââ ââââââââ âââââââ âââââââââ âââââââââ ââââââââ |
| | | ${AnsiColor.GREEN} âââ${AnsiColor.RED} âââ âââ âââââââââ âââââââââ ââââââââ âââââââââ âââââââââ âââââââââ |
| | | ${AnsiColor.GREEN} âââ${AnsiColor.RED} âââââââââ âââ âââââââââ âââââââ âââ âââââââ âââââââââ |
| | | ${AnsiColor.GREEN}âââ âââ${AnsiColor.RED} âââââââââ âââ ââââââââ âââââââ âââ âââââââ ââââââââ |
| | | ${AnsiColor.GREEN}âââââââââ${AnsiColor.RED} âââ âââ âââââââââ âââ ââââââââ âââ âââââââââ âââ ââââ |
| | | ${AnsiColor.GREEN} âââââââ ${AnsiColor.RED} âââ âââ âââââââââ âââ âââââââ âââ âââââââââ âââ âââ |
| | | |
| | | ${AnsiColor.BRIGHT_BLUE}:: JHipster ð¤ :: Running Spring Boot ${spring-boot.version} :: |
| | | :: https://www.jhipster.tech ::${AnsiColor.DEFAULT} |
¤ñ¹ï·sÀÉ®× |
| | |
| | | # =================================================================== |
| | | # Spring Boot configuration for the "dev" profile. |
| | | # |
| | | # This configuration overrides the application.yml file. |
| | | # |
| | | # More information on profiles: https://www.jhipster.tech/profiles/ |
| | | # More information on configuration properties: https://www.jhipster.tech/common-application-properties/ |
| | | # =================================================================== |
| | | |
| | | # =================================================================== |
| | | # Standard Spring Boot properties. |
| | | # Full reference is available at: |
| | | # http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html |
| | | # =================================================================== |
| | | |
| | | logging: |
| | | level: |
| | | ROOT: DEBUG |
| | | tech.jhipster: DEBUG |
| | | org.hibernate.SQL: DEBUG |
| | | com.pollex.pam: DEBUG |
| | | |
| | | spring: |
| | | devtools: |
| | | restart: |
| | | enabled: true |
| | | additional-exclude: static/** |
| | | livereload: |
| | | enabled: false # we use Webpack dev server + BrowserSync for livereload |
| | | jackson: |
| | | serialization: |
| | | indent-output: true |
| | | datasource: |
| | | type: com.zaxxer.hikari.HikariDataSource |
| | | url: jdbc:postgresql://localhost:5432/pamapi |
| | | username: pamapi |
| | | password: |
| | | hikari: |
| | | poolName: Hikari |
| | | auto-commit: false |
| | | jpa: |
| | | database-platform: tech.jhipster.domain.util.FixedPostgreSQL10Dialect |
| | | liquibase: |
| | | # Remove 'faker' if you do not want the sample data to be loaded automatically |
| | | contexts: dev, faker |
| | | mail: |
| | | host: localhost |
| | | port: 25 |
| | | username: |
| | | password: |
| | | messages: |
| | | cache-duration: PT1S # 1 second, see the ISO 8601 standard |
| | | thymeleaf: |
| | | cache: false |
| | | sleuth: |
| | | sampler: |
| | | probability: 1 # report 100% of traces |
| | | zipkin: # Use the "zipkin" Maven profile to have the Spring Cloud Zipkin dependencies |
| | | base-url: http://localhost:9411 |
| | | enabled: false |
| | | locator: |
| | | discovery: |
| | | enabled: true |
| | | |
| | | server: |
| | | port: 8080 |
| | | |
| | | # =================================================================== |
| | | # JHipster specific properties |
| | | # |
| | | # Full reference is available at: https://www.jhipster.tech/common-application-properties/ |
| | | # =================================================================== |
| | | |
| | | jhipster: |
| | | cache: # Cache configuration |
| | | ehcache: # Ehcache configuration |
| | | time-to-live-seconds: 3600 # By default objects stay 1 hour in the cache |
| | | max-entries: 100 # Number of objects in each cache entry |
| | | # 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' |
| | | allowed-methods: '*' |
| | | allowed-headers: '*' |
| | | exposed-headers: 'Authorization,Link,X-Total-Count,X-${jhipster.clientApp.name}-alert,X-${jhipster.clientApp.name}-error,X-${jhipster.clientApp.name}-params' |
| | | allow-credentials: true |
| | | max-age: 1800 |
| | | security: |
| | | authentication: |
| | | 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) |
| | | base64-secret: MjI3YWRiMzg1ZTY3ZmZkZDgxZmI5Yjc5YjVkOTIzMzc4MmI2OWM3NWVkZjFiOTNmNjg0YWFjZWQ4YzhlOTUzYzk3MGUzMzM5Y2U5MDdkZTMyN2Q0N2E0M2ZmM2FhYzkyNDY4MjBkYTY5OGM4YmIzMmYxODJhNWFkMmVhNmVhNTM= |
| | | # Token is valid 24 hours |
| | | token-validity-in-seconds: 86400 |
| | | token-validity-in-seconds-for-remember-me: 2592000 |
| | | mail: # specific JHipster mail property, for standard properties see MailProperties |
| | | base-url: http://127.0.0.1:8080 |
| | | logging: |
| | | use-json-format: false # By default, logs are not in Json format |
| | | logstash: # Forward logs to logstash over a socket, used by LoggingConfiguration |
| | | enabled: false |
| | | host: localhost |
| | | port: 5000 |
| | | queue-size: 512 |
| | | # =================================================================== |
| | | # Application specific properties |
| | | # Add your own application properties here, see the ApplicationProperties class |
| | | # to have type-safe configuration, like in the JHipsterProperties above |
| | | # |
| | | # More documentation is available at: |
| | | # https://www.jhipster.tech/common-application-properties/ |
| | | # =================================================================== |
| | | |
| | | # application: |
¤ñ¹ï·sÀÉ®× |
| | |
| | | # =================================================================== |
| | | # Spring Boot configuration for the "prod" profile. |
| | | # |
| | | # This configuration overrides the application.yml file. |
| | | # |
| | | # More information on profiles: https://www.jhipster.tech/profiles/ |
| | | # More information on configuration properties: https://www.jhipster.tech/common-application-properties/ |
| | | # =================================================================== |
| | | |
| | | # =================================================================== |
| | | # Standard Spring Boot properties. |
| | | # Full reference is available at: |
| | | # http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html |
| | | # =================================================================== |
| | | |
| | | logging: |
| | | level: |
| | | ROOT: INFO |
| | | tech.jhipster: INFO |
| | | com.pollex.pam: INFO |
| | | |
| | | management: |
| | | metrics: |
| | | export: |
| | | prometheus: |
| | | enabled: false |
| | | |
| | | spring: |
| | | devtools: |
| | | restart: |
| | | enabled: false |
| | | livereload: |
| | | enabled: false |
| | | datasource: |
| | | type: com.zaxxer.hikari.HikariDataSource |
| | | url: jdbc:postgresql://localhost:5432/pamapi |
| | | username: pamapi |
| | | password: |
| | | 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 |
| | | mail: |
| | | host: localhost |
| | | port: 25 |
| | | username: |
| | | password: |
| | | thymeleaf: |
| | | cache: true |
| | | sleuth: |
| | | sampler: |
| | | probability: 1 # report 100% of traces |
| | | zipkin: # Use the "zipkin" Maven profile to have the Spring Cloud Zipkin dependencies |
| | | base-url: http://localhost:9411 |
| | | enabled: false |
| | | locator: |
| | | discovery: |
| | | enabled: true |
| | | |
| | | # =================================================================== |
| | | # To enable TLS in production, generate a certificate using: |
| | | # keytool -genkey -alias pamapi -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 3650 |
| | | # |
| | | # You can also use Let's Encrypt: |
| | | # https://maximilian-boehm.com/hp2121/Create-a-Java-Keystore-JKS-from-Let-s-Encrypt-Certificates.htm |
| | | # |
| | | # Then, modify the server.ssl properties so your "server" configuration looks like: |
| | | # |
| | | # server: |
| | | # port: 443 |
| | | # ssl: |
| | | # key-store: classpath:config/tls/keystore.p12 |
| | | # key-store-password: password |
| | | # key-store-type: PKCS12 |
| | | # key-alias: selfsigned |
| | | # # The ciphers suite enforce the security by deactivating some old and deprecated SSL cipher, this list was tested against SSL Labs (https://www.ssllabs.com/ssltest/) |
| | | # ciphers: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 ,TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,TLS_RSA_WITH_CAMELLIA_128_CBC_SHA |
| | | # =================================================================== |
| | | server: |
| | | port: 8080 |
| | | shutdown: graceful # see https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-graceful-shutdown |
| | | compression: |
| | | enabled: true |
| | | mime-types: text/html,text/xml,text/plain,text/css,application/javascript,application/json,image/svg+xml |
| | | min-response-size: 1024 |
| | | |
| | | # =================================================================== |
| | | # JHipster specific properties |
| | | # |
| | | # Full reference is available at: https://www.jhipster.tech/common-application-properties/ |
| | | # =================================================================== |
| | | |
| | | jhipster: |
| | | http: |
| | | cache: # Used by the CachingHttpHeadersFilter |
| | | timeToLiveInDays: 1461 |
| | | cache: # Cache configuration |
| | | ehcache: # Ehcache configuration |
| | | time-to-live-seconds: 3600 # By default objects stay 1 hour in the cache |
| | | max-entries: 1000 # Number of objects in each cache entry |
| | | security: |
| | | authentication: |
| | | 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 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: MjI3YWRiMzg1ZTY3ZmZkZDgxZmI5Yjc5YjVkOTIzMzc4MmI2OWM3NWVkZjFiOTNmNjg0YWFjZWQ4YzhlOTUzYzk3MGUzMzM5Y2U5MDdkZTMyN2Q0N2E0M2ZmM2FhYzkyNDY4MjBkYTY5OGM4YmIzMmYxODJhNWFkMmVhNmVhNTM= |
| | | # Token is valid 24 hours |
| | | token-validity-in-seconds: 86400 |
| | | token-validity-in-seconds-for-remember-me: 2592000 |
| | | mail: # specific JHipster mail property, for standard properties see MailProperties |
| | | base-url: http://my-server-url-to-change # Modify according to your server's URL |
| | | logging: |
| | | use-json-format: false # By default, logs are not in Json format |
| | | logstash: # Forward logs to logstash over a socket, used by LoggingConfiguration |
| | | enabled: false |
| | | host: localhost |
| | | port: 5000 |
| | | queue-size: 512 |
| | | # =================================================================== |
| | | # Application specific properties |
| | | # Add your own application properties here, see the ApplicationProperties class |
| | | # to have type-safe configuration, like in the JHipsterProperties above |
| | | # |
| | | # More documentation is available at: |
| | | # https://www.jhipster.tech/common-application-properties/ |
| | | # =================================================================== |
| | | |
| | | # application: |
¤ñ¹ï·sÀÉ®× |
| | |
| | | # =================================================================== |
| | | # Activate this profile to enable TLS and HTTP/2. |
| | | # |
| | | # JHipster has generated a self-signed certificate, which will be used to encrypt traffic. |
| | | # As your browser will not understand this certificate, you will need to import it. |
| | | # |
| | | # Another (easiest) solution with Chrome is to enable the "allow-insecure-localhost" flag |
| | | # at chrome://flags/#allow-insecure-localhost |
| | | # =================================================================== |
| | | server: |
| | | ssl: |
| | | key-store: classpath:config/tls/keystore.p12 |
| | | key-store-password: password |
| | | key-store-type: PKCS12 |
| | | key-alias: selfsigned |
| | | ciphers: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA |
| | | enabled-protocols: TLSv1.2 |
| | | http2: |
| | | enabled: true |
¤ñ¹ï·sÀÉ®× |
| | |
| | | # =================================================================== |
| | | # Spring Boot configuration. |
| | | # |
| | | # This configuration will be overridden by the Spring profile you use, |
| | | # for example application-dev.yml if you use the "dev" profile. |
| | | # |
| | | # More information on profiles: https://www.jhipster.tech/profiles/ |
| | | # More information on configuration properties: https://www.jhipster.tech/common-application-properties/ |
| | | # =================================================================== |
| | | |
| | | # =================================================================== |
| | | # Standard Spring Boot properties. |
| | | # Full reference is available at: |
| | | # http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html |
| | | # =================================================================== |
| | | |
| | | management: |
| | | endpoints: |
| | | web: |
| | | base-path: /management |
| | | exposure: |
| | | include: |
| | | ['configprops', 'env', 'health', 'info', 'jhimetrics', 'logfile', 'loggers', 'prometheus', 'threaddump', 'caches', 'liquibase'] |
| | | endpoint: |
| | | health: |
| | | show-details: when_authorized |
| | | roles: 'ROLE_ADMIN' |
| | | probes: |
| | | enabled: true |
| | | jhimetrics: |
| | | enabled: true |
| | | info: |
| | | git: |
| | | mode: full |
| | | health: |
| | | group: |
| | | liveness: |
| | | include: livenessState |
| | | readiness: |
| | | include: readinessState,db |
| | | mail: |
| | | enabled: false # When using the MailService, configure an SMTP server and set this to true |
| | | metrics: |
| | | export: |
| | | # Prometheus is the default metrics backend |
| | | prometheus: |
| | | enabled: true |
| | | step: 60 |
| | | enable: |
| | | http: true |
| | | jvm: true |
| | | logback: true |
| | | process: true |
| | | system: true |
| | | distribution: |
| | | percentiles-histogram: |
| | | all: true |
| | | percentiles: |
| | | all: 0, 0.5, 0.75, 0.95, 0.99, 1.0 |
| | | tags: |
| | | application: ${spring.application.name} |
| | | web: |
| | | server: |
| | | request: |
| | | autotime: |
| | | enabled: true |
| | | |
| | | spring: |
| | | application: |
| | | name: pamapi |
| | | profiles: |
| | | # The commented value for `active` can be replaced with valid Spring profiles to load. |
| | | # Otherwise, it will be filled in by maven when building the JAR file |
| | | # Either way, it can be overridden by `--spring.profiles.active` value passed in the commandline or `-Dspring.profiles.active` set in `JAVA_OPTS` |
| | | active: #spring.profiles.active# |
| | | group: |
| | | dev: |
| | | - dev |
| | | - api-docs |
| | | # Uncomment to activate TLS for the dev profile |
| | | #- tls |
| | | jmx: |
| | | enabled: false |
| | | data: |
| | | jpa: |
| | | repositories: |
| | | bootstrap-mode: deferred |
| | | jpa: |
| | | open-in-view: false |
| | | properties: |
| | | hibernate.jdbc.time_zone: UTC |
| | | hibernate.id.new_generator_mappings: true |
| | | hibernate.connection.provider_disables_autocommit: true |
| | | hibernate.cache.use_second_level_cache: true |
| | | hibernate.cache.use_query_cache: false |
| | | hibernate.generate_statistics: false |
| | | # modify batch size as necessary |
| | | hibernate.jdbc.batch_size: 25 |
| | | hibernate.order_inserts: true |
| | | hibernate.order_updates: true |
| | | hibernate.query.fail_on_pagination_over_collection_fetch: true |
| | | hibernate.query.in_clause_parameter_padding: true |
| | | hibernate: |
| | | ddl-auto: none |
| | | naming: |
| | | 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 |
| | | task: |
| | | execution: |
| | | thread-name-prefix: pamapi-task- |
| | | pool: |
| | | core-size: 2 |
| | | max-size: 50 |
| | | queue-capacity: 10000 |
| | | scheduling: |
| | | thread-name-prefix: pamapi-scheduling- |
| | | pool: |
| | | size: 2 |
| | | thymeleaf: |
| | | mode: HTML |
| | | output: |
| | | ansi: |
| | | console-available: true |
| | | |
| | | server: |
| | | servlet: |
| | | session: |
| | | cookie: |
| | | http-only: true |
| | | |
| | | # Properties to be exposed on the /info management endpoint |
| | | info: |
| | | # Comma separated list of profiles that will trigger the ribbon to show |
| | | display-ribbon-on-profiles: 'dev' |
| | | |
| | | # =================================================================== |
| | | # JHipster specific properties |
| | | # |
| | | # Full reference is available at: https://www.jhipster.tech/common-application-properties/ |
| | | # =================================================================== |
| | | |
| | | jhipster: |
| | | clientApp: |
| | | name: 'pamapiApp' |
| | | # By default CORS is disabled. Uncomment to enable. |
| | | # cors: |
| | | # allowed-origins: "http://localhost:8100,http://localhost:9000" |
| | | # allowed-methods: "*" |
| | | # allowed-headers: "*" |
| | | # exposed-headers: "Authorization,Link,X-Total-Count,X-${jhipster.clientApp.name}-alert,X-${jhipster.clientApp.name}-error,X-${jhipster.clientApp.name}-params" |
| | | # allow-credentials: true |
| | | # max-age: 1800 |
| | | mail: |
| | | from: pamapi@localhost |
| | | api-docs: |
| | | default-include-pattern: ${server.servlet.context-path:}/api/.* |
| | | management-include-pattern: ${server.servlet.context-path:}/management/.* |
| | | title: Pamapi API |
| | | description: Pamapi API documentation |
| | | version: 0.0.1 |
| | | terms-of-service-url: |
| | | contact-name: |
| | | contact-url: |
| | | contact-email: |
| | | license: unlicensed |
| | | license-url: |
| | | security: |
| | | content-security-policy: "default-src 'self'; frame-src 'self' data:; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://storage.googleapis.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:" |
| | | # =================================================================== |
| | | # Application specific properties |
| | | # Add your own application properties here, see the ApplicationProperties class |
| | | # to have type-safe configuration, like in the JHipsterProperties above |
| | | # |
| | | # More documentation is available at: |
| | | # https://www.jhipster.tech/common-application-properties/ |
| | | # =================================================================== |
| | | |
| | | # application: |
¤ñ¹ï·sÀÉ®× |
| | |
| | | # =================================================================== |
| | | # Spring Cloud Config bootstrap configuration for the "prod" profile |
| | | # =================================================================== |
| | | |
| | | spring: |
| | | cloud: |
¤ñ¹ï·sÀÉ®× |
| | |
| | | # =================================================================== |
| | | # Spring Cloud Config bootstrap configuration for the "dev" profile |
| | | # In prod profile, properties will be overwritten by the ones defined in bootstrap-prod.yml |
| | | # =================================================================== |
| | | |
| | | spring: |
| | | application: |
| | | name: pamapi |
| | | profiles: |
| | | # The commented value for `active` can be replaced with valid Spring profiles to load. |
| | | # Otherwise, it will be filled in by maven when building the JAR file |
| | | # Either way, it can be overridden by `--spring.profiles.active` value passed in the commandline or `-Dspring.profiles.active` set in `JAVA_OPTS` |
| | | active: #spring.profiles.active# |
| | | cloud: |
¤ñ¹ï·sÀÉ®× |
| | |
| | | <?xml version="1.0" encoding="utf-8"?> |
| | | <databaseChangeLog |
| | | xmlns="http://www.liquibase.org/xml/ns/dbchangelog" |
| | | xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.5.xsd |
| | | http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd"> |
| | | |
| | | <changeSet id="00000000000000" author="jhipster"> |
| | | <createSequence sequenceName="sequence_generator" startValue="1050" incrementBy="50"/> |
| | | </changeSet> |
| | | |
| | | <!-- |
| | | JHipster core tables. |
| | | The initial schema has the '00000000000001' id, so that it is over-written if we re-generate it. |
| | | --> |
| | | <changeSet id="00000000000001" author="jhipster"> |
| | | <createTable tableName="jhi_user"> |
| | | <column name="id" type="bigint"> |
| | | <constraints primaryKey="true" nullable="false"/> |
| | | </column> |
| | | <column name="login" type="varchar(50)"> |
| | | <constraints unique="true" nullable="false" uniqueConstraintName="ux_user_login"/> |
| | | </column> |
| | | <column name="password_hash" type="varchar(60)"/> |
| | | <column name="first_name" type="varchar(50)"/> |
| | | <column name="last_name" type="varchar(50)"/> |
| | | <column name="email" type="varchar(191)"> |
| | | <constraints unique="true" nullable="true" uniqueConstraintName="ux_user_email"/> |
| | | </column> |
| | | <column name="image_url" type="varchar(256)"/> |
| | | <column name="activated" type="boolean" valueBoolean="false"> |
| | | <constraints nullable="false" /> |
| | | </column> |
| | | <column name="lang_key" type="varchar(10)"/> |
| | | <column name="activation_key" type="varchar(20)"/> |
| | | <column name="reset_key" type="varchar(20)"/> |
| | | <column name="created_by" type="varchar(50)"> |
| | | <constraints nullable="false"/> |
| | | </column> |
| | | <column name="created_date" type="timestamp"/> |
| | | <column name="reset_date" type="timestamp"> |
| | | <constraints nullable="true"/> |
| | | </column> |
| | | <column name="last_modified_by" type="varchar(50)"/> |
| | | <column name="last_modified_date" type="timestamp"/> |
| | | </createTable> |
| | | |
| | | <createTable tableName="jhi_authority"> |
| | | <column name="name" type="varchar(50)"> |
| | | <constraints primaryKey="true" nullable="false"/> |
| | | </column> |
| | | </createTable> |
| | | |
| | | <createTable tableName="jhi_user_authority"> |
| | | <column name="user_id" type="bigint"> |
| | | <constraints nullable="false"/> |
| | | </column> |
| | | <column name="authority_name" type="varchar(50)"> |
| | | <constraints nullable="false"/> |
| | | </column> |
| | | </createTable> |
| | | |
| | | <addPrimaryKey columnNames="user_id, authority_name" tableName="jhi_user_authority"/> |
| | | |
| | | <addForeignKeyConstraint baseColumnNames="authority_name" |
| | | baseTableName="jhi_user_authority" |
| | | constraintName="fk_authority_name" |
| | | referencedColumnNames="name" |
| | | referencedTableName="jhi_authority"/> |
| | | |
| | | <addForeignKeyConstraint baseColumnNames="user_id" |
| | | baseTableName="jhi_user_authority" |
| | | constraintName="fk_user_id" |
| | | referencedColumnNames="id" |
| | | referencedTableName="jhi_user"/> |
| | | |
| | | <addNotNullConstraint columnName="password_hash" |
| | | columnDataType="varchar(60)" |
| | | tableName="jhi_user"/> |
| | | <loadData |
| | | file="config/liquibase/data/user.csv" |
| | | separator=";" |
| | | tableName="jhi_user" |
| | | usePreparedStatements="true"> |
| | | <column name="id" type="numeric"/> |
| | | <column name="activated" type="boolean"/> |
| | | <column name="created_date" type="timestamp"/> |
| | | </loadData> |
| | | <dropDefaultValue tableName="jhi_user" columnName="created_date" columnDataType="${datetimeType}"/> |
| | | <loadData |
| | | file="config/liquibase/data/authority.csv" |
| | | separator=";" |
| | | tableName="jhi_authority" |
| | | usePreparedStatements="true"> |
| | | <column name="name" type="string"/> |
| | | </loadData> |
| | | <loadData |
| | | file="config/liquibase/data/user_authority.csv" |
| | | separator=";" |
| | | tableName="jhi_user_authority" |
| | | usePreparedStatements="true"> |
| | | <column name="user_id" type="numeric"/> |
| | | </loadData> |
| | | </changeSet> |
| | | |
| | | <changeSet author="jhipster" id="00000000000002" context="test"> |
| | | <createTable tableName="jhi_date_time_wrapper"> |
| | | <column name="id" type="BIGINT"> |
| | | <constraints primaryKey="true" primaryKeyName="jhi_date_time_wrapperPK"/> |
| | | </column> |
| | | <column name="instant" type="timestamp"/> |
| | | <column name="local_date_time" type="timestamp"/> |
| | | <column name="offset_date_time" type="timestamp"/> |
| | | <column name="zoned_date_time" type="timestamp"/> |
| | | <column name="local_time" type="time"/> |
| | | <column name="offset_time" type="time"/> |
| | | <column name="local_date" type="date"/> |
| | | </createTable> |
| | | </changeSet> |
| | | </databaseChangeLog> |
¤ñ¹ï·sÀÉ®× |
| | |
| | | name |
| | | ROLE_ADMIN |
| | | ROLE_USER |
¤ñ¹ï·sÀÉ®× |
| | |
| | | id;login;password_hash;first_name;last_name;email;image_url;activated;lang_key;created_by;last_modified_by |
| | | 1;admin;$2a$10$gSAhZrxMllrbgj/kkK9UceBPpChGWJA7SYIb1Mqo.n5aNLq1/oRrC;Administrator;Administrator;admin@localhost;;true;zh-tw;system;system |
| | | 2;user;$2a$10$VEjxo0jq2YG9Rbk2HmX9S.k1uZBGYUHdUcid3g/vfiEl7lwWgOH/K;User;User;user@localhost;;true;zh-tw;system;system |
¤ñ¹ï·sÀÉ®× |
| | |
| | | user_id;authority_name |
| | | 1;ROLE_ADMIN |
| | | 1;ROLE_USER |
| | | 2;ROLE_USER |
¤ñ¹ï·sÀÉ®× |
| | |
| | | <?xml version="1.0" encoding="utf-8"?> |
| | | <databaseChangeLog |
| | | xmlns="http://www.liquibase.org/xml/ns/dbchangelog" |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.5.xsd"> |
| | | |
| | | <property name="now" value="now()" dbms="h2"/> |
| | | <property name="now" value="current_timestamp" dbms="postgresql"/> |
| | | <property name="floatType" value="float4" dbms="postgresql, h2"/> |
| | | <property name="floatType" value="float" dbms="mysql, oracle, mssql, mariadb"/> |
| | | <property name="clobType" value="longvarchar" dbms="h2"/> |
| | | <property name="clobType" value="clob" dbms="mysql, oracle, mssql, mariadb, postgresql"/> |
| | | <property name="uuidType" value="uuid" dbms="h2, postgresql"/> |
| | | <property name="datetimeType" value="datetime(6)" dbms="mysql, mariadb"/> |
| | | <property name="datetimeType" value="datetime" dbms="oracle, mssql, postgresql, h2"/> |
| | | |
| | | <include file="config/liquibase/changelog/00000000000000_initial_schema.xml" relativeToChangelogFile="false"/> |
| | | <!-- jhipster-needle-liquibase-add-changelog - JHipster will add liquibase changelogs here --> |
| | | <!-- jhipster-needle-liquibase-add-constraints-changelog - JHipster will add liquibase constraints changelogs here --> |
| | | <!-- jhipster-needle-liquibase-add-incremental-changelog - JHipster will add incremental liquibase changelogs here --> |
| | | </databaseChangeLog> |
¤ñ¹ï·sÀÉ®× |
| | |
| | | # Error page |
| | | error.title=Your request cannot be processed |
| | | error.subtitle=Sorry, an error has occurred. |
| | | error.status=Status: |
| | | error.message=Message: |
| | | |
| | | # Activation email |
| | | email.activation.title=pamapi account activation is required |
| | | email.activation.greeting=Dear {0} |
| | | email.activation.text1=Your pamapi account has been created, please click on the URL below to activate it: |
| | | email.activation.text2=Regards, |
| | | email.signature=pamapi Team. |
| | | |
| | | # Creation email |
| | | email.creation.text1=Your pamapi account has been created, please click on the URL below to access it: |
| | | |
| | | # Reset email |
| | | email.reset.title=pamapi password reset |
| | | email.reset.greeting=Dear {0} |
| | | email.reset.text1=For your pamapi account a password reset was requested, please click on the URL below to reset it: |
| | | email.reset.text2=Regards, |
¤ñ¹ï·sÀÉ®× |
| | |
| | | # Error page |
| | | error.title=Your request cannot be processed |
| | | error.subtitle=Sorry, an error has occurred. |
| | | error.status=Status: |
| | | error.message=Message: |
| | | |
| | | # Activation email |
| | | email.activation.title=pamapi account activation |
| | | email.activation.greeting=Dear {0} |
| | | email.activation.text1=Your pamapi account has been created, please click on the URL below to activate it: |
| | | email.activation.text2=Regards, |
| | | email.signature=pamapi Team. |
| | | |
| | | # Creation email |
| | | email.creation.text1=Your pamapi account has been created, please click on the URL below to access it: |
| | | |
| | | # Reset email |
| | | email.reset.title=pamapi password reset |
| | | email.reset.greeting=Dear {0} |
| | | email.reset.text1=For your pamapi account a password reset was requested, please click on the URL below to reset it: |
| | | email.reset.text2=Regards, |
¤ñ¹ï·sÀÉ®× |
| | |
| | | # Error page |
| | | error.title=\u7121\u6CD5\u8655\u7406\u60A8\u7684\u8981\u6C42 |
| | | error.subtitle=\u5F88\u62B1\u6B49\uFF0C\u6211\u5011\u9047\u5230\u4E86\u4E00\u4E9B\u554F\u984C\u3002 |
| | | error.status=\u72C0\u614B: |
| | | error.message=\u8A0A\u606F: |
| | | |
| | | # Activation email |
| | | email.activation.title=pamapi \u5E33\u865F\u555F\u7528 |
| | | email.activation.greeting=\u89AA\u611B\u7684 {0} |
| | | email.activation.text1=\u60A8\u7684 pamapi \u5E33\u865F\u5EFA\u7ACB\u6210\u529F\uFF0C\u8ACB\u9EDE\u4E0B\u5217\u7DB2\u5740\u555F\u7528\u5E33\u865F: |
| | | email.activation.text2=\u795D\u60A8\u4F7F\u7528\u6109\u5FEB\uFF0C |
| | | email.signature=pamapi \u5718\u968A\u3002 |
| | | |
| | | # Creation email |
| | | email.creation.text1=\u60A8\u7684 pamapi \u5E33\u865F\u5EFA\u7ACB\u6210\u529F\uFF0C\u8ACB\u9EDE\u4E0B\u5217\u7DB2\u5740\u958B\u59CB\u4F7F\u7528: |
| | | |
| | | # Reset email |
| | | email.reset.title=pamapi \u5BC6\u78BC\u91CD\u8A2D |
| | | email.reset.greeting=\u89AA\u611B\u7684 {0} |
| | | email.reset.text1=\u60A8\u7684 pamapi \u5E33\u865F\u88AB\u8981\u6C42\u91CD\u65B0\u8A2D\u5B9A\u5BC6\u78BC\uFF0C\u8ACB\u9EDE\u4E0B\u5217\u7DB2\u5740\u8A2D\u5B9A: |
| | | email.reset.text2=\u795D\u60A8\u4F7F\u7528\u6109\u5FEB\uFF0C |
¤ñ¹ï·sÀÉ®× |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <!DOCTYPE configuration> |
| | | |
| | | <configuration scan="true"> |
| | | <include resource="org/springframework/boot/logging/logback/base.xml"/> |
| | | |
| | | <!-- The FILE and ASYNC appenders are here as examples for a production configuration --> |
| | | <!-- |
| | | <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
| | | <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
| | | <fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern> |
| | | <maxHistory>90</maxHistory> |
| | | </rollingPolicy> |
| | | <encoder> |
| | | <charset>utf-8</charset> |
| | | <Pattern>%d %-5level [%thread] %logger{0}: %msg%n</Pattern> |
| | | </encoder> |
| | | </appender> |
| | | |
| | | <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender"> |
| | | <queueSize>512</queueSize> |
| | | <appender-ref ref="FILE"/> |
| | | </appender> |
| | | |
| | | <root level="${logging.level.root}"> |
| | | <appender-ref ref="ASYNC"/> |
| | | </root> |
| | | --> |
| | | |
| | | <logger name="javax.activation" level="WARN"/> |
| | | <logger name="javax.mail" level="WARN"/> |
| | | <logger name="javax.management.remote" level="WARN"/> |
| | | <logger name="javax.xml.bind" level="WARN"/> |
| | | <logger name="ch.qos.logback" level="WARN"/> |
| | | <logger name="com.ryantenney" level="WARN"/> |
| | | <logger name="com.sun" level="WARN"/> |
| | | <logger name="com.zaxxer" level="WARN"/> |
| | | <logger name="io.undertow" level="WARN"/> |
| | | <logger name="io.undertow.websockets.jsr" level="ERROR"/> |
| | | <logger name="org.ehcache" level="WARN"/> |
| | | <logger name="org.apache" level="WARN"/> |
| | | <logger name="org.apache.catalina.startup.DigesterFactory" level="OFF"/> |
| | | <logger name="org.bson" level="WARN"/> |
| | | <logger name="org.hibernate.validator" level="WARN"/> |
| | | <logger name="org.hibernate" level="WARN"/> |
| | | <logger name="org.hibernate.ejb.HibernatePersistence" level="OFF"/> |
| | | <logger name="org.postgresql" level="WARN"/> |
| | | <logger name="org.springframework" level="WARN"/> |
| | | <logger name="org.springframework.web" level="WARN"/> |
| | | <logger name="org.springframework.security" level="WARN"/> |
| | | <logger name="org.springframework.cache" level="WARN"/> |
| | | <logger name="org.thymeleaf" level="WARN"/> |
| | | <logger name="org.xnio" level="WARN"/> |
| | | <logger name="springfox" level="WARN"/> |
| | | <logger name="sun.rmi" level="WARN"/> |
| | | <logger name="liquibase" level="WARN"/> |
| | | <logger name="LiquibaseSchemaResolver" level="INFO"/> |
| | | <logger name="springfox.documentation.schema.property" level="ERROR"/> |
| | | <logger name="sun.rmi.transport" level="WARN"/> |
| | | <!-- See https://github.com/jhipster/generator-jhipster/issues/13835 --> |
| | | <logger name="Validator" level="INFO"/> |
| | | <!-- See https://github.com/jhipster/generator-jhipster/issues/14444 --> |
| | | <logger name="_org.springframework.web.servlet.HandlerMapping.Mappings" level="INFO"/> |
| | | <!-- jhipster-needle-logback-add-log - JHipster will add a new log with level --> |
| | | |
| | | <!-- https://logback.qos.ch/manual/configuration.html#shutdownHook and https://jira.qos.ch/browse/LOGBACK-1090 --> |
| | | <shutdownHook class="ch.qos.logback.core.hook.DelayingShutdownHook"/> |
| | | |
| | | <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"> |
| | | <resetJUL>true</resetJUL> |
| | | </contextListener> |
| | | |
| | | </configuration> |
¤ñ¹ï·sÀÉ®× |
| | |
| | | <!DOCTYPE html> |
| | | <html |
| | | xmlns:th="http://www.thymeleaf.org" |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://www.thymeleaf.org" |
| | | th:lang="${#locale.language}" |
| | | lang="en" |
| | | > |
| | | <head> |
| | | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> |
| | | <link rel="icon" href="${baseUrl}/favicon.ico" /> |
| | | <title>Your request cannot be processed</title> |
| | | <style> |
| | | ::-moz-selection { |
| | | background: #b3d4fc; |
| | | text-shadow: none; |
| | | } |
| | | |
| | | ::selection { |
| | | background: #b3d4fc; |
| | | text-shadow: none; |
| | | } |
| | | |
| | | html { |
| | | padding: 30px 10px; |
| | | font-size: 20px; |
| | | line-height: 1.4; |
| | | color: #737373; |
| | | background: #3e8acc; |
| | | -webkit-text-size-adjust: 100%; |
| | | -ms-text-size-adjust: 100%; |
| | | } |
| | | |
| | | html, |
| | | input { |
| | | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; |
| | | } |
| | | |
| | | body { |
| | | max-width: 1000px; |
| | | _width: 500px; |
| | | padding: 30px 20px 50px; |
| | | border: 1px solid #b3b3b3; |
| | | border-radius: 4px; |
| | | margin: 0 auto; |
| | | box-shadow: 0 1px 10px #a7a7a7, inset 0 1px 0 #fff; |
| | | background: #fcfcfc; |
| | | } |
| | | |
| | | h1 { |
| | | margin: 0 10px; |
| | | font-size: 50px; |
| | | text-align: center; |
| | | } |
| | | |
| | | h1 span { |
| | | color: #bbb; |
| | | } |
| | | |
| | | h3 { |
| | | margin: 1.5em 0 0.5em; |
| | | } |
| | | |
| | | p { |
| | | margin: 1em 0; |
| | | } |
| | | |
| | | ul { |
| | | padding: 0 0 0 40px; |
| | | margin: 1em 0; |
| | | } |
| | | |
| | | .container { |
| | | max-width: 800px; |
| | | _width: 380px; |
| | | margin: 0 auto; |
| | | } |
| | | </style> |
| | | </head> |
| | | <body> |
| | | <div class="container"> |
| | | <h1 th:text="#{error.title}">Your request cannot be processed <span>:(</span></h1> |
| | | |
| | | <p th:text="#{error.subtitle}">Sorry, an error has occurred.</p> |
| | | |
| | | <span th:text="#{error.status}">Status:</span> <span th:text="${error}"></span> (<span th:text="${error}"></span>)<br /> |
| | | <span th:if="${!#strings.isEmpty(message)}"> |
| | | <span th:text="#{error.message}">Message:</span> <span th:text="${message}"></span><br /> |
| | | </span> |
| | | </div> |
| | | </body> |
| | | </html> |
¤ñ¹ï·sÀÉ®× |
| | |
| | | <!DOCTYPE html> |
| | | <html xmlns:th="http://www.thymeleaf.org" th:lang="${#locale.language}" lang="en"> |
| | | <head> |
| | | <title th:text="#{email.activation.title}">JHipster activation</title> |
| | | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> |
| | | <link rel="icon" th:href="@{|${baseUrl}/favicon.ico|}" /> |
| | | </head> |
| | | <body> |
| | | <p th:text="#{email.activation.greeting(${user.login})}">Dear</p> |
| | | <p th:text="#{email.activation.text1}">Your JHipster account has been created, please click on the URL below to activate it:</p> |
| | | <p> |
| | | <a th:with="url=(@{|${baseUrl}/account/activate?key=${user.activationKey}|})" th:href="${url}" th:text="${url}">Activation link</a> |
| | | </p> |
| | | <p> |
| | | <span th:text="#{email.activation.text2}">Regards, </span> |
| | | <br /> |
| | | <em th:text="#{email.signature}">JHipster.</em> |
| | | </p> |
| | | </body> |
| | | </html> |
¤ñ¹ï·sÀÉ®× |
| | |
| | | <!DOCTYPE html> |
| | | <html xmlns:th="http://www.thymeleaf.org" th:lang="${#locale.language}" lang="en"> |
| | | <head> |
| | | <title th:text="#{email.activation.title}">JHipster creation</title> |
| | | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> |
| | | <link rel="icon" th:href="@{|${baseUrl}/favicon.ico|}" /> |
| | | </head> |
| | | <body> |
| | | <p th:text="#{email.activation.greeting(${user.login})}">Dear</p> |
| | | <p th:text="#{email.creation.text1}">Your JHipster account has been created, please click on the URL below to access it:</p> |
| | | <p> |
| | | <a th:with="url=(@{|${baseUrl}/account/reset/finish?key=${user.resetKey}|})" th:href="${url}" th:text="${url}">Login link</a> |
| | | </p> |
| | | <p> |
| | | <span th:text="#{email.activation.text2}">Regards, </span> |
| | | <br /> |
| | | <em th:text="#{email.signature}">JHipster.</em> |
| | | </p> |
| | | </body> |
| | | </html> |
¤ñ¹ï·sÀÉ®× |
| | |
| | | <!DOCTYPE html> |
| | | <html xmlns:th="http://www.thymeleaf.org" th:lang="${#locale.language}" lang="en"> |
| | | <head> |
| | | <title th:text="#{email.reset.title}">JHipster password reset</title> |
| | | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> |
| | | <link rel="icon" th:href="@{|${baseUrl}/favicon.ico|}" /> |
| | | </head> |
| | | <body> |
| | | <p th:text="#{email.reset.greeting(${user.login})}">Dear</p> |
| | | <p th:text="#{email.reset.text1}"> |
| | | For your JHipster account a password reset was requested, please click on the URL below to reset it: |
| | | </p> |
| | | <p> |
| | | <a th:with="url=(@{|${baseUrl}/account/reset/finish?key=${user.resetKey}|})" th:href="${url}" th:text="${url}">Login link</a> |
| | | </p> |
| | | <p> |
| | | <span th:text="#{email.reset.text2}">Regards, </span> |
| | | <br /> |
| | | <em th:text="#{email.signature}">JHipster.</em> |
| | | </p> |
| | | </body> |
| | | </html> |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam; |
| | | |
| | | import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses; |
| | | |
| | | import com.tngtech.archunit.core.domain.JavaClasses; |
| | | import com.tngtech.archunit.core.importer.ClassFileImporter; |
| | | import com.tngtech.archunit.core.importer.ImportOption; |
| | | import org.junit.jupiter.api.Test; |
| | | |
| | | class ArchTest { |
| | | |
| | | @Test |
| | | void servicesAndRepositoriesShouldNotDependOnWebLayer() { |
| | | JavaClasses importedClasses = new ClassFileImporter() |
| | | .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS) |
| | | .importPackages("com.pollex.pam"); |
| | | |
| | | noClasses() |
| | | .that() |
| | | .resideInAnyPackage("com.pollex.pam.service..") |
| | | .or() |
| | | .resideInAnyPackage("com.pollex.pam.repository..") |
| | | .should() |
| | | .dependOnClassesThat() |
| | | .resideInAnyPackage("..com.pollex.pam.web..") |
| | | .because("Services and repositories should not depend on web layer") |
| | | .check(importedClasses); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam; |
| | | |
| | | import com.pollex.pam.PamapiApp; |
| | | 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; |
| | | |
| | | /** |
| | | * Base composite annotation for integration tests. |
| | | */ |
| | | @Target(ElementType.TYPE) |
| | | @Retention(RetentionPolicy.RUNTIME) |
| | | @SpringBootTest(classes = PamapiApp.class) |
| | | public @interface IntegrationTest { |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.config; |
| | | |
| | | import static org.mockito.ArgumentMatchers.any; |
| | | import static org.mockito.Mockito.doNothing; |
| | | import static org.mockito.Mockito.mock; |
| | | |
| | | import com.pollex.pam.service.MailService; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | |
| | | @Configuration |
| | | public class NoOpMailConfiguration { |
| | | |
| | | private final MailService mockMailService; |
| | | |
| | | public NoOpMailConfiguration() { |
| | | mockMailService = mock(MailService.class); |
| | | doNothing().when(mockMailService).sendActivationEmail(any()); |
| | | } |
| | | |
| | | @Bean |
| | | public MailService mailService() { |
| | | return mockMailService; |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.config; |
| | | |
| | | import static org.assertj.core.api.Assertions.assertThatCode; |
| | | import static org.mockito.ArgumentMatchers.any; |
| | | import static org.mockito.ArgumentMatchers.anyString; |
| | | import static org.mockito.Mockito.*; |
| | | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; |
| | | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.options; |
| | | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; |
| | | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
| | | |
| | | import java.util.*; |
| | | import javax.servlet.*; |
| | | import org.junit.jupiter.api.BeforeEach; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.springframework.http.HttpHeaders; |
| | | import org.springframework.mock.env.MockEnvironment; |
| | | import org.springframework.mock.web.MockServletContext; |
| | | import org.springframework.test.web.servlet.MockMvc; |
| | | import org.springframework.test.web.servlet.setup.MockMvcBuilders; |
| | | import tech.jhipster.config.JHipsterConstants; |
| | | import tech.jhipster.config.JHipsterProperties; |
| | | |
| | | /** |
| | | * Unit tests for the {@link WebConfigurer} class. |
| | | */ |
| | | class WebConfigurerTest { |
| | | |
| | | private WebConfigurer webConfigurer; |
| | | |
| | | private MockServletContext servletContext; |
| | | |
| | | private MockEnvironment env; |
| | | |
| | | private JHipsterProperties props; |
| | | |
| | | @BeforeEach |
| | | public void setup() { |
| | | servletContext = spy(new MockServletContext()); |
| | | doReturn(mock(FilterRegistration.Dynamic.class)).when(servletContext).addFilter(anyString(), any(Filter.class)); |
| | | doReturn(mock(ServletRegistration.Dynamic.class)).when(servletContext).addServlet(anyString(), any(Servlet.class)); |
| | | |
| | | env = new MockEnvironment(); |
| | | props = new JHipsterProperties(); |
| | | |
| | | webConfigurer = new WebConfigurer(env, props); |
| | | } |
| | | |
| | | @Test |
| | | void shouldStartUpProdServletContext() throws ServletException { |
| | | env.setActiveProfiles(JHipsterConstants.SPRING_PROFILE_PRODUCTION); |
| | | |
| | | assertThatCode(() -> webConfigurer.onStartup(servletContext)).doesNotThrowAnyException(); |
| | | } |
| | | |
| | | @Test |
| | | void shouldStartUpDevServletContext() throws ServletException { |
| | | env.setActiveProfiles(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT); |
| | | |
| | | assertThatCode(() -> webConfigurer.onStartup(servletContext)).doesNotThrowAnyException(); |
| | | } |
| | | |
| | | @Test |
| | | void shouldCorsFilterOnApiPath() throws Exception { |
| | | props.getCors().setAllowedOrigins(Collections.singletonList("other.domain.com")); |
| | | props.getCors().setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE")); |
| | | props.getCors().setAllowedHeaders(Collections.singletonList("*")); |
| | | props.getCors().setMaxAge(1800L); |
| | | props.getCors().setAllowCredentials(true); |
| | | |
| | | MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new WebConfigurerTestController()).addFilters(webConfigurer.corsFilter()).build(); |
| | | |
| | | mockMvc |
| | | .perform( |
| | | options("/api/test-cors") |
| | | .header(HttpHeaders.ORIGIN, "other.domain.com") |
| | | .header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "POST") |
| | | ) |
| | | .andExpect(status().isOk()) |
| | | .andExpect(header().string(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "other.domain.com")) |
| | | .andExpect(header().string(HttpHeaders.VARY, "Origin")) |
| | | .andExpect(header().string(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "GET,POST,PUT,DELETE")) |
| | | .andExpect(header().string(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true")) |
| | | .andExpect(header().string(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "1800")); |
| | | |
| | | mockMvc |
| | | .perform(get("/api/test-cors").header(HttpHeaders.ORIGIN, "other.domain.com")) |
| | | .andExpect(status().isOk()) |
| | | .andExpect(header().string(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "other.domain.com")); |
| | | } |
| | | |
| | | @Test |
| | | void shouldCorsFilterOnOtherPath() throws Exception { |
| | | props.getCors().setAllowedOrigins(Collections.singletonList("*")); |
| | | props.getCors().setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE")); |
| | | props.getCors().setAllowedHeaders(Collections.singletonList("*")); |
| | | props.getCors().setMaxAge(1800L); |
| | | props.getCors().setAllowCredentials(true); |
| | | |
| | | MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new WebConfigurerTestController()).addFilters(webConfigurer.corsFilter()).build(); |
| | | |
| | | mockMvc |
| | | .perform(get("/test/test-cors").header(HttpHeaders.ORIGIN, "other.domain.com")) |
| | | .andExpect(status().isOk()) |
| | | .andExpect(header().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)); |
| | | } |
| | | |
| | | @Test |
| | | void shouldCorsFilterDeactivatedForNullAllowedOrigins() throws Exception { |
| | | props.getCors().setAllowedOrigins(null); |
| | | |
| | | MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new WebConfigurerTestController()).addFilters(webConfigurer.corsFilter()).build(); |
| | | |
| | | mockMvc |
| | | .perform(get("/api/test-cors").header(HttpHeaders.ORIGIN, "other.domain.com")) |
| | | .andExpect(status().isOk()) |
| | | .andExpect(header().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)); |
| | | } |
| | | |
| | | @Test |
| | | void shouldCorsFilterDeactivatedForEmptyAllowedOrigins() throws Exception { |
| | | props.getCors().setAllowedOrigins(new ArrayList<>()); |
| | | |
| | | MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new WebConfigurerTestController()).addFilters(webConfigurer.corsFilter()).build(); |
| | | |
| | | mockMvc |
| | | .perform(get("/api/test-cors").header(HttpHeaders.ORIGIN, "other.domain.com")) |
| | | .andExpect(status().isOk()) |
| | | .andExpect(header().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.config; |
| | | |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | @RestController |
| | | public class WebConfigurerTestController { |
| | | |
| | | @GetMapping("/api/test-cors") |
| | | public void testCorsOnApiPath() {} |
| | | |
| | | @GetMapping("/test/test-cors") |
| | | public void testCorsOnOtherPath() {} |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.config.timezone; |
| | | |
| | | import static java.lang.String.format; |
| | | import static org.assertj.core.api.Assertions.assertThat; |
| | | |
| | | import com.pollex.pam.IntegrationTest; |
| | | import com.pollex.pam.repository.timezone.DateTimeWrapper; |
| | | import com.pollex.pam.repository.timezone.DateTimeWrapperRepository; |
| | | import java.time.*; |
| | | import java.time.format.DateTimeFormatter; |
| | | import org.junit.jupiter.api.BeforeEach; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import org.springframework.jdbc.core.JdbcTemplate; |
| | | import org.springframework.jdbc.support.rowset.SqlRowSet; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | /** |
| | | * Integration tests for the ZoneId Hibernate configuration. |
| | | */ |
| | | @IntegrationTest |
| | | class HibernateTimeZoneIT { |
| | | |
| | | @Autowired |
| | | private DateTimeWrapperRepository dateTimeWrapperRepository; |
| | | |
| | | @Autowired |
| | | private JdbcTemplate jdbcTemplate; |
| | | |
| | | @Value("${spring.jpa.properties.hibernate.jdbc.time_zone:UTC}") |
| | | private String zoneId; |
| | | |
| | | private DateTimeWrapper dateTimeWrapper; |
| | | private DateTimeFormatter dateTimeFormatter; |
| | | private DateTimeFormatter timeFormatter; |
| | | private DateTimeFormatter dateFormatter; |
| | | |
| | | @BeforeEach |
| | | public void setup() { |
| | | dateTimeWrapper = new DateTimeWrapper(); |
| | | dateTimeWrapper.setInstant(Instant.parse("2014-11-12T05:50:00.0Z")); |
| | | dateTimeWrapper.setLocalDateTime(LocalDateTime.parse("2014-11-12T07:50:00.0")); |
| | | dateTimeWrapper.setOffsetDateTime(OffsetDateTime.parse("2011-12-14T08:30:00.0Z")); |
| | | dateTimeWrapper.setZonedDateTime(ZonedDateTime.parse("2011-12-14T08:30:00.0Z")); |
| | | dateTimeWrapper.setLocalTime(LocalTime.parse("14:30:00")); |
| | | dateTimeWrapper.setOffsetTime(OffsetTime.parse("14:30:00+02:00")); |
| | | dateTimeWrapper.setLocalDate(LocalDate.parse("2016-09-10")); |
| | | |
| | | dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S").withZone(ZoneId.of(zoneId)); |
| | | |
| | | timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss").withZone(ZoneId.of(zoneId)); |
| | | |
| | | dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void storeInstantWithZoneIdConfigShouldBeStoredOnGMTTimeZone() { |
| | | dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper); |
| | | |
| | | String request = generateSqlRequest("instant", dateTimeWrapper.getId()); |
| | | SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request); |
| | | String expectedValue = dateTimeFormatter.format(dateTimeWrapper.getInstant()); |
| | | |
| | | assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void storeLocalDateTimeWithZoneIdConfigShouldBeStoredOnGMTTimeZone() { |
| | | dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper); |
| | | |
| | | String request = generateSqlRequest("local_date_time", dateTimeWrapper.getId()); |
| | | SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request); |
| | | String expectedValue = dateTimeWrapper.getLocalDateTime().atZone(ZoneId.systemDefault()).format(dateTimeFormatter); |
| | | |
| | | assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void storeOffsetDateTimeWithZoneIdConfigShouldBeStoredOnGMTTimeZone() { |
| | | dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper); |
| | | |
| | | String request = generateSqlRequest("offset_date_time", dateTimeWrapper.getId()); |
| | | SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request); |
| | | String expectedValue = dateTimeWrapper.getOffsetDateTime().format(dateTimeFormatter); |
| | | |
| | | assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void storeZoneDateTimeWithZoneIdConfigShouldBeStoredOnGMTTimeZone() { |
| | | dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper); |
| | | |
| | | String request = generateSqlRequest("zoned_date_time", dateTimeWrapper.getId()); |
| | | SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request); |
| | | String expectedValue = dateTimeWrapper.getZonedDateTime().format(dateTimeFormatter); |
| | | |
| | | assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void storeLocalTimeWithZoneIdConfigShouldBeStoredOnGMTTimeZoneAccordingToHis1stJan1970Value() { |
| | | dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper); |
| | | |
| | | String request = generateSqlRequest("local_time", dateTimeWrapper.getId()); |
| | | SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request); |
| | | String expectedValue = dateTimeWrapper |
| | | .getLocalTime() |
| | | .atDate(LocalDate.of(1970, Month.JANUARY, 1)) |
| | | .atZone(ZoneId.systemDefault()) |
| | | .format(timeFormatter); |
| | | |
| | | assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void storeOffsetTimeWithZoneIdConfigShouldBeStoredOnGMTTimeZoneAccordingToHis1stJan1970Value() { |
| | | dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper); |
| | | |
| | | String request = generateSqlRequest("offset_time", dateTimeWrapper.getId()); |
| | | SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request); |
| | | String expectedValue = dateTimeWrapper |
| | | .getOffsetTime() |
| | | .toLocalTime() |
| | | .atDate(LocalDate.of(1970, Month.JANUARY, 1)) |
| | | .atZone(ZoneId.systemDefault()) |
| | | .format(timeFormatter); |
| | | |
| | | assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void storeLocalDateWithZoneIdConfigShouldBeStoredWithoutTransformation() { |
| | | dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper); |
| | | |
| | | String request = generateSqlRequest("local_date", dateTimeWrapper.getId()); |
| | | SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request); |
| | | String expectedValue = dateTimeWrapper.getLocalDate().format(dateFormatter); |
| | | |
| | | assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue); |
| | | } |
| | | |
| | | private String generateSqlRequest(String fieldName, long id) { |
| | | return format("SELECT %s FROM jhi_date_time_wrapper where id=%d", fieldName, id); |
| | | } |
| | | |
| | | private void assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(SqlRowSet sqlRowSet, String expectedValue) { |
| | | while (sqlRowSet.next()) { |
| | | String dbValue = sqlRowSet.getString(1); |
| | | |
| | | assertThat(dbValue).isNotNull(); |
| | | assertThat(dbValue).isEqualTo(expectedValue); |
| | | } |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.repository.timezone; |
| | | |
| | | import java.io.Serializable; |
| | | import java.time.*; |
| | | import java.util.Objects; |
| | | import javax.persistence.*; |
| | | |
| | | @Entity |
| | | @Table(name = "jhi_date_time_wrapper") |
| | | public class DateTimeWrapper implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @Id |
| | | @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") |
| | | @SequenceGenerator(name = "sequenceGenerator") |
| | | private Long id; |
| | | |
| | | @Column(name = "instant") |
| | | private Instant instant; |
| | | |
| | | @Column(name = "local_date_time") |
| | | private LocalDateTime localDateTime; |
| | | |
| | | @Column(name = "offset_date_time") |
| | | private OffsetDateTime offsetDateTime; |
| | | |
| | | @Column(name = "zoned_date_time") |
| | | private ZonedDateTime zonedDateTime; |
| | | |
| | | @Column(name = "local_time") |
| | | private LocalTime localTime; |
| | | |
| | | @Column(name = "offset_time") |
| | | private OffsetTime offsetTime; |
| | | |
| | | @Column(name = "local_date") |
| | | private LocalDate localDate; |
| | | |
| | | public Long getId() { |
| | | return id; |
| | | } |
| | | |
| | | public void setId(Long id) { |
| | | this.id = id; |
| | | } |
| | | |
| | | public Instant getInstant() { |
| | | return instant; |
| | | } |
| | | |
| | | public void setInstant(Instant instant) { |
| | | this.instant = instant; |
| | | } |
| | | |
| | | public LocalDateTime getLocalDateTime() { |
| | | return localDateTime; |
| | | } |
| | | |
| | | public void setLocalDateTime(LocalDateTime localDateTime) { |
| | | this.localDateTime = localDateTime; |
| | | } |
| | | |
| | | public OffsetDateTime getOffsetDateTime() { |
| | | return offsetDateTime; |
| | | } |
| | | |
| | | public void setOffsetDateTime(OffsetDateTime offsetDateTime) { |
| | | this.offsetDateTime = offsetDateTime; |
| | | } |
| | | |
| | | public ZonedDateTime getZonedDateTime() { |
| | | return zonedDateTime; |
| | | } |
| | | |
| | | public void setZonedDateTime(ZonedDateTime zonedDateTime) { |
| | | this.zonedDateTime = zonedDateTime; |
| | | } |
| | | |
| | | public LocalTime getLocalTime() { |
| | | return localTime; |
| | | } |
| | | |
| | | public void setLocalTime(LocalTime localTime) { |
| | | this.localTime = localTime; |
| | | } |
| | | |
| | | public OffsetTime getOffsetTime() { |
| | | return offsetTime; |
| | | } |
| | | |
| | | public void setOffsetTime(OffsetTime offsetTime) { |
| | | this.offsetTime = offsetTime; |
| | | } |
| | | |
| | | public LocalDate getLocalDate() { |
| | | return localDate; |
| | | } |
| | | |
| | | public void setLocalDate(LocalDate localDate) { |
| | | this.localDate = localDate; |
| | | } |
| | | |
| | | @Override |
| | | public boolean equals(Object o) { |
| | | if (this == o) { |
| | | return true; |
| | | } |
| | | if (o == null || getClass() != o.getClass()) { |
| | | return false; |
| | | } |
| | | |
| | | DateTimeWrapper dateTimeWrapper = (DateTimeWrapper) o; |
| | | return !(dateTimeWrapper.getId() == null || getId() == null) && Objects.equals(getId(), dateTimeWrapper.getId()); |
| | | } |
| | | |
| | | @Override |
| | | public int hashCode() { |
| | | return Objects.hashCode(getId()); |
| | | } |
| | | |
| | | // prettier-ignore |
| | | @Override |
| | | public String toString() { |
| | | return "TimeZoneTest{" + |
| | | "id=" + id + |
| | | ", instant=" + instant + |
| | | ", localDateTime=" + localDateTime + |
| | | ", offsetDateTime=" + offsetDateTime + |
| | | ", zonedDateTime=" + zonedDateTime + |
| | | '}'; |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.repository.timezone; |
| | | |
| | | import org.springframework.data.jpa.repository.JpaRepository; |
| | | import org.springframework.stereotype.Repository; |
| | | |
| | | /** |
| | | * Spring Data JPA repository for the {@link DateTimeWrapper} entity. |
| | | */ |
| | | @Repository |
| | | public interface DateTimeWrapperRepository extends JpaRepository<DateTimeWrapper, Long> {} |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.security; |
| | | |
| | | import static org.assertj.core.api.Assertions.assertThat; |
| | | import static org.assertj.core.api.Assertions.assertThatExceptionOfType; |
| | | |
| | | import com.pollex.pam.IntegrationTest; |
| | | import com.pollex.pam.domain.User; |
| | | import com.pollex.pam.repository.UserRepository; |
| | | import java.util.Locale; |
| | | import org.apache.commons.lang3.RandomStringUtils; |
| | | import org.junit.jupiter.api.BeforeEach; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.security.core.userdetails.UserDetails; |
| | | import org.springframework.security.core.userdetails.UserDetailsService; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | /** |
| | | * Integrations tests for {@link DomainUserDetailsService}. |
| | | */ |
| | | @Transactional |
| | | @IntegrationTest |
| | | class DomainUserDetailsServiceIT { |
| | | |
| | | private static final String USER_ONE_LOGIN = "test-user-one"; |
| | | private static final String USER_ONE_EMAIL = "test-user-one@localhost"; |
| | | private static final String USER_TWO_LOGIN = "test-user-two"; |
| | | private static final String USER_TWO_EMAIL = "test-user-two@localhost"; |
| | | private static final String USER_THREE_LOGIN = "test-user-three"; |
| | | private static final String USER_THREE_EMAIL = "test-user-three@localhost"; |
| | | |
| | | @Autowired |
| | | private UserRepository userRepository; |
| | | |
| | | @Autowired |
| | | private UserDetailsService domainUserDetailsService; |
| | | |
| | | @BeforeEach |
| | | public void init() { |
| | | User userOne = new User(); |
| | | userOne.setLogin(USER_ONE_LOGIN); |
| | | userOne.setPassword(RandomStringUtils.random(60)); |
| | | userOne.setActivated(true); |
| | | userOne.setEmail(USER_ONE_EMAIL); |
| | | userOne.setFirstName("userOne"); |
| | | userOne.setLastName("doe"); |
| | | userOne.setLangKey("en"); |
| | | userRepository.save(userOne); |
| | | |
| | | User userTwo = new User(); |
| | | userTwo.setLogin(USER_TWO_LOGIN); |
| | | userTwo.setPassword(RandomStringUtils.random(60)); |
| | | userTwo.setActivated(true); |
| | | userTwo.setEmail(USER_TWO_EMAIL); |
| | | userTwo.setFirstName("userTwo"); |
| | | userTwo.setLastName("doe"); |
| | | userTwo.setLangKey("en"); |
| | | userRepository.save(userTwo); |
| | | |
| | | User userThree = new User(); |
| | | userThree.setLogin(USER_THREE_LOGIN); |
| | | userThree.setPassword(RandomStringUtils.random(60)); |
| | | userThree.setActivated(false); |
| | | userThree.setEmail(USER_THREE_EMAIL); |
| | | userThree.setFirstName("userThree"); |
| | | userThree.setLastName("doe"); |
| | | userThree.setLangKey("en"); |
| | | userRepository.save(userThree); |
| | | } |
| | | |
| | | @Test |
| | | void assertThatUserCanBeFoundByLogin() { |
| | | UserDetails userDetails = domainUserDetailsService.loadUserByUsername(USER_ONE_LOGIN); |
| | | assertThat(userDetails).isNotNull(); |
| | | assertThat(userDetails.getUsername()).isEqualTo(USER_ONE_LOGIN); |
| | | } |
| | | |
| | | @Test |
| | | void assertThatUserCanBeFoundByLoginIgnoreCase() { |
| | | UserDetails userDetails = domainUserDetailsService.loadUserByUsername(USER_ONE_LOGIN.toUpperCase(Locale.ENGLISH)); |
| | | assertThat(userDetails).isNotNull(); |
| | | assertThat(userDetails.getUsername()).isEqualTo(USER_ONE_LOGIN); |
| | | } |
| | | |
| | | @Test |
| | | void assertThatUserCanBeFoundByEmail() { |
| | | UserDetails userDetails = domainUserDetailsService.loadUserByUsername(USER_TWO_EMAIL); |
| | | assertThat(userDetails).isNotNull(); |
| | | assertThat(userDetails.getUsername()).isEqualTo(USER_TWO_LOGIN); |
| | | } |
| | | |
| | | @Test |
| | | void assertThatUserCanBeFoundByEmailIgnoreCase() { |
| | | UserDetails userDetails = domainUserDetailsService.loadUserByUsername(USER_TWO_EMAIL.toUpperCase(Locale.ENGLISH)); |
| | | assertThat(userDetails).isNotNull(); |
| | | assertThat(userDetails.getUsername()).isEqualTo(USER_TWO_LOGIN); |
| | | } |
| | | |
| | | @Test |
| | | void assertThatEmailIsPrioritizedOverLogin() { |
| | | UserDetails userDetails = domainUserDetailsService.loadUserByUsername(USER_ONE_EMAIL); |
| | | assertThat(userDetails).isNotNull(); |
| | | assertThat(userDetails.getUsername()).isEqualTo(USER_ONE_LOGIN); |
| | | } |
| | | |
| | | @Test |
| | | void assertThatUserNotActivatedExceptionIsThrownForNotActivatedUsers() { |
| | | assertThatExceptionOfType(UserNotActivatedException.class) |
| | | .isThrownBy(() -> domainUserDetailsService.loadUserByUsername(USER_THREE_LOGIN)); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.security; |
| | | |
| | | import static org.assertj.core.api.Assertions.assertThat; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Collection; |
| | | import java.util.Optional; |
| | | import org.junit.jupiter.api.AfterEach; |
| | | import org.junit.jupiter.api.BeforeEach; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
| | | import org.springframework.security.core.GrantedAuthority; |
| | | import org.springframework.security.core.authority.SimpleGrantedAuthority; |
| | | import org.springframework.security.core.context.SecurityContext; |
| | | import org.springframework.security.core.context.SecurityContextHolder; |
| | | |
| | | /** |
| | | * Test class for the {@link SecurityUtils} utility class. |
| | | */ |
| | | class SecurityUtilsUnitTest { |
| | | |
| | | @BeforeEach |
| | | @AfterEach |
| | | void cleanup() { |
| | | SecurityContextHolder.clearContext(); |
| | | } |
| | | |
| | | @Test |
| | | void testGetCurrentUserLogin() { |
| | | SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); |
| | | securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("admin", "admin")); |
| | | SecurityContextHolder.setContext(securityContext); |
| | | Optional<String> login = SecurityUtils.getCurrentUserLogin(); |
| | | assertThat(login).contains("admin"); |
| | | } |
| | | |
| | | @Test |
| | | void testGetCurrentUserJWT() { |
| | | SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); |
| | | securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("admin", "token")); |
| | | SecurityContextHolder.setContext(securityContext); |
| | | Optional<String> jwt = SecurityUtils.getCurrentUserJWT(); |
| | | assertThat(jwt).contains("token"); |
| | | } |
| | | |
| | | @Test |
| | | void testIsAuthenticated() { |
| | | SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); |
| | | securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("admin", "admin")); |
| | | SecurityContextHolder.setContext(securityContext); |
| | | boolean isAuthenticated = SecurityUtils.isAuthenticated(); |
| | | assertThat(isAuthenticated).isTrue(); |
| | | } |
| | | |
| | | @Test |
| | | void testAnonymousIsNotAuthenticated() { |
| | | SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); |
| | | Collection<GrantedAuthority> authorities = new ArrayList<>(); |
| | | authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.ANONYMOUS)); |
| | | securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("anonymous", "anonymous", authorities)); |
| | | SecurityContextHolder.setContext(securityContext); |
| | | boolean isAuthenticated = SecurityUtils.isAuthenticated(); |
| | | assertThat(isAuthenticated).isFalse(); |
| | | } |
| | | |
| | | @Test |
| | | void testHasCurrentUserThisAuthority() { |
| | | SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); |
| | | Collection<GrantedAuthority> authorities = new ArrayList<>(); |
| | | authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.USER)); |
| | | securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("user", "user", authorities)); |
| | | SecurityContextHolder.setContext(securityContext); |
| | | |
| | | assertThat(SecurityUtils.hasCurrentUserThisAuthority(AuthoritiesConstants.USER)).isTrue(); |
| | | assertThat(SecurityUtils.hasCurrentUserThisAuthority(AuthoritiesConstants.ADMIN)).isFalse(); |
| | | } |
| | | |
| | | @Test |
| | | void testHasCurrentUserAnyOfAuthorities() { |
| | | SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); |
| | | Collection<GrantedAuthority> authorities = new ArrayList<>(); |
| | | authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.USER)); |
| | | securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("user", "user", authorities)); |
| | | SecurityContextHolder.setContext(securityContext); |
| | | |
| | | assertThat(SecurityUtils.hasCurrentUserAnyOfAuthorities(AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN)).isTrue(); |
| | | assertThat(SecurityUtils.hasCurrentUserAnyOfAuthorities(AuthoritiesConstants.ANONYMOUS, AuthoritiesConstants.ADMIN)).isFalse(); |
| | | } |
| | | |
| | | @Test |
| | | void testHasCurrentUserNoneOfAuthorities() { |
| | | SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); |
| | | Collection<GrantedAuthority> authorities = new ArrayList<>(); |
| | | authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.USER)); |
| | | securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("user", "user", authorities)); |
| | | SecurityContextHolder.setContext(securityContext); |
| | | |
| | | assertThat(SecurityUtils.hasCurrentUserNoneOfAuthorities(AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN)).isFalse(); |
| | | assertThat(SecurityUtils.hasCurrentUserNoneOfAuthorities(AuthoritiesConstants.ANONYMOUS, AuthoritiesConstants.ADMIN)).isTrue(); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.security.jwt; |
| | | |
| | | import static org.assertj.core.api.Assertions.assertThat; |
| | | |
| | | import com.pollex.pam.security.AuthoritiesConstants; |
| | | import io.jsonwebtoken.io.Decoders; |
| | | import io.jsonwebtoken.security.Keys; |
| | | 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); |
| | | tokenProvider = new TokenProvider(jHipsterProperties); |
| | | 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(); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.security.jwt; |
| | | |
| | | import static org.assertj.core.api.Assertions.assertThat; |
| | | |
| | | import com.pollex.pam.security.AuthoritiesConstants; |
| | | import io.jsonwebtoken.Jwts; |
| | | import io.jsonwebtoken.SignatureAlgorithm; |
| | | import io.jsonwebtoken.io.Decoders; |
| | | import io.jsonwebtoken.security.Keys; |
| | | 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); |
| | | tokenProvider = new TokenProvider(jHipsterProperties); |
| | | 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); |
| | | |
| | | TokenProvider tokenProvider = new TokenProvider(jHipsterProperties); |
| | | |
| | | 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); |
| | | |
| | | TokenProvider tokenProvider = new TokenProvider(jHipsterProperties); |
| | | |
| | | Key key = (Key) ReflectionTestUtils.getField(tokenProvider, "key"); |
| | | assertThat(key).isNotNull().isEqualTo(Keys.hmacShaKeyFor(Decoders.BASE64.decode(base64Secret))); |
| | | } |
| | | |
| | | private Authentication createAuthentication() { |
| | | Collection<GrantedAuthority> 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(); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.service; |
| | | |
| | | import static org.assertj.core.api.Assertions.*; |
| | | import static org.mockito.ArgumentMatchers.any; |
| | | import static org.mockito.Mockito.*; |
| | | |
| | | import com.pollex.pam.IntegrationTest; |
| | | import com.pollex.pam.config.Constants; |
| | | import com.pollex.pam.domain.User; |
| | | import java.io.ByteArrayOutputStream; |
| | | import java.io.File; |
| | | import java.io.FileInputStream; |
| | | import java.io.InputStreamReader; |
| | | import java.net.URI; |
| | | import java.net.URL; |
| | | import java.nio.charset.Charset; |
| | | import java.util.Properties; |
| | | import java.util.regex.Matcher; |
| | | import java.util.regex.Pattern; |
| | | import javax.mail.Multipart; |
| | | 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; |
| | | import org.mockito.Captor; |
| | | import org.mockito.MockitoAnnotations; |
| | | import org.mockito.Spy; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.context.MessageSource; |
| | | import org.springframework.mail.MailSendException; |
| | | import org.springframework.mail.javamail.JavaMailSenderImpl; |
| | | import org.thymeleaf.spring5.SpringTemplateEngine; |
| | | import tech.jhipster.config.JHipsterProperties; |
| | | |
| | | /** |
| | | * Integration tests for {@link MailService}. |
| | | */ |
| | | @IntegrationTest |
| | | class MailServiceIT { |
| | | |
| | | private static final String[] languages = { |
| | | "zh-tw", |
| | | "en", |
| | | // jhipster-needle-i18n-language-constant - JHipster will add/remove languages in this array |
| | | }; |
| | | private static final Pattern PATTERN_LOCALE_3 = Pattern.compile("([a-z]{2})-([a-zA-Z]{4})-([a-z]{2})"); |
| | | private static final Pattern PATTERN_LOCALE_2 = Pattern.compile("([a-z]{2})-([a-z]{2})"); |
| | | |
| | | @Autowired |
| | | private JHipsterProperties jHipsterProperties; |
| | | |
| | | @Autowired |
| | | private MessageSource messageSource; |
| | | |
| | | @Autowired |
| | | private SpringTemplateEngine templateEngine; |
| | | |
| | | @Spy |
| | | private JavaMailSenderImpl javaMailSender; |
| | | |
| | | @Captor |
| | | private ArgumentCaptor<MimeMessage> messageCaptor; |
| | | |
| | | private MailService mailService; |
| | | |
| | | @BeforeEach |
| | | public void setup() { |
| | | MockitoAnnotations.initMocks(this); |
| | | doNothing().when(javaMailSender).send(any(MimeMessage.class)); |
| | | mailService = new MailService(jHipsterProperties, javaMailSender, messageSource, templateEngine); |
| | | } |
| | | |
| | | @Test |
| | | void testSendEmail() throws Exception { |
| | | mailService.sendEmail("john.doe@example.com", "testSubject", "testContent", false, false); |
| | | verify(javaMailSender).send(messageCaptor.capture()); |
| | | MimeMessage message = messageCaptor.getValue(); |
| | | assertThat(message.getSubject()).isEqualTo("testSubject"); |
| | | assertThat(message.getAllRecipients()[0]).hasToString("john.doe@example.com"); |
| | | assertThat(message.getFrom()[0]).hasToString(jHipsterProperties.getMail().getFrom()); |
| | | assertThat(message.getContent()).isInstanceOf(String.class); |
| | | assertThat(message.getContent()).hasToString("testContent"); |
| | | assertThat(message.getDataHandler().getContentType()).isEqualTo("text/plain; charset=UTF-8"); |
| | | } |
| | | |
| | | @Test |
| | | void testSendHtmlEmail() throws Exception { |
| | | mailService.sendEmail("john.doe@example.com", "testSubject", "testContent", false, true); |
| | | verify(javaMailSender).send(messageCaptor.capture()); |
| | | MimeMessage message = messageCaptor.getValue(); |
| | | assertThat(message.getSubject()).isEqualTo("testSubject"); |
| | | assertThat(message.getAllRecipients()[0]).hasToString("john.doe@example.com"); |
| | | assertThat(message.getFrom()[0]).hasToString(jHipsterProperties.getMail().getFrom()); |
| | | assertThat(message.getContent()).isInstanceOf(String.class); |
| | | assertThat(message.getContent()).hasToString("testContent"); |
| | | assertThat(message.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8"); |
| | | } |
| | | |
| | | @Test |
| | | void testSendMultipartEmail() throws Exception { |
| | | mailService.sendEmail("john.doe@example.com", "testSubject", "testContent", true, false); |
| | | verify(javaMailSender).send(messageCaptor.capture()); |
| | | MimeMessage message = messageCaptor.getValue(); |
| | | MimeMultipart mp = (MimeMultipart) message.getContent(); |
| | | MimeBodyPart part = (MimeBodyPart) ((MimeMultipart) mp.getBodyPart(0).getContent()).getBodyPart(0); |
| | | ByteArrayOutputStream aos = new ByteArrayOutputStream(); |
| | | part.writeTo(aos); |
| | | assertThat(message.getSubject()).isEqualTo("testSubject"); |
| | | assertThat(message.getAllRecipients()[0]).hasToString("john.doe@example.com"); |
| | | assertThat(message.getFrom()[0]).hasToString(jHipsterProperties.getMail().getFrom()); |
| | | assertThat(message.getContent()).isInstanceOf(Multipart.class); |
| | | assertThat(aos).hasToString("\r\ntestContent"); |
| | | assertThat(part.getDataHandler().getContentType()).isEqualTo("text/plain; charset=UTF-8"); |
| | | } |
| | | |
| | | @Test |
| | | void testSendMultipartHtmlEmail() throws Exception { |
| | | mailService.sendEmail("john.doe@example.com", "testSubject", "testContent", true, true); |
| | | verify(javaMailSender).send(messageCaptor.capture()); |
| | | MimeMessage message = messageCaptor.getValue(); |
| | | MimeMultipart mp = (MimeMultipart) message.getContent(); |
| | | MimeBodyPart part = (MimeBodyPart) ((MimeMultipart) mp.getBodyPart(0).getContent()).getBodyPart(0); |
| | | ByteArrayOutputStream aos = new ByteArrayOutputStream(); |
| | | part.writeTo(aos); |
| | | assertThat(message.getSubject()).isEqualTo("testSubject"); |
| | | assertThat(message.getAllRecipients()[0]).hasToString("john.doe@example.com"); |
| | | assertThat(message.getFrom()[0]).hasToString(jHipsterProperties.getMail().getFrom()); |
| | | assertThat(message.getContent()).isInstanceOf(Multipart.class); |
| | | assertThat(aos).hasToString("\r\ntestContent"); |
| | | assertThat(part.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8"); |
| | | } |
| | | |
| | | @Test |
| | | void testSendEmailFromTemplate() throws Exception { |
| | | User user = new User(); |
| | | user.setLogin("john"); |
| | | user.setEmail("john.doe@example.com"); |
| | | user.setLangKey("en"); |
| | | mailService.sendEmailFromTemplate(user, "mail/testEmail", "email.test.title"); |
| | | verify(javaMailSender).send(messageCaptor.capture()); |
| | | MimeMessage message = messageCaptor.getValue(); |
| | | assertThat(message.getSubject()).isEqualTo("test title"); |
| | | assertThat(message.getAllRecipients()[0]).hasToString(user.getEmail()); |
| | | assertThat(message.getFrom()[0]).hasToString(jHipsterProperties.getMail().getFrom()); |
| | | assertThat(message.getContent().toString()).isEqualToNormalizingNewlines("<html>test title, http://127.0.0.1:8080, john</html>\n"); |
| | | assertThat(message.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8"); |
| | | } |
| | | |
| | | @Test |
| | | void testSendActivationEmail() throws Exception { |
| | | User user = new User(); |
| | | user.setLangKey(Constants.DEFAULT_LANGUAGE); |
| | | user.setLogin("john"); |
| | | user.setEmail("john.doe@example.com"); |
| | | mailService.sendActivationEmail(user); |
| | | verify(javaMailSender).send(messageCaptor.capture()); |
| | | MimeMessage message = messageCaptor.getValue(); |
| | | assertThat(message.getAllRecipients()[0]).hasToString(user.getEmail()); |
| | | assertThat(message.getFrom()[0]).hasToString(jHipsterProperties.getMail().getFrom()); |
| | | assertThat(message.getContent().toString()).isNotEmpty(); |
| | | assertThat(message.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8"); |
| | | } |
| | | |
| | | @Test |
| | | void testCreationEmail() throws Exception { |
| | | User user = new User(); |
| | | user.setLangKey(Constants.DEFAULT_LANGUAGE); |
| | | user.setLogin("john"); |
| | | user.setEmail("john.doe@example.com"); |
| | | mailService.sendCreationEmail(user); |
| | | verify(javaMailSender).send(messageCaptor.capture()); |
| | | MimeMessage message = messageCaptor.getValue(); |
| | | assertThat(message.getAllRecipients()[0]).hasToString(user.getEmail()); |
| | | assertThat(message.getFrom()[0]).hasToString(jHipsterProperties.getMail().getFrom()); |
| | | assertThat(message.getContent().toString()).isNotEmpty(); |
| | | assertThat(message.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8"); |
| | | } |
| | | |
| | | @Test |
| | | void testSendPasswordResetMail() throws Exception { |
| | | User user = new User(); |
| | | user.setLangKey(Constants.DEFAULT_LANGUAGE); |
| | | user.setLogin("john"); |
| | | user.setEmail("john.doe@example.com"); |
| | | mailService.sendPasswordResetMail(user); |
| | | verify(javaMailSender).send(messageCaptor.capture()); |
| | | MimeMessage message = messageCaptor.getValue(); |
| | | assertThat(message.getAllRecipients()[0]).hasToString(user.getEmail()); |
| | | assertThat(message.getFrom()[0]).hasToString(jHipsterProperties.getMail().getFrom()); |
| | | assertThat(message.getContent().toString()).isNotEmpty(); |
| | | assertThat(message.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8"); |
| | | } |
| | | |
| | | @Test |
| | | void testSendEmailWithException() { |
| | | doThrow(MailSendException.class).when(javaMailSender).send(any(MimeMessage.class)); |
| | | try { |
| | | mailService.sendEmail("john.doe@example.com", "testSubject", "testContent", false, false); |
| | | } catch (Exception e) { |
| | | fail("Exception shouldn't have been thrown"); |
| | | } |
| | | } |
| | | |
| | | @Test |
| | | void testSendLocalizedEmailForAllSupportedLanguages() throws Exception { |
| | | User user = new User(); |
| | | user.setLogin("john"); |
| | | user.setEmail("john.doe@example.com"); |
| | | for (String langKey : languages) { |
| | | user.setLangKey(langKey); |
| | | mailService.sendEmailFromTemplate(user, "mail/testEmail", "email.test.title"); |
| | | verify(javaMailSender, atLeastOnce()).send(messageCaptor.capture()); |
| | | MimeMessage message = messageCaptor.getValue(); |
| | | |
| | | 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(); |
| | | properties.load(new InputStreamReader(new FileInputStream(file), Charset.forName("UTF-8"))); |
| | | |
| | | String emailTitle = (String) properties.get("email.test.title"); |
| | | assertThat(message.getSubject()).isEqualTo(emailTitle); |
| | | assertThat(message.getContent().toString()) |
| | | .isEqualToNormalizingNewlines("<html>" + emailTitle + ", http://127.0.0.1:8080, john</html>\n"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Convert a lang key to the Java locale. |
| | | */ |
| | | private String getJavaLocale(String langKey) { |
| | | String javaLangKey = langKey; |
| | | Matcher matcher2 = PATTERN_LOCALE_2.matcher(langKey); |
| | | if (matcher2.matches()) { |
| | | javaLangKey = matcher2.group(1) + "_" + matcher2.group(2).toUpperCase(); |
| | | } |
| | | Matcher matcher3 = PATTERN_LOCALE_3.matcher(langKey); |
| | | if (matcher3.matches()) { |
| | | javaLangKey = matcher3.group(1) + "_" + matcher3.group(2) + "_" + matcher3.group(3).toUpperCase(); |
| | | } |
| | | return javaLangKey; |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.service; |
| | | |
| | | import static org.assertj.core.api.Assertions.assertThat; |
| | | import static org.mockito.Mockito.when; |
| | | |
| | | import com.pollex.pam.IntegrationTest; |
| | | import com.pollex.pam.config.Constants; |
| | | import com.pollex.pam.domain.User; |
| | | import com.pollex.pam.repository.UserRepository; |
| | | import com.pollex.pam.service.dto.AdminUserDTO; |
| | | import java.time.Instant; |
| | | import java.time.LocalDateTime; |
| | | import java.time.temporal.ChronoUnit; |
| | | import java.util.List; |
| | | import java.util.Optional; |
| | | import org.apache.commons.lang3.RandomStringUtils; |
| | | import org.junit.jupiter.api.BeforeEach; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.boot.test.mock.mockito.MockBean; |
| | | import org.springframework.data.auditing.AuditingHandler; |
| | | import org.springframework.data.auditing.DateTimeProvider; |
| | | import org.springframework.data.domain.Page; |
| | | import org.springframework.data.domain.PageRequest; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import tech.jhipster.security.RandomUtil; |
| | | |
| | | /** |
| | | * Integration tests for {@link UserService}. |
| | | */ |
| | | @IntegrationTest |
| | | @Transactional |
| | | class UserServiceIT { |
| | | |
| | | private static final String DEFAULT_LOGIN = "johndoe"; |
| | | |
| | | private static final String DEFAULT_EMAIL = "johndoe@localhost"; |
| | | |
| | | private static final String DEFAULT_FIRSTNAME = "john"; |
| | | |
| | | private static final String DEFAULT_LASTNAME = "doe"; |
| | | |
| | | private static final String DEFAULT_IMAGEURL = "http://placehold.it/50x50"; |
| | | |
| | | private static final String DEFAULT_LANGKEY = "dummy"; |
| | | |
| | | @Autowired |
| | | private UserRepository userRepository; |
| | | |
| | | @Autowired |
| | | private UserService userService; |
| | | |
| | | @Autowired |
| | | private AuditingHandler auditingHandler; |
| | | |
| | | @MockBean |
| | | private DateTimeProvider dateTimeProvider; |
| | | |
| | | private User user; |
| | | |
| | | @BeforeEach |
| | | public void init() { |
| | | user = new User(); |
| | | user.setLogin(DEFAULT_LOGIN); |
| | | user.setPassword(RandomStringUtils.random(60)); |
| | | user.setActivated(true); |
| | | user.setEmail(DEFAULT_EMAIL); |
| | | user.setFirstName(DEFAULT_FIRSTNAME); |
| | | user.setLastName(DEFAULT_LASTNAME); |
| | | user.setImageUrl(DEFAULT_IMAGEURL); |
| | | user.setLangKey(DEFAULT_LANGKEY); |
| | | |
| | | when(dateTimeProvider.getNow()).thenReturn(Optional.of(LocalDateTime.now())); |
| | | auditingHandler.setDateTimeProvider(dateTimeProvider); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void assertThatUserMustExistToResetPassword() { |
| | | userRepository.saveAndFlush(user); |
| | | Optional<User> maybeUser = userService.requestPasswordReset("invalid.login@localhost"); |
| | | assertThat(maybeUser).isNotPresent(); |
| | | |
| | | maybeUser = userService.requestPasswordReset(user.getEmail()); |
| | | assertThat(maybeUser).isPresent(); |
| | | assertThat(maybeUser.orElse(null).getEmail()).isEqualTo(user.getEmail()); |
| | | assertThat(maybeUser.orElse(null).getResetDate()).isNotNull(); |
| | | assertThat(maybeUser.orElse(null).getResetKey()).isNotNull(); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void assertThatOnlyActivatedUserCanRequestPasswordReset() { |
| | | user.setActivated(false); |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | Optional<User> maybeUser = userService.requestPasswordReset(user.getLogin()); |
| | | assertThat(maybeUser).isNotPresent(); |
| | | userRepository.delete(user); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void assertThatResetKeyMustNotBeOlderThan24Hours() { |
| | | Instant daysAgo = Instant.now().minus(25, ChronoUnit.HOURS); |
| | | String resetKey = RandomUtil.generateResetKey(); |
| | | user.setActivated(true); |
| | | user.setResetDate(daysAgo); |
| | | user.setResetKey(resetKey); |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | Optional<User> maybeUser = userService.completePasswordReset("johndoe2", user.getResetKey()); |
| | | assertThat(maybeUser).isNotPresent(); |
| | | userRepository.delete(user); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void assertThatResetKeyMustBeValid() { |
| | | Instant daysAgo = Instant.now().minus(25, ChronoUnit.HOURS); |
| | | user.setActivated(true); |
| | | user.setResetDate(daysAgo); |
| | | user.setResetKey("1234"); |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | Optional<User> maybeUser = userService.completePasswordReset("johndoe2", user.getResetKey()); |
| | | assertThat(maybeUser).isNotPresent(); |
| | | userRepository.delete(user); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void assertThatUserCanResetPassword() { |
| | | String oldPassword = user.getPassword(); |
| | | Instant daysAgo = Instant.now().minus(2, ChronoUnit.HOURS); |
| | | String resetKey = RandomUtil.generateResetKey(); |
| | | user.setActivated(true); |
| | | user.setResetDate(daysAgo); |
| | | user.setResetKey(resetKey); |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | Optional<User> maybeUser = userService.completePasswordReset("johndoe2", user.getResetKey()); |
| | | assertThat(maybeUser).isPresent(); |
| | | assertThat(maybeUser.orElse(null).getResetDate()).isNull(); |
| | | assertThat(maybeUser.orElse(null).getResetKey()).isNull(); |
| | | assertThat(maybeUser.orElse(null).getPassword()).isNotEqualTo(oldPassword); |
| | | |
| | | userRepository.delete(user); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void assertThatNotActivatedUsersWithNotNullActivationKeyCreatedBefore3DaysAreDeleted() { |
| | | Instant now = Instant.now(); |
| | | when(dateTimeProvider.getNow()).thenReturn(Optional.of(now.minus(4, ChronoUnit.DAYS))); |
| | | user.setActivated(false); |
| | | user.setActivationKey(RandomStringUtils.random(20)); |
| | | User dbUser = userRepository.saveAndFlush(user); |
| | | dbUser.setCreatedDate(now.minus(4, ChronoUnit.DAYS)); |
| | | userRepository.saveAndFlush(user); |
| | | Instant threeDaysAgo = now.minus(3, ChronoUnit.DAYS); |
| | | List<User> users = userRepository.findAllByActivatedIsFalseAndActivationKeyIsNotNullAndCreatedDateBefore(threeDaysAgo); |
| | | assertThat(users).isNotEmpty(); |
| | | userService.removeNotActivatedUsers(); |
| | | users = userRepository.findAllByActivatedIsFalseAndActivationKeyIsNotNullAndCreatedDateBefore(threeDaysAgo); |
| | | assertThat(users).isEmpty(); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void assertThatNotActivatedUsersWithNullActivationKeyCreatedBefore3DaysAreNotDeleted() { |
| | | Instant now = Instant.now(); |
| | | when(dateTimeProvider.getNow()).thenReturn(Optional.of(now.minus(4, ChronoUnit.DAYS))); |
| | | user.setActivated(false); |
| | | User dbUser = userRepository.saveAndFlush(user); |
| | | dbUser.setCreatedDate(now.minus(4, ChronoUnit.DAYS)); |
| | | userRepository.saveAndFlush(user); |
| | | Instant threeDaysAgo = now.minus(3, ChronoUnit.DAYS); |
| | | List<User> users = userRepository.findAllByActivatedIsFalseAndActivationKeyIsNotNullAndCreatedDateBefore(threeDaysAgo); |
| | | assertThat(users).isEmpty(); |
| | | userService.removeNotActivatedUsers(); |
| | | Optional<User> maybeDbUser = userRepository.findById(dbUser.getId()); |
| | | assertThat(maybeDbUser).contains(dbUser); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.service.mapper; |
| | | |
| | | import static org.assertj.core.api.Assertions.assertThat; |
| | | |
| | | import com.pollex.pam.domain.User; |
| | | import com.pollex.pam.service.dto.AdminUserDTO; |
| | | import com.pollex.pam.service.dto.UserDTO; |
| | | import java.util.ArrayList; |
| | | import java.util.HashSet; |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | import org.apache.commons.lang3.RandomStringUtils; |
| | | import org.junit.jupiter.api.BeforeEach; |
| | | import org.junit.jupiter.api.Test; |
| | | |
| | | /** |
| | | * Unit tests for {@link UserMapper}. |
| | | */ |
| | | class UserMapperTest { |
| | | |
| | | private static final String DEFAULT_LOGIN = "johndoe"; |
| | | private static final Long DEFAULT_ID = 1L; |
| | | |
| | | private UserMapper userMapper; |
| | | private User user; |
| | | private AdminUserDTO userDto; |
| | | |
| | | @BeforeEach |
| | | public void init() { |
| | | userMapper = new UserMapper(); |
| | | user = new User(); |
| | | user.setLogin(DEFAULT_LOGIN); |
| | | user.setPassword(RandomStringUtils.random(60)); |
| | | user.setActivated(true); |
| | | user.setEmail("johndoe@localhost"); |
| | | user.setFirstName("john"); |
| | | user.setLastName("doe"); |
| | | user.setImageUrl("image_url"); |
| | | user.setLangKey("en"); |
| | | |
| | | userDto = new AdminUserDTO(user); |
| | | } |
| | | |
| | | @Test |
| | | void usersToUserDTOsShouldMapOnlyNonNullUsers() { |
| | | List<User> users = new ArrayList<>(); |
| | | users.add(user); |
| | | users.add(null); |
| | | |
| | | List<UserDTO> userDTOS = userMapper.usersToUserDTOs(users); |
| | | |
| | | assertThat(userDTOS).isNotEmpty().size().isEqualTo(1); |
| | | } |
| | | |
| | | @Test |
| | | void userDTOsToUsersShouldMapOnlyNonNullUsers() { |
| | | List<AdminUserDTO> usersDto = new ArrayList<>(); |
| | | usersDto.add(userDto); |
| | | usersDto.add(null); |
| | | |
| | | List<User> users = userMapper.userDTOsToUsers(usersDto); |
| | | |
| | | assertThat(users).isNotEmpty().size().isEqualTo(1); |
| | | } |
| | | |
| | | @Test |
| | | void userDTOsToUsersWithAuthoritiesStringShouldMapToUsersWithAuthoritiesDomain() { |
| | | Set<String> authoritiesAsString = new HashSet<>(); |
| | | authoritiesAsString.add("ADMIN"); |
| | | userDto.setAuthorities(authoritiesAsString); |
| | | |
| | | List<AdminUserDTO> usersDto = new ArrayList<>(); |
| | | usersDto.add(userDto); |
| | | |
| | | List<User> users = userMapper.userDTOsToUsers(usersDto); |
| | | |
| | | assertThat(users).isNotEmpty().size().isEqualTo(1); |
| | | assertThat(users.get(0).getAuthorities()).isNotNull(); |
| | | assertThat(users.get(0).getAuthorities()).isNotEmpty(); |
| | | assertThat(users.get(0).getAuthorities().iterator().next().getName()).isEqualTo("ADMIN"); |
| | | } |
| | | |
| | | @Test |
| | | void userDTOsToUsersMapWithNullAuthoritiesStringShouldReturnUserWithEmptyAuthorities() { |
| | | userDto.setAuthorities(null); |
| | | |
| | | List<AdminUserDTO> usersDto = new ArrayList<>(); |
| | | usersDto.add(userDto); |
| | | |
| | | List<User> users = userMapper.userDTOsToUsers(usersDto); |
| | | |
| | | assertThat(users).isNotEmpty().size().isEqualTo(1); |
| | | assertThat(users.get(0).getAuthorities()).isNotNull(); |
| | | assertThat(users.get(0).getAuthorities()).isEmpty(); |
| | | } |
| | | |
| | | @Test |
| | | void userDTOToUserMapWithAuthoritiesStringShouldReturnUserWithAuthorities() { |
| | | Set<String> authoritiesAsString = new HashSet<>(); |
| | | authoritiesAsString.add("ADMIN"); |
| | | userDto.setAuthorities(authoritiesAsString); |
| | | |
| | | User user = userMapper.userDTOToUser(userDto); |
| | | |
| | | assertThat(user).isNotNull(); |
| | | assertThat(user.getAuthorities()).isNotNull(); |
| | | assertThat(user.getAuthorities()).isNotEmpty(); |
| | | assertThat(user.getAuthorities().iterator().next().getName()).isEqualTo("ADMIN"); |
| | | } |
| | | |
| | | @Test |
| | | void userDTOToUserMapWithNullAuthoritiesStringShouldReturnUserWithEmptyAuthorities() { |
| | | userDto.setAuthorities(null); |
| | | |
| | | User user = userMapper.userDTOToUser(userDto); |
| | | |
| | | assertThat(user).isNotNull(); |
| | | assertThat(user.getAuthorities()).isNotNull(); |
| | | assertThat(user.getAuthorities()).isEmpty(); |
| | | } |
| | | |
| | | @Test |
| | | void userDTOToUserMapWithNullUserShouldReturnNull() { |
| | | assertThat(userMapper.userDTOToUser(null)).isNull(); |
| | | } |
| | | |
| | | @Test |
| | | void testUserFromId() { |
| | | assertThat(userMapper.userFromId(DEFAULT_ID).getId()).isEqualTo(DEFAULT_ID); |
| | | assertThat(userMapper.userFromId(null)).isNull(); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.rest; |
| | | |
| | | import static com.pollex.pam.web.rest.AccountResourceIT.TEST_USER_LOGIN; |
| | | import static org.assertj.core.api.Assertions.assertThat; |
| | | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; |
| | | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; |
| | | |
| | | import com.pollex.pam.IntegrationTest; |
| | | import com.pollex.pam.config.Constants; |
| | | import com.pollex.pam.domain.User; |
| | | import com.pollex.pam.repository.AuthorityRepository; |
| | | import com.pollex.pam.repository.UserRepository; |
| | | import com.pollex.pam.security.AuthoritiesConstants; |
| | | import com.pollex.pam.service.UserService; |
| | | import com.pollex.pam.service.dto.AdminUserDTO; |
| | | import com.pollex.pam.service.dto.PasswordChangeDTO; |
| | | import com.pollex.pam.service.dto.UserDTO; |
| | | import com.pollex.pam.web.rest.vm.KeyAndPasswordVM; |
| | | import com.pollex.pam.web.rest.vm.ManagedUserVM; |
| | | import java.time.Instant; |
| | | import java.util.*; |
| | | import org.apache.commons.lang3.RandomStringUtils; |
| | | 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.http.MediaType; |
| | | import org.springframework.security.crypto.password.PasswordEncoder; |
| | | import org.springframework.security.test.context.support.WithMockUser; |
| | | import org.springframework.test.web.servlet.MockMvc; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | /** |
| | | * Integration tests for the {@link AccountResource} REST controller. |
| | | */ |
| | | @AutoConfigureMockMvc |
| | | @WithMockUser(value = TEST_USER_LOGIN) |
| | | @IntegrationTest |
| | | class AccountResourceIT { |
| | | |
| | | static final String TEST_USER_LOGIN = "test"; |
| | | |
| | | @Autowired |
| | | private UserRepository userRepository; |
| | | |
| | | @Autowired |
| | | private AuthorityRepository authorityRepository; |
| | | |
| | | @Autowired |
| | | private UserService userService; |
| | | |
| | | @Autowired |
| | | private PasswordEncoder passwordEncoder; |
| | | |
| | | @Autowired |
| | | private MockMvc restAccountMockMvc; |
| | | |
| | | @Test |
| | | @WithUnauthenticatedMockUser |
| | | void testNonAuthenticatedUser() throws Exception { |
| | | restAccountMockMvc |
| | | .perform(get("/api/authenticate").accept(MediaType.APPLICATION_JSON)) |
| | | .andExpect(status().isOk()) |
| | | .andExpect(content().string("")); |
| | | } |
| | | |
| | | @Test |
| | | void testAuthenticatedUser() throws Exception { |
| | | restAccountMockMvc |
| | | .perform( |
| | | get("/api/authenticate") |
| | | .with(request -> { |
| | | request.setRemoteUser(TEST_USER_LOGIN); |
| | | return request; |
| | | }) |
| | | .accept(MediaType.APPLICATION_JSON) |
| | | ) |
| | | .andExpect(status().isOk()) |
| | | .andExpect(content().string(TEST_USER_LOGIN)); |
| | | } |
| | | |
| | | @Test |
| | | void testGetExistingAccount() throws Exception { |
| | | Set<String> authorities = new HashSet<>(); |
| | | authorities.add(AuthoritiesConstants.ADMIN); |
| | | |
| | | AdminUserDTO user = new AdminUserDTO(); |
| | | user.setLogin(TEST_USER_LOGIN); |
| | | user.setFirstName("john"); |
| | | user.setLastName("doe"); |
| | | user.setEmail("john.doe@jhipster.com"); |
| | | user.setImageUrl("http://placehold.it/50x50"); |
| | | user.setLangKey("en"); |
| | | user.setAuthorities(authorities); |
| | | userService.createUser(user); |
| | | |
| | | restAccountMockMvc |
| | | .perform(get("/api/account").accept(MediaType.APPLICATION_JSON)) |
| | | .andExpect(status().isOk()) |
| | | .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) |
| | | .andExpect(jsonPath("$.login").value(TEST_USER_LOGIN)) |
| | | .andExpect(jsonPath("$.firstName").value("john")) |
| | | .andExpect(jsonPath("$.lastName").value("doe")) |
| | | .andExpect(jsonPath("$.email").value("john.doe@jhipster.com")) |
| | | .andExpect(jsonPath("$.imageUrl").value("http://placehold.it/50x50")) |
| | | .andExpect(jsonPath("$.langKey").value("en")) |
| | | .andExpect(jsonPath("$.authorities").value(AuthoritiesConstants.ADMIN)); |
| | | } |
| | | |
| | | @Test |
| | | void testGetUnknownAccount() throws Exception { |
| | | restAccountMockMvc |
| | | .perform(get("/api/account").accept(MediaType.APPLICATION_PROBLEM_JSON)) |
| | | .andExpect(status().isInternalServerError()); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void testRegisterValid() throws Exception { |
| | | ManagedUserVM validUser = new ManagedUserVM(); |
| | | validUser.setLogin("test-register-valid"); |
| | | validUser.setPassword("password"); |
| | | validUser.setFirstName("Alice"); |
| | | validUser.setLastName("Test"); |
| | | validUser.setEmail("test-register-valid@example.com"); |
| | | validUser.setImageUrl("http://placehold.it/50x50"); |
| | | validUser.setLangKey(Constants.DEFAULT_LANGUAGE); |
| | | validUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); |
| | | assertThat(userRepository.findOneByLogin("test-register-valid")).isEmpty(); |
| | | |
| | | restAccountMockMvc |
| | | .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(validUser))) |
| | | .andExpect(status().isCreated()); |
| | | |
| | | assertThat(userRepository.findOneByLogin("test-register-valid")).isPresent(); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void testRegisterInvalidLogin() throws Exception { |
| | | ManagedUserVM invalidUser = new ManagedUserVM(); |
| | | invalidUser.setLogin("funky-log(n"); // <-- invalid |
| | | invalidUser.setPassword("password"); |
| | | invalidUser.setFirstName("Funky"); |
| | | invalidUser.setLastName("One"); |
| | | invalidUser.setEmail("funky@example.com"); |
| | | invalidUser.setActivated(true); |
| | | invalidUser.setImageUrl("http://placehold.it/50x50"); |
| | | invalidUser.setLangKey(Constants.DEFAULT_LANGUAGE); |
| | | invalidUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); |
| | | |
| | | restAccountMockMvc |
| | | .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(invalidUser))) |
| | | .andExpect(status().isBadRequest()); |
| | | |
| | | Optional<User> user = userRepository.findOneByEmailIgnoreCase("funky@example.com"); |
| | | assertThat(user).isEmpty(); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void testRegisterInvalidEmail() throws Exception { |
| | | ManagedUserVM invalidUser = new ManagedUserVM(); |
| | | invalidUser.setLogin("bob"); |
| | | invalidUser.setPassword("password"); |
| | | invalidUser.setFirstName("Bob"); |
| | | invalidUser.setLastName("Green"); |
| | | invalidUser.setEmail("invalid"); // <-- invalid |
| | | invalidUser.setActivated(true); |
| | | invalidUser.setImageUrl("http://placehold.it/50x50"); |
| | | invalidUser.setLangKey(Constants.DEFAULT_LANGUAGE); |
| | | invalidUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); |
| | | |
| | | restAccountMockMvc |
| | | .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(invalidUser))) |
| | | .andExpect(status().isBadRequest()); |
| | | |
| | | Optional<User> user = userRepository.findOneByLogin("bob"); |
| | | assertThat(user).isEmpty(); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void testRegisterInvalidPassword() throws Exception { |
| | | ManagedUserVM invalidUser = new ManagedUserVM(); |
| | | invalidUser.setLogin("bob"); |
| | | invalidUser.setPassword("123"); // password with only 3 digits |
| | | invalidUser.setFirstName("Bob"); |
| | | invalidUser.setLastName("Green"); |
| | | invalidUser.setEmail("bob@example.com"); |
| | | invalidUser.setActivated(true); |
| | | invalidUser.setImageUrl("http://placehold.it/50x50"); |
| | | invalidUser.setLangKey(Constants.DEFAULT_LANGUAGE); |
| | | invalidUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); |
| | | |
| | | restAccountMockMvc |
| | | .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(invalidUser))) |
| | | .andExpect(status().isBadRequest()); |
| | | |
| | | Optional<User> user = userRepository.findOneByLogin("bob"); |
| | | assertThat(user).isEmpty(); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void testRegisterNullPassword() throws Exception { |
| | | ManagedUserVM invalidUser = new ManagedUserVM(); |
| | | invalidUser.setLogin("bob"); |
| | | invalidUser.setPassword(null); // invalid null password |
| | | invalidUser.setFirstName("Bob"); |
| | | invalidUser.setLastName("Green"); |
| | | invalidUser.setEmail("bob@example.com"); |
| | | invalidUser.setActivated(true); |
| | | invalidUser.setImageUrl("http://placehold.it/50x50"); |
| | | invalidUser.setLangKey(Constants.DEFAULT_LANGUAGE); |
| | | invalidUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); |
| | | |
| | | restAccountMockMvc |
| | | .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(invalidUser))) |
| | | .andExpect(status().isBadRequest()); |
| | | |
| | | Optional<User> user = userRepository.findOneByLogin("bob"); |
| | | assertThat(user).isEmpty(); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void testRegisterDuplicateLogin() throws Exception { |
| | | // First registration |
| | | ManagedUserVM firstUser = new ManagedUserVM(); |
| | | firstUser.setLogin("alice"); |
| | | firstUser.setPassword("password"); |
| | | firstUser.setFirstName("Alice"); |
| | | firstUser.setLastName("Something"); |
| | | firstUser.setEmail("alice@example.com"); |
| | | firstUser.setImageUrl("http://placehold.it/50x50"); |
| | | firstUser.setLangKey(Constants.DEFAULT_LANGUAGE); |
| | | firstUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); |
| | | |
| | | // Duplicate login, different email |
| | | ManagedUserVM secondUser = new ManagedUserVM(); |
| | | secondUser.setLogin(firstUser.getLogin()); |
| | | secondUser.setPassword(firstUser.getPassword()); |
| | | secondUser.setFirstName(firstUser.getFirstName()); |
| | | secondUser.setLastName(firstUser.getLastName()); |
| | | secondUser.setEmail("alice2@example.com"); |
| | | secondUser.setImageUrl(firstUser.getImageUrl()); |
| | | secondUser.setLangKey(firstUser.getLangKey()); |
| | | secondUser.setCreatedBy(firstUser.getCreatedBy()); |
| | | secondUser.setCreatedDate(firstUser.getCreatedDate()); |
| | | secondUser.setLastModifiedBy(firstUser.getLastModifiedBy()); |
| | | secondUser.setLastModifiedDate(firstUser.getLastModifiedDate()); |
| | | secondUser.setAuthorities(new HashSet<>(firstUser.getAuthorities())); |
| | | |
| | | // First user |
| | | restAccountMockMvc |
| | | .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(firstUser))) |
| | | .andExpect(status().isCreated()); |
| | | |
| | | // Second (non activated) user |
| | | restAccountMockMvc |
| | | .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(secondUser))) |
| | | .andExpect(status().isCreated()); |
| | | |
| | | Optional<User> testUser = userRepository.findOneByEmailIgnoreCase("alice2@example.com"); |
| | | assertThat(testUser).isPresent(); |
| | | 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().is4xxClientError()); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void testRegisterDuplicateEmail() throws Exception { |
| | | // First user |
| | | ManagedUserVM firstUser = new ManagedUserVM(); |
| | | firstUser.setLogin("test-register-duplicate-email"); |
| | | firstUser.setPassword("password"); |
| | | firstUser.setFirstName("Alice"); |
| | | firstUser.setLastName("Test"); |
| | | firstUser.setEmail("test-register-duplicate-email@example.com"); |
| | | firstUser.setImageUrl("http://placehold.it/50x50"); |
| | | firstUser.setLangKey(Constants.DEFAULT_LANGUAGE); |
| | | firstUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); |
| | | |
| | | // Register first user |
| | | restAccountMockMvc |
| | | .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(firstUser))) |
| | | .andExpect(status().isCreated()); |
| | | |
| | | Optional<User> testUser1 = userRepository.findOneByLogin("test-register-duplicate-email"); |
| | | assertThat(testUser1).isPresent(); |
| | | |
| | | // Duplicate email, different login |
| | | ManagedUserVM secondUser = new ManagedUserVM(); |
| | | secondUser.setLogin("test-register-duplicate-email-2"); |
| | | secondUser.setPassword(firstUser.getPassword()); |
| | | secondUser.setFirstName(firstUser.getFirstName()); |
| | | secondUser.setLastName(firstUser.getLastName()); |
| | | secondUser.setEmail(firstUser.getEmail()); |
| | | secondUser.setImageUrl(firstUser.getImageUrl()); |
| | | secondUser.setLangKey(firstUser.getLangKey()); |
| | | secondUser.setAuthorities(new HashSet<>(firstUser.getAuthorities())); |
| | | |
| | | // Register second (non activated) user |
| | | restAccountMockMvc |
| | | .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(secondUser))) |
| | | .andExpect(status().isCreated()); |
| | | |
| | | Optional<User> testUser2 = userRepository.findOneByLogin("test-register-duplicate-email"); |
| | | assertThat(testUser2).isEmpty(); |
| | | |
| | | Optional<User> testUser3 = userRepository.findOneByLogin("test-register-duplicate-email-2"); |
| | | assertThat(testUser3).isPresent(); |
| | | |
| | | // Duplicate email - with uppercase email address |
| | | ManagedUserVM userWithUpperCaseEmail = new ManagedUserVM(); |
| | | userWithUpperCaseEmail.setId(firstUser.getId()); |
| | | userWithUpperCaseEmail.setLogin("test-register-duplicate-email-3"); |
| | | userWithUpperCaseEmail.setPassword(firstUser.getPassword()); |
| | | userWithUpperCaseEmail.setFirstName(firstUser.getFirstName()); |
| | | userWithUpperCaseEmail.setLastName(firstUser.getLastName()); |
| | | userWithUpperCaseEmail.setEmail("TEST-register-duplicate-email@example.com"); |
| | | userWithUpperCaseEmail.setImageUrl(firstUser.getImageUrl()); |
| | | userWithUpperCaseEmail.setLangKey(firstUser.getLangKey()); |
| | | userWithUpperCaseEmail.setAuthorities(new HashSet<>(firstUser.getAuthorities())); |
| | | |
| | | // Register third (not activated) user |
| | | restAccountMockMvc |
| | | .perform( |
| | | post("/api/register") |
| | | .contentType(MediaType.APPLICATION_JSON) |
| | | .content(TestUtil.convertObjectToJsonBytes(userWithUpperCaseEmail)) |
| | | ) |
| | | .andExpect(status().isCreated()); |
| | | |
| | | Optional<User> testUser4 = userRepository.findOneByLogin("test-register-duplicate-email-3"); |
| | | assertThat(testUser4).isPresent(); |
| | | assertThat(testUser4.get().getEmail()).isEqualTo("test-register-duplicate-email@example.com"); |
| | | |
| | | 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().is4xxClientError()); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void testRegisterAdminIsIgnored() throws Exception { |
| | | ManagedUserVM validUser = new ManagedUserVM(); |
| | | validUser.setLogin("badguy"); |
| | | validUser.setPassword("password"); |
| | | validUser.setFirstName("Bad"); |
| | | validUser.setLastName("Guy"); |
| | | validUser.setEmail("badguy@example.com"); |
| | | validUser.setActivated(true); |
| | | validUser.setImageUrl("http://placehold.it/50x50"); |
| | | validUser.setLangKey(Constants.DEFAULT_LANGUAGE); |
| | | validUser.setAuthorities(Collections.singleton(AuthoritiesConstants.ADMIN)); |
| | | |
| | | restAccountMockMvc |
| | | .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(validUser))) |
| | | .andExpect(status().isCreated()); |
| | | |
| | | Optional<User> userDup = userRepository.findOneWithAuthoritiesByLogin("badguy"); |
| | | assertThat(userDup).isPresent(); |
| | | assertThat(userDup.get().getAuthorities()) |
| | | .hasSize(1) |
| | | .containsExactly(authorityRepository.findById(AuthoritiesConstants.USER).get()); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void testActivateAccount() throws Exception { |
| | | final String activationKey = "some activation key"; |
| | | User user = new User(); |
| | | user.setLogin("activate-account"); |
| | | user.setEmail("activate-account@example.com"); |
| | | user.setPassword(RandomStringUtils.random(60)); |
| | | user.setActivated(false); |
| | | user.setActivationKey(activationKey); |
| | | |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | restAccountMockMvc.perform(get("/api/activate?key={activationKey}", activationKey)).andExpect(status().isOk()); |
| | | |
| | | user = userRepository.findOneByLogin(user.getLogin()).orElse(null); |
| | | assertThat(user.isActivated()).isTrue(); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void testActivateAccountWithWrongKey() throws Exception { |
| | | restAccountMockMvc.perform(get("/api/activate?key=wrongActivationKey")).andExpect(status().isInternalServerError()); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | @WithMockUser("save-account") |
| | | void testSaveAccount() throws Exception { |
| | | User user = new User(); |
| | | user.setLogin("save-account"); |
| | | user.setEmail("save-account@example.com"); |
| | | user.setPassword(RandomStringUtils.random(60)); |
| | | user.setActivated(true); |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | AdminUserDTO userDTO = new AdminUserDTO(); |
| | | userDTO.setLogin("not-used"); |
| | | userDTO.setFirstName("firstname"); |
| | | userDTO.setLastName("lastname"); |
| | | userDTO.setEmail("save-account@example.com"); |
| | | userDTO.setActivated(false); |
| | | userDTO.setImageUrl("http://placehold.it/50x50"); |
| | | userDTO.setLangKey(Constants.DEFAULT_LANGUAGE); |
| | | userDTO.setAuthorities(Collections.singleton(AuthoritiesConstants.ADMIN)); |
| | | |
| | | restAccountMockMvc |
| | | .perform(post("/api/account").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(userDTO))) |
| | | .andExpect(status().isOk()); |
| | | |
| | | User updatedUser = userRepository.findOneWithAuthoritiesByLogin(user.getLogin()).orElse(null); |
| | | assertThat(updatedUser.getFirstName()).isEqualTo(userDTO.getFirstName()); |
| | | assertThat(updatedUser.getLastName()).isEqualTo(userDTO.getLastName()); |
| | | assertThat(updatedUser.getEmail()).isEqualTo(userDTO.getEmail()); |
| | | assertThat(updatedUser.getLangKey()).isEqualTo(userDTO.getLangKey()); |
| | | assertThat(updatedUser.getPassword()).isEqualTo(user.getPassword()); |
| | | assertThat(updatedUser.getImageUrl()).isEqualTo(userDTO.getImageUrl()); |
| | | assertThat(updatedUser.isActivated()).isTrue(); |
| | | assertThat(updatedUser.getAuthorities()).isEmpty(); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | @WithMockUser("save-invalid-email") |
| | | void testSaveInvalidEmail() throws Exception { |
| | | User user = new User(); |
| | | user.setLogin("save-invalid-email"); |
| | | user.setEmail("save-invalid-email@example.com"); |
| | | user.setPassword(RandomStringUtils.random(60)); |
| | | user.setActivated(true); |
| | | |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | AdminUserDTO userDTO = new AdminUserDTO(); |
| | | userDTO.setLogin("not-used"); |
| | | userDTO.setFirstName("firstname"); |
| | | userDTO.setLastName("lastname"); |
| | | userDTO.setEmail("invalid email"); |
| | | userDTO.setActivated(false); |
| | | userDTO.setImageUrl("http://placehold.it/50x50"); |
| | | userDTO.setLangKey(Constants.DEFAULT_LANGUAGE); |
| | | userDTO.setAuthorities(Collections.singleton(AuthoritiesConstants.ADMIN)); |
| | | |
| | | restAccountMockMvc |
| | | .perform(post("/api/account").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(userDTO))) |
| | | .andExpect(status().isBadRequest()); |
| | | |
| | | assertThat(userRepository.findOneByEmailIgnoreCase("invalid email")).isNotPresent(); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | @WithMockUser("save-existing-email") |
| | | void testSaveExistingEmail() throws Exception { |
| | | User user = new User(); |
| | | user.setLogin("save-existing-email"); |
| | | user.setEmail("save-existing-email@example.com"); |
| | | user.setPassword(RandomStringUtils.random(60)); |
| | | user.setActivated(true); |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | User anotherUser = new User(); |
| | | anotherUser.setLogin("save-existing-email2"); |
| | | anotherUser.setEmail("save-existing-email2@example.com"); |
| | | anotherUser.setPassword(RandomStringUtils.random(60)); |
| | | anotherUser.setActivated(true); |
| | | |
| | | userRepository.saveAndFlush(anotherUser); |
| | | |
| | | AdminUserDTO userDTO = new AdminUserDTO(); |
| | | userDTO.setLogin("not-used"); |
| | | userDTO.setFirstName("firstname"); |
| | | userDTO.setLastName("lastname"); |
| | | userDTO.setEmail("save-existing-email2@example.com"); |
| | | userDTO.setActivated(false); |
| | | userDTO.setImageUrl("http://placehold.it/50x50"); |
| | | userDTO.setLangKey(Constants.DEFAULT_LANGUAGE); |
| | | userDTO.setAuthorities(Collections.singleton(AuthoritiesConstants.ADMIN)); |
| | | |
| | | restAccountMockMvc |
| | | .perform(post("/api/account").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(userDTO))) |
| | | .andExpect(status().isBadRequest()); |
| | | |
| | | User updatedUser = userRepository.findOneByLogin("save-existing-email").orElse(null); |
| | | assertThat(updatedUser.getEmail()).isEqualTo("save-existing-email@example.com"); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | @WithMockUser("save-existing-email-and-login") |
| | | void testSaveExistingEmailAndLogin() throws Exception { |
| | | User user = new User(); |
| | | user.setLogin("save-existing-email-and-login"); |
| | | user.setEmail("save-existing-email-and-login@example.com"); |
| | | user.setPassword(RandomStringUtils.random(60)); |
| | | user.setActivated(true); |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | AdminUserDTO userDTO = new AdminUserDTO(); |
| | | userDTO.setLogin("not-used"); |
| | | userDTO.setFirstName("firstname"); |
| | | userDTO.setLastName("lastname"); |
| | | userDTO.setEmail("save-existing-email-and-login@example.com"); |
| | | userDTO.setActivated(false); |
| | | userDTO.setImageUrl("http://placehold.it/50x50"); |
| | | userDTO.setLangKey(Constants.DEFAULT_LANGUAGE); |
| | | userDTO.setAuthorities(Collections.singleton(AuthoritiesConstants.ADMIN)); |
| | | |
| | | restAccountMockMvc |
| | | .perform(post("/api/account").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(userDTO))) |
| | | .andExpect(status().isOk()); |
| | | |
| | | User updatedUser = userRepository.findOneByLogin("save-existing-email-and-login").orElse(null); |
| | | assertThat(updatedUser.getEmail()).isEqualTo("save-existing-email-and-login@example.com"); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | @WithMockUser("change-password-wrong-existing-password") |
| | | void testChangePasswordWrongExistingPassword() throws Exception { |
| | | User user = new User(); |
| | | String currentPassword = RandomStringUtils.random(60); |
| | | user.setPassword(passwordEncoder.encode(currentPassword)); |
| | | user.setLogin("change-password-wrong-existing-password"); |
| | | user.setEmail("change-password-wrong-existing-password@example.com"); |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | restAccountMockMvc |
| | | .perform( |
| | | post("/api/account/change-password") |
| | | .contentType(MediaType.APPLICATION_JSON) |
| | | .content(TestUtil.convertObjectToJsonBytes(new PasswordChangeDTO("1" + currentPassword, "new password"))) |
| | | ) |
| | | .andExpect(status().isBadRequest()); |
| | | |
| | | User updatedUser = userRepository.findOneByLogin("change-password-wrong-existing-password").orElse(null); |
| | | assertThat(passwordEncoder.matches("new password", updatedUser.getPassword())).isFalse(); |
| | | assertThat(passwordEncoder.matches(currentPassword, updatedUser.getPassword())).isTrue(); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | @WithMockUser("change-password") |
| | | void testChangePassword() throws Exception { |
| | | User user = new User(); |
| | | String currentPassword = RandomStringUtils.random(60); |
| | | user.setPassword(passwordEncoder.encode(currentPassword)); |
| | | user.setLogin("change-password"); |
| | | user.setEmail("change-password@example.com"); |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | restAccountMockMvc |
| | | .perform( |
| | | post("/api/account/change-password") |
| | | .contentType(MediaType.APPLICATION_JSON) |
| | | .content(TestUtil.convertObjectToJsonBytes(new PasswordChangeDTO(currentPassword, "new password"))) |
| | | ) |
| | | .andExpect(status().isOk()); |
| | | |
| | | User updatedUser = userRepository.findOneByLogin("change-password").orElse(null); |
| | | assertThat(passwordEncoder.matches("new password", updatedUser.getPassword())).isTrue(); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | @WithMockUser("change-password-too-small") |
| | | void testChangePasswordTooSmall() throws Exception { |
| | | User user = new User(); |
| | | String currentPassword = RandomStringUtils.random(60); |
| | | user.setPassword(passwordEncoder.encode(currentPassword)); |
| | | user.setLogin("change-password-too-small"); |
| | | user.setEmail("change-password-too-small@example.com"); |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | String newPassword = RandomStringUtils.random(ManagedUserVM.PASSWORD_MIN_LENGTH - 1); |
| | | |
| | | restAccountMockMvc |
| | | .perform( |
| | | post("/api/account/change-password") |
| | | .contentType(MediaType.APPLICATION_JSON) |
| | | .content(TestUtil.convertObjectToJsonBytes(new PasswordChangeDTO(currentPassword, newPassword))) |
| | | ) |
| | | .andExpect(status().isBadRequest()); |
| | | |
| | | User updatedUser = userRepository.findOneByLogin("change-password-too-small").orElse(null); |
| | | assertThat(updatedUser.getPassword()).isEqualTo(user.getPassword()); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | @WithMockUser("change-password-too-long") |
| | | void testChangePasswordTooLong() throws Exception { |
| | | User user = new User(); |
| | | String currentPassword = RandomStringUtils.random(60); |
| | | user.setPassword(passwordEncoder.encode(currentPassword)); |
| | | user.setLogin("change-password-too-long"); |
| | | user.setEmail("change-password-too-long@example.com"); |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | String newPassword = RandomStringUtils.random(ManagedUserVM.PASSWORD_MAX_LENGTH + 1); |
| | | |
| | | restAccountMockMvc |
| | | .perform( |
| | | post("/api/account/change-password") |
| | | .contentType(MediaType.APPLICATION_JSON) |
| | | .content(TestUtil.convertObjectToJsonBytes(new PasswordChangeDTO(currentPassword, newPassword))) |
| | | ) |
| | | .andExpect(status().isBadRequest()); |
| | | |
| | | User updatedUser = userRepository.findOneByLogin("change-password-too-long").orElse(null); |
| | | assertThat(updatedUser.getPassword()).isEqualTo(user.getPassword()); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | @WithMockUser("change-password-empty") |
| | | void testChangePasswordEmpty() throws Exception { |
| | | User user = new User(); |
| | | String currentPassword = RandomStringUtils.random(60); |
| | | user.setPassword(passwordEncoder.encode(currentPassword)); |
| | | user.setLogin("change-password-empty"); |
| | | user.setEmail("change-password-empty@example.com"); |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | restAccountMockMvc |
| | | .perform( |
| | | post("/api/account/change-password") |
| | | .contentType(MediaType.APPLICATION_JSON) |
| | | .content(TestUtil.convertObjectToJsonBytes(new PasswordChangeDTO(currentPassword, ""))) |
| | | ) |
| | | .andExpect(status().isBadRequest()); |
| | | |
| | | User updatedUser = userRepository.findOneByLogin("change-password-empty").orElse(null); |
| | | assertThat(updatedUser.getPassword()).isEqualTo(user.getPassword()); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void testRequestPasswordReset() throws Exception { |
| | | User user = new User(); |
| | | user.setPassword(RandomStringUtils.random(60)); |
| | | user.setActivated(true); |
| | | user.setLogin("password-reset"); |
| | | user.setEmail("password-reset@example.com"); |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | restAccountMockMvc |
| | | .perform(post("/api/account/reset-password/init").content("password-reset@example.com")) |
| | | .andExpect(status().isOk()); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void testRequestPasswordResetUpperCaseEmail() throws Exception { |
| | | User user = new User(); |
| | | user.setPassword(RandomStringUtils.random(60)); |
| | | user.setActivated(true); |
| | | user.setLogin("password-reset-upper-case"); |
| | | user.setEmail("password-reset-upper-case@example.com"); |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | restAccountMockMvc |
| | | .perform(post("/api/account/reset-password/init").content("password-reset-upper-case@EXAMPLE.COM")) |
| | | .andExpect(status().isOk()); |
| | | } |
| | | |
| | | @Test |
| | | void testRequestPasswordResetWrongEmail() throws Exception { |
| | | restAccountMockMvc |
| | | .perform(post("/api/account/reset-password/init").content("password-reset-wrong-email@example.com")) |
| | | .andExpect(status().isOk()); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void testFinishPasswordReset() throws Exception { |
| | | User user = new User(); |
| | | user.setPassword(RandomStringUtils.random(60)); |
| | | user.setLogin("finish-password-reset"); |
| | | user.setEmail("finish-password-reset@example.com"); |
| | | user.setResetDate(Instant.now().plusSeconds(60)); |
| | | user.setResetKey("reset key"); |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | KeyAndPasswordVM keyAndPassword = new KeyAndPasswordVM(); |
| | | keyAndPassword.setKey(user.getResetKey()); |
| | | keyAndPassword.setNewPassword("new password"); |
| | | |
| | | restAccountMockMvc |
| | | .perform( |
| | | post("/api/account/reset-password/finish") |
| | | .contentType(MediaType.APPLICATION_JSON) |
| | | .content(TestUtil.convertObjectToJsonBytes(keyAndPassword)) |
| | | ) |
| | | .andExpect(status().isOk()); |
| | | |
| | | User updatedUser = userRepository.findOneByLogin(user.getLogin()).orElse(null); |
| | | assertThat(passwordEncoder.matches(keyAndPassword.getNewPassword(), updatedUser.getPassword())).isTrue(); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void testFinishPasswordResetTooSmall() throws Exception { |
| | | User user = new User(); |
| | | user.setPassword(RandomStringUtils.random(60)); |
| | | user.setLogin("finish-password-reset-too-small"); |
| | | user.setEmail("finish-password-reset-too-small@example.com"); |
| | | user.setResetDate(Instant.now().plusSeconds(60)); |
| | | user.setResetKey("reset key too small"); |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | KeyAndPasswordVM keyAndPassword = new KeyAndPasswordVM(); |
| | | keyAndPassword.setKey(user.getResetKey()); |
| | | keyAndPassword.setNewPassword("foo"); |
| | | |
| | | restAccountMockMvc |
| | | .perform( |
| | | post("/api/account/reset-password/finish") |
| | | .contentType(MediaType.APPLICATION_JSON) |
| | | .content(TestUtil.convertObjectToJsonBytes(keyAndPassword)) |
| | | ) |
| | | .andExpect(status().isBadRequest()); |
| | | |
| | | User updatedUser = userRepository.findOneByLogin(user.getLogin()).orElse(null); |
| | | assertThat(passwordEncoder.matches(keyAndPassword.getNewPassword(), updatedUser.getPassword())).isFalse(); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void testFinishPasswordResetWrongKey() throws Exception { |
| | | KeyAndPasswordVM keyAndPassword = new KeyAndPasswordVM(); |
| | | keyAndPassword.setKey("wrong reset key"); |
| | | keyAndPassword.setNewPassword("new password"); |
| | | |
| | | restAccountMockMvc |
| | | .perform( |
| | | post("/api/account/reset-password/finish") |
| | | .contentType(MediaType.APPLICATION_JSON) |
| | | .content(TestUtil.convertObjectToJsonBytes(keyAndPassword)) |
| | | ) |
| | | .andExpect(status().isInternalServerError()); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.rest; |
| | | |
| | | import static org.hamcrest.Matchers.hasItem; |
| | | import static org.hamcrest.Matchers.hasItems; |
| | | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; |
| | | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; |
| | | |
| | | import com.pollex.pam.IntegrationTest; |
| | | import com.pollex.pam.domain.User; |
| | | import com.pollex.pam.repository.UserRepository; |
| | | import com.pollex.pam.security.AuthoritiesConstants; |
| | | import javax.persistence.EntityManager; |
| | | import org.junit.jupiter.api.BeforeEach; |
| | | 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.cache.CacheManager; |
| | | import org.springframework.http.MediaType; |
| | | import org.springframework.security.test.context.support.WithMockUser; |
| | | import org.springframework.test.web.servlet.MockMvc; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | /** |
| | | * Integration tests for the {@link UserResource} REST controller. |
| | | */ |
| | | @AutoConfigureMockMvc |
| | | @WithMockUser(authorities = AuthoritiesConstants.ADMIN) |
| | | @IntegrationTest |
| | | class PublicUserResourceIT { |
| | | |
| | | private static final String DEFAULT_LOGIN = "johndoe"; |
| | | |
| | | @Autowired |
| | | private UserRepository userRepository; |
| | | |
| | | @Autowired |
| | | private EntityManager em; |
| | | |
| | | @Autowired |
| | | private CacheManager cacheManager; |
| | | |
| | | @Autowired |
| | | private MockMvc restUserMockMvc; |
| | | |
| | | private User user; |
| | | |
| | | @BeforeEach |
| | | public void setup() { |
| | | cacheManager.getCache(UserRepository.USERS_BY_LOGIN_CACHE).clear(); |
| | | cacheManager.getCache(UserRepository.USERS_BY_EMAIL_CACHE).clear(); |
| | | } |
| | | |
| | | @BeforeEach |
| | | public void initTest() { |
| | | user = UserResourceIT.initTestUser(userRepository, em); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void getAllPublicUsers() throws Exception { |
| | | // Initialize the database |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | // Get all the users |
| | | restUserMockMvc |
| | | .perform(get("/api/users?sort=id,desc").accept(MediaType.APPLICATION_JSON)) |
| | | .andExpect(status().isOk()) |
| | | .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) |
| | | .andExpect(jsonPath("$.[*].login").value(hasItem(DEFAULT_LOGIN))) |
| | | .andExpect(jsonPath("$.[*].email").doesNotExist()) |
| | | .andExpect(jsonPath("$.[*].imageUrl").doesNotExist()) |
| | | .andExpect(jsonPath("$.[*].langKey").doesNotExist()); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void getAllAuthorities() throws Exception { |
| | | restUserMockMvc |
| | | .perform(get("/api/authorities").accept(MediaType.APPLICATION_JSON).contentType(MediaType.APPLICATION_JSON)) |
| | | .andExpect(status().isOk()) |
| | | .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) |
| | | .andExpect(jsonPath("$").isArray()) |
| | | .andExpect(jsonPath("$").value(hasItems(AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN))); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void getAllUsersSortedByParameters() throws Exception { |
| | | // Initialize the database |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | restUserMockMvc.perform(get("/api/users?sort=resetKey,desc").accept(MediaType.APPLICATION_JSON)).andExpect(status().isBadRequest()); |
| | | restUserMockMvc.perform(get("/api/users?sort=password,desc").accept(MediaType.APPLICATION_JSON)).andExpect(status().isBadRequest()); |
| | | restUserMockMvc |
| | | .perform(get("/api/users?sort=resetKey,id,desc").accept(MediaType.APPLICATION_JSON)) |
| | | .andExpect(status().isBadRequest()); |
| | | restUserMockMvc.perform(get("/api/users?sort=id,desc").accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.rest; |
| | | |
| | | import static org.assertj.core.api.Assertions.assertThat; |
| | | |
| | | import com.fasterxml.jackson.annotation.JsonInclude; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import com.fasterxml.jackson.databind.SerializationFeature; |
| | | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; |
| | | 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; |
| | | import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar; |
| | | import org.springframework.format.support.DefaultFormattingConversionService; |
| | | import org.springframework.format.support.FormattingConversionService; |
| | | |
| | | /** |
| | | * Utility class for testing REST controllers. |
| | | */ |
| | | public final class TestUtil { |
| | | |
| | | private static final ObjectMapper mapper = createObjectMapper(); |
| | | |
| | | private static ObjectMapper createObjectMapper() { |
| | | ObjectMapper mapper = new ObjectMapper(); |
| | | mapper.configure(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS, false); |
| | | mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); |
| | | mapper.registerModule(new JavaTimeModule()); |
| | | return mapper; |
| | | } |
| | | |
| | | /** |
| | | * Convert an object to JSON byte array. |
| | | * |
| | | * @param object the object to convert. |
| | | * @return the JSON byte array. |
| | | * @throws IOException |
| | | */ |
| | | public static byte[] convertObjectToJsonBytes(Object object) throws IOException { |
| | | return mapper.writeValueAsBytes(object); |
| | | } |
| | | |
| | | /** |
| | | * Create a byte array with a specific size filled with specified data. |
| | | * |
| | | * @param size the size of the byte array. |
| | | * @param data the data to put in the byte array. |
| | | * @return the JSON byte array. |
| | | */ |
| | | public static byte[] createByteArray(int size, String data) { |
| | | byte[] byteArray = new byte[size]; |
| | | for (int i = 0; i < size; i++) { |
| | | byteArray[i] = Byte.parseByte(data, 2); |
| | | } |
| | | return byteArray; |
| | | } |
| | | |
| | | /** |
| | | * A matcher that tests that the examined string represents the same instant as the reference datetime. |
| | | */ |
| | | public static class ZonedDateTimeMatcher extends TypeSafeDiagnosingMatcher<String> { |
| | | |
| | | private final ZonedDateTime date; |
| | | |
| | | public ZonedDateTimeMatcher(ZonedDateTime date) { |
| | | this.date = date; |
| | | } |
| | | |
| | | @Override |
| | | protected boolean matchesSafely(String item, Description mismatchDescription) { |
| | | try { |
| | | if (!date.isEqual(ZonedDateTime.parse(item))) { |
| | | mismatchDescription.appendText("was ").appendValue(item); |
| | | return false; |
| | | } |
| | | return true; |
| | | } catch (DateTimeParseException e) { |
| | | mismatchDescription.appendText("was ").appendValue(item).appendText(", which could not be parsed as a ZonedDateTime"); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void describeTo(Description description) { |
| | | description.appendText("a String representing the same Instant as ").appendValue(date); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Creates a matcher that matches when the examined string represents the same instant as the reference datetime. |
| | | * |
| | | * @param date the reference datetime against which the examined string is checked. |
| | | */ |
| | | public static ZonedDateTimeMatcher sameInstant(ZonedDateTime date) { |
| | | return new ZonedDateTimeMatcher(date); |
| | | } |
| | | |
| | | /** |
| | | * A matcher that tests that the examined number represents the same value - it can be Long, Double, etc - as the reference BigDecimal. |
| | | */ |
| | | public static class NumberMatcher extends TypeSafeMatcher<Number> { |
| | | |
| | | final BigDecimal value; |
| | | |
| | | public NumberMatcher(BigDecimal value) { |
| | | this.value = value; |
| | | } |
| | | |
| | | @Override |
| | | public void describeTo(Description description) { |
| | | description.appendText("a numeric value is ").appendValue(value); |
| | | } |
| | | |
| | | @Override |
| | | protected boolean matchesSafely(Number item) { |
| | | BigDecimal bigDecimal = asDecimal(item); |
| | | return bigDecimal != null && value.compareTo(bigDecimal) == 0; |
| | | } |
| | | |
| | | private static BigDecimal asDecimal(Number item) { |
| | | if (item == null) { |
| | | return null; |
| | | } |
| | | if (item instanceof BigDecimal) { |
| | | return (BigDecimal) item; |
| | | } else if (item instanceof Long) { |
| | | return BigDecimal.valueOf((Long) item); |
| | | } else if (item instanceof Integer) { |
| | | return BigDecimal.valueOf((Integer) item); |
| | | } else if (item instanceof Double) { |
| | | return BigDecimal.valueOf((Double) item); |
| | | } else if (item instanceof Float) { |
| | | return BigDecimal.valueOf((Float) item); |
| | | } else { |
| | | return BigDecimal.valueOf(item.doubleValue()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Creates a matcher that matches when the examined number represents the same value as the reference BigDecimal. |
| | | * |
| | | * @param number the reference BigDecimal against which the examined number is checked. |
| | | */ |
| | | public static NumberMatcher sameNumber(BigDecimal number) { |
| | | return new NumberMatcher(number); |
| | | } |
| | | |
| | | /** |
| | | * Verifies the equals/hashcode contract on the domain object. |
| | | */ |
| | | public static <T> void equalsVerifier(Class<T> clazz) throws Exception { |
| | | T domainObject1 = clazz.getConstructor().newInstance(); |
| | | assertThat(domainObject1.toString()).isNotNull(); |
| | | assertThat(domainObject1).isEqualTo(domainObject1); |
| | | assertThat(domainObject1).hasSameHashCodeAs(domainObject1); |
| | | // Test with an instance of another class |
| | | Object testOtherObject = new Object(); |
| | | assertThat(domainObject1).isNotEqualTo(testOtherObject); |
| | | assertThat(domainObject1).isNotEqualTo(null); |
| | | // Test with an instance of the same class |
| | | T domainObject2 = clazz.getConstructor().newInstance(); |
| | | assertThat(domainObject1).isNotEqualTo(domainObject2); |
| | | // HashCodes are equals because the objects are not persisted yet |
| | | assertThat(domainObject1).hasSameHashCodeAs(domainObject2); |
| | | } |
| | | |
| | | /** |
| | | * Create a {@link FormattingConversionService} which use ISO date format, instead of the localized one. |
| | | * @return the {@link FormattingConversionService}. |
| | | */ |
| | | public static FormattingConversionService createFormattingConversionService() { |
| | | DefaultFormattingConversionService dfcs = new DefaultFormattingConversionService(); |
| | | DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar(); |
| | | registrar.setUseIsoFormat(true); |
| | | registrar.registerFormatters(dfcs); |
| | | return dfcs; |
| | | } |
| | | |
| | | /** |
| | | * Makes a an executes a query to the EntityManager finding all stored objects. |
| | | * @param <T> The type of objects to be searched |
| | | * @param em The instance of the EntityManager |
| | | * @param clss The class type to be searched |
| | | * @return A list of all found objects |
| | | */ |
| | | public static <T> List<T> findAll(EntityManager em, Class<T> clss) { |
| | | CriteriaBuilder cb = em.getCriteriaBuilder(); |
| | | CriteriaQuery<T> cq = cb.createQuery(clss); |
| | | Root<T> rootEntry = cq.from(clss); |
| | | CriteriaQuery<T> all = cq.select(rootEntry); |
| | | TypedQuery<T> allQuery = em.createQuery(all); |
| | | return allQuery.getResultList(); |
| | | } |
| | | |
| | | private TestUtil() {} |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.rest; |
| | | |
| | | import static org.hamcrest.Matchers.emptyString; |
| | | import static org.hamcrest.Matchers.is; |
| | | import static org.hamcrest.Matchers.not; |
| | | import static org.hamcrest.Matchers.nullValue; |
| | | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; |
| | | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; |
| | | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; |
| | | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
| | | |
| | | import com.pollex.pam.IntegrationTest; |
| | | import com.pollex.pam.domain.User; |
| | | import com.pollex.pam.repository.UserRepository; |
| | | import com.pollex.pam.web.rest.vm.LoginVM; |
| | | 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.http.MediaType; |
| | | import org.springframework.security.crypto.password.PasswordEncoder; |
| | | import org.springframework.test.web.servlet.MockMvc; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | /** |
| | | * Integration tests for the {@link UserJWTController} REST controller. |
| | | */ |
| | | @AutoConfigureMockMvc |
| | | @IntegrationTest |
| | | class UserJWTControllerIT { |
| | | |
| | | @Autowired |
| | | private UserRepository userRepository; |
| | | |
| | | @Autowired |
| | | private PasswordEncoder passwordEncoder; |
| | | |
| | | @Autowired |
| | | private MockMvc mockMvc; |
| | | |
| | | @Test |
| | | @Transactional |
| | | void testAuthorize() throws Exception { |
| | | User user = new User(); |
| | | user.setLogin("user-jwt-controller"); |
| | | user.setEmail("user-jwt-controller@example.com"); |
| | | user.setActivated(true); |
| | | user.setPassword(passwordEncoder.encode("test")); |
| | | |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | LoginVM login = new LoginVM(); |
| | | login.setUsername("user-jwt-controller"); |
| | | login.setPassword("test"); |
| | | mockMvc |
| | | .perform(post("/api/authenticate").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(login))) |
| | | .andExpect(status().isOk()) |
| | | .andExpect(jsonPath("$.id_token").isString()) |
| | | .andExpect(jsonPath("$.id_token").isNotEmpty()) |
| | | .andExpect(header().string("Authorization", not(nullValue()))) |
| | | .andExpect(header().string("Authorization", not(is(emptyString())))); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void testAuthorizeWithRememberMe() throws Exception { |
| | | User user = new User(); |
| | | user.setLogin("user-jwt-controller-remember-me"); |
| | | user.setEmail("user-jwt-controller-remember-me@example.com"); |
| | | user.setActivated(true); |
| | | user.setPassword(passwordEncoder.encode("test")); |
| | | |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | LoginVM login = new LoginVM(); |
| | | login.setUsername("user-jwt-controller-remember-me"); |
| | | login.setPassword("test"); |
| | | login.setRememberMe(true); |
| | | mockMvc |
| | | .perform(post("/api/authenticate").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(login))) |
| | | .andExpect(status().isOk()) |
| | | .andExpect(jsonPath("$.id_token").isString()) |
| | | .andExpect(jsonPath("$.id_token").isNotEmpty()) |
| | | .andExpect(header().string("Authorization", not(nullValue()))) |
| | | .andExpect(header().string("Authorization", not(is(emptyString())))); |
| | | } |
| | | |
| | | @Test |
| | | void testAuthorizeFails() throws Exception { |
| | | LoginVM login = new LoginVM(); |
| | | login.setUsername("wrong-user"); |
| | | login.setPassword("wrong password"); |
| | | mockMvc |
| | | .perform(post("/api/authenticate").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(login))) |
| | | .andExpect(status().isUnauthorized()) |
| | | .andExpect(jsonPath("$.id_token").doesNotExist()) |
| | | .andExpect(header().doesNotExist("Authorization")); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.rest; |
| | | |
| | | import static org.assertj.core.api.Assertions.assertThat; |
| | | import static org.hamcrest.Matchers.hasItem; |
| | | import static org.hamcrest.Matchers.hasItems; |
| | | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; |
| | | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; |
| | | |
| | | import com.pollex.pam.IntegrationTest; |
| | | import com.pollex.pam.domain.Authority; |
| | | import com.pollex.pam.domain.User; |
| | | import com.pollex.pam.repository.UserRepository; |
| | | import com.pollex.pam.security.AuthoritiesConstants; |
| | | import com.pollex.pam.service.dto.AdminUserDTO; |
| | | import com.pollex.pam.service.dto.UserDTO; |
| | | import com.pollex.pam.service.mapper.UserMapper; |
| | | import com.pollex.pam.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; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; |
| | | import org.springframework.cache.CacheManager; |
| | | import org.springframework.http.MediaType; |
| | | import org.springframework.security.test.context.support.WithMockUser; |
| | | import org.springframework.test.web.servlet.MockMvc; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | /** |
| | | * Integration tests for the {@link UserResource} REST controller. |
| | | */ |
| | | @AutoConfigureMockMvc |
| | | @WithMockUser(authorities = AuthoritiesConstants.ADMIN) |
| | | @IntegrationTest |
| | | class UserResourceIT { |
| | | |
| | | private static final String DEFAULT_LOGIN = "johndoe"; |
| | | private static final String UPDATED_LOGIN = "jhipster"; |
| | | |
| | | private static final Long DEFAULT_ID = 1L; |
| | | |
| | | private static final String DEFAULT_PASSWORD = "passjohndoe"; |
| | | private static final String UPDATED_PASSWORD = "passjhipster"; |
| | | |
| | | private static final String DEFAULT_EMAIL = "johndoe@localhost"; |
| | | private static final String UPDATED_EMAIL = "jhipster@localhost"; |
| | | |
| | | private static final String DEFAULT_FIRSTNAME = "john"; |
| | | private static final String UPDATED_FIRSTNAME = "jhipsterFirstName"; |
| | | |
| | | private static final String DEFAULT_LASTNAME = "doe"; |
| | | private static final String UPDATED_LASTNAME = "jhipsterLastName"; |
| | | |
| | | private static final String DEFAULT_IMAGEURL = "http://placehold.it/50x50"; |
| | | private static final String UPDATED_IMAGEURL = "http://placehold.it/40x40"; |
| | | |
| | | private static final String DEFAULT_LANGKEY = "en"; |
| | | private static final String UPDATED_LANGKEY = "fr"; |
| | | |
| | | @Autowired |
| | | private UserRepository userRepository; |
| | | |
| | | @Autowired |
| | | private UserMapper userMapper; |
| | | |
| | | @Autowired |
| | | private EntityManager em; |
| | | |
| | | @Autowired |
| | | private CacheManager cacheManager; |
| | | |
| | | @Autowired |
| | | private MockMvc restUserMockMvc; |
| | | |
| | | private User user; |
| | | |
| | | @BeforeEach |
| | | public void setup() { |
| | | cacheManager.getCache(UserRepository.USERS_BY_LOGIN_CACHE).clear(); |
| | | cacheManager.getCache(UserRepository.USERS_BY_EMAIL_CACHE).clear(); |
| | | } |
| | | |
| | | /** |
| | | * Create a User. |
| | | * |
| | | * This is a static method, as tests for other entities might also need it, |
| | | * if they test an entity which has a required relationship to the User entity. |
| | | */ |
| | | public static User createEntity(EntityManager em) { |
| | | User user = new User(); |
| | | user.setLogin(DEFAULT_LOGIN + RandomStringUtils.randomAlphabetic(5)); |
| | | user.setPassword(RandomStringUtils.random(60)); |
| | | user.setActivated(true); |
| | | user.setEmail(RandomStringUtils.randomAlphabetic(5) + DEFAULT_EMAIL); |
| | | user.setFirstName(DEFAULT_FIRSTNAME); |
| | | user.setLastName(DEFAULT_LASTNAME); |
| | | user.setImageUrl(DEFAULT_IMAGEURL); |
| | | user.setLangKey(DEFAULT_LANGKEY); |
| | | return user; |
| | | } |
| | | |
| | | /** |
| | | * Setups the database with one user. |
| | | */ |
| | | public static User initTestUser(UserRepository userRepository, EntityManager em) { |
| | | User user = createEntity(em); |
| | | user.setLogin(DEFAULT_LOGIN); |
| | | user.setEmail(DEFAULT_EMAIL); |
| | | return user; |
| | | } |
| | | |
| | | @BeforeEach |
| | | public void initTest() { |
| | | user = initTestUser(userRepository, em); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void createUser() throws Exception { |
| | | int databaseSizeBeforeCreate = userRepository.findAll().size(); |
| | | |
| | | // Create the 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(managedUserVM)) |
| | | ) |
| | | .andExpect(status().isCreated()); |
| | | |
| | | // Validate the User in the database |
| | | assertPersistedUsers(users -> { |
| | | assertThat(users).hasSize(databaseSizeBeforeCreate + 1); |
| | | User testUser = users.get(users.size() - 1); |
| | | assertThat(testUser.getLogin()).isEqualTo(DEFAULT_LOGIN); |
| | | assertThat(testUser.getFirstName()).isEqualTo(DEFAULT_FIRSTNAME); |
| | | assertThat(testUser.getLastName()).isEqualTo(DEFAULT_LASTNAME); |
| | | assertThat(testUser.getEmail()).isEqualTo(DEFAULT_EMAIL); |
| | | assertThat(testUser.getImageUrl()).isEqualTo(DEFAULT_IMAGEURL); |
| | | assertThat(testUser.getLangKey()).isEqualTo(DEFAULT_LANGKEY); |
| | | }); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void createUserWithExistingId() throws Exception { |
| | | int databaseSizeBeforeCreate = userRepository.findAll().size(); |
| | | |
| | | 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(managedUserVM)) |
| | | ) |
| | | .andExpect(status().isBadRequest()); |
| | | |
| | | // Validate the User in the database |
| | | assertPersistedUsers(users -> assertThat(users).hasSize(databaseSizeBeforeCreate)); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void createUserWithExistingLogin() throws Exception { |
| | | // Initialize the database |
| | | userRepository.saveAndFlush(user); |
| | | int databaseSizeBeforeCreate = userRepository.findAll().size(); |
| | | |
| | | 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(managedUserVM)) |
| | | ) |
| | | .andExpect(status().isBadRequest()); |
| | | |
| | | // Validate the User in the database |
| | | assertPersistedUsers(users -> assertThat(users).hasSize(databaseSizeBeforeCreate)); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void createUserWithExistingEmail() throws Exception { |
| | | // Initialize the database |
| | | userRepository.saveAndFlush(user); |
| | | int databaseSizeBeforeCreate = userRepository.findAll().size(); |
| | | |
| | | 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(managedUserVM)) |
| | | ) |
| | | .andExpect(status().isBadRequest()); |
| | | |
| | | // Validate the User in the database |
| | | assertPersistedUsers(users -> assertThat(users).hasSize(databaseSizeBeforeCreate)); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void getAllUsers() throws Exception { |
| | | // Initialize the database |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | // Get all the users |
| | | restUserMockMvc |
| | | .perform(get("/api/admin/users?sort=id,desc").accept(MediaType.APPLICATION_JSON)) |
| | | .andExpect(status().isOk()) |
| | | .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) |
| | | .andExpect(jsonPath("$.[*].login").value(hasItem(DEFAULT_LOGIN))) |
| | | .andExpect(jsonPath("$.[*].firstName").value(hasItem(DEFAULT_FIRSTNAME))) |
| | | .andExpect(jsonPath("$.[*].lastName").value(hasItem(DEFAULT_LASTNAME))) |
| | | .andExpect(jsonPath("$.[*].email").value(hasItem(DEFAULT_EMAIL))) |
| | | .andExpect(jsonPath("$.[*].imageUrl").value(hasItem(DEFAULT_IMAGEURL))) |
| | | .andExpect(jsonPath("$.[*].langKey").value(hasItem(DEFAULT_LANGKEY))); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void getUser() throws Exception { |
| | | // Initialize the database |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | assertThat(cacheManager.getCache(UserRepository.USERS_BY_LOGIN_CACHE).get(user.getLogin())).isNull(); |
| | | |
| | | // Get the user |
| | | restUserMockMvc |
| | | .perform(get("/api/admin/users/{login}", user.getLogin())) |
| | | .andExpect(status().isOk()) |
| | | .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) |
| | | .andExpect(jsonPath("$.login").value(user.getLogin())) |
| | | .andExpect(jsonPath("$.firstName").value(DEFAULT_FIRSTNAME)) |
| | | .andExpect(jsonPath("$.lastName").value(DEFAULT_LASTNAME)) |
| | | .andExpect(jsonPath("$.email").value(DEFAULT_EMAIL)) |
| | | .andExpect(jsonPath("$.imageUrl").value(DEFAULT_IMAGEURL)) |
| | | .andExpect(jsonPath("$.langKey").value(DEFAULT_LANGKEY)); |
| | | |
| | | assertThat(cacheManager.getCache(UserRepository.USERS_BY_LOGIN_CACHE).get(user.getLogin())).isNotNull(); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void getNonExistingUser() throws Exception { |
| | | restUserMockMvc.perform(get("/api/admin/users/unknown")).andExpect(status().isNotFound()); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void updateUser() throws Exception { |
| | | // Initialize the database |
| | | userRepository.saveAndFlush(user); |
| | | int databaseSizeBeforeUpdate = userRepository.findAll().size(); |
| | | |
| | | // Update the 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(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().get(); |
| | | assertThat(testUser.getFirstName()).isEqualTo(UPDATED_FIRSTNAME); |
| | | assertThat(testUser.getLastName()).isEqualTo(UPDATED_LASTNAME); |
| | | assertThat(testUser.getEmail()).isEqualTo(UPDATED_EMAIL); |
| | | assertThat(testUser.getImageUrl()).isEqualTo(UPDATED_IMAGEURL); |
| | | assertThat(testUser.getLangKey()).isEqualTo(UPDATED_LANGKEY); |
| | | }); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void updateUserLogin() throws Exception { |
| | | // Initialize the database |
| | | userRepository.saveAndFlush(user); |
| | | int databaseSizeBeforeUpdate = userRepository.findAll().size(); |
| | | |
| | | // Update the 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(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().get(); |
| | | assertThat(testUser.getLogin()).isEqualTo(UPDATED_LOGIN); |
| | | assertThat(testUser.getFirstName()).isEqualTo(UPDATED_FIRSTNAME); |
| | | assertThat(testUser.getLastName()).isEqualTo(UPDATED_LASTNAME); |
| | | assertThat(testUser.getEmail()).isEqualTo(UPDATED_EMAIL); |
| | | assertThat(testUser.getImageUrl()).isEqualTo(UPDATED_IMAGEURL); |
| | | assertThat(testUser.getLangKey()).isEqualTo(UPDATED_LANGKEY); |
| | | }); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void updateUserExistingEmail() throws Exception { |
| | | // Initialize the database with 2 users |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | User anotherUser = new User(); |
| | | anotherUser.setLogin("jhipster"); |
| | | anotherUser.setPassword(RandomStringUtils.random(60)); |
| | | anotherUser.setActivated(true); |
| | | anotherUser.setEmail("jhipster@localhost"); |
| | | anotherUser.setFirstName("java"); |
| | | anotherUser.setLastName("hipster"); |
| | | anotherUser.setImageUrl(""); |
| | | anotherUser.setLangKey("en"); |
| | | userRepository.saveAndFlush(anotherUser); |
| | | |
| | | // Update the 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(managedUserVM)) |
| | | ) |
| | | .andExpect(status().isBadRequest()); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void updateUserExistingLogin() throws Exception { |
| | | // Initialize the database |
| | | userRepository.saveAndFlush(user); |
| | | |
| | | User anotherUser = new User(); |
| | | anotherUser.setLogin("jhipster"); |
| | | anotherUser.setPassword(RandomStringUtils.random(60)); |
| | | anotherUser.setActivated(true); |
| | | anotherUser.setEmail("jhipster@localhost"); |
| | | anotherUser.setFirstName("java"); |
| | | anotherUser.setLastName("hipster"); |
| | | anotherUser.setImageUrl(""); |
| | | anotherUser.setLangKey("en"); |
| | | userRepository.saveAndFlush(anotherUser); |
| | | |
| | | // Update the 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(managedUserVM)) |
| | | ) |
| | | .andExpect(status().isBadRequest()); |
| | | } |
| | | |
| | | @Test |
| | | @Transactional |
| | | void deleteUser() throws Exception { |
| | | // Initialize the database |
| | | userRepository.saveAndFlush(user); |
| | | int databaseSizeBeforeDelete = userRepository.findAll().size(); |
| | | |
| | | // Delete the user |
| | | restUserMockMvc |
| | | .perform(delete("/api/admin/users/{login}", user.getLogin()).accept(MediaType.APPLICATION_JSON)) |
| | | .andExpect(status().isNoContent()); |
| | | |
| | | assertThat(cacheManager.getCache(UserRepository.USERS_BY_LOGIN_CACHE).get(user.getLogin())).isNull(); |
| | | |
| | | // Validate the database is empty |
| | | assertPersistedUsers(users -> assertThat(users).hasSize(databaseSizeBeforeDelete - 1)); |
| | | } |
| | | |
| | | @Test |
| | | void testUserEquals() throws Exception { |
| | | TestUtil.equalsVerifier(User.class); |
| | | User user1 = new User(); |
| | | user1.setId(DEFAULT_ID); |
| | | User user2 = new User(); |
| | | user2.setId(user1.getId()); |
| | | assertThat(user1).isEqualTo(user2); |
| | | user2.setId(2L); |
| | | assertThat(user1).isNotEqualTo(user2); |
| | | user1.setId(null); |
| | | assertThat(user1).isNotEqualTo(user2); |
| | | } |
| | | |
| | | @Test |
| | | void testUserDTOtoUser() { |
| | | AdminUserDTO userDTO = new AdminUserDTO(); |
| | | userDTO.setId(DEFAULT_ID); |
| | | userDTO.setLogin(DEFAULT_LOGIN); |
| | | userDTO.setFirstName(DEFAULT_FIRSTNAME); |
| | | userDTO.setLastName(DEFAULT_LASTNAME); |
| | | userDTO.setEmail(DEFAULT_EMAIL); |
| | | userDTO.setActivated(true); |
| | | userDTO.setImageUrl(DEFAULT_IMAGEURL); |
| | | userDTO.setLangKey(DEFAULT_LANGKEY); |
| | | userDTO.setCreatedBy(DEFAULT_LOGIN); |
| | | userDTO.setLastModifiedBy(DEFAULT_LOGIN); |
| | | userDTO.setAuthorities(Collections.singleton(AuthoritiesConstants.USER)); |
| | | |
| | | User user = userMapper.userDTOToUser(userDTO); |
| | | assertThat(user.getId()).isEqualTo(DEFAULT_ID); |
| | | assertThat(user.getLogin()).isEqualTo(DEFAULT_LOGIN); |
| | | assertThat(user.getFirstName()).isEqualTo(DEFAULT_FIRSTNAME); |
| | | assertThat(user.getLastName()).isEqualTo(DEFAULT_LASTNAME); |
| | | assertThat(user.getEmail()).isEqualTo(DEFAULT_EMAIL); |
| | | assertThat(user.isActivated()).isTrue(); |
| | | assertThat(user.getImageUrl()).isEqualTo(DEFAULT_IMAGEURL); |
| | | assertThat(user.getLangKey()).isEqualTo(DEFAULT_LANGKEY); |
| | | assertThat(user.getCreatedBy()).isNull(); |
| | | assertThat(user.getCreatedDate()).isNotNull(); |
| | | assertThat(user.getLastModifiedBy()).isNull(); |
| | | assertThat(user.getLastModifiedDate()).isNotNull(); |
| | | assertThat(user.getAuthorities()).extracting("name").containsExactly(AuthoritiesConstants.USER); |
| | | } |
| | | |
| | | @Test |
| | | void testUserToUserDTO() { |
| | | user.setId(DEFAULT_ID); |
| | | user.setCreatedBy(DEFAULT_LOGIN); |
| | | user.setCreatedDate(Instant.now()); |
| | | user.setLastModifiedBy(DEFAULT_LOGIN); |
| | | user.setLastModifiedDate(Instant.now()); |
| | | Set<Authority> authorities = new HashSet<>(); |
| | | Authority authority = new Authority(); |
| | | authority.setName(AuthoritiesConstants.USER); |
| | | authorities.add(authority); |
| | | user.setAuthorities(authorities); |
| | | |
| | | AdminUserDTO userDTO = userMapper.userToAdminUserDTO(user); |
| | | |
| | | assertThat(userDTO.getId()).isEqualTo(DEFAULT_ID); |
| | | assertThat(userDTO.getLogin()).isEqualTo(DEFAULT_LOGIN); |
| | | assertThat(userDTO.getFirstName()).isEqualTo(DEFAULT_FIRSTNAME); |
| | | assertThat(userDTO.getLastName()).isEqualTo(DEFAULT_LASTNAME); |
| | | assertThat(userDTO.getEmail()).isEqualTo(DEFAULT_EMAIL); |
| | | assertThat(userDTO.isActivated()).isTrue(); |
| | | assertThat(userDTO.getImageUrl()).isEqualTo(DEFAULT_IMAGEURL); |
| | | assertThat(userDTO.getLangKey()).isEqualTo(DEFAULT_LANGKEY); |
| | | assertThat(userDTO.getCreatedBy()).isEqualTo(DEFAULT_LOGIN); |
| | | assertThat(userDTO.getCreatedDate()).isEqualTo(user.getCreatedDate()); |
| | | assertThat(userDTO.getLastModifiedBy()).isEqualTo(DEFAULT_LOGIN); |
| | | assertThat(userDTO.getLastModifiedDate()).isEqualTo(user.getLastModifiedDate()); |
| | | assertThat(userDTO.getAuthorities()).containsExactly(AuthoritiesConstants.USER); |
| | | assertThat(userDTO.toString()).isNotNull(); |
| | | } |
| | | |
| | | @Test |
| | | void testAuthorityEquals() { |
| | | Authority authorityA = new Authority(); |
| | | assertThat(authorityA).isNotEqualTo(null).isNotEqualTo(new Object()); |
| | | assertThat(authorityA.hashCode()).isZero(); |
| | | assertThat(authorityA.toString()).isNotNull(); |
| | | |
| | | Authority authorityB = new Authority(); |
| | | assertThat(authorityA).isEqualTo(authorityB); |
| | | |
| | | authorityB.setName(AuthoritiesConstants.ADMIN); |
| | | assertThat(authorityA).isNotEqualTo(authorityB); |
| | | |
| | | authorityA.setName(AuthoritiesConstants.USER); |
| | | assertThat(authorityA).isNotEqualTo(authorityB); |
| | | |
| | | authorityB.setName(AuthoritiesConstants.USER); |
| | | assertThat(authorityA).isEqualTo(authorityB).hasSameHashCodeAs(authorityB); |
| | | } |
| | | |
| | | private void assertPersistedUsers(Consumer<List<User>> userAssertion) { |
| | | userAssertion.accept(userRepository.findAll()); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.rest; |
| | | |
| | | import java.lang.annotation.ElementType; |
| | | import java.lang.annotation.Retention; |
| | | import java.lang.annotation.RetentionPolicy; |
| | | import java.lang.annotation.Target; |
| | | import org.springframework.security.core.context.SecurityContext; |
| | | import org.springframework.security.core.context.SecurityContextHolder; |
| | | import org.springframework.security.test.context.support.WithSecurityContext; |
| | | import org.springframework.security.test.context.support.WithSecurityContextFactory; |
| | | |
| | | @Target({ ElementType.METHOD, ElementType.TYPE }) |
| | | @Retention(RetentionPolicy.RUNTIME) |
| | | @WithSecurityContext(factory = WithUnauthenticatedMockUser.Factory.class) |
| | | public @interface WithUnauthenticatedMockUser { |
| | | class Factory implements WithSecurityContextFactory<WithUnauthenticatedMockUser> { |
| | | |
| | | @Override |
| | | public SecurityContext createSecurityContext(WithUnauthenticatedMockUser annotation) { |
| | | return SecurityContextHolder.createEmptyContext(); |
| | | } |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.rest.errors; |
| | | |
| | | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; |
| | | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; |
| | | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; |
| | | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; |
| | | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
| | | |
| | | import com.pollex.pam.IntegrationTest; |
| | | 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.boot.test.context.SpringBootTest; |
| | | import org.springframework.http.MediaType; |
| | | import org.springframework.security.test.context.support.WithMockUser; |
| | | import org.springframework.test.web.servlet.MockMvc; |
| | | |
| | | /** |
| | | * Integration tests {@link ExceptionTranslator} controller advice. |
| | | */ |
| | | @WithMockUser |
| | | @AutoConfigureMockMvc |
| | | @IntegrationTest |
| | | class ExceptionTranslatorIT { |
| | | |
| | | @Autowired |
| | | private MockMvc mockMvc; |
| | | |
| | | @Test |
| | | void testConcurrencyFailure() throws Exception { |
| | | mockMvc |
| | | .perform(get("/api/exception-translator-test/concurrency-failure")) |
| | | .andExpect(status().isConflict()) |
| | | .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) |
| | | .andExpect(jsonPath("$.message").value(ErrorConstants.ERR_CONCURRENCY_FAILURE)); |
| | | } |
| | | |
| | | @Test |
| | | void testMethodArgumentNotValid() throws Exception { |
| | | mockMvc |
| | | .perform(post("/api/exception-translator-test/method-argument").content("{}").contentType(MediaType.APPLICATION_JSON)) |
| | | .andExpect(status().isBadRequest()) |
| | | .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) |
| | | .andExpect(jsonPath("$.message").value(ErrorConstants.ERR_VALIDATION)) |
| | | .andExpect(jsonPath("$.fieldErrors.[0].objectName").value("test")) |
| | | .andExpect(jsonPath("$.fieldErrors.[0].field").value("test")) |
| | | .andExpect(jsonPath("$.fieldErrors.[0].message").value("must not be null")); |
| | | } |
| | | |
| | | @Test |
| | | void testMissingServletRequestPartException() throws Exception { |
| | | mockMvc |
| | | .perform(get("/api/exception-translator-test/missing-servlet-request-part")) |
| | | .andExpect(status().isBadRequest()) |
| | | .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) |
| | | .andExpect(jsonPath("$.message").value("error.http.400")); |
| | | } |
| | | |
| | | @Test |
| | | void testMissingServletRequestParameterException() throws Exception { |
| | | mockMvc |
| | | .perform(get("/api/exception-translator-test/missing-servlet-request-parameter")) |
| | | .andExpect(status().isBadRequest()) |
| | | .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) |
| | | .andExpect(jsonPath("$.message").value("error.http.400")); |
| | | } |
| | | |
| | | @Test |
| | | void testAccessDenied() throws Exception { |
| | | mockMvc |
| | | .perform(get("/api/exception-translator-test/access-denied")) |
| | | .andExpect(status().isForbidden()) |
| | | .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) |
| | | .andExpect(jsonPath("$.message").value("error.http.403")) |
| | | .andExpect(jsonPath("$.detail").value("test access denied!")); |
| | | } |
| | | |
| | | @Test |
| | | void testUnauthorized() throws Exception { |
| | | mockMvc |
| | | .perform(get("/api/exception-translator-test/unauthorized")) |
| | | .andExpect(status().isUnauthorized()) |
| | | .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) |
| | | .andExpect(jsonPath("$.message").value("error.http.401")) |
| | | .andExpect(jsonPath("$.path").value("/api/exception-translator-test/unauthorized")) |
| | | .andExpect(jsonPath("$.detail").value("test authentication failed!")); |
| | | } |
| | | |
| | | @Test |
| | | void testMethodNotSupported() throws Exception { |
| | | mockMvc |
| | | .perform(post("/api/exception-translator-test/access-denied")) |
| | | .andExpect(status().isMethodNotAllowed()) |
| | | .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) |
| | | .andExpect(jsonPath("$.message").value("error.http.405")) |
| | | .andExpect(jsonPath("$.detail").value("Request method 'POST' not supported")); |
| | | } |
| | | |
| | | @Test |
| | | void testExceptionWithResponseStatus() throws Exception { |
| | | mockMvc |
| | | .perform(get("/api/exception-translator-test/response-status")) |
| | | .andExpect(status().isBadRequest()) |
| | | .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) |
| | | .andExpect(jsonPath("$.message").value("error.http.400")) |
| | | .andExpect(jsonPath("$.title").value("test response status")); |
| | | } |
| | | |
| | | @Test |
| | | void testInternalServerError() throws Exception { |
| | | mockMvc |
| | | .perform(get("/api/exception-translator-test/internal-server-error")) |
| | | .andExpect(status().isInternalServerError()) |
| | | .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON)) |
| | | .andExpect(jsonPath("$.message").value("error.http.500")) |
| | | .andExpect(jsonPath("$.title").value("Internal Server Error")); |
| | | } |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | package com.pollex.pam.web.rest.errors; |
| | | |
| | | 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; |
| | | import org.springframework.security.authentication.BadCredentialsException; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | @RestController |
| | | @RequestMapping("/api/exception-translator-test") |
| | | public class ExceptionTranslatorTestController { |
| | | |
| | | @GetMapping("/concurrency-failure") |
| | | public void concurrencyFailure() { |
| | | throw new ConcurrencyFailureException("test concurrency failure"); |
| | | } |
| | | |
| | | @PostMapping("/method-argument") |
| | | public void methodArgument(@Valid @RequestBody TestDTO testDTO) {} |
| | | |
| | | @GetMapping("/missing-servlet-request-part") |
| | | public void missingServletRequestPartException(@RequestPart String part) {} |
| | | |
| | | @GetMapping("/missing-servlet-request-parameter") |
| | | public void missingServletRequestParameterException(@RequestParam String param) {} |
| | | |
| | | @GetMapping("/access-denied") |
| | | public void accessdenied() { |
| | | throw new AccessDeniedException("test access denied!"); |
| | | } |
| | | |
| | | @GetMapping("/unauthorized") |
| | | public void unauthorized() { |
| | | throw new BadCredentialsException("test authentication failed!"); |
| | | } |
| | | |
| | | @GetMapping("/response-status") |
| | | public void exceptionWithResponseStatus() { |
| | | throw new TestResponseStatusException(); |
| | | } |
| | | |
| | | @GetMapping("/internal-server-error") |
| | | public void internalServerError() { |
| | | throw new RuntimeException(); |
| | | } |
| | | |
| | | public static class TestDTO { |
| | | |
| | | @NotNull |
| | | private String test; |
| | | |
| | | public String getTest() { |
| | | return test; |
| | | } |
| | | |
| | | public void setTest(String test) { |
| | | this.test = test; |
| | | } |
| | | } |
| | | |
| | | @ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "test response status") |
| | | @SuppressWarnings("serial") |
| | | public static class TestResponseStatusException extends RuntimeException {} |
| | | } |
¤ñ¹ï·sÀÉ®× |
| | |
| | | # =================================================================== |
| | | # Spring Boot configuration. |
| | | # |
| | | # This configuration is used for unit/integration tests with testcontainers database containers. |
| | | # |
| | | # To activate this configuration launch integration tests with the 'testcontainers' profile |
| | | # |
| | | # More information on database containers: https://www.testcontainers.org/modules/databases/ |
| | | # =================================================================== |
| | | |
| | | spring: |
| | | datasource: |
| | | type: com.zaxxer.hikari.HikariDataSource |
| | | driver-class-name: org.testcontainers.jdbc.ContainerDatabaseDriver |
| | | url: jdbc:tc:postgresql:13.4:///pamapi?TC_TMPFS=/testtmpfs:rw |
| | | username: pamapi |
| | | password: |
| | | hikari: |
| | | poolName: Hikari |
| | | auto-commit: false |
| | | jpa: |
| | | database-platform: tech.jhipster.domain.util.FixedPostgreSQL10Dialect |
¤ñ¹ï·sÀÉ®× |
| | |
| | | # =================================================================== |
| | | # Spring Boot configuration. |
| | | # |
| | | # This configuration is used for unit/integration tests. |
| | | # |
| | | # More information on profiles: https://www.jhipster.tech/profiles/ |
| | | # More information on configuration properties: https://www.jhipster.tech/common-application-properties/ |
| | | # =================================================================== |
| | | |
| | | # =================================================================== |
| | | # Standard Spring Boot properties. |
| | | # Full reference is available at: |
| | | # http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html |
| | | # =================================================================== |
| | | |
| | | spring: |
| | | profiles: |
| | | # Uncomment the following line to enable tests against production database type rather than H2, using Testcontainers |
| | | #active: testcontainers |
| | | application: |
| | | name: pamapi |
| | | datasource: |
| | | type: com.zaxxer.hikari.HikariDataSource |
| | | url: jdbc:h2:mem:pamapi;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE |
| | | name: |
| | | username: |
| | | password: |
| | | hikari: |
| | | auto-commit: false |
| | | jackson: |
| | | serialization: |
| | | write-durations-as-timestamps: false |
| | | jpa: |
| | | database-platform: tech.jhipster.domain.util.FixedH2Dialect |
| | | open-in-view: false |
| | | hibernate: |
| | | ddl-auto: none |
| | | naming: |
| | | 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 |
| | | hibernate.connection.provider_disables_autocommit: true |
| | | hibernate.cache.use_second_level_cache: false |
| | | hibernate.cache.use_query_cache: false |
| | | hibernate.generate_statistics: false |
| | | hibernate.hbm2ddl.auto: validate |
| | | hibernate.jdbc.time_zone: UTC |
| | | hibernate.query.fail_on_pagination_over_collection_fetch: true |
| | | liquibase: |
| | | contexts: test |
| | | mail: |
| | | host: localhost |
| | | main: |
| | | allow-bean-definition-overriding: true |
| | | messages: |
| | | basename: i18n/messages |
| | | task: |
| | | execution: |
| | | thread-name-prefix: pamapi-task- |
| | | pool: |
| | | core-size: 1 |
| | | max-size: 50 |
| | | queue-capacity: 10000 |
| | | scheduling: |
| | | thread-name-prefix: pamapi-scheduling- |
| | | pool: |
| | | size: 1 |
| | | thymeleaf: |
| | | mode: HTML |
| | | |
| | | server: |
| | | port: 10344 |
| | | address: localhost |
| | | |
| | | # =================================================================== |
| | | # JHipster specific properties |
| | | # |
| | | # Full reference is available at: https://www.jhipster.tech/common-application-properties/ |
| | | # =================================================================== |
| | | |
| | | jhipster: |
| | | clientApp: |
| | | name: 'pamapiApp' |
| | | logging: |
| | | # To test json console appender |
| | | use-json-format: false |
| | | logstash: |
| | | enabled: false |
| | | host: localhost |
| | | port: 5000 |
| | | queue-size: 512 |
| | | mail: |
| | | from: test@localhost |
| | | base-url: http://127.0.0.1:8080 |
| | | security: |
| | | authentication: |
| | | jwt: |
| | | # This token must be encoded using Base64 (you can type `echo 'secret-key'|base64` on your command line) |
| | | base64-secret: MjI3YWRiMzg1ZTY3ZmZkZDgxZmI5Yjc5YjVkOTIzMzc4MmI2OWM3NWVkZjFiOTNmNjg0YWFjZWQ4YzhlOTUzYzk3MGUzMzM5Y2U5MDdkZTMyN2Q0N2E0M2ZmM2FhYzkyNDY4MjBkYTY5OGM4YmIzMmYxODJhNWFkMmVhNmVhNTM= |
| | | # Token is valid 24 hours |
| | | token-validity-in-seconds: 86400 |
| | | # =================================================================== |
| | | # Application specific properties |
| | | # Add your own application properties here, see the ApplicationProperties class |
| | | # to have type-safe configuration, like in the JHipsterProperties above |
| | | # |
| | | # More documentation is available at: |
| | | # https://www.jhipster.tech/common-application-properties/ |
| | | # =================================================================== |
| | | |
| | | # application: |
¤ñ¹ï·sÀÉ®× |
| | |
| | | email.test.title=test title |
| | | # Value used for English locale unit test in MailServiceIT |
| | | # as this file is loaded instead of real file |
| | | email.activation.title=pamapi account activation |
¤ñ¹ï·sÀÉ®× |
| | |
| | | email.test.title=\u5E33\u865F\u555F\u7528 |
¤ñ¹ï·sÀÉ®× |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <!DOCTYPE configuration> |
| | | |
| | | <configuration scan="true"> |
| | | <include resource="org/springframework/boot/logging/logback/base.xml"/> |
| | | |
| | | <logger name="com.pollex.pam" level="INFO"/> |
| | | |
| | | <logger name="tech.jhipster" level="WARN"/> |
| | | |
| | | <logger name="javax.activation" level="WARN"/> |
| | | <logger name="javax.mail" level="WARN"/> |
| | | <logger name="javax.xml.bind" level="WARN"/> |
| | | <logger name="ch.qos.logback" level="WARN"/> |
| | | <logger name="com.jayway.jsonpath" level="WARN"/> |
| | | <logger name="com.ryantenney" level="WARN"/> |
| | | <logger name="com.sun" level="WARN"/> |
| | | <logger name="com.zaxxer" level="WARN"/> |
| | | <logger name="com.github.dockerjava" level="WARN"/> |
| | | <logger name="org.testcontainers" level="WARN"/> |
| | | <logger name="io.undertow" level="WARN"/> |
| | | <logger name="io.undertow.websockets.jsr" level="ERROR"/> |
| | | <logger name="org.ehcache" level="WARN"/> |
| | | <logger name="org.apache" level="WARN"/> |
| | | <logger name="org.apache.catalina.startup.DigesterFactory" level="OFF"/> |
| | | <logger name="org.bson" level="WARN"/> |
| | | <logger name="org.hibernate.validator" level="WARN"/> |
| | | <logger name="org.hibernate" level="WARN"/> |
| | | <logger name="org.hibernate.ejb.HibernatePersistence" level="OFF"/> |
| | | <logger name="org.postgresql.jdbc" level="WARN"/> |
| | | <logger name="org.springframework" level="WARN"/> |
| | | <logger name="org.springframework.web" level="WARN"/> |
| | | <logger name="org.springframework.security" level="WARN"/> |
| | | <logger name="org.springframework.cache" level="WARN"/> |
| | | <logger name="org.thymeleaf" level="WARN"/> |
| | | <logger name="org.xnio" level="WARN"/> |
| | | <logger name="springfox" level="WARN"/> |
| | | <logger name="sun.rmi" level="WARN"/> |
| | | <logger name="liquibase" level="WARN"/> |
| | | <logger name="LiquibaseSchemaResolver" level="INFO"/> |
| | | <logger name="sun.rmi.transport" level="WARN"/> |
| | | <logger name="com.tngtech.archunit.core.importer" level="ERROR"/> |
| | | |
| | | <root> |
| | | <level>WARN</level> |
| | | <appender-ref ref="CONSOLE"/> |
| | | </root> |
| | | |
| | | </configuration> |
¤ñ¹ï·sÀÉ®× |
| | |
| | | <html xmlns:th="http://www.thymeleaf.org" th:text="|#{email.test.title}, ${baseUrl}, ${user.login}|"></html> |