removing JHipster

This commit is contained in:
Michael Hoennig 2022-07-22 13:31:37 +02:00
parent 31cd92f3be
commit f2d0fbe67a
747 changed files with 2225 additions and 92268 deletions

View File

@ -18,7 +18,3 @@ insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[package.json]
indent_style = space
indent_size = 2

View File

@ -1,5 +0,0 @@
{
"hooks": {
"pre-commit": "lint-staged"
}
}

View File

@ -1,61 +0,0 @@
{
"name": "Asset",
"fields": [
{
"fieldName": "documentDate",
"fieldType": "LocalDate",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "valueDate",
"fieldType": "LocalDate",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "action",
"fieldType": "AssetAction",
"fieldValues": "PAYMENT,HANDOVER,ADOPTION,LOSS,CLEARING,PAYBACK",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "amount",
"fieldType": "BigDecimal",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "remark",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 160
}
],
"relationships": [
{
"relationshipType": "many-to-one",
"otherEntityName": "membership",
"otherEntityRelationshipName": "asset",
"relationshipValidateRules": "required",
"relationshipName": "membership",
"otherEntityField": "admissionDocumentDate"
}
],
"changelogDate": "20190507105335",
"entityTableName": "asset",
"dto": "mapstruct",
"pagination": "infinite-scroll",
"service": "serviceClass",
"jpaMetamodelFiltering": true,
"fluentMethods": true,
"clientRootFolder": "",
"applications": "*"
}

View File

@ -1,154 +0,0 @@
{
"name": "Customer",
"fields": [
{
"fieldName": "reference",
"fieldType": "Integer",
"fieldValidateRules": [
"required",
"unique",
"min",
"max"
],
"fieldValidateRulesMin": 10000,
"fieldValidateRulesMax": 99999
},
{
"fieldName": "prefix",
"fieldType": "String",
"fieldValidateRules": [
"required",
"maxlength",
"unique",
"pattern"
],
"fieldValidateRulesMaxlength": 3,
"fieldValidateRulesPattern": "[a-z][a-z0-9]+"
},
{
"fieldName": "name",
"fieldType": "String",
"fieldValidateRules": [
"required",
"maxlength"
],
"fieldValidateRulesMaxlength": 80
},
{
"fieldName": "kind",
"fieldType": "CustomerKind",
"fieldValues": "NATURAL,LEGAL",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "birthDate",
"fieldType": "LocalDate"
},
{
"fieldName": "birthPlace",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 80
},
{
"fieldName": "registrationCourt",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 80
},
{
"fieldName": "registrationNumber",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 80
},
{
"fieldName": "vatRegion",
"fieldType": "VatRegion",
"fieldValues": "DOMESTIC,EU,OTHER",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "vatNumber",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 40
},
{
"fieldName": "contractualSalutation",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 80
},
{
"fieldName": "contractualAddress",
"fieldType": "String",
"fieldValidateRules": [
"required",
"maxlength"
],
"fieldValidateRulesMaxlength": 400
},
{
"fieldName": "billingSalutation",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 80
},
{
"fieldName": "billingAddress",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 400
},
{
"fieldName": "remark",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 160
}
],
"relationships": [
{
"relationshipType": "one-to-many",
"otherEntityName": "membership",
"otherEntityRelationshipName": "customer",
"relationshipName": "membership"
},
{
"relationshipType": "one-to-many",
"otherEntityName": "sepaMandate",
"otherEntityRelationshipName": "customer",
"relationshipName": "sepamandate"
}
],
"changelogDate": "20190507105332",
"entityTableName": "customer",
"dto": "mapstruct",
"pagination": "infinite-scroll",
"service": "serviceClass",
"jpaMetamodelFiltering": true,
"fluentMethods": true,
"clientRootFolder": "",
"applications": "*"
}

View File

@ -1,66 +0,0 @@
{
"name": "Membership",
"fields": [
{
"fieldName": "admissionDocumentDate",
"fieldType": "LocalDate",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "cancellationDocumentDate",
"fieldType": "LocalDate"
},
{
"fieldName": "memberFromDate",
"fieldType": "LocalDate",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "memberUntilDate",
"fieldType": "LocalDate"
},
{
"fieldName": "remark",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 160
}
],
"relationships": [
{
"relationshipType": "one-to-many",
"otherEntityName": "share",
"otherEntityRelationshipName": "membership",
"relationshipName": "share"
},
{
"relationshipType": "one-to-many",
"otherEntityName": "asset",
"otherEntityRelationshipName": "membership",
"relationshipName": "asset"
},
{
"relationshipType": "many-to-one",
"otherEntityName": "customer",
"otherEntityRelationshipName": "membership",
"relationshipValidateRules": "required",
"relationshipName": "customer",
"otherEntityField": "prefix"
}
],
"changelogDate": "20190507105333",
"entityTableName": "membership",
"dto": "mapstruct",
"pagination": "infinite-scroll",
"service": "serviceClass",
"jpaMetamodelFiltering": true,
"fluentMethods": true,
"clientRootFolder": "",
"applications": "*"
}

View File

