removing JHipster
This commit is contained in:
parent
31cd92f3be
commit
f2d0fbe67a
@ -18,7 +18,3 @@ insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[package.json]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
@ -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": "*"
|
||||
}
|
@ -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": "*"
|
||||
}
|
@ -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": "*"
|
||||
}
|
@ -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": "*"
|
||||
}
|
@ -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": "*"
|
||||
}
|
@ -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": "*"
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
node_modules
|
||||
target
|
||||
package-lock.json
|
12
.prettierrc
12
.prettierrc
@ -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
|
38
.yo-rc.json
38
.yo-rc.json
@ -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
18
Glossary.md
Normal 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
|
196
JHIPSTER.md
196
JHIPSTER.md
@ -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
57
Jenkinsfile
vendored
@ -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
363
README.md
@ -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.
|
||||
|
160
adr/2022-07-18.row-level-security-mechanism.md
Normal file
160
adr/2022-07-18.row-level-security-mechanism.md
Normal 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.
|
39
angular.json
39
angular.json
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
297
build.gradle
297
build.gradle
@ -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}"
|
||||