@ -1,84 +0,0 @@
{
"name": "SepaMandate",
"fields": [
{
"fieldName": "reference",
"fieldType": "String",
"fieldValidateRules": [
"maxlength",
"unique",
"required"
],
"fieldValidateRulesMaxlength": 40
},
{
"fieldName": "iban",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 34
},
{
"fieldName": "bic",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 11
},
{
"fieldName": "grantingDocumentDate",
"fieldType": "LocalDate",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "revokationDocumentDate",
"fieldType": "LocalDate"
},
{
"fieldName": "validFromDate",
"fieldType": "LocalDate",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "validUntilDate",
"fieldType": "LocalDate"
},
{
"fieldName": "lastUsedDate",
"fieldType": "LocalDate"
},
{
"fieldName": "remark",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 160
}
],
"relationships": [
{
"relationshipType": "many-to-one",
"otherEntityName": "customer",
"otherEntityRelationshipName": "sepamandate",
"relationshipValidateRules": "required",
"relationshipName": "customer",
"otherEntityField": "prefix"
}
],
"changelogDate": "20190507105336",
"entityTableName": "sepa_mandate",
"dto": "mapstruct",
"pagination": "infinite-scroll",
"service": "serviceClass",
"jpaMetamodelFiltering": true,
"fluentMethods": true,
"clientRootFolder": "",
"applications": "*"
}

View File

@ -1,61 +0,0 @@
{
"name": "Share",
"fields": [
{
"fieldName": "documentDate",
"fieldType": "LocalDate",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "valueDate",
"fieldType": "LocalDate",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "action",
"fieldType": "ShareAction",
"fieldValues": "SUBSCRIPTION,CANCELLATION",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "quantity",
"fieldType": "Integer",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "remark",
"fieldType": "String",
"fieldValidateRules": [
"maxlength"
],
"fieldValidateRulesMaxlength": 160
}
],
"relationships": [
{
"relationshipType": "many-to-one",
"otherEntityName": "membership",
"otherEntityRelationshipName": "share",
"relationshipValidateRules": "required",
"relationshipName": "membership",
"otherEntityField": "admissionDocumentDate"
}
],
"changelogDate": "20190507105334",
"entityTableName": "share",
"dto": "mapstruct",
"pagination": "infinite-scroll",
"service": "serviceClass",
"jpaMetamodelFiltering": true,
"fluentMethods": true,
"clientRootFolder": "",
"applications": "*"
}

View File

@ -1,47 +0,0 @@
{
"name": "UserRoleAssignment",
"fields": [
{
"fieldName": "entityTypeId",
"fieldType": "String",
"fieldValidateRules": [
"required",
"maxlength"
],
"fieldValidateRulesMaxlength": 32
},
{
"fieldName": "entityObjectId",
"fieldType": "Long",
"fieldValidateRules": [
"required"
]
},
{
"fieldName": "assignedRole",
"fieldType": "UserRole",
"fieldValues": "HOSTMASTER,ADMIN,SUPPORTER,CONTRACTUAL_CONTACT,FINANCIAL_CONTACT,TECHNICAL_CONTACT,CUSTOMER_USER",
"fieldValidateRules": [
"required"
]
}
],
"relationships": [
{
"relationshipType": "many-to-one",
"otherEntityName": "user",
"otherEntityRelationshipName": "required",
"relationshipName": "user",
"otherEntityField": "login"
}
],
"changelogDate": "20190507105342",
"entityTableName": "user_role_assignment",
"dto": "no",
"pagination": "infinite-scroll",
"service": "serviceClass",
"jpaMetamodelFiltering": true,
"fluentMethods": true,
"clientRootFolder": "",
"applications": "*"
}

View File

@ -1,3 +0,0 @@
node_modules
target
package-lock.json

View File

@ -1,12 +0,0 @@
# Prettier configuration
printWidth: 140
singleQuote: true
tabWidth: 4
useTabs: false
# js and ts rules:
arrowParens: avoid
# jsx and tsx rules:
jsxBracketSameLine: false

View File

@ -1,38 +0,0 @@
{
"generator-jhipster": {
"promptValues": {
"packageName": "org.hostsharing.hsadminng",
"nativeLanguage": "de"
},
"jhipsterVersion": "5.8.2",
"applicationType": "monolith",
"baseName": "hsadminNg",
"packageName": "org.hostsharing.hsadminng",
"packageFolder": "org/hostsharing/hsadminng",
"serverPort": "8080",
"authenticationType": "jwt",
"cacheProvider": "ehcache",
"enableHibernateCache": false,
"websocket": false,
"databaseType": "sql",
"devDatabaseType": "h2Memory",
"prodDatabaseType": "postgresql",
"searchEngine": false,
"messageBroker": false,
"serviceDiscoveryType": false,
"buildTool": "gradle",
"enableSwaggerCodegen": true,
"jwtSecretKey": "ZDFlMDUzODIzMTUzZDEwZjExN2E5ZjAzY2VhZmYzNDE1YjhlYWUxZGRhMGU3ODZiNjRkNjVlNzEwZjExYWY4YzczM2NlYzI5YWE1OTRkNWM0YThlYjZjZjA5Zjc5YWJkOTgzYjdhZjQxZWQyZGUyYjFlYjI5ZDE3NmE4M2UzYjQ=",
"clientFramework": "angularX",
"useSass": false,
"clientPackageManager": "npm",
"testFrameworks": ["cucumber"],
"jhiPrefix": "jhi",
"entitySuffix": "",
"dtoSuffix": "DTO",
"otherModules": [],
"enableTranslation": true,
"nativeLanguage": "de",
"languages": ["de", "en"]
}
}

18
Glossary.md Normal file
View File

@ -0,0 +1,18 @@
# hsadminNg Glossary
### Business Object
Represents an object from the
### Tenant
The RBAC
### RBAC
abbreviation for *Role Based Access Control*
### Role Based Access Control (RBAC)
A system to control access to business objects by defining users, roles, and permissions.
For more information see

View File

@ -1,196 +0,0 @@
# hsadminNg
This application was generated using JHipster 5.8.2, you can find documentation and help at [https://www.jhipster.tech/documentation-archive/v5.8.2](https://www.jhipster.tech/documentation-archive/v5.8.2).
## Development
Before you can build this project, you must install and configure the following dependencies on your machine:
1. [Node.js][]: We use Node to run a development web server and build the project.
Depending on your system, you can install Node either from source or as a pre-packaged bundle.
After installing Node, you should be able to run the following command to install development tools.
You will only need to run this command when dependencies change in [package.json](package.json).
npm install
We use npm scripts and [Webpack][] as our build system.
Run the following commands in two separate terminals to create a blissful development experience where your browser
auto-refreshes when files change on your hard drive.
./gradlew
npm start
Npm is also used to manage CSS and JavaScript dependencies used in this application. You can upgrade dependencies by
specifying a newer version in [package.json](package.json). You can also run `npm update` and `npm install` to manage dependencies.
Add the `help` flag on any command to see how you can use it. For example, `npm help update`.
The `npm run` command will list all of the scripts available to run for this project.
### Service workers
Service workers are commented by default, to enable them please uncomment the following code.
- The service worker registering script in index.html
```html
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('./service-worker.js').then(function() {
console.log('Service Worker Registered');
});
}
</script>
```
Note: workbox creates the respective service worker and dynamically generate the `service-worker.js`
### Managing dependencies
For example, to add [Leaflet][] library as a runtime dependency of your application, you would run following command:
npm install --save --save-exact leaflet
To benefit from TypeScript type definitions from [DefinitelyTyped][] repository in development, you would run following command:
npm install --save-dev --save-exact @types/leaflet
Then you would import the JS and CSS files specified in library's installation instructions so that [Webpack][] knows about them:
Edit [src/main/webapp/app/vendor.ts](src/main/webapp/app/vendor.ts) file:
```
import 'leaflet/dist/leaflet.js';
```
Edit [src/main/webapp/content/css/vendor.css](src/main/webapp/content/css/vendor.css) file:
```
@import '~leaflet/dist/leaflet.css';
```
Note: there are still few other things remaining to do for Leaflet that we won't detail here.
For further instructions on how to develop with JHipster, have a look at [Using JHipster in development][].
### Using angular-cli
You can also use [Angular CLI][] to generate some custom client code.
For example, the following command:
ng generate component my-component
will generate few files:
create src/main/webapp/app/my-component/my-component.component.html
create src/main/webapp/app/my-component/my-component.component.ts
update src/main/webapp/app/app.module.ts
### Doing API-First development using openapi-generator
[OpenAPI-Generator]() is configured for this application. You can generate API code from the `src/main/resources/swagger/api.yml` definition file by running:
```bash
./gradlew openApiGenerate
```
Then implements the generated delegate classes with `@Service` classes.
To edit the `api.yml` definition file, you can use a tool such as [Swagger-Editor](). Start a local instance of the swagger-editor using docker by running: `docker-compose -f src/main/docker/swagger-editor.yml up -d`. The editor will then be reachable at [http://localhost:7742](http://localhost:7742).
Refer to [Doing API-First development][] for more details.
## Building for production
To optimize the hsadminNg application for production, run:
./gradlew -Pprod clean bootWar
This will concatenate and minify the client CSS and JavaScript files. It will also modify `index.html` so it references these new files.
To ensure everything worked, run:
java -jar build/libs/*.war
Then navigate to [http://localhost:8080](http://localhost:8080) in your browser.
Refer to [Using JHipster in production][] for more details.
## Testing
To launch your application's tests, run:
./gradlew test
### Client tests
Unit tests are run by [Jest][] and written with [Jasmine][]. They're located in [src/test/javascript/](src/test/javascript/) and can be run with:
npm test
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
```
Then, run a Sonar analysis:
```
./gradlew -Pprod clean test sonarqube
```
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:
./gradlew bootWar -Pprod jibDockerBuild
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 5.8.2 archive]: https://www.jhipster.tech/documentation-archive/v5.8.2
[using jhipster in development]: https://www.jhipster.tech/documentation-archive/v5.8.2/development/
[using docker and docker-compose]: https://www.jhipster.tech/documentation-archive/v5.8.2/docker-compose
[using jhipster in production]: https://www.jhipster.tech/documentation-archive/v5.8.2/production/
[running tests page]: https://www.jhipster.tech/documentation-archive/v5.8.2/running-tests/
[code quality page]: https://www.jhipster.tech/documentation-archive/v5.8.2/code-quality/
[setting up continuous integration]: https://www.jhipster.tech/documentation-archive/v5.8.2/setting-up-ci/
[node.js]: https://nodejs.org/
[yarn]: https://yarnpkg.org/
[webpack]: https://webpack.github.io/
[angular cli]: https://cli.angular.io/
[browsersync]: http://www.browsersync.io/
[jest]: https://facebook.github.io/jest/
[jasmine]: http://jasmine.github.io/2.0/introduction.html
[protractor]: https://angular.github.io/protractor/
[leaflet]: http://leafletjs.com/
[definitelytyped]: http://definitelytyped.org/
[openapi-generator]: https://openapi-generator.tech
[swagger-editor]: http://editor.swagger.io
[doing api-first development]: https://www.jhipster.tech/documentation-archive/v5.8.2/doing-api-first-development/

57
Jenkinsfile vendored
View File

@ -1,57 +0,0 @@
#!/usr/bin/env groovy
node {
withEnv(["PATH=$HOME/bin:$PATH"]) {
stage('checkout') {
checkout scm
}
stage('check java') {
sh "java -version"
}
stage('clean+spotless') {
sh "chmod +x gradlew"
sh "./gradlew clean spotlessCheck --no-daemon"
}
stage('npm install') {
sh "./gradlew npm_install -PnodeInstall --no-daemon"
}
stage('backend tests') {
try {
sh "./gradlew test -PnodeInstall --no-daemon"
} catch (err) {
throw err
} finally {
junit '**/build/**/TEST-*.xml'
}
}
stage('backend check') {
try {
sh "./gradlew check -PnodeInstall --no-daemon"
} catch (err) {
throw err
} finally {
archiveArtifacts artifacts: '**/build/reports/jacoco/test/html/', fingerprint: true
}
}
stage('frontend tests') {
try {
sh "./gradlew npm_run_test -PnodeInstall --no-daemon"
} catch (err) {
throw err
} finally {
junit '**/build/test-results/TESTS-*.xml'
}
}
stage('packaging') {
sh "./gradlew bootWar -x test -Pprod -PnodeInstall --no-daemon"
archiveArtifacts artifacts: '**/build/libs/*.war', fingerprint: true
}
}
}

363
README.md
View File

@ -1,350 +1,77 @@
# hsadminNg Development
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [Setting up the Development Environment](#setting-up-the-development-environment)
- [Frequent Tasks](#frequent-tasks)
- [Building the Application with Test Execution](#building-the-application-with-test-execution)
- [Starting the Application](#starting-the-application)
- [Running JUnit tests with branch coverage](#running-junit-tests-with-branch-coverage)
- [HOWTO Commits](#howto-commits)
- [Creating HOWTO Commits](#creating-howto-commits)
- [Special Build Tasks](#special-build-tasks)
- [Spotless Formatting](#spotless-formatting)
- [Mutation Testing PiTest](#mutation-testing-pitest)
- [Git Workflow for JHipster Generator](#git-workflow-for-jhipster-generator)
- [Generating the Table of Contents for Markdown](#generating-the-table-of-contents-for-markdown)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Setting up the Development Environment
You'll often need to execute `./gradlew`, therefore we suggest to define this alias:
### PostgreSQL Server
alias gw='./gradlew'
So far the spike contains almost only PostgreSQL Code.
All you need so far, is a PostgreSQL database, for now with full admin rights.
The easiest way to set it up is using docker:
TODO: Instructions for setting up the dev environment from scratch.
Initially, pull an image compatible to current PostgreSQL version of Hostsharing:
## Frequent Tasks
docker pull postgres:13.7-bullseye
### Building the Application with Test Execution
Create and run a container with the given PostgreSQL version:
gw build
docker run --name hsadmin-ng-postgres -e POSTGRES_PASSWORD=password -p 5432:5432 -d postgres:13.7-bullseye
### Starting the Application
To check if the PostgreSQL container is running, the following command should list a container with the name "hsadmin-ng-postgres":
To use an **H2 in-memory database** populated with sample-data.
docker container ls
gw bootRun
Stop the PostgreSQL container:
docker stop hsadmin-ng-postgres
To use an **H2 file-based database**, start the application with the h2file profile:
Start the PostgreSQL container again:
gw bootRun -Ph2file
gw bootRun -Ph2file -Psample-data # populated with sample data
docker container start hsadmin-ng-postgres
To use a **local Postgres database**, first prepare your environment:
Remove the PostgreSQL container:
export HSADMINNG_DB_URL='jdbc:postgresql://localhost:5432/DBNAME'
export HSADMINNG_DB_USER='DBUSER'
export HSADMINNG_DB_PASS='DBPASS'
docker rm hsadmin-ng-postgres
Where `DBNAME`, `DBUSER` and `DBPASS` are replaced by your credentials.
After the PostgreSQL container is removed, you need to create it again as shown in "Create and run ..." above.
Then start the application with the pgsql profile:
### Markdown with PlantUML plugin
gw bootRun -Ppgsql
gw bootRun -Ppgsql -Psample-data # populated with sample data
Can you see the following diagram?
To use a **remote Postgres database** on a Hostsharing server,
```plantuml
@startuml
me -> you: Can you see this diagram?
you -> me: Sorry, I don't :-(
me -> you: Install some tooling!
@enduml
```
autossh -M 0 -o "ServerAliveInterval 60" -o "ServerAliveCountMax 3" \
-f -N -L 55432:127.0.0.1:5432 "xyz00@xyz.hostsharing.net"
If not, you need to install some tooling.
Then prepare your environment, e.g. like this:
#### for IntelliJ IDEA (or derived products)
export HSADMINNG_DB_URL='jdbc:postgresql://localhost:55432/xyz00_hsadminng'
export HSADMINNG_DB_USER='xyz00_hsadminng'
export HSADMINNG_DB_PASS='whatever'
You just need the bundled Markdown plugin enabled and install and activate the PlantUML plugin in its settings:
In all cases, you can also **specify the port** to used for the application via environment:
jetbrains://idea/settings?name=Languages+%26+Frameworks--Markdown
SERVER_PORT=8081 gw bootRun ...
You might also need to install Graphviz on your operating system.
For Debian-based Linux systems this might work:
For starting the JVM of the application in **debug-mode**, add `--debug-jvm` to any of the options above, e.g.
```sh
sudo apt install graphviz
```
gw bootRun -Ppgsql -Psample-data --debug-jvm
### Running JUnit tests with branch coverage
### Ubuntu Linux command line
#### for IntelliJ IDEA
```sh
sudo apt-get install pandoc texlive-latex-base texlive-fonts-recommended texlive-extra-utils texlive-latex-extra pandoc-plantuml-filter
```
see: https://confluence.jetbrains.com/display/IDEADEV/IDEA+Coverage+Runner
```sh
pandoc --filter pandoc-plantuml rbac.md -o rbac.pdf
```
Either apply it to specific test configurations or,
better, delete the previous test configurations and amend the JUnit template.
### for other IDEs / operating systems
## HOWTO Commits
There are git tags on some commits which show how to add certain features.
Find all of such tags with:
git tag | grep HOWTO
### Creating HOWTO Commits
If you want to add such a commit, make sure that it contains no clutter
(no changes which are not necessary for whatever the commit is about to explain),
and is complete with all unit tests, code coverage, pitest and other checks.
Otherwise the next developer would run into the same problems again.
One way to keep the commit clean, is to develop it on a local branch.
If any other changes (e.g. bugfixes, API extensions etc.) are necessary,
apply these only to the master or cherry-pick just these to the master,
then rebase your local branch. Do not forget to run all checks locally:
gw clean check pitest # might need over an hour
(Check the PiTest section for speeding up mutation testing.)
To create and push a new tag use:
git tag HOWTO-... master
git push origin HOWTO-...
To moved an existing the tag to another commit (here current master again), do this:
git tag --force HOWTO-... master
git push --force origin HOWTO-...
## Special Build Tasks
Besides common build tasks like `build`, `test` or `bootRun` this projects has some not so common tasks which are explained in this section.
### Spotless Formatting
To make sure that no IDE auto-formatter destroys the git history of any file and
especially to avoid merge conflicts from JHipster generated files after these had been changed,
we are using a standard formatter enforced by _spotless_, which is based on the standard Eclipse formatter.
The rules can be checked and applied with these commands:
gw spotlessCheck
gw spotlessApply
The spotlessCheck task is included as an early step in our Jenkins build pipeline.
Therefore wrong formatting is automatically detected.
Our configuration can be found under the directory `cfg/spotless`.
Currently we only have specific rules for _\*.java_-files and their import-order.
#### Our Changes to the Standard Eclipse Formatter
We amended the Standard Eclipse Formatter in these respects:
- Lines of code are never joined, thus the developer has control about linebreaks,
which is important for readability in some implementations like toString().
- Lines in comments are never joined either, because that often destroys readable stucture.
- Parts of files can be excluded from getting formatted, by using `@formatter:off` and `@formatter:on` in a comment.
See for example in class `SecurityConfiguration`.
#### Pre-Commit Hook
If you like, you could add this code to the _pre-commit or \_pre_push_ hook\_ in your `.git/hooks` directory:
if ! ./gradlew spotlessCheck; then
exit 1
fi
#### The Tagged Spotless Commit
The commit which introduces the spotless configuration is tagged.
Through this tag it can easily be cherry-picked in the JHipster workflow.
If you need to amend the commit tagged 'spotless', e.g. to change the spotless configuration,
it can be done with these steps:
git tag REAL-HEAD
git reset --hard spotless^
git cherry-pick -n spotless
...
git add .
# do NOT run: gw spotlessApply yet!
# for the case you have a commit hook which runs spotlessCheck:
git commit --no-verify
git tag --force spotless
git push --no-verify origin spotless
git reset --hard REAL-HEAD
git tag -d REAL-HEAD
### Mutation Testing PiTest
./gradlew pitest
Runs (almost) all JUnit tests under mutation testing.
Mutation testing is a means to determine the quality of the tests.
On Jenkins, the results can be found in the build artifacts under:
- https://ci.hostsharing.net/job/hsadmin-ng-pitest/XX/artifact/build/reports/pitest/index.html
Where XX is the build number. Or for the latest build under:
- https://ci.hostsharing.net/job/hsadmin-ng-pitest/lastCompletedBuild/artifact/build/reports/pitest/index.html
#### Some Background Information on Mutation Testing
PiTest does it with these steps:
- initially PiTest checks which production code is executed by which tests
- if the tests don't pass, it stops
- otherwise the production code is 'mutated' and PiTest checks whether this makes a test fail ('mutant killed')
- Finally it checks thresholds for coverage and mutant killing.
More information about can be found here:
- PiTest: http://pitest.org/
- gradle-plugin: https://gradle-pitest-plugin.solidsoft.info/
#### How to Configure PiTest
These thresholds can be configured in `build.gradle`,
but we should generally not lower these.
There is also a list of excluded files, all generated by JHipster or MapStruct, not containing any changes by us.
As you might figure, mutation testing is CPU-hungry.
To limit load in our Jenkins build server, it only uses 2 CPU threads, thus it needs over an hour.
If you want to spend more CPU threads on your local system, you can change that via command line:
gw pitest -Doverride.pitest.threads=7
I suggest to leave one CPU thread for other tasks or your might lag extremely.
### Git Workflow for JHipster Generator
The following workflow steps make sure that
- JHipster re-imports work properly,
- the git history of changes to the JDL-files, the generated code and the master is comprehensible,
- and merging newly generated code to the master branch is smooth.
It uses a git branch `jhipster-generated` to track the history of the JDL model file and the generated source code.
Applying commits which contain non-generated changes to that branch breaks the normal git history for generated files.
Therefore, this documentation is also not available in that branch.
Thus:
**MANUAL STEP before starting:** Copy this workflow documentation, because this file will be gone once you switched the branch.
| WARNING: The following steps are just a guideline. You should understand what you are doing! |
| -------------------------------------------------------------------------------------------- |
#### 1. Preparing the `jhipster-generated` git Branch
This step assumes that the latest `*.jdl` files are on the `HEAD` of the `jhipster-generated` git branch.
On a re-import of a JDL-file, JHipster does not remove any generated classes which belong to entities deleted from the JDL-file.
Therefore, the project has to be reset to a clean state before changes to the JDL file can be re-imported.
We have not yet finally tested a simplified workflow for just adding new entities or properties.
A git tag `jdl-base` is assumed to sit on the base commit after the application was generated, but before any entities were imported.
git checkout jhipster-generated
git pull
git tag REAL-HEAD
git reset --hard jdl-base
git clean -f -d
git cherry-pick -n spotless
git reset --soft REAL-HEAD
git checkout REAL-HEAD src/main/jdl/customer.jdl
git checkout REAL-HEAD src/main/jdl/accessrights.jdl
git checkout REAL-HEAD src/main/jdl/... # once there are more
git tag -d REAL-HEAD
#### 2. Amending and Re-Importing the JDL
**MANUAL STEP:** First apply all necessary changes to the JDL files.
Then re-import like this:
# (Re-) Importing
jhipster import-jdl src/main/jdl/customer.jdl
jhipster import-jdl src/main/jdl/accessrights.jdl
jhipster import-jdl src/main/jdl/... # once there are more
For smoothly being able to merge, we need the same formatting in the generated code as on the master:
gw spotlessApply
#### 3. Committing our Changes
git add .
git commit -m"..."
#### 4. Merging our Changes to the `master` Branch
git checkout master
git pull
**MANUAL STEP:** If you've renamed any identifiers, use the refactoring feature of your IDE to rename in master as well.
To avoid oodles of merge-conflicts, you need to do that **BEFORE MERGING!**
Commit any of such changes, if any.
Now we can finally merge our changes to master.
git merge jhipster-generated
It's a good idea doing this step in an IDE because it makes conflict resolving much easier.
Typical merge conflicts stem from:
- Random numbers in test data of `*IntTest.java` files.
- Timestamps in Liquibase-xml-Files.
Now, I suggest to run all tests locally:
gw clean test
Once everything works again, we can push our new version:
git push
#### 5. General Aftermath
Think about which additional code could be effected by your JDL-changes!
Files which are not at all in the `jhipster-generated` branch, don't show conflicts even though they might need changes.
Here some examples for amendments to be done:
- in `historicization_*.xml`: the columns or their constraints
- `sampledata/*.xml/csv`
If you find more of such general cases, please add them here!
#### 6. Special Aftermath for new Entities
Because we have added quite some functionality, after introducing new entities, there is a lot more to amend.
Here some issues to consider:
- add sample-data for the new entity
- internal (Angular) frontend: add table filters
- internal (Angular) frontend: amend input fields for multiline, if applicable
- internal (Angular) frontend: check if dates are properly formatted
- \*Mapper: add displayLabel for entity itself and parents
- \*DTO: add access-right annotations with customized JSON serializer/deserializer
- Validator: implement entity-based validator and call it in the generated service
- external API: add new type to client library
WARNING: This list is most likely incomplete. Pleas add any new found issue!
For many of these issues look for HOWTO-commits in git or HOWTO comments in the source code.
### Generating the Table of Contents for Markdown
This README file contains a table of contents generated by _doctoc_.
It's quite simple to use:
npm install -g doctoc
doctoc --maxlevel 3 README.md
Further information can be found [https://github.com/thlorenz/doctoc/blob/master/README.md](on the _doctoc_ github page).
If you have figured out how it works, please add instructions above this section.

View File

@ -0,0 +1,160 @@
# Use VIEWs with JOIN into Permission-Assignments for Row-Level-Security
**Status:**
- [x] proposed by Michael Hönnig
- [ ] accepted by (Participants)
- [ ] rejected by (Participants)
- [ ] superseded by (superseding ADR)
## Context and Problem Statement
We need to decide how to apply the access rules defined in our RBAC system to the visibility of table rows for the accessing user.
The core problem here is, that in our RBAC system, determining the permissions of the accessing user has to consider a hierarchy of roles.
### Technical Background
The session variable `hsadminng.currentUser` contains the accessing (domain-level) user, which is unrelated to the PostgreSQL user).
Given is a stored function `isPermissionGrantedToSubject` which detects if the accessing user has a given permission (e.g. 'view').
Given is also a stored function `queryAllPermissionsOfSubjectId` which returns the flattened view to all permissions assigned to the given accessing user.
In the following code snippets `customer` is just an example domain table.
## Considered Options
* Perform Visibility-Checks programmatically in the Backend
* Add Visibility-Checks in the Backend
* POLICY with ENABLE ROW LEVEL SECURITY
* VIEW-RULE with ON SELECT DO INSTEAD
* VIEW with JOIN into Flattened Permissions
### Perform Visibility-Checks programmatically in the Backend
In this solution, the database ignores row level visibility and returns all rows which match a given query. Afterwards, the result is filtered programmatically with Java-code in the backend.
#### Advantages
Very flexible access, programmatic, rules could be implemented.
The role-hierarchy and permissions for currently logged-in users user could be cached in the backend.
The access logic can be tested in pure Java unit tests.
At least regarding this aspect, an in-memory database could be used for integration testing; though the recursive Role-evaluation uses PostgreSQL features anyway.
#### Disadvantages
It's inefficient when initial query is not very restrictive, e.g. as on overview pages in a frontend, which often show all accessible objects, large parts or even whole database tables need to be transferred from the database to the backend.
It's error-prone and security leaks can happen too easily, because after every query the access rights for all participating joins have to be considered.
### Add Visibility-Checks in the Backend
In this solution again, the database ignores row level visibility and returns all rows which match a given query. And the backend adds filter conditions to each query sent to the database.
#### Advantages
At least regarding this aspect, an in-memory database could be used for integration testing.
#### Disadvantages
It's error-prone and security leaks can happen too easily, because for every query the access rights for all participating joins have to be considered.
### POLICY with ENABLE ROW LEVEL SECURITY
For restricted DB-users, which are used by the backend, access to rows is filtered using a policy:
SET SESSION AUTHORIZATION DEFAULT;
CREATE ROLE restricted;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO restricted;
ALTER TABLE customer ENABLE ROW LEVEL SECURITY;
CREATE POLICY customer_policy ON customer
FOR SELECT
TO restricted
USING (
isPermissionGrantedToSubject(findPermissionId('customer', id, 'view'), currentUserId())
);
SET SESSION AUTHORIZATION restricted;
SET hsadminng.currentUser TO 'alex@example.com';
SELECT * from customer; -- will only return visible rows
#### Advantages
Using POLICY together with ENABLE ROW LEVEL SECURITY is the PostgreSQL native mechanism to control access to data on the role level. Therefore, it looked like an obvious and elegant solution.
Every access at from the backend is under access control at the database level.
### Disadvantages
Unfortunately security mechanisms in PostgreSQL prevent the query optimizer to work well beyond ownership barriers (session user vs. table owner) and a SELECT from a table with 1 million objects needed over 30 seconds with our hierarchical RBAC policy.
We are bound to PostgreSQL, including integration tests and testing the RBAC system itself.
### VIEW-RULE with ON SELECT DO INSTEAD
SET SESSION SESSION AUTHORIZATION DEFAULT;
CREATE VIEW cust_view AS
SELECT * FROM customer;
CREATE OR REPLACE RULE "_RETURN" AS
ON SELECT TO cust_view
DO INSTEAD
SELECT * FROM customer WHERE isPermissionGrantedToSubject(findPermissionId('customer', id, 'view'), currentUserId());
SET SESSION AUTHORIZATION restricted;
SET hsadminng.currentUser TO 'alex@example.com';
SELECT * from customer; -- will only return visible rows
#### Advantages
Every access at from the backend is under access control at the database level.
Also using ON UPDATE etc., original tables could be completely hidden from the backend, and thus improved security.
### Disadvantages
Unfortunately security mechanisms in PostgreSQL prevent the query optimizer to work well beyond ownership barriers (session user vs. table owner) and a SELECT from a table with 1 million objects needed over 30 seconds with our hierarchical RBAC policy.
We are bound to PostgreSQL, including integration tests and testing the RBAC system itself.
An extra view needed for every table.
### VIEW with JOIN into flattened permissions
We do not access the tables directly from the backend, but via views which join the flattened permissions
SET SESSION SESSION AUTHORIZATION DEFAULT;
CREATE OR REPLACE VIEW cust_view AS
SELECT c.id, c.reference, c.prefix
FROM customer AS c
JOIN queryAllPermissionsOfSubjectId(currentUserId()) AS p
ON p.tableName='customer' AND p.rowId=c.id AND p.op='view';
GRANT ALL PRIVILEGES ON cust_view TO restricted;
SET SESSION SESSION AUTHORIZATION restricted;
SET hsadminng.currentUser TO 'alex@example.com';
SELECT * from cust_view; -- will only return visible rows
Alternatively the JOIN could also be applied in a "ON SELECT DO INSTEAD"-RULE, if there is any advantage for later features.
#### Advantages
Every access at from the backend is under access control at the database level.
No special PostgreSQL features needed; though the recursive Role-evaluation uses PostgreSQL features anyway.
Very fast, on my laptop a SELECT * FROM a table with 1 million rows just took about 50ms.
Also using ON UPDATE etc., original tables could be completely hidden from the backend, and thus improved security.
### Disadvantages
An extra view needed for every table.
## Decision Outcome
We chose the option **"VIEW with JOIN into flattened permissions"** because it supports the best combination of performance and security with almost no disadvantge.

View File

@ -1,39 +0,0 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"hsadmin-ng": {
"root": "",
"sourceRoot": "src/main/webapp",
"projectType": "application",
"architect": {}
}
},
"defaultProject": "hsadmin-ng",
"cli": {
"packageManager": "npm"
},
"schematics": {
"@schematics/angular:component": {
"inlineStyle": true,
"inlineTemplate": false,
"spec": false,
"prefix": "jhi",
"styleExt": "css"
},
"@schematics/angular:directive": {
"spec": false,
"prefix": "jhi"
},
"@schematics/angular:guard": {
"spec": false
},
"@schematics/angular:pipe": {
"spec": false
},
"@schematics/angular:service": {
"spec": false
}
}
}

View File

@ -1,24 +0,0 @@
// Behaviour tests based on a deployed application.
task cucumberTest(type: Test) {
description = "Execute cucumber BDD tests."
group = "verification"
include '**/CucumberTest*'
// uncomment if the tests reports are not generated
// see https://github.com/jhipster/generator-jhipster/pull/2771 and https://github.com/jhipster/generator-jhipster/pull/4484
// ignoreFailures true
reports.html.enabled = false
}
check.dependsOn cucumberTest
task testReport(type: TestReport) {
destinationDir = file("$buildDir/reports/tests")
reportOn test
}
task cucumberTestReport(type: TestReport) {
destinationDir = file("$buildDir/reports/tests")
reportOn cucumberTest
}

View File

@ -1,84 +0,0 @@
// Checks code coverage of JUnit based tests.
apply plugin: 'jacoco'
jacoco {
toolVersion = "0.8.3a"
}
test.finalizedBy jacocoTestReport
check.dependsOn jacocoTestCoverageVerification
// Only for purely JHipster/MapStruct generated classes.
// Please do NOT add any self coded classes!
// Keep in mind, git will blame you ;-)
def jhipsterGeneratedClassesWithDecentCoverage = [
'org.hostsharing.hsadminng.repository.CustomAuditEventRepository',
'org.hostsharing.hsadminng.service.ContactQueryService',
'org.hostsharing.hsadminng.service.UserService',
'org.hostsharing.hsadminng.service.CustomerContactQueryService'
]
// Only for purely JHipster/MapStruct generated classes.
// Please do NOT add any self coded classes!
// Keep in mind, git will blame you ;-)
def jhipsterGeneratedClassesWithLowCoverage = [
'org.hostsharing.hsadminng.service.MailService',
'org.hostsharing.hsadminng.security.SecurityUtils',
'org.hostsharing.hsadminng.config.DefaultProfileUtil',
'org.hostsharing.hsadminng.config.WebConfigurer',
'org.hostsharing.hsadminng.web.rest.AccountResource',
'org.hostsharing.hsadminng.web.rest.errors.ExceptionTranslator',
'org.hostsharing.hsadminng.web.rest.errors.CustomParameterizedException',
'org.hostsharing.hsadminng.config.audit.AuditEventConverter',
'org.hostsharing.hsadminng.security.jwt.TokenProvider',
'org.hostsharing.hsadminng.aop.logging.LoggingAspect',
'org.hostsharing.hsadminng.HsadminNgApp',
'*.*QueryService',
'*.*Configuration',
'*MapperImpl',
'*Criteria',
'*_'
]
def specialExceptions = [
// lots of unreachable code due to error handling / verifications
'org.hostsharing.hsadminng.service.accessfilter.JSonAccessFilter',
'org.hostsharing.hsadminng.service.util.ReflectionUtil'
]
jacocoTestCoverageVerification {
violationRules {
rule {
element = 'CLASS'
limit {
counter = 'BRANCH'
value = 'COVEREDRATIO'
// Increasing the threshold is fine, decreasing is not.
// Keep in mind, git will blame you ;-)
minimum = 0.95
}
excludes = jhipsterGeneratedClassesWithDecentCoverage + jhipsterGeneratedClassesWithLowCoverage + specialExceptions
}
rule {
element = 'CLASS'
limit {
counter = 'BRANCH'
value = 'COVEREDRATIO'
minimum = 0.80
}
includes = jhipsterGeneratedClassesWithDecentCoverage
}
rule {
element = 'CLASS'
limit {
counter = 'LINE'
value = 'COVEREDRATIO'
minimum = 0.85
}
includes = specialExceptions
}
}
}

View File

@ -1,36 +0,0 @@
// PiTest based mutation testing
pitest {
targetClasses = ['org.hostsharing.hsadminng.*']
excludedClasses = [
// Unit Testing Spring configurations makes little sense in most cases.
'org.hostsharing.hsadminng.config.*',
'org.hostsharing.hsadminng.ApplicationWebXml',
'org.hostsharing.hsadminng.HsadminNgApp',
// Unit testing this would need PowerMock and
// blackbox testing of random values has little value.
'org.hostsharing.hsadminng.service.util.RandomUtil',
// The following are mostly generated classes,
// as soon as we amend these, consider removing the exclude.
'org.hostsharing.hsadminng.**Criteria',
'org.hostsharing.hsadminng.**MapperImpl',
'org.hostsharing.hsadminng.aop.logging.*',
'org.hostsharing.hsadminng.web.rest.vm.*',
'org.hostsharing.hsadminng.security.jwt.TokenProvider',
'org.hostsharing.hsadminng.web.api.*' // API helpers, not the API itself
]
threads = 2
// Do not set these limit lower! 96% each might sound great, but keep in mind:
// 91%*91% means that ~8% of the code are NOT properly covered by automated tests
// (100%-94%*96% = ~8%). Not counting defects which come through missing code :-)
coverageThreshold = 94
mutationThreshold = 96
outputFormats = ['XML', 'HTML']
timestampedReports = false
verbose = false
}

View File

@ -1,15 +0,0 @@
// apply and check standard formatting of files
apply plugin: "com.diffplug.gradle.spotless"
spotless {
// automatically format source files, see https://github.com/diffplug/spotless
java {
licenseHeader '// Licensed under Apache-2.0'
importOrderFile 'cfg/spotless/hsadminng.importorder'
eclipse().configFile 'cfg/spotless/eclipse_formatter.xml'
target 'src/main/**/*.java', 'src/test/**/*.java'
removeUnusedImports()
endWithNewline()
}
}

View File

@ -1,297 +0,0 @@
import org.gradle.internal.os.OperatingSystem
buildscript {
repositories {
mavenLocal()
mavenCentral()
maven { url "http://repo.spring.io/plugins-release" }
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:${spring_boot_version}"