Merge remote-tracking branch 'origin/spike/ATN+HST'
# Conflicts: # .gitignore # TODO.md # tools/todo-progress # tools/todo-progress.gnuplot
This commit is contained in:
commit
9945eddf7a
9
.aliases
Normal file
9
.aliases
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
alias gw='./gradlew'
|
||||||
|
alias pg-sql-run='docker run --name hsadmin-ng-postgres -e POSTGRES_PASSWORD=password -p 5432:5432 -d postgres:13.7-bullseye'
|
||||||
|
alias pg-sql-stop='docker stop hsadmin-ng-postgres'
|
||||||
|
alias pg-sql-start='docker container start hsadmin-ng-postgres'
|
||||||
|
alias pg-sql-remove='docker rm hsadmin-ng-postgres'
|
||||||
|
alias pg-sql-reset='pg-sql-stop; pg-sql-remove; pg-sql-run'
|
||||||
|
alias pg-sql-backup='docker exec -i hsadmin-ng-postgres /usr/bin/pg_dump --clean --create -U postgres postgres | gzip -9'
|
||||||
|
alias pg-sql-restore='gunzip --stdout | docker exec -i hsadmin-ng-postgres psql -U postgres -d postgres'
|
||||||
|
|
@ -18,7 +18,3 @@ insert_final_newline = true
|
|||||||
|
|
||||||
[*.md]
|
[*.md]
|
||||||
trim_trailing_whitespace = false
|
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
|
|
8
.run/00-util.sql.run.xml
Normal file
8
.run/00-util.sql.run.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="00-util.sql" type="DatabaseScript" editBeforeRun="true" nameIsGenerated="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/00-util.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
8
.run/10-rbac-base.sql.run.xml
Normal file
8
.run/10-rbac-base.sql.run.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="10-rbac-base.sql" type="DatabaseScript" editBeforeRun="true" nameIsGenerated="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/10-rbac-base.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
8
.run/12-rbac-role-builder.sql.run.xml
Normal file
8
.run/12-rbac-role-builder.sql.run.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="12-rbac-role-builder.sql" type="DatabaseScript" editBeforeRun="true" nameIsGenerated="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/12-rbac-role-builder.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
8
.run/18--rbac-all.sql.run.xml
Normal file
8
.run/18--rbac-all.sql.run.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="18--rbac-all.sql" type="DatabaseScript" editBeforeRun="true" nameIsGenerated="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/18--rbac-all.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
8
.run/20-hs-base.sql.run.xml
Normal file
8
.run/20-hs-base.sql.run.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="20-hs-base.sql" type="DatabaseScript" editBeforeRun="true" nameIsGenerated="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/20-hs-base.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
8
.run/21-hs-customer.sql.run.xml
Normal file
8
.run/21-hs-customer.sql.run.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="21-hs-customer.sql" type="DatabaseScript" editBeforeRun="true" nameIsGenerated="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/21-hs-customer.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
8
.run/22-hs-packages.sql.run.xml
Normal file
8
.run/22-hs-packages.sql.run.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="22-hs-packages.sql" type="DatabaseScript" editBeforeRun="true" nameIsGenerated="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/22-hs-packages.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
8
.run/23-hs-unixuser.sql.run.xml
Normal file
8
.run/23-hs-unixuser.sql.run.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="23-hs-unixuser.sql" type="DatabaseScript" editBeforeRun="true" nameIsGenerated="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/23-hs-unixuser.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
8
.run/24-hs-domain.sql.run.xml
Normal file
8
.run/24-hs-domain.sql.run.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="24-hs-domain.sql" type="DatabaseScript" editBeforeRun="true" nameIsGenerated="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/24-hs-domain.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
8
.run/25-hs-emailaddress.sql.run.xml
Normal file
8
.run/25-hs-emailaddress.sql.run.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="25-hs-emailaddress.sql" type="DatabaseScript" editBeforeRun="true" nameIsGenerated="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/25-hs-emailaddress.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
8
.run/29-hs-statistics.sql.run.xml
Normal file
8
.run/29-hs-statistics.sql.run.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="29-hs-statistics.sql" type="DatabaseScript" editBeforeRun="true" nameIsGenerated="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/29-hs-statistics.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
18
.run/run all up to emailaddresses.run.xml
Normal file
18
.run/run all up to emailaddresses.run.xml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="run all up to statistics" type="DatabaseScript" editBeforeRun="true">
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/00-util.sql" />
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/10-rbac-base.sql" />
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/12-rbac-role-builder.sql" />
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/18-rbac-statistics.sql" />
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/20-hs-base.sql" />
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/21-hs-customer.sql" />
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/22-hs-packages.sql" />
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/23-hs-unixuser.sql" />
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/24-hs-domain.sql" />
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/25-hs-emailaddress.sql" />
|
||||||
|
<script-file value="$PROJECT_DIR$/sql/29-hs-statistics.sql" />
|
||||||
|
<script-mode>FILE</script-mode>
|
||||||
|
<data-source id="58980aaf-09d7-4782-a6fa-859aa1fc3986" namespace="database/"postgres"/schema/"public"" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
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"]
|
|
||||||
}
|
|
||||||
}
|
|
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
26
LICENSE.md
Normal file
26
LICENSE.md
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Copyright ©2022 Michael Hönnig
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person
|
||||||
|
obtaining a copy of this software and associated documentation
|
||||||
|
files (the “Software”), to deal in the Software without
|
||||||
|
restriction, including without limitation the rights to use,
|
||||||
|
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following
|
||||||
|
conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||||
|
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
454
README.md
454
README.md
@ -1,350 +1,332 @@
|
|||||||
# hsadminNg Development
|
# hsadminNg Development
|
||||||
|
|
||||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
This documents gives an overview of the development environment and tools.
|
||||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
For architecture consider the files in the `doc` and `adr` folder.
|
||||||
|
|
||||||
- [Setting up the Development Environment](#setting-up-the-development-environment)
|
<!-- generated TOC begin: -->
|
||||||
- [Frequent Tasks](#frequent-tasks)
|
- [Setting up the Development Environment](#setting-up-the-development-environment)
|
||||||
- [Building the Application with Test Execution](#building-the-application-with-test-execution)
|
- [SDKMAN](#sdkman)
|
||||||
- [Starting the Application](#starting-the-application)
|
- [PostgreSQL Server](#postgresql-server)
|
||||||
- [Running JUnit tests with branch coverage](#running-junit-tests-with-branch-coverage)
|
- [Markdown](#markdown)
|
||||||
- [HOWTO Commits](#howto-commits)
|
- [Render Markdown embedded PlantUML](#render-markdown-embedded-plantuml)
|
||||||
- [Creating HOWTO Commits](#creating-howto-commits)
|
- [Other Tools](#other-tools)
|
||||||
- [Special Build Tasks](#special-build-tasks)
|
- [Running the SQL files](#running-the-sql-files)
|
||||||
- [Spotless Formatting](#spotless-formatting)
|
- [For RBAC](#for-rbac)
|
||||||
- [Mutation Testing PiTest](#mutation-testing-pitest)
|
- [For Historization](#for-historization)
|
||||||
- [Git Workflow for JHipster Generator](#git-workflow-for-jhipster-generator)
|
<!-- generated TOC end. -->
|
||||||
- [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
|
## Setting up the Development Environment
|
||||||
|
|
||||||
You'll often need to execute `./gradlew`, therefore we suggest to define this alias:
|
All instructions assume that you're using a current _Linux_ or _MacOS_ operating system.
|
||||||
|
Everything is tested on _Ubuntu Linux 22.04_ and _MacOS Monterey (12.4)_.
|
||||||
|
|
||||||
alias gw='./gradlew'
|
To be able to build and run the Java Spring Boot application, you need the following tools:
|
||||||
|
|
||||||
TODO: Instructions for setting up the dev environment from scratch.
|
- Docker 20.x (on MacOS you also need *Docker Desktop* or similar)
|
||||||
|
- PostgreSQL Server 13.7-bullseye (see instructions below to install and run in Docker)
|
||||||
|
- Java JDK 17.x
|
||||||
|
- Gradle in some not too outdated version (7.4 will be installed via wrapper)
|
||||||
|
|
||||||
## Frequent Tasks
|
You also might need an IDE (e.g. *IntelliJ IDEA* or *Eclipse* or *VS Code* with *[STS](https://spring.io/tools)* and a GUI Frontend for *PostgreSQL* like *Postbird*.
|
||||||
|
|
||||||
### Building the Application with Test Execution
|
If you have at least Docker, the Java JDK and Gradle installed in appropriate versions and in your `PATH`, then you can start like this:
|
||||||
|
|
||||||
gw build
|
cd your-hsadmin-ng-directory
|
||||||
|
|
||||||
|
gradle wrapper # downloads Gradle 7.5 into the project
|
||||||
|
source .aliases # creates some comforable bash aliases, e.g. 'gw'='./gradlew'
|
||||||
|
|
||||||
### Starting the Application
|
gw test # compiles and runs unit- and integration-tests
|
||||||
|
|
||||||
|
pg-sql-run # downloads + runs PostgreSQL in a Docker container on localhost:5432
|
||||||
|
gw bootRun # compiles and runs the application on localhost:8080
|
||||||
|
|
||||||
To use an **H2 in-memory database** populated with sample-data.
|
# the following command should reply with "pong":
|
||||||
|
curl http://localhost:8080/api/ping
|
||||||
|
|
||||||
gw bootRun
|
# the following command should return a JSON array with just all customers:
|
||||||
|
curl \
|
||||||
|
-H 'current-user: mike@hostsharing.net' \
|
||||||
|
http://localhost:8080/api/customers
|
||||||
|
|
||||||
To use an **H2 file-based database**, start the application with the h2file profile:
|
# the following command should return a JSON array with just all packages visible for the admin of the customer aab:
|
||||||
|
curl \
|
||||||
|
-H 'current-user: mike@hostsharing.net' -H 'assumed-roles: customer#aab.admin' \
|
||||||
|
http://localhost:8080/api/packages
|
||||||
|
|
||||||
gw bootRun -Ph2file
|
# add a new customer
|
||||||
gw bootRun -Ph2file -Psample-data # populated with sample data
|
curl \
|
||||||
|
-H 'current-user: mike@hostsharing.net' -H "Content-Type: application/json" \
|
||||||
|
-d '{ "prefix":"baa", "reference":80001, "adminUserName":"admin@baa.example.com" }' \
|
||||||
|
-X POST http://localhost:8080/api/customers
|
||||||
|
|
||||||
To use a **local Postgres database**, first prepare your environment:
|
If you wonder who 'mike@hostsharing.net' and 'sven@hostsharing.net' are and where the data comes from:
|
||||||
|
Mike and Sven are just example Hostsharing hostmaster accounts as part of the example data which is automatically inserted in Testcontainers and Development environments.
|
||||||
|
Also try for example 'admin@aaa.example.com' or 'unknown@example.org'.
|
||||||
|
|
||||||
export HSADMINNG_DB_URL='jdbc:postgresql://localhost:5432/DBNAME'
|
If you want a formatted JSON output, you can pipe the result to `jq` or similar.
|
||||||
export HSADMINNG_DB_USER='DBUSER'
|
|
||||||
export HSADMINNG_DB_PASS='DBPASS'
|
|
||||||
|
|
||||||
Where `DBNAME`, `DBUSER` and `DBPASS` are replaced by your credentials.
|
And to see the full, currently implemented, API, open http://localhost:8080/swagger-ui/index.html.
|
||||||
|
|
||||||
Then start the application with the pgsql profile:
|
If you still need to install some of these tools, find some hints in the next chapters.
|
||||||
|
|
||||||
gw bootRun -Ppgsql
|
|
||||||
gw bootRun -Ppgsql -Psample-data # populated with sample data
|
|
||||||
|
|
||||||
To use a **remote Postgres database** on a Hostsharing server,
|
### SDKMAN
|
||||||
|
|
||||||
autossh -M 0 -o "ServerAliveInterval 60" -o "ServerAliveCountMax 3" \
|
*SdkMan* is not necessary, but helpful to install and switch between different versions of SDKs (Software-Development-Kits) and development tools in general, e.g. *JDK* and *Gradle*.
|
||||||
-f -N -L 55432:127.0.0.1:5432 "xyz00@xyz.hostsharing.net"
|
It is available for _Linux_ and _MacOS_, _WSL_, _Cygwin_, _Solaris_ and _FreeBSD_.
|
||||||
|
|
||||||
Then prepare your environment, e.g. like this:
|
You can get it from: https://sdkman.io/.
|
||||||
|
|
||||||
export HSADMINNG_DB_URL='jdbc:postgresql://localhost:55432/xyz00_hsadminng'
|
<big>**⚠**</big>
|
||||||
export HSADMINNG_DB_USER='xyz00_hsadminng'
|
Yeah, the `curl ... | bash` install method looks quite scary;
|
||||||
export HSADMINNG_DB_PASS='whatever'
|
but in a development environment you're downloading executables all the time,
|
||||||
|
e.g. through `npm`, `Maven` or `Gradle` when downloading dependencies.
|
||||||
|
Thus, maybe you should at least use a separate Linux account for development.
|
||||||
|
|
||||||
In all cases, you can also **specify the port** to used for the application via environment:
|
Once it's installed, you can install *JDK* and *Gradle*:
|
||||||
|
|
||||||
SERVER_PORT=8081 gw bootRun ...
|
sdk install java 17.0.3-tem
|
||||||
|
sdk install gradle
|
||||||
|
|
||||||
For starting the JVM of the application in **debug-mode**, add `--debug-jvm` to any of the options above, e.g.
|
sdk use java 17.0.3-tem # use this to switch between installed JDK versions
|
||||||
|
|
||||||
gw bootRun -Ppgsql -Psample-data --debug-jvm
|
|
||||||
|
|
||||||
### Running JUnit tests with branch coverage
|
### PostgreSQL Server
|
||||||
|
|
||||||
#### for IntelliJ IDEA
|
You could use any PostgreSQL Server (from version 13 on) installed on your machine.
|
||||||
|
You might amend the port and user settings in `src/main/resources/application.yml`, though.
|
||||||
|
|
||||||
see: https://confluence.jetbrains.com/display/IDEADEV/IDEA+Coverage+Runner
|
But the easiest way to run PostgreSQL is via Docker.
|
||||||
|
|
||||||
Either apply it to specific test configurations or,
|
Initially, pull an image compatible to current PostgreSQL version of Hostsharing:
|
||||||
better, delete the previous test configurations and amend the JUnit template.
|
|
||||||
|
|
||||||
## HOWTO Commits
|
docker pull postgres:13.7-bullseye
|
||||||
|
|
||||||
There are git tags on some commits which show how to add certain features.
|
<big>**⚠**</big>
|
||||||
|
If we switch the version, please also amend the documentation as well as the aliases file. Thanks!
|
||||||
|
|
||||||
Find all of such tags with:
|
Create and run a container with the given PostgreSQL version:
|
||||||
|
|
||||||
git tag | grep HOWTO
|
docker run --name hsadmin-ng-postgres -e POSTGRES_PASSWORD=password -p 5432:5432 -d postgres:13.7-bullseye
|
||||||
|
|
||||||
### Creating HOWTO Commits
|
# or via alias:
|
||||||
|
pg-sql-run
|
||||||
|
|
||||||
If you want to add such a commit, make sure that it contains no clutter
|
To check if the PostgreSQL container is running, the following command should list a container with the name "hsadmin-ng-postgres":
|
||||||
(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.
|
docker container ls
|
||||||
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
|
Stop the PostgreSQL container:
|
||||||
|
|
||||||
|
docker stop hsadmin-ng-postgres
|
||||||
|
# or via alias: pg-sql-stop
|
||||||
|
|
||||||
(Check the PiTest section for speeding up mutation testing.)
|
Start the PostgreSQL container again:
|
||||||
|
|
||||||
To create and push a new tag use:
|
docker container start hsadmin-ng-postgres
|
||||||
|
# or via alias: pg-sql-start
|
||||||
|
|
||||||
git tag HOWTO-... master
|
Remove the PostgreSQL container:
|
||||||
git push origin HOWTO-...
|
|
||||||
|
|
||||||
To moved an existing the tag to another commit (here current master again), do this:
|
docker rm hsadmin-ng-postgres
|
||||||
|
|
||||||
|
# or via alias:
|
||||||
|
pg-sql-remove
|
||||||
|
|
||||||
git tag --force HOWTO-... master
|
To reset to a clean database, use:
|
||||||
git push --force origin HOWTO-...
|
|
||||||
|
|
||||||
## Special Build Tasks
|
pg-sql-stop; pg-sql-remove; pg-sql-run
|
||||||
|
|
||||||
Besides common build tasks like `build`, `test` or `bootRun` this projects has some not so common tasks which are explained in this section.
|
# or via alias:
|
||||||
|
pg-sql-reset
|
||||||
|
|
||||||
### Spotless Formatting
|
After the PostgreSQL container is removed, you need to create it again as shown in "Create and run ..." above.
|
||||||
|
|
||||||
To make sure that no IDE auto-formatter destroys the git history of any file and
|
Given the container is running, to create a backup in ~/backup, run:
|
||||||
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:
|
docker exec -i hsadmin-ng-postgres /usr/bin/pg_dump --clean --create -U postgres postgres | gzip -9 > ~/backup/hsadmin-ng-postgres.sql.gz
|
||||||
|
|
||||||
gw spotlessCheck
|
# or via alias:
|
||||||
gw spotlessApply
|
pg-sql-backup >~/backup/hsadmin-ng-postgres.sql.gz
|
||||||
|
|
||||||
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`.
|
Again, given the container is running, to restore the backup from ~/backup, run:
|
||||||
Currently we only have specific rules for _\*.java_-files and their import-order.
|
|
||||||
|
|
||||||
#### Our Changes to the Standard Eclipse Formatter
|
gunzip --stdout --keep ~/backup/hsadmin-ng-postgres.sql.gz | docker exec -i hsadmin-ng-postgres psql -U postgres -d postgres
|
||||||
|
|
||||||
We amended the Standard Eclipse Formatter in these respects:
|
# or via alias:
|
||||||
|
pg-sql-restore <~/backup/hsadmin-ng-postgres.sql.gz
|
||||||
|
|
||||||
- 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
|
### Markdown
|
||||||
|
|
||||||
If you like, you could add this code to the _pre-commit or \_pre_push_ hook\_ in your `.git/hooks` directory:
|
To generate the TOC (Table of Contents), a little bash script from a
|
||||||
|
[Blog Article](https://medium.com/@acrodriguez/one-liner-to-generate-a-markdown-toc-f5292112fd14) was used.
|
||||||
|
|
||||||
if ! ./gradlew spotlessCheck; then
|
To render the Markdown files, especially to watch embedded PlantUML diagrams, you can use one of the following methods:
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
#### The Tagged Spotless Commit
|
#### Render Markdown embedded PlantUML
|
||||||
|
|
||||||
The commit which introduces the spotless configuration is tagged.
|
Can you see the following diagram right in your IDE?
|
||||||
Through this tag it can easily be cherry-picked in the JHipster workflow.
|
I mean a real graphic diagram, not just some markup code.
|
||||||
|
|
||||||
If you need to amend the commit tagged 'spotless', e.g. to change the spotless configuration,
|
```plantuml
|
||||||
it can be done with these steps:
|
@startuml
|
||||||
|
me -> you: Can you see this diagram?
|
||||||
|
you -> me: Sorry, I don't :-(
|
||||||
|
me -> you: Install some tooling!
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
git tag REAL-HEAD
|
If not, you need to install some tooling.
|
||||||
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
|
##### for IntelliJ IDEA (or derived products)
|
||||||
|
|
||||||
./gradlew pitest
|
You just need the bundled Markdown plugin enabled and install and activate the PlantUML plugin in its settings:
|
||||||
|
|
||||||
Runs (almost) all JUnit tests under mutation testing.
|
jetbrains://idea/settings?name=Languages+%26+Frameworks--Markdown
|
||||||
Mutation testing is a means to determine the quality of the tests.
|
|
||||||
|
|
||||||
On Jenkins, the results can be found in the build artifacts under:
|
You might also need to install Graphviz on your operating system.
|
||||||
|
For Debian-based Linux systems this might work:
|
||||||
|
|
||||||
- https://ci.hostsharing.net/job/hsadmin-ng-pitest/XX/artifact/build/reports/pitest/index.html
|
```sh
|
||||||
|
sudo apt install graphviz
|
||||||
|
```
|
||||||
|
|
||||||
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
|
##### Ubuntu Linux command line
|
||||||
|
|
||||||
#### Some Background Information on Mutation Testing
|
```sh
|
||||||
|
sudo apt-get install pandoc texlive-latex-base texlive-fonts-recommended texlive-extra-utils texlive-latex-extra pandoc-plantuml-filter
|
||||||
|
```
|
||||||
|
|
||||||
PiTest does it with these steps:
|
```sh
|
||||||
|
pandoc --filter pandoc-plantuml rbac.md -o rbac.pdf
|
||||||
|
```
|
||||||
|
|
||||||
- initially PiTest checks which production code is executed by which tests
|
##### for other IDEs / operating systems
|
||||||
- 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:
|
If you have figured out how it works, please add instructions above this section.
|
||||||
|
|
||||||
- PiTest: http://pitest.org/
|
### Other Tools
|
||||||
- gradle-plugin: https://gradle-pitest-plugin.solidsoft.info/
|
|
||||||
|
|
||||||
#### How to Configure PiTest
|
**jq**: a JSON formatter.
|
||||||
|
On _Debian_'oid systems you can install it with `sudo apt-get install jq`.
|
||||||
|
On _MacOS_ you can install it with `brew install jq`, given you have _brew_ installed.
|
||||||
|
|
||||||
These thresholds can be configured in `build.gradle`,
|
## Running the SQL files
|
||||||
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.
|
### For RBAC
|
||||||
|
|
||||||
As you might figure, mutation testing is CPU-hungry.
|
The Schema is automatically created via *Liquibase*, a database migration library.
|
||||||
To limit load in our Jenkins build server, it only uses 2 CPU threads, thus it needs over an hour.
|
Currently, also some test data is automatically created.
|
||||||
|
|
||||||
If you want to spend more CPU threads on your local system, you can change that via command line:
|
To increase the amount of test data, increase the number of generated customers in `2022-07-28-051-hs-customer.sql` and run that
|
||||||
|
|
||||||
gw pitest -Doverride.pitest.threads=7
|
If you already have data, e.g. for customers 0..999 (thus with reference numbers 10000..10999) and want to add another 1000 customers, amend the for loop to 1000...1999 and also uncomment and amend the `CONTINUE WHEN` or `WHERE` conditions in the other test data generators, using the first new customer reference number (in the example that's 11000).
|
||||||
|
|
||||||
I suggest to leave one CPU thread for other tasks or your might lag extremely.
|
### For Historization
|
||||||
|
|
||||||
### Git Workflow for JHipster Generator
|
The historization is not yet integrated into the *Liquibase*-scripts.
|
||||||
|
You can explore the prototype as follows:
|
||||||
|
|
||||||
The following workflow steps make sure that
|
- start with an empty database
|
||||||
|
(the example tables are currently not compatible with RBAC),
|
||||||
|
- then run `historization.sql` in the database,
|
||||||
|
- finally run `examples.sql` in the database.
|
||||||
|
|
||||||
- JHipster re-imports work properly,
|
## Coding Guidelines
|
||||||
- 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.
|
### Directory and Package Structure
|
||||||
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.
|
Generally, the standard Java directory structure is used, where productive and test code are sparated like this:
|
||||||
|
|
||||||
| WARNING: The following steps are just a guideline. You should understand what you are doing! |
|
```
|
||||||
| -------------------------------------------------------------------------------------------- |
|
src
|
||||||
|
main/
|
||||||
|
java/
|
||||||
|
net.hostsharing.hasadminng/
|
||||||
|
resources/
|
||||||
|
|
||||||
|
test/
|
||||||
|
java/
|
||||||
|
net.hostsharing.hasadminng/
|
||||||
|
resources/
|
||||||
|
```
|
||||||
|
|
||||||
|
The Java package structure below contains:
|
||||||
|
|
||||||
#### 1. Preparing the `jhipster-generated` git Branch
|
- config and global (utility) packages,
|
||||||
|
these should not access any other packages within the project
|
||||||
|
- rbac, containing all packages related to the RBAC subsystem
|
||||||
|
- hs, containing Hostsharing business object related packages
|
||||||
|
|
||||||
This step assumes that the latest `*.jdl` files are on the `HEAD` of the `jhipster-generated` git branch.
|
Underneath of rbac and hs, the structure is business oriented, NOT technical / layer -oriented.
|
||||||
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.
|
Some of these rules are checked with *ArchUnit* unit tests.
|
||||||
|
|
||||||
git checkout jhipster-generated
|
### Spotless Code Formatting
|
||||||
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
|
Code formatting for Java is checked via *spotless*.
|
||||||
|
The formatting style can be checked with this command:
|
||||||
|
|
||||||
**MANUAL STEP:** First apply all necessary changes to the JDL files.
|
```shell
|
||||||
Then re-import like this:
|
gw spotlessCheck
|
||||||
|
```
|
||||||
|
|
||||||
# (Re-) Importing
|
This task is also included in `gw build`.
|
||||||
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:
|
To apply formatting rules, use:
|
||||||
|
|
||||||
gw spotlessApply
|
```shell
|
||||||
|
gw spotlessApply
|
||||||
|
```
|
||||||
|
|
||||||
#### 3. Committing our Changes
|
|
||||||
|
|
||||||
git add .
|
## How To
|
||||||
git commit -m"..."
|
|
||||||
|
|
||||||
#### 4. Merging our Changes to the `master` Branch
|
### How to Use a Persistent Database for Integration Tests?
|
||||||
|
|
||||||
git checkout master
|
Usually, the `DataJpaTest` integration tests run against a database in a temporary docker container.
|
||||||
git pull
|
As soon as the test ends, the database is gone; this might make debugging difficult.
|
||||||
|
|
||||||
**MANUAL STEP:** If you've renamed any identifiers, use the refactoring feature of your IDE to rename in master as well.
|
Alternatively
|
||||||
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.
|
If the persistent database and the temporary database show different results, one of these reasons could be the cause:
|
||||||
|
|
||||||
git merge jhipster-generated
|
1. You might have some changesets only running in either context,
|
||||||
|
check the `context: ...` in the changeset control lines.
|
||||||
|
2. You might have changes in the database which interfere with the tests,
|
||||||
|
e.g. from a previous run of tests or manually applied.
|
||||||
|
It's best to run `pg-sql-reset && gw bootRun` before each test run, to have a clean database.
|
||||||
|
|
||||||
|
## How to Amend Liquibase SQL Changesets?
|
||||||
|
|
||||||
It's a good idea doing this step in an IDE because it makes conflict resolving much easier.
|
Liquibase changesets are meant to be immutable and based on each other.
|
||||||
Typical merge conflicts stem from:
|
That means, once a changeset is written, it never changes, not even a whitespace or comment.
|
||||||
|
Liquibase is a *database migration tool*, not a *database initialization tool*.
|
||||||
|
|
||||||
- Random numbers in test data of `*IntTest.java` files.
|
This, if you need to add change a table, stored procedure or whatever,
|
||||||
- Timestamps in Liquibase-xml-Files.
|
create a new changeset and apply `ALTER`, `DROP`, `CREATE OR REPLACE` or whatever SQL commands to perform your changes.
|
||||||
|
These changes will be automatically applied once the application starts up again.
|
||||||
|
This way, any staging or production database will always match the application code.
|
||||||
|
|
||||||
Now, I suggest to run all tests locally:
|
But, during initial development that can be a big hassle because the database structure changes a lot in that stage.
|
||||||
|
Also, the actual structure of the database won't be easily recognized anymore through lots of migration changesets.
|
||||||
|
|
||||||
gw clean test
|
Therefore, during initial development, it's good approach just to amend the existing changesets and delete the database:
|
||||||
|
|
||||||
Once everything works again, we can push our new version:
|
```shell
|
||||||
|
pg-sql-reset
|
||||||
|
gw bootRun
|
||||||
|
```
|
||||||
|
|
||||||
git push
|
<big>**⚠**</big>
|
||||||
|
Just don't forget switching to the migration mode, once there is a production database!
|
||||||
|
|
||||||
#### 5. General Aftermath
|
## Further Documentation
|
||||||
|
|
||||||
Think about which additional code could be effected by your JDL-changes!
|
- the `doc` directory contains architecture concepts and a glossary
|
||||||
Files which are not at all in the `jhipster-generated` branch, don't show conflicts even though they might need changes.
|
- TODO.md tracks requirements and progress for the contract of the initial project,
|
||||||
|
please do not amend anything in this document
|
||||||
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).
|
|
||||||
|
BIN
TODO-progress.png
Normal file
BIN
TODO-progress.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.3 KiB |
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()
|
|
||||||
}
|
|
||||||
}
|
|
331
build.gradle
331
build.gradle
@ -1,297 +1,68 @@
|
|||||||
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}"
|
|
||||||
classpath "io.spring.gradle:propdeps-plugin:0.0.10.RELEASE"
|
|
||||||
classpath "org.openapitools:openapi-generator-gradle-plugin:3.3.0"
|
|
||||||
classpath "gradle.plugin.com.gorylenko.gradle-git-properties:gradle-git-properties:1.5.2"
|
|
||||||
//jhipster-needle-gradle-buildscript-dependency - JHipster will add additional gradle build script plugins here
|
|
||||||
|
|
||||||
classpath "com.diffplug.spotless:spotless-plugin-gradle:3.22.0"
|
|
||||||
classpath 'org.owasp:dependency-check-gradle:4.0.2'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id "org.sonarqube" version "2.6.2"
|
id 'java'
|
||||||
id "net.ltgt.apt-eclipse" version "0.19"
|
id 'org.springframework.boot' version '2.7.2'
|
||||||
id "net.ltgt.apt-idea" version "0.19"
|
id 'io.spring.dependency-management' version '1.0.12.RELEASE'
|
||||||
id "net.ltgt.apt" version "0.19"
|
id "com.diffplug.spotless" version "6.9.0"
|
||||||
id "io.spring.dependency-management" version "1.0.6.RELEASE"
|
|
||||||
id "com.moowork.node" version "1.2.0"
|
|
||||||
id 'org.liquibase.gradle' version '2.0.1'
|
|
||||||
id 'info.solidsoft.pitest' version '1.4.0'
|
|
||||||
//jhipster-needle-gradle-plugins - JHipster will add additional gradle plugins here
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'java'
|
group = 'net.hostsharing'
|
||||||
apply plugin: 'org.owasp.dependencycheck'
|
|
||||||
sourceCompatibility=1.8
|
|
||||||
targetCompatibility=1.8
|
|
||||||
|
|
||||||
apply plugin: 'maven'
|
|
||||||
apply plugin: 'org.springframework.boot'
|
|
||||||
apply plugin: 'war'
|
|
||||||
apply plugin: 'propdeps'
|
|
||||||
apply plugin: 'com.moowork.node'
|
|
||||||
apply plugin: 'io.spring.dependency-management'
|
|
||||||
apply plugin: 'idea'
|
|
||||||
|
|
||||||
apply from: 'build-jacoco.gradle'
|
|
||||||
apply from: 'build-pitest.gradle'
|
|
||||||
apply from: 'build-spotless.gradle'
|
|
||||||
|
|
||||||
idea {
|
|
||||||
module {
|
|
||||||
excludeDirs += files('node_modules')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencyManagement {
|
|
||||||
imports {
|
|
||||||
mavenBom 'io.github.jhipster:jhipster-dependencies:' + jhipster_dependencies_version
|
|
||||||
//jhipster-needle-gradle-dependency-management - JHipster will add additional dependencies management here
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultTasks 'bootRun'
|
|
||||||
|
|
||||||
group = 'org.hostsharing.hsadminng'
|
|
||||||
version = '0.0.1-SNAPSHOT'
|
version = '0.0.1-SNAPSHOT'
|
||||||
|
sourceCompatibility = '17'
|
||||||
description = ''
|
|
||||||
|
|
||||||
bootWar {
|
|
||||||
mainClassName = 'org.hostsharing.hsadminng.HsadminNgApp'
|
|
||||||
}
|
|
||||||
|
|
||||||
war {
|
|
||||||
webAppDirName = 'build/www/'
|
|
||||||
enabled = true
|
|
||||||
extension = 'war.original'
|
|
||||||
}
|
|
||||||
|
|
||||||
springBoot {
|
|
||||||
mainClassName = 'org.hostsharing.hsadminng.HsadminNgApp'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OperatingSystem.current().isWindows()) {
|
|
||||||
// https://stackoverflow.com/questions/40037487/the-filename-or-extension-is-too-long-error-using-gradle
|
|
||||||
task classpathJar(type: Jar) {
|
|
||||||
dependsOn configurations.runtime
|
|
||||||
appendix = 'classpath'
|
|
||||||
|
|
||||||
doFirst {
|
|
||||||
manifest {
|
|
||||||
attributes 'Class-Path': configurations.runtime.files.collect {
|
|
||||||
it.toURI().toURL().toString().replaceFirst(/file:\/+/, '/').replaceAll(' ', '%20')
|
|
||||||
}.join(' ')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bootRun {
|
|
||||||
dependsOn classpathJar
|
|
||||||
doFirst {
|
|
||||||
classpath = files("$buildDir/classes/java/main", "$buildDir/resources/main", classpathJar.archivePath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test {
|
|
||||||
exclude '**/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
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
apply from: 'gradle/docker.gradle'
|
|
||||||
apply from: 'gradle/sonar.gradle'
|
|
||||||
apply from: 'gradle/swagger.gradle'
|
|
||||||
//jhipster-needle-gradle-apply-from - JHipster will add additional gradle scripts to be applied here
|
|
||||||
|
|
||||||
if (project.hasProperty('prod')) {
|
|
||||||
apply from: 'gradle/profile_prod.gradle'
|
|
||||||
} else {
|
|
||||||
apply from: 'gradle/profile_dev.gradle'
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!project.hasProperty('runList')) {
|
|
||||||
project.ext.runList = 'main'
|
|
||||||
}
|
|
||||||
|
|
||||||
project.ext.diffChangelogFile = 'src/main/resources/config/liquibase/changelog/' + new Date().format('yyyyMMddHHmmss') + '_changelog.xml'
|
|
||||||
|
|
||||||
liquibase {
|
|
||||||
activities {
|
|
||||||
main {
|
|
||||||
driver ''
|
|
||||||
url ''
|
|
||||||
username 'hsadminNg'
|
|
||||||
password ''
|
|
||||||
changeLogFile 'src/main/resources/config/liquibase/master.xml'
|
|
||||||
defaultSchemaName ''
|
|
||||||
logLevel 'debug'
|
|
||||||
classpath 'src/main/resources/'
|
|
||||||
if (project.hasProperty('sample-data')) {
|
|
||||||
contexts 'sample-data'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
diffLog {
|
|
||||||
driver ''
|
|
||||||
url ''
|
|
||||||
username 'hsadminNg'
|
|
||||||
password ''
|
|
||||||
changeLogFile project.ext.diffChangelogFile
|
|
||||||
referenceUrl 'hibernate:spring:org.hostsharing.hsadminng.domain?dialect=&hibernate.physical_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy&hibernate.implicit_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy'
|
|
||||||
defaultSchemaName ''
|
|
||||||
logLevel 'debug'
|
|
||||||
classpath "$buildDir/classes/java/main"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
runList = project.ext.runList
|
|
||||||
}
|
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
providedRuntime
|
compileOnly {
|
||||||
compile.exclude module: "spring-boot-starter-tomcat"
|
extendsFrom annotationProcessor
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenLocal()
|
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
jcenter()
|
|
||||||
//jhipster-needle-gradle-repositories - JHipster will add additional repositories
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ext {
|
||||||
|
set('testcontainersVersion', "1.17.3")
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrapper
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// Use ", version: jhipster_dependencies_version, changing: true" if you want
|
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||||
// to use a SNAPSHOT release instead of a stable release
|
implementation 'org.springframework.boot:spring-boot-starter-data-rest'
|
||||||
compile group: "io.github.jhipster", name: "jhipster-framework"
|
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
|
||||||
compile "org.springframework.boot:spring-boot-starter-cache"
|
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||||
compile "io.dropwizard.metrics:metrics-core"
|
implementation 'org.springdoc:springdoc-openapi-ui:1.6.9'
|
||||||
compile 'io.micrometer:micrometer-registry-prometheus'
|
implementation 'org.liquibase:liquibase-core'
|
||||||
compile "net.logstash.logback:logstash-logback-encoder"
|
implementation 'com.vladmihalcea:hibernate-types-55:2.17.1'
|
||||||
compile "com.fasterxml.jackson.datatype:jackson-datatype-hppc"
|
|
||||||
compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310"
|
compileOnly 'org.projectlombok:lombok'
|
||||||
compile "com.fasterxml.jackson.datatype:jackson-datatype-hibernate5"
|
|
||||||
compile "com.fasterxml.jackson.core:jackson-annotations"
|
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
||||||
compile "com.fasterxml.jackson.core:jackson-databind"
|
|
||||||
compile "com.fasterxml.jackson.module:jackson-module-afterburner"
|
runtimeOnly 'org.postgresql:postgresql'
|
||||||
compile "javax.cache:cache-api"
|
|
||||||
compile "org.hibernate:hibernate-core"
|
annotationProcessor 'org.projectlombok:lombok'
|
||||||
compile "com.zaxxer:HikariCP"
|
|
||||||
compile "org.apache.commons:commons-lang3"
|
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||||
compile "commons-io:commons-io"
|
testImplementation 'org.testcontainers:testcontainers'
|
||||||
compile "javax.transaction:javax.transaction-api"
|
testImplementation 'org.testcontainers:junit-jupiter'
|
||||||
compile "org.ehcache:ehcache"
|
testImplementation 'org.testcontainers:postgresql'
|
||||||
compile "org.hibernate:hibernate-entitymanager"
|
testImplementation 'com.tngtech.archunit:archunit-junit5:1.0.0-rc1'
|
||||||
compile "org.hibernate:hibernate-envers"
|
|
||||||
compile "org.hibernate.validator:hibernate-validator"
|
|
||||||
compile "org.liquibase:liquibase-core"
|
|
||||||
compile "com.mattbertolini:liquibase-slf4j"
|
|
||||||
liquibaseRuntime "org.liquibase:liquibase-core"
|
|
||||||
liquibaseRuntime "org.liquibase.ext:liquibase-hibernate5:${liquibase_hibernate5_version}"
|
|
||||||
liquibaseRuntime sourceSets.main.compileClasspath
|
|
||||||
compile "org.springframework.boot:spring-boot-loader-tools"
|
|
||||||
compile "org.springframework.boot:spring-boot-starter-mail"
|
|
||||||
compile "org.springframework.boot:spring-boot-starter-logging"
|
|
||||||
compile "org.springframework.boot:spring-boot-starter-actuator"
|
|
||||||
compile "org.springframework.boot:spring-boot-starter-aop"
|
|
||||||
compile "org.springframework.boot:spring-boot-starter-data-jpa"
|
|
||||||
compile "org.springframework.boot:spring-boot-starter-security"
|
|
||||||
compile ("org.springframework.boot:spring-boot-starter-web") {
|
|
||||||
exclude module: 'spring-boot-starter-tomcat'
|
|
||||||
}
|
|
||||||
compile "org.springframework.boot:spring-boot-starter-undertow"
|
|
||||||
compile "org.springframework.boot:spring-boot-starter-thymeleaf"
|
|
||||||
compile "org.zalando:problem-spring-web:0.24.0-RC.0"
|
|
||||||
compile "org.springframework.boot:spring-boot-starter-cloud-connectors"
|
|
||||||
compile "org.springframework.security:spring-security-config"
|
|
||||||
compile "org.springframework.security:spring-security-data"
|
|
||||||
compile "org.springframework.security:spring-security-web"
|
|
||||||
compile "io.jsonwebtoken:jjwt-api"
|
|
||||||
runtime "io.jsonwebtoken:jjwt-impl"
|
|
||||||
runtime "io.jsonwebtoken:jjwt-jackson"
|
|
||||||
compile ("io.springfox:springfox-swagger2") {
|
|
||||||
exclude module: 'mapstruct'
|
|
||||||
}
|
|
||||||
compile "io.springfox:springfox-bean-validators"
|
|
||||||
compile "org.postgresql:postgresql"
|
|
||||||
liquibaseRuntime "org.postgresql:postgresql"
|
|
||||||
compile "org.mapstruct:mapstruct-jdk8:${mapstruct_version}"
|
|
||||||
annotationProcessor "org.mapstruct:mapstruct-processor:${mapstruct_version}"
|
|
||||||
annotationProcessor "org.hibernate:hibernate-jpamodelgen"
|
|
||||||
annotationProcessor ("org.springframework.boot:spring-boot-configuration-processor") {
|
|
||||||
exclude group: 'com.vaadin.external.google', module: 'android-json'
|
|
||||||
}
|
|
||||||
testCompile "com.jayway.jsonpath:json-path"
|
|
||||||
testCompile "io.cucumber:cucumber-junit"
|
|
||||||
testCompile "io.cucumber:cucumber-spring"
|
|
||||||
testCompile ("org.springframework.boot:spring-boot-starter-test") {
|
|
||||||
exclude group: 'com.vaadin.external.google', module: 'android-json'
|
|
||||||
}
|
|
||||||
testCompile "org.springframework.security:spring-security-test"
|
|
||||||
testCompile "org.springframework.boot:spring-boot-test"
|
|
||||||
testCompile "org.assertj:assertj-core"
|
|
||||||
testCompile "junit:junit"
|
|
||||||
testCompile "org.mockito:mockito-core"
|
|
||||||
testCompile "com.mattbertolini:liquibase-slf4j"
|
|
||||||
testCompile "org.hamcrest:hamcrest-library"
|
|
||||||
testCompile "com.h2database:h2"
|
|
||||||
liquibaseRuntime "com.h2database:h2"
|
|
||||||
//jhipster-needle-gradle-dependency - JHipster will add additional dependencies here
|
|
||||||
}
|
}
|
||||||
|
|
||||||
task cleanResources(type: Delete) {
|
dependencyManagement {
|
||||||
delete 'build/resources'
|
imports {
|
||||||
}
|
mavenBom "org.testcontainers:testcontainers-bom:${testcontainersVersion}"
|
||||||
|
}
|
||||||
wrapper {
|
}
|
||||||
gradleVersion = '4.10.2'
|
|
||||||
}
|
tasks.named('test') {
|
||||||
|
useJUnitPlatform()
|
||||||
task stage(dependsOn: 'bootWar') {
|
}
|
||||||
}
|
|
||||||
|
spotless {
|
||||||
if (project.hasProperty('nodeInstall')) {
|
java {
|
||||||
node {
|
removeUnusedImports()
|
||||||
version = "${node_version}"
|
endWithNewline()
|
||||||
npmVersion = "${npm_version}"
|
toggleOffOn()
|
||||||
yarnVersion = "${yarn_version}"
|
|
||||||
download = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,315 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<profiles version="13">
|
|
||||||
<profile kind="CodeFormatterProfile" name="Eclipse Formatter" version="13">
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="common_lines"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="49"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="82"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="128"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="82"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="82"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="48"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="48"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="48"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="16"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="1"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="48"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="48"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode" value="enabled"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="2147483647"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="82"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="80"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.compiler.source" value="1.8"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.8"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="48"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="48"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="48"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.8"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="0"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="128"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
|
|
||||||
</profile>
|
|
||||||
</profiles>
|
|
@ -1,8 +0,0 @@
|
|||||||
#Organize Import Order
|
|
||||||
6=javax
|
|
||||||
5=java
|
|
||||||
4=org
|
|
||||||
3=com
|
|
||||||
2=
|
|
||||||
1=org.hostsharing
|
|
||||||
0=\#
|
|
@ -1,267 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<profiles version="11">
|
|
||||||
<profile kind="CodeFormatterProfile" name="CleanCode JS-Formatter" version="11">
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.alignment_for_binary_expression" value="16"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.comment.format_header" value="false"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.compact_else_if" value="true"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.align_type_members_on_columns" value="false"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_colon_in_object_initializer" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_new_line_after_comma_in_objlit_initializer" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.wrap_before_binary_operator" value="true"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.indentation.size" value="2"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.alignment_for_assignment" value="0"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.alignment_for_multiple_fields" value="16"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.compiler.compliance" value="1.5"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_new_line_after_opening_brace_in_objlit_initializer" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.blank_lines_after_package" value="1"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.blank_lines_before_method" value="1"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.compiler.problem.assertIdentifier" value="error"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.tabulation.size" value="2"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.comment.format_source_code" value="true"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.indent_statements_compare_to_block" value="true"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.continuation_indentation" value="2"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.blank_lines_after_imports" value="1"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.keep_empty_objlit_initializer_on_one_line" value="false"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.blank_lines_between_import_groups" value="1"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.blank_lines_before_field" value="0"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.compiler.source" value="1.5"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.alignment_for_conditional_expression" value="80"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.comment.format_block_comments" value="true"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.comment.format_html" value="true"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.blank_lines_before_package" value="0"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.brace_position_for_objlit_initializer" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.brace_position_for_block" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.indent_empty_lines" value="false"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.blank_lines_before_member_type" value="1"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.blank_lines_before_imports" value="1"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_colon_in_object_initializer" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.blank_lines_between_type_declarations" value="0"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.indent_statements_compare_to_body" value="true"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_new_line_before_closing_brace_in_objlit_initializer" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.comment.indent_root_tags" value="false"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.comment.format_javadoc_comments" value="true"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.continuation_indentation_for_objlit_initializer" value="1"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.comment.format_line_comments" value="false"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.compiler.codegen.targetPlatform" value="1.5"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.lineSplit" value="180"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.tabulation.char" value="space"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_new_line_after_annotation" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.alignment_for_enum_constants" value="0"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.alignment_for_compact_if" value="16"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.comment.line_length" value="80"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.alignment_for_parameters_in_method_declaration" value="48"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.comment.indent_parameter_description" value="false"/>
|
|
||||||
<setting id="org.eclipse.wst.jsdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
|
|
||||||
</profile>
|
|
||||||
</profiles>
|
|
160
doc/adr/2022-07-18.row-level-security-mechanism.md
Normal file
160
doc/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.
|
64
doc/glossary.md
Normal file
64
doc/glossary.md
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
### hsadminNg Glossary
|
||||||
|
|
||||||
|
This is a collection of terms used in this project, which either might not be generally known or unclear in meaning.
|
||||||
|
If you miss something, please add it with a `TODO` marker.
|
||||||
|
|
||||||
|
#### Blackbox-Test
|
||||||
|
|
||||||
|
A blackbox-test does not know and not consider such internals of an implementation, it just tests externally observable behaviour.
|
||||||
|
|
||||||
|
|
||||||
|
#### Business Object
|
||||||
|
|
||||||
|
Used in the RBAC-system to refer to an object from the business realm.
|
||||||
|
The usual term is *domain object* but in our context, the term *domain* could be too easily confused with a DNS *Internet domain*.
|
||||||
|
|
||||||
|
|
||||||
|
#### Dummy
|
||||||
|
|
||||||
|
A *dummy* is a kind of *Test-Double* which replaces a real dependency which is not really needed in the test case.
|
||||||
|
|
||||||
|
|
||||||
|
#### Fake
|
||||||
|
|
||||||
|
A *fake* is a kind of *Test-Double* without using any library, but rather a manual fake implementation of a dependency.
|
||||||
|
|
||||||
|
|
||||||
|
#### Mock
|
||||||
|
|
||||||
|
A *mock* is a kind of *Test-Double* which can be configured to behaviours as needed by a test-case.
|
||||||
|
|
||||||
|
Often the term "mock" is used in a generic way, because typical mocking libraries like *Mockito* can also be used as dummies or spies and can replace fakes.
|
||||||
|
|
||||||
|
|
||||||
|
#### RBAC
|
||||||
|
|
||||||
|
Abbreviation for *Role Based Access Control*.
|
||||||
|
A system to control access to business objects by defining users, roles, and permissions.
|
||||||
|
See also [The INCITS 359-2012 Standard](https://www.techstreet.com/standards/incits-359-2012?product_id=1837530).
|
||||||
|
|
||||||
|
In our case we are implementing a hierarchical RBAC for a hierarchical and dynamic business object structure.
|
||||||
|
More information can be found in our [RBAC Architecture Document](rbac.md).
|
||||||
|
|
||||||
|
|
||||||
|
#### Tenant
|
||||||
|
|
||||||
|
*Tenant* is one of the standard roles of Hostsharing's RBAC system.
|
||||||
|
It is assigned as a sub-role to those who have rights on sub-objects of a business object.
|
||||||
|
Usually, tenants can only view the contents.
|
||||||
|
|
||||||
|
Generally, tenant roles only apply for the mere existence, id and name of a business object,
|
||||||
|
not for internal details.
|
||||||
|
E.g. a tenant of a customer could be the administrator of a hosting package of that customer.
|
||||||
|
They can view some identifying information of that customer, but not view their billing and banking information.
|
||||||
|
|
||||||
|
|
||||||
|
#### Whitebox-Test
|
||||||
|
|
||||||
|
A whitebox-test knows and considers the internals of an implementation, e.g. it knows which dependencies it needs and can test special, implementation-dependent cases.
|
||||||
|
|
||||||
|
|
||||||
|
#### Test-Double
|
||||||
|
|
||||||
|
A "double" is a general term for something which replaces a real implementation of a dependency of the unit under test.
|
||||||
|
This can be a "dummy", a "fake", a "mock", a "spy" or a "stub".
|
635
doc/rbac.md
Normal file
635
doc/rbac.md
Normal file
@ -0,0 +1,635 @@
|
|||||||
|
## *hsadmin-ng*'s Role-Based-Access-Management (RBAC)
|
||||||
|
|
||||||
|
The requirements of *hsadmin-ng* include table-m row- and column-level-security for read and write access to business-objects.
|
||||||
|
More precisely, any access has to be controlled according to given rules depending on the accessing users, their roles and the accessed business-object.
|
||||||
|
Further, roles and business-objects are hierarchical.
|
||||||
|
|
||||||
|
To avoid misunderstandings, we are using the term "business-object" what's usually called a "domain-object".
|
||||||
|
But as we are in the context of a webhosting infrastructure provider, "domain" would have a double meaning.
|
||||||
|
|
||||||
|
Our implementation is based on Role-Based-Access-Management (RBAC) in conjunction with views and triggers on the business-objects.
|
||||||
|
As far as possible, we are using the same terms as defined in the RBAC standard, for our function names though, we chose more expressive names.
|
||||||
|
|
||||||
|
In RBAC, subjects can be assigned to roles, roles can be hierarchical and eventually have assigned permissions.
|
||||||
|
A permission allows a specific operation (e.g. view or edit) on a specific (business-) object.
|
||||||
|
|
||||||
|
You can find the entity structure as a UML class diagram as follows:
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
' left to right direction
|
||||||
|
top to bottom direction
|
||||||
|
|
||||||
|
' hide the ugly E in a circle left to the entity name
|
||||||
|
hide circle
|
||||||
|
|
||||||
|
' use right-angled line routing
|
||||||
|
skinparam linetype ortho
|
||||||
|
|
||||||
|
package RBAC {
|
||||||
|
|
||||||
|
' forward declarations
|
||||||
|
entity RbacUser
|
||||||
|
|
||||||
|
together {
|
||||||
|
|
||||||
|
entity RbacRole
|
||||||
|
entity RbacPermission
|
||||||
|
|
||||||
|
|
||||||
|
RbacUser -[hidden]> RbacRole
|
||||||
|
RbacRole -[hidden]> RbacUser
|
||||||
|
}
|
||||||
|
|
||||||
|
together {
|
||||||
|
entity RbacGrant
|
||||||
|
enum RbacReferenceType
|
||||||
|
entity RbacReference
|
||||||
|
}
|
||||||
|
RbacReference -[hidden]> RbacReferenceType
|
||||||
|
|
||||||
|
entity RbacGrant {
|
||||||
|
ascendantUuid: uuid(RbackReference)
|
||||||
|
descendantUuid: uuid(RbackReference)
|
||||||
|
auto
|
||||||
|
}
|
||||||
|
RbacGrant o-u-> RbacReference
|
||||||
|
RbacGrant o-u-> RbacReference
|
||||||
|
|
||||||
|
enum RbacReferenceType {
|
||||||
|
RbacUser
|
||||||
|
RbacRole
|
||||||
|
RbacPermission
|
||||||
|
}
|
||||||
|
RbacReferenceType ..> RbacUser
|
||||||
|
RbacReferenceType ..> RbacRole
|
||||||
|
RbacReferenceType ..> RbacPermission
|
||||||
|
|
||||||
|
entity RbacReference {
|
||||||
|
*uuid : uuid <<generated>>
|
||||||
|
--
|
||||||
|
type : RbacReferenceType
|
||||||
|
}
|
||||||
|
RbacReference o--> RbacReferenceType
|
||||||
|
entity RbacUser {
|
||||||
|
*uuid : uuid <<generated>>
|
||||||
|
--
|
||||||
|
name : varchar
|
||||||
|
}
|
||||||
|
RbacUser o-- RbacReference
|
||||||
|
|
||||||
|
entity RbacRole {
|
||||||
|
*uuid : uuid(RbacReference)
|
||||||
|
--
|
||||||
|
name : varchar
|
||||||
|
}
|
||||||
|
RbacRole o-- RbacReference
|
||||||
|
|
||||||
|
together {
|
||||||
|
enum RbacOperation
|
||||||
|
entity RbacObject
|
||||||
|
}
|
||||||
|
|
||||||
|
entity RbacPermission {
|
||||||
|
*uuid : uuid(RbacReference)
|
||||||
|
--
|
||||||
|
objectUuid: RbacObject
|
||||||
|
op: RbacOperation
|
||||||
|
}
|
||||||
|
RbacPermission o-- RbacReference
|
||||||
|
RbacPermission o-- RbacOperation
|
||||||
|
RbacPermission *-- RbacObject
|
||||||
|
|
||||||
|
enum RbacOperation {
|
||||||
|
add-package
|
||||||
|
add-domain
|
||||||
|
add-unixuser
|
||||||
|
...
|
||||||
|
view
|
||||||
|
edit
|
||||||
|
delete
|
||||||
|
}
|
||||||
|
|
||||||
|
entity RbacObject {
|
||||||
|
*uuid : uuid <<generated>>
|
||||||
|
--
|
||||||
|
objectTable: varchar
|
||||||
|
}
|
||||||
|
RbacObject o- "Business Objects"
|
||||||
|
}
|
||||||
|
|
||||||
|
package "Business Objects" {
|
||||||
|
|
||||||
|
entity package
|
||||||
|
package *--u- RbacObject
|
||||||
|
|
||||||
|
entity customer
|
||||||
|
customer *--u- RbacObject
|
||||||
|
|
||||||
|
entity "..." as moreBusinessObjects
|
||||||
|
moreBusinessObjects *-u- RbacObject
|
||||||
|
}
|
||||||
|
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
|
### The RBAC Entity Types
|
||||||
|
|
||||||
|
#### RbacReference
|
||||||
|
|
||||||
|
An *RbacReference* is a generalization of all entity types which participate in the hierarchical role system, defined via *RbacGrant*.
|
||||||
|
|
||||||
|
The primary key of the *RbacReference* and its referred object is always identical.
|
||||||
|
|
||||||
|
#### RbacReferenceType
|
||||||
|
|
||||||
|
The enum *RbacReferenceType* describes the type of reference.
|
||||||
|
It's only needed to make it easier to find the referred object in *RbacUser*, *RbacRole* or *RbacPermission*.
|
||||||
|
|
||||||
|
#### RbacUser
|
||||||
|
|
||||||
|
An *RbacUser* is a type of RBAC-subject which references a login account outside this system, identified by a name (usually an email-address).
|
||||||
|
|
||||||
|
*RbacUser*s can be assigned to multiple *RbacRole*s, through which they can get permissions to *RbacObject*s.
|
||||||
|
|
||||||
|
The primary key of the *RbacUser* is identical to its related *RbacReference*.
|
||||||
|
|
||||||
|
#### RbacRole
|
||||||
|
|
||||||
|
An *RbacRole* represents a collection of directly or indirectly assigned *RbacPermission*s.
|
||||||
|
Each *RbacRole* can be assigned to *RbacUser*s or to another *RbacRole*.
|
||||||
|
|
||||||
|
Both kinds of assignments are represented via *RbacGrant*.
|
||||||
|
|
||||||
|
*RbacRole* entities can *RbacObject*s, or more precise
|
||||||
|
|
||||||
|
#### RbacPermission
|
||||||
|
|
||||||
|
An *RbacPermission* allows a specific *RbacOperation* on a specific *RbacObject*.
|
||||||
|
|
||||||
|
#### RbacOperation
|
||||||
|
|
||||||
|
An *RbacOperation* determines, <u>what</u> an *RbacPermission* allows to do.
|
||||||
|
It can be one of:
|
||||||
|
|
||||||
|
- **'add-...'** - permits creating new instances of specific entity types underneath the object specified by the permission, e.g. "add-package"
|
||||||
|
- **'view'** - permits reading the contents of the object specified by the permission
|
||||||
|
- **'edit'** - change the contents of the object specified by the permission
|
||||||
|
- **'delete'** - delete the object specified by the permission
|
||||||
|
- **'\*'**
|
||||||
|
|
||||||
|
This list is extensible according to the needs of the access rule system.
|
||||||
|
|
||||||
|
Please notice, that there is no **create** operation to create new instances of unrelated business-object-types.
|
||||||
|
For such a singleton business-object-type, e.g. *Organization" or "Hostsharing" has to be defined, and its single entity is referred in the permission.
|
||||||
|
Only with this rule, the foreign key in *RbacPermission* can be defined as `NOT NULL`.
|
||||||
|
|
||||||
|
#### RbacGrant
|
||||||
|
|
||||||
|
The *RbacGrant* entities represent the access-rights structure from *RbacUser*s via hierarchical *RbacRoles* down to *RbacPermission*s.
|
||||||
|
|
||||||
|
The core SQL queries to determine access rights are all recursive queries on the *RbacGrant* table.
|
||||||
|
|
||||||
|
### Role naming
|
||||||
|
|
||||||
|
The naming pattern of a role is important to be able to address specific roles.
|
||||||
|
E.g. if a new package is added, the admin-role of the related customer has to be addressed.
|
||||||
|
|
||||||
|
There can be global roles like 'administrators'.
|
||||||
|
Most roles, though, are specific for certain business-objects and automatically generated as such:
|
||||||
|
|
||||||
|
business-object-table#business-object-name.relative-role
|
||||||
|
|
||||||
|
|
||||||
|
Where *business-object-table* is the name of the SQL table of the business object (e.g *customer* or 'package'),
|
||||||
|
*business-object-name* is generated from an immutable business key(e.g. a prefix like 'xyz' or 'xyz00')
|
||||||
|
and the *relative-role*' describes the role relative to the referenced business-object as follows:
|
||||||
|
|
||||||
|
#### owner
|
||||||
|
|
||||||
|
The owner-role is granted to the subject which created the business object.
|
||||||
|
E.g. for a new *customer* it would be granted to 'administrators' and for a new *package* to the 'customer#...admin'.
|
||||||
|
|
||||||
|
Whoever has the owner-role assigned can do everything with the related business-object, including deleting (or deactivating) it.
|
||||||
|
|
||||||
|
In most cases, the permissions to other operations than 'delete' are granted through the 'admin' role.
|
||||||
|
By this, all roles ob sub-objects, which are assigned to the 'admin' role, are also granted to the 'owner'.
|
||||||
|
|
||||||
|
#### admin
|
||||||
|
|
||||||
|
The admin-role is granted to a role of those subjects who manage the business object.
|
||||||
|
E.g. a 'package' is manged by the admin of the customer.
|
||||||
|
|
||||||
|
Whoever has the admin-role assigned, do everything with the related business-object, including deleting (or deactivating) it.
|
||||||
|
|
||||||
|
In most cases, the permissions to the 'view' operation is granted through the 'tenant' role.
|
||||||
|
By this, all roles ob sub-objects, which are assigned to the 'tenent' role, are also granted to the 'admin'.
|
||||||
|
|
||||||
|
|
||||||
|
#### tenant
|
||||||
|
|
||||||
|
The tenant-role is granted to everybody who needs to be able to view the business-object.
|
||||||
|
Usually all owners, admins and tenants of sub-objects get this role granted.
|
||||||
|
|
||||||
|
Some business-objects only have very limited data directly in the main business-object and store more sensitive data in special sub-objects (e.g. 'customer-details') to which tenants of sub-objects of the main-object (e.g. package admins) do not get view permission.
|
||||||
|
|
||||||
|
|
||||||
|
## Example Users, Roles, Permissions and Business-Objects
|
||||||
|
|
||||||
|
The following diagram shows how users, roles and permissions could be granted access to operations on business objects.
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
' left to right direction
|
||||||
|
top to bottom direction
|
||||||
|
|
||||||
|
' hide the ugly E in a circle left to the entity name
|
||||||
|
hide circle
|
||||||
|
|
||||||
|
' use right-angled line routing
|
||||||
|
' skinparam linetype ortho
|
||||||
|
|
||||||
|
package RbacUsers {
|
||||||
|
object UserMike
|
||||||
|
object UserSuse
|
||||||
|
object UserPaul
|
||||||
|
}
|
||||||
|
|
||||||
|
package RbacRoles {
|
||||||
|
object RoleAdministrators
|
||||||
|
object RoleCustXyz_Owner
|
||||||
|
object RoleCustXyz_Admin
|
||||||
|
object RolePackXyz00_Owner
|
||||||
|
}
|
||||||
|
RbacUsers -[hidden]> RbacRoles
|
||||||
|
|
||||||
|
package RbacPermissions {
|
||||||
|
object PermCustXyz_View
|
||||||
|
object PermCustXyz_Edit
|
||||||
|
object PermCustXyz_Delete
|
||||||
|
object PermCustXyz_AddPackage
|
||||||
|
object PermPackXyz00_View
|
||||||
|
object PermPackXyz00_Edit
|
||||||
|
object PermPackXyz00_Delete
|
||||||
|
object PermPackXyz00_AddUser
|
||||||
|
}
|
||||||
|
RbacRoles -[hidden]> RbacPermissions
|
||||||
|
|
||||||
|
package BusinessObjects {
|
||||||
|
object CustXyz
|
||||||
|
object PackXyz00
|
||||||
|
}
|
||||||
|
RbacPermissions -[hidden]> BusinessObjects
|
||||||
|
|
||||||
|
UserMike o---> RoleAdministrators
|
||||||
|
UserSuse o--> RoleCustXyz_Admin
|
||||||
|
UserPaul o--> RolePackXyz00_Owner
|
||||||
|
|
||||||
|
RoleAdministrators o..> RoleCustXyz_Owner
|
||||||
|
RoleCustXyz_Owner o-> RoleCustXyz_Admin
|
||||||
|
RoleCustXyz_Admin o-> RolePackXyz00_Owner
|
||||||
|
|
||||||
|
RoleCustXyz_Owner o--> PermCustXyz_Edit
|
||||||
|
RoleCustXyz_Owner o--> PermCustXyz_Delete
|
||||||
|
RoleCustXyz_Admin o--> PermCustXyz_View
|
||||||
|
RoleCustXyz_Admin o--> PermCustXyz_AddPackage
|
||||||
|
RolePackXyz00_Owner o--> PermPackXyz00_View
|
||||||
|
RolePackXyz00_Owner o--> PermPackXyz00_Edit
|
||||||
|
RolePackXyz00_Owner o--> PermPackXyz00_Delete
|
||||||
|
RolePackXyz00_Owner o--> PermPackXyz00_AddUser
|
||||||
|
|
||||||
|
PermCustXyz_View o--> CustXyz
|
||||||
|
PermCustXyz_Edit o--> CustXyz
|
||||||
|
PermCustXyz_Delete o--> CustXyz
|
||||||
|
PermCustXyz_AddPackage o--> CustXyz
|
||||||
|
PermPackXyz00_View o--> PackXyz00
|
||||||
|
PermPackXyz00_Edit o--> PackXyz00
|
||||||
|
PermPackXyz00_Delete o--> PackXyz00
|
||||||
|
PermPackXyz00_AddUser o--> PackXyz00
|
||||||
|
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Business-Object-Tables, Triggers and Views
|
||||||
|
|
||||||
|
To support the RBAC system, for each business-object-table, some more artifacts are created in the database:
|
||||||
|
|
||||||
|
- a `BEFORE INSERT TRIGGER` which creates the related *RbacObject* instance,
|
||||||
|
- an `AFTER INSERT TRIGGER` which creates the related *RbacRole*s, *RbacPermission*s together with their related *RbacReference*s as well as *RbacGrant*s,
|
||||||
|
- a restricted view (e.g. *customer_rv*) through which restricted users can access the underlying data.
|
||||||
|
|
||||||
|
Not yet implemented, but planned are these actions:
|
||||||
|
|
||||||
|
- an `ON DELETE ... DO INSTEAD` rule to allow `SQL DELETE` if applicable for the business-object-table and the user has 'delete' permission,
|
||||||
|
- an `ON UPDATE ... DO INSTEAD` rule to allow `SQL UPDATE` if the user has 'edit' right,
|
||||||
|
- an `ON INSERT ... DO INSTEAD` rule to allow `SQL INSERT` if the user has 'add-..' right to the parent-business-object.
|
||||||
|
|
||||||
|
The restricted view takes the current user from a session property and applies the hierarchy of its roles all the way down to the permissions related to the respective business-object-table.
|
||||||
|
This way, each user can only view the data they have 'view'-permission for, only create those they have 'add-...'-permission, only update those they have 'edit'- and only delete those they have 'delete'-permission to.
|
||||||
|
|
||||||
|
### Current User
|
||||||
|
|
||||||
|
The current use is taken from the session variable `hsadminng.currentUser` which contains the name of the user as stored in the
|
||||||
|
*RbacUser*s table. Example:
|
||||||
|
|
||||||
|
SET LOCAL hsadminng.currentUser = 'mike@hostsharing.net';
|
||||||
|
|
||||||
|
That user is also used for historicization and audit log, but which is a different topic.
|
||||||
|
|
||||||
|
### Assuming Roles
|
||||||
|
|
||||||
|
If the session variable `hsadminng.assumedRoles` is set to a non-empty value, its content is interpreted as a list of semicolon-separated role names.
|
||||||
|
Example:
|
||||||
|
|
||||||
|
SET LOCAL hsadminng.assumedRoles = 'customer#aab.admin;customer#aac.admin';
|
||||||
|
|
||||||
|
In this case, not the current user but the assumed roles are used as a starting point for any further queries.
|
||||||
|
Roles which are not granted to the current user, directly or indirectly, cannot be assumed.
|
||||||
|
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
A full example is shown here:
|
||||||
|
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
SET SESSION SESSION AUTHORIZATION restricted;
|
||||||
|
SET LOCAL hsadminng.currentUser = 'mike@hostsharing.net';
|
||||||
|
SET LOCAL hsadminng.assumedRoles = 'customer#aab.admin;customer#aac.admin';
|
||||||
|
|
||||||
|
SELECT c.prefix, p.name as "package", ema.localPart || '@' || dom.name as "email-address"
|
||||||
|
FROM emailaddress_rv ema
|
||||||
|
JOIN domain_rv dom ON dom.uuid = ema.domainuuid
|
||||||
|
JOIN unixuser_rv uu ON uu.uuid = dom.unixuseruuid
|
||||||
|
JOIN package_rv p ON p.uuid = uu.packageuuid
|
||||||
|
JOIN customer_rv c ON c.uuid = p.customeruuid;
|
||||||
|
END TRANSACTION;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Roles and Their Assignments for Certain Business Objects
|
||||||
|
|
||||||
|
To give you an overview of the business-object-types for the following role-examples,
|
||||||
|
check this diagram:
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
left to right direction
|
||||||
|
' top to bottom direction
|
||||||
|
|
||||||
|
' hide the ugly E in a circle left to the entity name
|
||||||
|
hide circle
|
||||||
|
|
||||||
|
' use right-angled line routing
|
||||||
|
' skinparam linetype ortho
|
||||||
|
|
||||||
|
entity EMailAddress
|
||||||
|
|
||||||
|
entity Domain
|
||||||
|
Domain o-- "*" EMailAddress
|
||||||
|
|
||||||
|
entity UnixUser
|
||||||
|
UnixUser o-- "*" Domain
|
||||||
|
|
||||||
|
entity Package
|
||||||
|
Package o.. "*" UnixUser
|
||||||
|
|
||||||
|
entity Customer
|
||||||
|
Customer o-- "*" Package
|
||||||
|
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
|
It's mostly an example hierarchy of business-object-types, but resembles a part of Hostsharing's actual hosting infrastructure.
|
||||||
|
|
||||||
|
The following diagrams show which roles are created for each business-object-type
|
||||||
|
and how they relate to roles from other business-object-types.
|
||||||
|
|
||||||
|
### Customer Roles
|
||||||
|
|
||||||
|
The highest level of the business-object-type-hierarchy is the *Customer*.
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
' left to right direction
|
||||||
|
top to bottom direction
|
||||||
|
|
||||||
|
' hide the ugly E in a circle left to the entity name
|
||||||
|
hide circle
|
||||||
|
|
||||||
|
' use right-angled line routing
|
||||||
|
' skinparam linetype ortho
|
||||||
|
|
||||||
|
' needs PlantUML 1.2021.14 as Markdown plugin
|
||||||
|
allow_mixing
|
||||||
|
|
||||||
|
entity "BObj customer#xyz" as boCustXyz
|
||||||
|
|
||||||
|
together {
|
||||||
|
entity "Perm customer#xyz *" as permCustomerXyzAll
|
||||||
|
permCustomerXyzAll --> boCustXyz
|
||||||
|
|
||||||
|
entity "Perm customer#xyz add-package" as permCustomerXyzAddPack
|
||||||
|
permCustomerXyzAddPack --> boCustXyz
|
||||||
|
|
||||||
|
entity "Perm customer#xyz view" as permCustomerXyzView
|
||||||
|
permCustomerXyzView --> boCustXyz
|
||||||
|
}
|
||||||
|
|
||||||
|
entity "Role customer#xyz.tenant" as roleCustXyzTenant
|
||||||
|
roleCustXyzTenant --> permCustomerXyzView
|
||||||
|
|
||||||
|
entity "Role customer#xyz.admin" as roleCustXyzAdmin
|
||||||
|
roleCustXyzAdmin --> roleCustXyzTenant
|
||||||
|
roleCustXyzAdmin --> permCustomerXyzAddPack
|
||||||
|
|
||||||
|
entity "Role customer#xyz.owner" as roleCustXyzOwner
|
||||||
|
roleCustXyzOwner ..> roleCustXyzAdmin
|
||||||
|
roleCustXyzOwner --> permCustomerXyzAll
|
||||||
|
|
||||||
|
actor "Customer XYZ Admin" as actorCustXyzAdmin
|
||||||
|
actorCustXyzAdmin --> roleCustXyzAdmin
|
||||||
|
|
||||||
|
entity "Role administrators" as roleAdmins
|
||||||
|
roleAdmins --> roleCustXyzOwner
|
||||||
|
|
||||||
|
actor "Any Hostmaster" as actorHostmaster
|
||||||
|
actorHostmaster --> roleAdmins
|
||||||
|
|
||||||
|
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
|
As you can see, there something special:
|
||||||
|
From the 'Role customer#xyz.owner' to the 'Role customer#xyz.admin' there is a dashed line, whereas all other lines are solid lines.
|
||||||
|
Solid lines means, that one role is granted to another and followed in all queries to the restricted views.
|
||||||
|
The dashed line means that one role is granted to another but not automatically followed in queries to the restricted views.
|
||||||
|
|
||||||
|
The reason here is that otherwise simply too many objects would be accessible to those with the 'administrators' role and all queries would be slowed down vastly.
|
||||||
|
|
||||||
|
Grants which are not followed are still valid grants for `hsadminng.assumedRoles`.
|
||||||
|
Thus, if you want to access anything below a customer, assume its role first.
|
||||||
|
|
||||||
|
There is actually another speciality in the customer roles:
|
||||||
|
For all others, a user defined by the customer gets the owner role assigned, just for the customer, the owner's role is assigned to the 'administrators' role.
|
||||||
|
|
||||||
|
|
||||||
|
### Package Roles
|
||||||
|
|
||||||
|
One example of the business-object-type-level right below is the *Package*.
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
' left to right direction
|
||||||
|
top to bottom direction
|
||||||
|
|
||||||
|
' hide the ugly E in a circle left to the entity name
|
||||||
|
hide circle
|
||||||
|
|
||||||
|
' use right-angled line routing
|
||||||
|
' skinparam linetype ortho
|
||||||
|
|
||||||
|
' needs PlantUML 1.2021.14 as Markdown plugin
|
||||||
|
allow_mixing
|
||||||
|
|
||||||
|
entity "BObj package#xyz00" as boPacXyz00
|
||||||
|
|
||||||
|
together {
|
||||||
|
entity "Perm package#xyz00 *" as permPackageXyzAll
|
||||||
|
permPackageXyzAll --> boPacXyz00
|
||||||
|
|
||||||
|
entity "Perm package#xyz00 add-unixuser" as permPacXyz00AddUser
|
||||||
|
permPacXyz00AddUser --> boPacXyz00
|
||||||
|
|
||||||
|
entity "Perm package#xyz00 edit" as permPacXyz00Edit
|
||||||
|
permPacXyz00Edit --> boPacXyz00
|
||||||
|
|
||||||
|
entity "Perm package#xyz00 view" as permPacXyz00View
|
||||||
|
permPacXyz00View --> boPacXyz00
|
||||||
|
}
|
||||||
|
|
||||||
|
package {
|
||||||
|
entity "Role customer#xyz.tenant" as roleCustXyzTenant
|
||||||
|
entity "Role customer#xyz.admin" as roleCustXyzAdmin
|
||||||
|
entity "Role customer#xyz.owner" as roleCustXyzOwner
|
||||||
|
}
|
||||||
|
|
||||||
|
package {
|
||||||
|
entity "Role package#xyz00.owner" as rolePacXyz00Owner
|
||||||
|
entity "Role package#xyz00.admin" as rolePacXyz00Admin
|
||||||
|
entity "Role package#xyz00.tenant" as rolePacXyz00Tenant
|
||||||
|
}
|
||||||
|
|
||||||
|
rolePacXyz00Tenant --> permPacXyz00View
|
||||||
|
rolePacXyz00Tenant --> roleCustXyzTenant
|
||||||
|
|
||||||
|
rolePacXyz00Owner --> rolePacXyz00Admin
|
||||||
|
rolePacXyz00Owner --> permPackageXyzAll
|
||||||
|
|
||||||
|
roleCustXyzAdmin --> rolePacXyz00Owner
|
||||||
|
roleCustXyzAdmin --> roleCustXyzTenant
|
||||||
|
|
||||||
|
roleCustXyzOwner ..> roleCustXyzAdmin
|
||||||
|
|
||||||
|
rolePacXyz00Admin --> rolePacXyz00Tenant
|
||||||
|
rolePacXyz00Admin --> permPacXyz00AddUser
|
||||||
|
rolePacXyz00Admin --> permPacXyz00Edit
|
||||||
|
|
||||||
|
actor "Package XYZ00 Admin" as actorPacXyzAdmin
|
||||||
|
actorPacXyzAdmin -l-> rolePacXyz00Admin
|
||||||
|
|
||||||
|
actor "Customer XYZ Admin" as actorCustXyzAdmin
|
||||||
|
actorCustXyzAdmin --> roleCustXyzAdmin
|
||||||
|
|
||||||
|
entity "Role administrators" as roleAdmins
|
||||||
|
roleAdmins --> roleCustXyzOwner
|
||||||
|
|
||||||
|
actor "Any Hostmaster" as actorHostmaster
|
||||||
|
actorHostmaster --> roleAdmins
|
||||||
|
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
|
Initially, the customer's admin role is assigned to the package owner role.
|
||||||
|
They can use the package's admin role to hand over most management functionality to a third party.
|
||||||
|
The 'administrators' can get access through an assumed customer's admin role or directly by assuming the package's owner or admin role.
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
We did not define maximum response time in our requirements,
|
||||||
|
but set a target of 7.000 customers, 15.000 packages, 150.000 Unix users, 100.000 domains and 500.000 email-addresses.
|
||||||
|
|
||||||
|
For such a dataset the response time for typical queries from a UI should be acceptable.
|
||||||
|
Also, when adding data beyond these quantities, increase in response time should be roughly linear or below.
|
||||||
|
For this, we increased the dataset by 14% and then by another 25%, ending up with 10.000 customers, almost 25.000 packages, over 174.000 unix users, over 120.000 domains and almost 750.000 email-addresses.
|
||||||
|
|
||||||
|
The performance test suite comprised 8 SELECT queries issued by an administrator, mostly with two assumed customer owner roles.
|
||||||
|
The tests started with finding a specific customer and ended with listing all accessible email-addresses joined with their domains, unix-users, packages and customers.
|
||||||
|
|
||||||
|
Find the SQL script here: `28-hs-tests.sql`.
|
||||||
|
|
||||||
|
### Two View Query Variants
|
||||||
|
|
||||||
|
We have tested two variants of the query for the restricted view,
|
||||||
|
both utilizing a PostgreSQL function like this:
|
||||||
|
|
||||||
|
FUNCTION queryAccessibleObjectUuidsOfSubjectIds(
|
||||||
|
requiredOp RbacOp,
|
||||||
|
forObjectTable varchar,
|
||||||
|
subjectIds uuid[],
|
||||||
|
maxObjects integer = 16000)
|
||||||
|
RETURNS SETOF uuid
|
||||||
|
|
||||||
|
The function returns all object uuids for which the given subjectIds (user o assumed roles) have a permission or required operation.
|
||||||
|
|
||||||
|
Let's have a look at the two view queries:
|
||||||
|
|
||||||
|
#### Using WHERE ... IN
|
||||||
|
|
||||||
|
CREATE OR REPLACE VIEW customer_rv AS
|
||||||
|
SELECT DISTINCT target.*
|
||||||
|
FROM customer AS target
|
||||||
|
WHERE target.uuid IN (
|
||||||
|
SELECT uuid
|
||||||
|
FROM queryAccessibleObjectUuidsOfSubjectIds(
|
||||||
|
'view', 'customer', currentSubjectIds()));
|
||||||
|
|
||||||
|
This view should be automatically updatable.
|
||||||
|
Where, for updates, we actually have to check for 'edit' instead of 'view' operation, which makes it a bit more complicated.
|
||||||
|
|
||||||
|
With the larger dataset, the test suite initially needed over 7 seconds with this view query.
|
||||||
|
At this point the second variant was tried.
|
||||||
|
|
||||||
|
But after the initial query, the execution time was drastically reduced,
|
||||||
|
even with different query values.
|
||||||
|
Looks like the query optimizer needed some statistics to find the best path.
|
||||||
|
|
||||||
|
#### Using A JOIN
|
||||||
|
|
||||||
|
CREATE OR REPLACE VIEW customer_rv AS
|
||||||
|
SELECT DISTINCT target.*
|
||||||
|
FROM customer AS target
|
||||||
|
JOIN queryAccessibleObjectUuidsOfSubjectIds(
|
||||||
|
'view', 'customer', currentSubjectIds()) AS allowedObjId
|
||||||
|
ON target.uuid = allowedObjId;
|
||||||
|
|
||||||
|
This view cannot is not updatable automatically,
|
||||||
|
but it was quite fast from the beginning.
|
||||||
|
|
||||||
|
### Performance Results
|
||||||
|
|
||||||
|
The following table shows the average between the second and the third repeat of the test-suite:
|
||||||
|
|
||||||
|
| Dataset | using JOIN | using WHERE IN |
|
||||||
|
|----------------:|-----------:|---------------:|
|
||||||
|
| 7000 customers | 670ms | 1040ms |
|
||||||
|
| 10000 customers | 1050ms | 1125ms |
|
||||||
|
| +43% | +57% | +8% |
|
||||||
|
|
||||||
|
The JOIN-variant is still faster, but the growth in execution time exceeded the growth of the dataset.
|
||||||
|
|
||||||
|
The WHERE-IN-variant is about 50% slower on the smaller dataset, but almost keeps its performance on the larger dataset.
|
||||||
|
|
||||||
|
Both variants a viable option, depending on other needs, e.g. updatable views.
|
||||||
|
|
||||||
|
|
||||||
|
|
100
doc/test-concept.md
Normal file
100
doc/test-concept.md
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
## Test-Concept
|
||||||
|
|
||||||
|
<!-- generated TOC begin: -->
|
||||||
|
- [Unit-Tests](#unit-tests)
|
||||||
|
- [REST-Tests](#rest-tests)
|
||||||
|
- [Integration-Tests](#integration-tests)
|
||||||
|
- [Acceptance-Tests](#acceptance-tests)
|
||||||
|
- [Performance-Tests](#performance-tests)
|
||||||
|
- [System-Integration-Tests](#system-integration-tests)
|
||||||
|
<!-- generated TOC end. -->
|
||||||
|
|
||||||
|
### General Issues
|
||||||
|
|
||||||
|
The following test concept uses terms like "double" and "mock" (maybe in inflected form like "mocking" or "mocked"), "whitebox-test" and "blackbox-tests" and "test-fixture".
|
||||||
|
Please look up their definition in the [glossary](glossary.md)
|
||||||
|
|
||||||
|
Where our APIs should be designed in a way that it's possible, using a mocking library like *Mockito* often leads to shorter test code.
|
||||||
|
|
||||||
|
|
||||||
|
### Kinds of Tests
|
||||||
|
|
||||||
|
Depending on the concrete aspects which we want to test, we are using different kinds of tests as described as follows.
|
||||||
|
|
||||||
|
#### Unit-Tests
|
||||||
|
|
||||||
|
In this project a *Unit* for *UnitTests* can be a single method (function), a class or even a group of classes which express a common concept.
|
||||||
|
|
||||||
|
The unit are technically whitebox-tests and count into test-code-coverage.
|
||||||
|
But the whitebox-knowledge should only be used for the text-fixture.
|
||||||
|
|
||||||
|
Unit-Test in this project are implemented with *JUnit Jupiter*, *Mockito* and *AssertJ*.
|
||||||
|
|
||||||
|
Unit-Tests do not use any external systems, not even a database.
|
||||||
|
They just test the unit, not any dependencies or proper integration with dependencies.
|
||||||
|
|
||||||
|
Such tests usually run very fast and should test all branches.
|
||||||
|
|
||||||
|
These Tests are always named `...UnitTest` and can automatically run in the build-process.
|
||||||
|
|
||||||
|
|
||||||
|
#### REST-Tests
|
||||||
|
|
||||||
|
At the level of REST-Controllers, *Spring's* `WebMvcTest`, a special kind of Unit-Test, are utilized.
|
||||||
|
Such tests issue REST-requests through a mocked REST-Layer and therefore use the controllers similar to a real client.
|
||||||
|
Otherwise, the implementation technologies are like those of Unit-Tests.
|
||||||
|
|
||||||
|
Being unit-tests, also REST-tests are whitebox-tests and count into test-code-coverage.
|
||||||
|
|
||||||
|
Like other Unit-Tests, REST-Test do not use any external systems, not even a database.
|
||||||
|
They just test the REST-related parts of the unit, e.g. URL-Mappings, HTTP-Headers and proper JSON encoding of request and response data.
|
||||||
|
Other dependencies and integrations with such are not tested on this level.
|
||||||
|
|
||||||
|
Such tests usually run very fast, but should focus on REST-specific issues, leaving branch-testing to pure Unit-Tests.
|
||||||
|
|
||||||
|
These Tests are always named `...RestTest` and can automatically run in the build-process.
|
||||||
|
|
||||||
|
|
||||||
|
#### Integration-Tests
|
||||||
|
|
||||||
|
Integration-Tests in this context mean integration with support systems like databases or messaging-systems, but not integration with external systems.
|
||||||
|
|
||||||
|
Integration-tests, are blackbox-tests and do <u>not</u> count into test-code-coverage.
|
||||||
|
|
||||||
|
Such tests are implemented with *JUnit Jupiter* through some sort of `@SpringBootTest`, e.g. `DataJpaTest` and usually utilize *Testcontainers* and *Docker* to wrap the supporting system, e.g. the *PostgreSQL* database.
|
||||||
|
*Mockito* can also be used for this kind of tests, to separate multiple integrations.
|
||||||
|
|
||||||
|
Integration-Tests are relatively slow and therefore should focus on the integration.
|
||||||
|
Internal issues should be tested through Unit-Tests.
|
||||||
|
|
||||||
|
These Tests are always named `...IntegrationTest` and can automatically run in the build-process.
|
||||||
|
|
||||||
|
|
||||||
|
#### Acceptance-Tests
|
||||||
|
|
||||||
|
We define Acceptance-Tests as test which describe user-stories, respectively high-level business requirements.
|
||||||
|
Acceptance-Tests run on a fully integrated and deployed system with deployed doubles for external systems.
|
||||||
|
|
||||||
|
Acceptance-tests, are blackbox-tests and do <u>not</u> count into test-code-coverage.
|
||||||
|
|
||||||
|
TODO: Complete the Acceptance-Tests test concept.
|
||||||
|
|
||||||
|
|
||||||
|
#### Performance-Tests
|
||||||
|
|
||||||
|
Performance-critical scenarios have to be identified and a special performance-test has to be implemented.
|
||||||
|
|
||||||
|
The implementation-technologie depends on the scenario.
|
||||||
|
|
||||||
|
Performance-tests, are blackbox-tests and do <u>not</u> count into test-code-coverage.
|
||||||
|
|
||||||
|
Such tests usually are very slow and should not be automatically run in the build-pipeline but manually, after critical areas have been changed.
|
||||||
|
|
||||||
|
|
||||||
|
#### System-Integration-Tests
|
||||||
|
|
||||||
|
We define System-Integration-Tests as test in which this system is deployed in a production-like environment to test integration with external systems.
|
||||||
|
|
||||||
|
System-Integration-tests, are blackbox-tests and do <u>not</u> count into test-code-coverage.
|
||||||
|
|
||||||
|
TODO: Complete the System-Integration-Tests test concept.
|
@ -1,53 +0,0 @@
|
|||||||
rootProject.name=hsadmin-ng
|
|
||||||
profile=dev
|
|
||||||
|
|
||||||
# Build properties
|
|
||||||
node_version=10.15.3
|
|
||||||
npm_version=6.4.1
|
|
||||||
yarn_version=1.13.0
|
|
||||||
|
|
||||||
# Dependency versions
|
|
||||||
jhipster_dependencies_version=2.1.1
|
|
||||||
# The spring-boot version should match the one managed by
|
|
||||||
# https://mvnrepository.com/artifact/io.github.jhipster/jhipster-dependencies/${jhipster_dependencies_version}
|
|
||||||
spring_boot_version=2.0.8.RELEASE
|
|
||||||
# The hibernate version should match the one managed by
|
|
||||||
# https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-dependencies/${spring-boot.version} -->
|
|
||||||
hibernate_version=5.2.17.Final
|
|
||||||
mapstruct_version=1.2.0.Final
|
|
||||||
|
|
||||||
liquibase_hibernate5_version=3.6
|
|
||||||
liquibaseTaskPrefix=liquibase
|
|
||||||
|
|
||||||
# jhipster-needle-gradle-property - JHipster will add additional properties here
|
|
||||||
|
|
||||||
## below are some of the gradle performance improvement settings that can be used as required, these are not enabled by default
|
|
||||||
|
|
||||||
## The Gradle daemon aims to improve the startup and execution time of Gradle.
|
|
||||||
## The daemon is enabled by default in Gradle 3+ setting this to false will disable this.
|
|
||||||
## TODO: disable daemon on CI, since builds should be clean and reliable on servers
|
|
||||||
## https://docs.gradle.org/current/userguide/gradle_daemon.html#sec:ways_to_disable_gradle_daemon
|
|
||||||
## un comment the below line to disable the daemon
|
|
||||||
|
|
||||||
#org.gradle.daemon=false
|
|
||||||
|
|
||||||
## Specifies the JVM arguments used for the daemon process.
|
|
||||||
## The setting is particularly useful for tweaking memory settings.
|
|
||||||
## Default value: -Xmx1024m -XX:MaxPermSize=256m
|
|
||||||
## un comment the below line to override the daemon defaults
|
|
||||||
|
|
||||||
#org.gradle.jvmargs=-Xmx1024m -XX:MaxPermSize=256m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
|
||||||
|
|
||||||
## When configured, Gradle will run in incubating parallel mode.
|
|
||||||
## This option should only be used with decoupled projects. More details, visit
|
|
||||||
## http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
|
||||||
## un comment the below line to enable parallel mode
|
|
||||||
|
|
||||||
#org.gradle.parallel=true
|
|
||||||
|
|
||||||
## Enables new incubating mode that makes Gradle selective when configuring projects.
|
|
||||||
## Only relevant projects are configured which results in faster builds for large multi-projects.
|
|
||||||
## http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:configuration_on_demand
|
|
||||||
## un comment the below line to enable the selective mode
|
|
||||||
|
|
||||||
#org.gradle.configureondemand=true
|
|
@ -1,35 +0,0 @@
|
|||||||
buildscript {
|
|
||||||
repositories {
|
|
||||||
gradlePluginPortal()
|
|
||||||
}
|
|
||||||
dependencies {
|
|
||||||
classpath "gradle.plugin.com.google.cloud.tools:jib-gradle-plugin:0.9.11"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
apply plugin: com.google.cloud.tools.jib.gradle.JibPlugin
|
|
||||||
|
|
||||||
jib {
|
|
||||||
from {
|
|
||||||
image = 'openjdk:8-jre-alpine'
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
image = 'hsadminng:latest'
|
|
||||||
}
|
|
||||||
container {
|
|
||||||
entrypoint = ['sh', '-c', 'chmod +x /entrypoint.sh && sync && /entrypoint.sh']
|
|
||||||
ports = ['8080']
|
|
||||||
environment = [
|
|
||||||
SPRING_OUTPUT_ANSI_ENABLED: 'ALWAYS',
|
|
||||||
JHIPSTER_SLEEP: '0'
|
|
||||||
]
|
|
||||||
useCurrentTimestamp = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task copyWwwIntoStatic (type: Copy) {
|
|
||||||
from 'build/www/'
|
|
||||||
into 'build/resources/main/static'
|
|
||||||
}
|
|
||||||
|
|
||||||
jibDockerBuild.dependsOn copyWwwIntoStatic
|
|
@ -1,72 +0,0 @@
|
|||||||
import org.gradle.internal.os.OperatingSystem
|
|
||||||
|
|
||||||
apply plugin: 'org.springframework.boot'
|
|
||||||
apply plugin: 'com.moowork.node'
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
compile "org.springframework.boot:spring-boot-devtools"
|
|
||||||
compile "com.h2database:h2"
|
|
||||||
}
|
|
||||||
|
|
||||||
def profiles = "";
|
|
||||||
if (project.hasProperty('pgsql')) {
|
|
||||||
profiles += 'pgsql'
|
|
||||||
} else if (project.hasProperty('h2file')) {
|
|
||||||
profiles += 'h2file'
|
|
||||||
} else {
|
|
||||||
profiles += 'h2mem'
|
|
||||||
}
|
|
||||||
if (project.hasProperty('no-liquibase')) {
|
|
||||||
profiles += ',no-liquibase'
|
|
||||||
}
|
|
||||||
if (project.hasProperty('tls')) {
|
|
||||||
profiles += ',tls'
|
|
||||||
}
|
|
||||||
|
|
||||||
println 'activating profiles: ' + profiles
|
|
||||||
|
|
||||||
springBoot {
|
|
||||||
buildInfo {
|
|
||||||
properties {
|
|
||||||
time = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bootRun {
|
|
||||||
args = []
|
|
||||||
}
|
|
||||||
|
|
||||||
task webpackBuildDev(type: NpmTask) {
|
|
||||||
inputs.files(fileTree('src/main/webapp/'))
|
|
||||||
|
|
||||||
def webpackDevFiles = fileTree('webpack//')
|
|
||||||
webpackDevFiles.exclude('webpack.prod.js')
|
|
||||||
inputs.files(webpackDevFiles)
|
|
||||||
|
|
||||||
outputs.files(fileTree("build/www/"))
|
|
||||||
|
|
||||||
dependsOn npmInstall
|
|
||||||
|
|
||||||
args = ["run", "webpack:build"]
|
|
||||||
}
|
|
||||||
|
|
||||||
task copyIntoStatic (type: Copy) {
|
|
||||||
from 'build/www/'
|
|
||||||
into 'build/resources/main/static'
|
|
||||||
}
|
|
||||||
|
|
||||||
processResources {
|
|
||||||
filesMatching('**/application.yml') {
|
|
||||||
filter {
|
|
||||||
it.replace('#project.version#', version)
|
|
||||||
}
|
|
||||||
filter {
|
|
||||||
it.replace('#spring.profiles.active#', profiles)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
processResources.dependsOn webpackBuildDev
|
|
||||||
copyIntoStatic.dependsOn processResources
|
|
||||||
bootJar.dependsOn copyIntoStatic
|
|
@ -1,63 +0,0 @@
|
|||||||
apply plugin: 'org.springframework.boot'
|
|
||||||
apply plugin: 'com.gorylenko.gradle-git-properties'
|
|
||||||
apply plugin: 'com.moowork.node'
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
testCompile "com.h2database:h2"
|
|
||||||
}
|
|
||||||
|
|
||||||
def profiles = 'prod'
|
|
||||||
if (project.hasProperty('no-liquibase')) {
|
|
||||||
profiles += ',no-liquibase'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (project.hasProperty('swagger')) {
|
|
||||||
profiles += ',swagger'
|
|
||||||
}
|
|
||||||
|
|
||||||
springBoot {
|
|
||||||
buildInfo()
|
|
||||||
}
|
|
||||||
|
|
||||||
bootRun {
|
|
||||||
args = []
|
|
||||||
}
|
|
||||||
|
|
||||||
task webpack_test(type: NpmTask, dependsOn: 'npm_install') {
|
|
||||||
args = ["run", "webpack:test"]
|
|
||||||
}
|
|
||||||
|
|
||||||
task webpack(type: NpmTask, dependsOn: 'npm_install') {
|
|
||||||
args = ["run", "webpack:prod"]
|
|
||||||
}
|
|
||||||
|
|
||||||
task copyIntoStatic (type: Copy) {
|
|
||||||
from 'build/www/'
|
|
||||||
into 'build/resources/main/static'
|
|
||||||
}
|
|
||||||
|
|
||||||
processResources {
|
|
||||||
filesMatching('**/application.yml') {
|
|
||||||
filter {
|
|
||||||
it.replace('#project.version#', version)
|
|
||||||
}
|
|
||||||
filter {
|
|
||||||
it.replace('#spring.profiles.active#', profiles)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
generateGitProperties {
|
|
||||||
onlyIf {
|
|
||||||
!source.isEmpty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gitProperties {
|
|
||||||
keys = ['git.branch', 'git.commit.id.abbrev', 'git.commit.id.describe']
|
|
||||||
}
|
|
||||||
|
|
||||||
test.dependsOn webpack_test
|
|
||||||
processResources.dependsOn webpack
|
|
||||||
copyIntoStatic.dependsOn processResources
|
|
||||||
bootJar.dependsOn copyIntoStatic
|
|
@ -1,47 +0,0 @@
|
|||||||
apply plugin: "org.sonarqube"
|
|
||||||
apply plugin: 'jacoco'
|
|
||||||
|
|
||||||
jacoco {
|
|
||||||
toolVersion = '0.8.2'
|
|
||||||
}
|
|
||||||
|
|
||||||
jacocoTestReport {
|
|
||||||
reports {
|
|
||||||
xml.enabled true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sonarqube {
|
|
||||||
properties {
|
|
||||||
property "sonar.host.url", "http://localhost:9001"
|
|
||||||
property "sonar.exclusions", "src/main/webapp/content/**/*.*,src/main/webapp/i18n/*.js, build/www/**/*.*"
|
|
||||||
|
|
||||||
property "sonar.issue.ignore.multicriteria", "S3437,S4502,S4684,UndocumentedApi,BoldAndItalicTagsCheck"
|
|
||||||
|
|
||||||
// Rule https://sonarcloud.io/coding_rules?open=Web%3ABoldAndItalicTagsCheck&rule_key=Web%3ABoldAndItalicTagsCheck is ignored. Even if we agree that using the "i" tag is an awful practice, this is what is recommended by http://fontawesome.io/examples/
|
|
||||||
property "sonar.issue.ignore.multicriteria.BoldAndItalicTagsCheck.resourceKey", ">src/main/webapp/app/**/*.*"
|
|
||||||
property "sonar.issue.ignore.multicriteria.BoldAndItalicTagsCheck.ruleKey", "Web:BoldAndItalicTagsCheck"
|
|
||||||
|
|
||||||
// Rule https://sonarcloud.io/coding_rules?open=squid%3AS3437&rule_key=squid%3AS3437 is ignored, as a JPA-managed field cannot be transient
|
|
||||||
property "sonar.issue.ignore.multicriteria.S3437.resourceKey", "src/main/java/**/*"
|
|
||||||
property "sonar.issue.ignore.multicriteria.S3437.ruleKey", "squid:S3437"
|
|
||||||
|
|
||||||
// Rule https://sonarcloud.io/coding_rules?open=squid%3AUndocumentedApi&rule_key=squid%3AUndocumentedApi is ignored, as we want to follow "clean code" guidelines and classes, methods and arguments names should be self-explanatory
|
|
||||||
property "sonar.issue.ignore.multicriteria.UndocumentedApi.resourceKey", "src/main/java/**/*"
|
|
||||||
property "sonar.issue.ignore.multicriteria.UndocumentedApi.ruleKey", "squid:UndocumentedApi"
|
|
||||||
// Rule https://sonarcloud.io/coding_rules?open=squid%3AS4502&rule_key=squid%3AS4502 is ignored, as for JWT tokens we are not subject to CSRF attack
|
|
||||||
property "sonar.issue.ignore.multicriteria.S4502.resourceKey", "src/main/java/**/*"
|
|
||||||
property "sonar.issue.ignore.multicriteria.S4502.ruleKey", "squid:S4502"
|
|
||||||
|
|
||||||
// Rule https://sonarcloud.io/coding_rules?open=squid%3AS4684&rule_key=squid%3AS4684
|
|
||||||
property "sonar.issue.ignore.multicriteria.S4684.resourceKey", "src/main/java/**/*"
|
|
||||||
property "sonar.issue.ignore.multicriteria.S4684.ruleKey", "squid:S4684"
|
|
||||||
|
|
||||||
property "sonar.jacoco.reportPaths", "${project.buildDir}/jacoco/test.exec"
|
|
||||||
property "sonar.java.codeCoveragePlugin", "jacoco"
|
|
||||||
property "sonar.typescript.lcov.reportPaths", "${project.buildDir}/test-results/lcov.info"
|
|
||||||
property "sonar.junit.reportPaths", "${project.buildDir}/test-results"
|
|
||||||
property "sonar.sources", "${project.projectDir}/src/main/"
|
|
||||||
property "sonar.tests", "${project.projectDir}/src/test/"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* Plugin that provides API-first development using OpenAPI-generator to
|
|
||||||
* generate Spring-MVC endpoint stubs at compile time from an OpenAPI definition file
|
|
||||||
*/
|
|
||||||
apply plugin: 'org.openapi.generator'
|
|
||||||
|
|
||||||
openApiGenerate {
|
|
||||||
generatorName = "spring"
|
|
||||||
inputSpec = "$rootDir/src/main/resources/swagger/api.yml".toString()
|
|
||||||
outputDir = "$buildDir/openapi".toString()
|
|
||||||
apiPackage = "org.hostsharing.hsadminng.web.api"
|
|
||||||
modelPackage = "org.hostsharing.hsadminng.web.api.model"
|
|
||||||
apiFilesConstrainedTo = [""]
|
|
||||||
modelFilesConstrainedTo = [""]
|
|
||||||
supportingFilesConstrainedTo = ["ApiUtil.java"]
|
|
||||||
configOptions = [delegatePattern: "true"]
|
|
||||||
validateSpec = true
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceSets {
|
|
||||||
main {
|
|
||||||
java {
|
|
||||||
srcDir file("${project.buildDir.path}/openapi/src/main/java")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compileJava.dependsOn("openApiGenerate")
|
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
vendored
6
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +0,0 @@
|
|||||||
#Sun Apr 28 06:46:48 CEST 2019
|
|
||||||
distributionBase=GRADLE_USER_HOME
|
|
||||||
distributionPath=wrapper/dists
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
|
||||||
zipStorePath=wrapper/dists
|
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
|
|
@ -1,3 +0,0 @@
|
|||||||
dependencies {
|
|
||||||
compile "org.springframework.cloud:spring-cloud-starter-zipkin"
|
|
||||||
}
|
|
292
gradlew
vendored
292
gradlew
vendored
@ -1,78 +1,129 @@
|
|||||||
#!/usr/bin/env sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright © 2015-2021 the original authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
##
|
#
|
||||||
## Gradle start up script for UN*X
|
# Gradle start up script for POSIX generated by Gradle.
|
||||||
##
|
#
|
||||||
|
# Important for running:
|
||||||
|
#
|
||||||
|
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||||
|
# noncompliant, but you have some other compliant shell such as ksh or
|
||||||
|
# bash, then to run this script, type that shell name before the whole
|
||||||
|
# command line, like:
|
||||||
|
#
|
||||||
|
# ksh Gradle
|
||||||
|
#
|
||||||
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
|
# requires all of these POSIX shell features:
|
||||||
|
# * functions;
|
||||||
|
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||||
|
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||||
|
# * compound commands having a testable exit status, especially «case»;
|
||||||
|
# * various built-in commands including «command», «set», and «ulimit».
|
||||||
|
#
|
||||||
|
# Important for patching:
|
||||||
|
#
|
||||||
|
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||||
|
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||||
|
#
|
||||||
|
# The "traditional" practice of packing multiple parameters into a
|
||||||
|
# space-separated string is a well documented source of bugs and security
|
||||||
|
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||||
|
# options in "$@", and eventually passing that to Java.
|
||||||
|
#
|
||||||
|
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||||
|
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||||
|
# see the in-line comments for details.
|
||||||
|
#
|
||||||
|
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||||
|
# Darwin, MinGW, and NonStop.
|
||||||
|
#
|
||||||
|
# (3) This script is generated from the Groovy template
|
||||||
|
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
|
# within the Gradle project.
|
||||||
|
#
|
||||||
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
# Attempt to set APP_HOME
|
# Attempt to set APP_HOME
|
||||||
|
|
||||||
# Resolve links: $0 may be a link
|
# Resolve links: $0 may be a link
|
||||||
PRG="$0"
|
app_path=$0
|
||||||
# Need this for relative symlinks.
|
|
||||||
while [ -h "$PRG" ] ; do
|
# Need this for daisy-chained symlinks.
|
||||||
ls=`ls -ld "$PRG"`
|
while
|
||||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||||
if expr "$link" : '/.*' > /dev/null; then
|
[ -h "$app_path" ]
|
||||||
PRG="$link"
|
do
|
||||||
else
|
ls=$( ls -ld "$app_path" )
|
||||||
PRG=`dirname "$PRG"`"/$link"
|
link=${ls#*' -> '}
|
||||||
fi
|
case $link in #(
|
||||||
|
/*) app_path=$link ;; #(
|
||||||
|
*) app_path=$APP_HOME$link ;;
|
||||||
|
esac
|
||||||
done
|
done
|
||||||
SAVED="`pwd`"
|
|
||||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||||
APP_HOME="`pwd -P`"
|
|
||||||
cd "$SAVED" >/dev/null
|
|
||||||
|
|
||||||
APP_NAME="Gradle"
|
APP_NAME="Gradle"
|
||||||
APP_BASE_NAME=`basename "$0"`
|
APP_BASE_NAME=${0##*/}
|
||||||
|
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
DEFAULT_JVM_OPTS=""
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD="maximum"
|
MAX_FD=maximum
|
||||||
|
|
||||||
warn () {
|
warn () {
|
||||||
echo "$*"
|
echo "$*"
|
||||||
}
|
} >&2
|
||||||
|
|
||||||
die () {
|
die () {
|
||||||
echo
|
echo
|
||||||
echo "$*"
|
echo "$*"
|
||||||
echo
|
echo
|
||||||
exit 1
|
exit 1
|
||||||
}
|
} >&2
|
||||||
|
|
||||||
# OS specific support (must be 'true' or 'false').
|
# OS specific support (must be 'true' or 'false').
|
||||||
cygwin=false
|
cygwin=false
|
||||||
msys=false
|
msys=false
|
||||||
darwin=false
|
darwin=false
|
||||||
nonstop=false
|
nonstop=false
|
||||||
case "`uname`" in
|
case "$( uname )" in #(
|
||||||
CYGWIN* )
|
CYGWIN* ) cygwin=true ;; #(
|
||||||
cygwin=true
|
Darwin* ) darwin=true ;; #(
|
||||||
;;
|
MSYS* | MINGW* ) msys=true ;; #(
|
||||||
Darwin* )
|
NONSTOP* ) nonstop=true ;;
|
||||||
darwin=true
|
|
||||||
;;
|
|
||||||
MINGW* )
|
|
||||||
msys=true
|
|
||||||
;;
|
|
||||||
NONSTOP* )
|
|
||||||
nonstop=true
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
# Determine the Java command to use to start the JVM.
|
||||||
if [ -n "$JAVA_HOME" ] ; then
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
# IBM's JDK on AIX uses strange locations for the executables
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||||
else
|
else
|
||||||
JAVACMD="$JAVA_HOME/bin/java"
|
JAVACMD=$JAVA_HOME/bin/java
|
||||||
fi
|
fi
|
||||||
if [ ! -x "$JAVACMD" ] ; then
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
@ -81,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
|
|||||||
location of your Java installation."
|
location of your Java installation."
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
JAVACMD="java"
|
JAVACMD=java
|
||||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
@ -89,84 +140,101 @@ location of your Java installation."
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
# Increase the maximum file descriptors if we can.
|
||||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
MAX_FD_LIMIT=`ulimit -H -n`
|
case $MAX_FD in #(
|
||||||
if [ $? -eq 0 ] ; then
|
max*)
|
||||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
MAX_FD="$MAX_FD_LIMIT"
|
warn "Could not query maximum file descriptor limit"
|
||||||
fi
|
esac
|
||||||
ulimit -n $MAX_FD
|
case $MAX_FD in #(
|
||||||
if [ $? -ne 0 ] ; then
|
'' | soft) :;; #(
|
||||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
*)
|
||||||
fi
|
ulimit -n "$MAX_FD" ||
|
||||||
else
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Darwin, add options to specify how the application appears in the dock
|
|
||||||
if $darwin; then
|
|
||||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Cygwin, switch paths to Windows format before running java
|
|
||||||
if $cygwin ; then
|
|
||||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
|
||||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
|
||||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
|
||||||
|
|
||||||
# We build the pattern for arguments to be converted via cygpath
|
|
||||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
|
||||||
SEP=""
|
|
||||||
for dir in $ROOTDIRSRAW ; do
|
|
||||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
|
||||||
SEP="|"
|
|
||||||
done
|
|
||||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
|
||||||
# Add a user-defined pattern to the cygpath arguments
|
|
||||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
|
||||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
|
||||||
fi
|
|
||||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
|
||||||
i=0
|
|
||||||
for arg in "$@" ; do
|
|
||||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
|
||||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
|
||||||
|
|
||||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
|
||||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
|
||||||
else
|
|
||||||
eval `echo args$i`="\"$arg\""
|
|
||||||
fi
|
|
||||||
i=$((i+1))
|
|
||||||
done
|
|
||||||
case $i in
|
|
||||||
(0) set -- ;;
|
|
||||||
(1) set -- "$args0" ;;
|
|
||||||
(2) set -- "$args0" "$args1" ;;
|
|
||||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
|
||||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
|
||||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
|
||||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
|
||||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
|
||||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
|
||||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Escape application args
|
# Collect all arguments for the java command, stacking in reverse order:
|
||||||
save () {
|
# * args from the command line
|
||||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
# * the main class name
|
||||||
echo " "
|
# * -classpath
|
||||||
}
|
# * -D...appname settings
|
||||||
APP_ARGS=$(save "$@")
|
# * --module-path (only if needed)
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||||
|
|
||||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
if "$cygwin" || "$msys" ; then
|
||||||
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
|
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||||
|
|
||||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
|
||||||
cd "$(dirname "$0")"
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
for arg do
|
||||||
|
if
|
||||||
|
case $arg in #(
|
||||||
|
-*) false ;; # don't mess with options #(
|
||||||
|
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||||
|
[ -e "$t" ] ;; #(
|
||||||
|
*) false ;;
|
||||||
|
esac
|
||||||
|
then
|
||||||
|
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||||
|
fi
|
||||||
|
# Roll the args list around exactly as many times as the number of
|
||||||
|
# args, so each arg winds up back in the position where it started, but
|
||||||
|
# possibly modified.
|
||||||
|
#
|
||||||
|
# NB: a `for` loop captures its iteration list before it begins, so
|
||||||
|
# changing the positional parameters here affects neither the number of
|
||||||
|
# iterations, nor the values presented in `arg`.
|
||||||
|
shift # remove old arg
|
||||||
|
set -- "$@" "$arg" # push replacement arg
|
||||||
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command;
|
||||||
|
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||||
|
# shell script including quotes and variable substitutions, so put them in
|
||||||
|
# double quotes to make sure that they get re-expanded; and
|
||||||
|
# * put everything else in single quotes, so that it's not re-expanded.
|
||||||
|
|
||||||
|
set -- \
|
||||||
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
-classpath "$CLASSPATH" \
|
||||||
|
org.gradle.wrapper.GradleWrapperMain \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# Stop when "xargs" is not available.
|
||||||
|
if ! command -v xargs >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "xargs is not available"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use "xargs" to parse quoted args.
|
||||||
|
#
|
||||||
|
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||||
|
#
|
||||||
|
# In Bash we could simply go:
|
||||||
|
#
|
||||||
|
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||||
|
# set -- "${ARGS[@]}" "$@"
|
||||||
|
#
|
||||||
|
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||||
|
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||||
|
# character that might be a shell metacharacter, then use eval to reverse
|
||||||
|
# that process (while maintaining the separation between arguments), and wrap
|
||||||
|
# the whole thing up as a single "set" statement.
|
||||||
|
#
|
||||||
|
# This will of course break if any of these variables contains a newline or
|
||||||
|
# an unmatched quote.
|
||||||
|
#
|
||||||
|
|
||||||
|
eval "set -- $(
|
||||||
|
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||||
|
xargs -n1 |
|
||||||
|
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||||
|
tr '\n' ' '
|
||||||
|
)" '"$@"'
|
||||||
|
|
||||||
exec "$JAVACMD" "$@"
|
exec "$JAVACMD" "$@"
|
||||||
|
55
gradlew.bat
vendored
55
gradlew.bat
vendored
@ -1,4 +1,20 @@
|
|||||||
@if "%DEBUG%" == "" @echo off
|
@rem
|
||||||
|
@rem Copyright 2015 the original author or authors.
|
||||||
|
@rem
|
||||||
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@rem you may not use this file except in compliance with the License.
|
||||||
|
@rem You may obtain a copy of the License at
|
||||||
|
@rem
|
||||||
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@rem
|
||||||
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@rem See the License for the specific language governing permissions and
|
||||||
|
@rem limitations under the License.
|
||||||
|
@rem
|
||||||
|
|
||||||
|
@if "%DEBUG%"=="" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
@rem
|
@rem
|
||||||
@rem Gradle startup script for Windows
|
@rem Gradle startup script for Windows
|
||||||
@ -9,19 +25,22 @@
|
|||||||
if "%OS%"=="Windows_NT" setlocal
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
set DIRNAME=%~dp0
|
||||||
if "%DIRNAME%" == "" set DIRNAME=.
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
set APP_BASE_NAME=%~n0
|
set APP_BASE_NAME=%~n0
|
||||||
set APP_HOME=%DIRNAME%
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
set DEFAULT_JVM_OPTS=
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
@rem Find java.exe
|
@rem Find java.exe
|
||||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
set JAVA_EXE=java.exe
|
set JAVA_EXE=java.exe
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if "%ERRORLEVEL%" == "0" goto init
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
@ -35,7 +54,7 @@ goto fail
|
|||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto init
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
@ -45,38 +64,26 @@ echo location of your Java installation.
|
|||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
:init
|
|
||||||
@rem Get command-line arguments, handling Windows variants
|
|
||||||
|
|
||||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
|
||||||
|
|
||||||
:win9xME_args
|
|
||||||
@rem Slurp the command line arguments.
|
|
||||||
set CMD_LINE_ARGS=
|
|
||||||
set _SKIP=2
|
|
||||||
|
|
||||||
:win9xME_args_slurp
|
|
||||||
if "x%~1" == "x" goto execute
|
|
||||||
|
|
||||||
set CMD_LINE_ARGS=%*
|
|
||||||
|
|
||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute Gradle
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
:end
|
:end
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem End local scope for the variables with windows NT shell
|
||||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||||
|
|
||||||
:fail
|
:fail
|
||||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
rem the _cmd.exe /c_ return code!
|
rem the _cmd.exe /c_ return code!
|
||||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
set EXIT_CODE=%ERRORLEVEL%
|
||||||
exit /b 1
|
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||||
|
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||||
|
exit /b %EXIT_CODE%
|
||||||
|
|
||||||
:mainEnd
|
:mainEnd
|
||||||
if "%OS%"=="Windows_NT" endlocal
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
18180
package-lock.json
generated
18180
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
126
package.json
126
package.json
@ -1,126 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "hsadmin-ng",
|
|
||||||
"version": "0.0.0",
|
|
||||||
"description": "Description for hsadminNg",
|
|
||||||
"private": true,
|
|
||||||
"license": "UNLICENSED",
|
|
||||||
"cacheDirectories": [
|
|
||||||
"node_modules"
|
|
||||||
],
|
|
||||||
"dependencies": {
|
|
||||||
"@angular/common": "7.2.4",
|
|
||||||
"@angular/compiler": "7.2.4",
|
|
||||||
"@angular/core": "7.2.4",
|
|
||||||
"@angular/forms": "7.2.4",
|
|
||||||
"@angular/platform-browser": "7.2.4",
|
|
||||||
"@angular/platform-browser-dynamic": "7.2.4",
|
|
||||||
"@angular/router": "7.2.4",
|
|
||||||
"@fortawesome/angular-fontawesome": "0.3.0",
|
|
||||||
"@fortawesome/fontawesome-svg-core": "1.2.14",
|
|
||||||
"@fortawesome/free-solid-svg-icons": "5.7.1",
|
|
||||||
"@ng-bootstrap/ng-bootstrap": "4.0.2",
|
|
||||||
"@ngx-translate/core": "11.0.1",
|
|
||||||
"@ngx-translate/http-loader": "4.0.0",
|
|
||||||
"bootstrap": "4.2.1",
|
|
||||||
"core-js": "2.6.4",
|
|
||||||
"moment": "2.24.0",
|
|
||||||
"ng-jhipster": "0.9.1",
|
|
||||||
"ngx-cookie": "2.0.1",
|
|
||||||
"ngx-infinite-scroll": "7.0.1",
|
|
||||||
"ngx-webstorage": "2.0.1",
|
|
||||||
"rxjs": "6.4.0",
|
|
||||||
"swagger-ui": "2.2.10",
|
|
||||||
"tslib": "1.9.3",
|
|
||||||
"zone.js": "0.8.29"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@angular/cli": "7.3.1",
|
|
||||||
"@angular/compiler-cli": "7.2.4",
|
|
||||||
"@ngtools/webpack": "7.3.1",
|
|
||||||
"@types/jest": "24.0.0",
|
|
||||||
"@types/node": "10.12.24",
|
|
||||||
"angular-router-loader": "0.8.5",
|
|
||||||
"angular2-template-loader": "0.6.2",
|
|
||||||
"autoprefixer": "9.4.7",
|
|
||||||
"browser-sync": "2.26.3",
|
|
||||||
"browser-sync-webpack-plugin": "2.2.2",
|
|
||||||
"cache-loader": "2.0.1",
|
|
||||||
"codelyzer": "4.5.0",
|
|
||||||
"copy-webpack-plugin": "4.6.0",
|
|
||||||
"css-loader": "2.1.0",
|
|
||||||
"file-loader": "3.0.1",
|
|
||||||
"fork-ts-checker-webpack-plugin": "0.5.2",
|
|
||||||
"friendly-errors-webpack-plugin": "1.7.0",
|
|
||||||
"generator-jhipster": "5.8.2",
|
|
||||||
"html-loader": "0.5.5",
|
|
||||||
"html-webpack-plugin": "3.2.0",
|
|
||||||
"husky": "1.3.1",
|
|
||||||
"jest": "24.1.0",
|
|
||||||
"jest-junit": "6.2.1",
|
|
||||||
"jest-preset-angular": "6.0.2",
|
|
||||||
"jest-sonar-reporter": "2.0.0",
|
|
||||||
"lint-staged": "8.1.3",
|
|
||||||
"merge-jsons-webpack-plugin": "1.0.18",
|
|
||||||
"mini-css-extract-plugin": "0.5.0",
|
|
||||||
"moment-locales-webpack-plugin": "1.0.7",
|
|
||||||
"optimize-css-assets-webpack-plugin": "5.0.1",
|
|
||||||
"prettier": "1.16.4",
|
|
||||||
"reflect-metadata": "0.1.13",
|
|
||||||
"rimraf": "2.6.3",
|
|
||||||
"simple-progress-webpack-plugin": "1.1.2",
|
|
||||||
"style-loader": "0.23.1",
|
|
||||||
"terser-webpack-plugin": "1.2.2",
|
|
||||||
"thread-loader": "2.1.2",
|
|
||||||
"to-string-loader": "1.1.5",
|
|
||||||
"ts-loader": "5.3.3",
|
|
||||||
"tslint": "5.12.1",
|
|
||||||
"tslint-config-prettier": "1.18.0",
|
|
||||||
"tslint-loader": "3.6.0",
|
|
||||||
"typescript": "3.2.4",
|
|
||||||
"postcss-loader": "3.0.0",
|
|
||||||
"webpack": "4.29.3",
|
|
||||||
"webpack-cli": "3.2.3",
|
|
||||||
"webpack-dev-server": "3.1.14",
|
|
||||||
"webpack-merge": "4.2.1",
|
|
||||||
"webpack-notifier": "1.7.0",
|
|
||||||
"webpack-visualizer-plugin": "0.1.11",
|
|
||||||
"workbox-webpack-plugin": "3.6.3",
|
|
||||||
"write-file-webpack-plugin": "4.5.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8.9.0"
|
|
||||||
},
|
|
||||||
"lint-staged": {
|
|
||||||
"{,src/**/}*.{md,json,ts,css,scss}": [
|
|
||||||
"prettier --write",
|
|
||||||
"git add"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"prettier:format": "prettier --write \"{,src/**/}*.{md,json,ts,css,scss}\"",
|
|
||||||
"lint": "tslint --project tsconfig.json -e 'node_modules/**'",
|
|
||||||
"lint:fix": "npm run lint -- --fix",
|
|
||||||
"ngc": "ngc -p tsconfig-aot.json",
|
|
||||||
"cleanup": "rimraf build/{aot,www}",
|
|
||||||
"clean-www": "rimraf build//www/app/{src,build/}",
|
|
||||||
"start": "npm run webpack:dev",
|
|
||||||
"start-tls": "npm run webpack:dev -- --env.tls",
|
|
||||||
"serve": "npm run start",
|
|
||||||
"build": "npm run webpack:prod",
|
|
||||||
"test": "npm run lint && jest --coverage --logHeapUsage -w=2 --config src/test/javascript/jest.conf.js",
|
|
||||||
"test:watch": "npm run test -- --watch",
|
|
||||||
"webpack:dev": "npm run webpack-dev-server -- --config webpack/webpack.dev.js --inline --hot --port=9060 --watch-content-base --env.stats=minimal",
|
|
||||||
"webpack:dev-verbose": "npm run webpack-dev-server -- --config webpack/webpack.dev.js --inline --hot --port=9060 --watch-content-base --profile --progress --env.stats=normal",
|
|
||||||
"webpack:build:main": "npm run webpack -- --config webpack/webpack.dev.js --env.stats=minimal",
|
|
||||||
"webpack:build": "npm run cleanup && npm run webpack:build:main",
|
|
||||||
"webpack:prod:main": "npm run webpack -- --config webpack/webpack.prod.js --profile",
|
|
||||||
"webpack:prod": "npm run cleanup && npm run webpack:prod:main && npm run clean-www",
|
|
||||||
"webpack:test": "npm run test",
|
|
||||||
"webpack-dev-server": "node --max_old_space_size=4096 node_modules/webpack-dev-server/bin/webpack-dev-server.js",
|
|
||||||
"webpack": "node --max_old_space_size=4096 node_modules/webpack/bin/webpack.js"
|
|
||||||
},
|
|
||||||
"jestSonar": {
|
|
||||||
"reportPath": "build/test-results/jest",
|
|
||||||
"reportFile": "TESTS-results-sonar.xml"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
plugins: [
|
|
||||||
require('autoprefixer')
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"*": {
|
|
||||||
"target": "http://localhost:8080",
|
|
||||||
"secure": false,
|
|
||||||
"loglevel": "debug"
|
|
||||||
}
|
|
||||||
}
|
|
134
sql/28-hs-tests.sql
Normal file
134
sql/28-hs-tests.sql
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
ABORT;
|
||||||
|
SET SESSION SESSION AUTHORIZATION DEFAULT;
|
||||||
|
|
||||||
|
-- there are some random ractors in test data generation, thus a range has to be accepted
|
||||||
|
CREATE OR REPLACE PROCEDURE expectBetween(actualCount integer, expectedFrom integer, expectedTo integer)
|
||||||
|
LANGUAGE plpgsql AS $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT actualCount BETWEEN expectedFrom AND expectedTo THEN
|
||||||
|
RAISE EXCEPTION 'count expected to be between % and %, but got %', expectedFrom, expectedTo, actualCount;
|
||||||
|
END IF;
|
||||||
|
END; $$;
|
||||||
|
|
||||||
|
DO LANGUAGE plpgsql $$
|
||||||
|
DECLARE
|
||||||
|
resultCount integer;
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
-- hostmaster accessing a single customer
|
||||||
|
SET SESSION SESSION AUTHORIZATION restricted;
|
||||||
|
SET LOCAL hsadminng.currentUser = 'mike@hostsharing.net';
|
||||||
|
SET LOCAL hsadminng.assumedRoles = '';
|
||||||
|
-- SELECT *
|
||||||
|
SELECT count(*) INTO resultCount
|
||||||
|
from customer_rv c
|
||||||
|
where c.prefix='aab';
|
||||||
|
call expectBetween(resultCount, 1, 1);
|
||||||
|
|
||||||
|
-- hostmaster listing all customers
|
||||||
|
SET SESSION SESSION AUTHORIZATION restricted;
|
||||||
|
SET LOCAL hsadminng.currentUser = 'mike@hostsharing.net';
|
||||||
|
SET LOCAL hsadminng.assumedRoles = '';
|
||||||
|
-- SELECT *
|
||||||
|
SELECT count(*) INTO resultCount
|
||||||
|
FROM customer_rv;
|
||||||
|
call expectBetween(resultCount, 10, 20000);
|
||||||
|
|
||||||
|
-- customer admin listing all their packages
|
||||||
|
SET SESSION SESSION AUTHORIZATION restricted;
|
||||||
|
SET LOCAL hsadminng.currentUser = 'admin@aae.example.com';
|
||||||
|
SET LOCAL hsadminng.assumedRoles = '';
|
||||||
|
-- SELECT *
|
||||||
|
SELECT count(*) INTO resultCount
|
||||||
|
FROM package_rv;
|
||||||
|
call expectBetween(resultCount, 2, 10);
|
||||||
|
|
||||||
|
-- cutomer admin listing all their unix users
|
||||||
|
SET SESSION SESSION AUTHORIZATION restricted;
|
||||||
|
SET LOCAL hsadminng.currentUser = 'admin@aae.example.com';
|
||||||
|
SET LOCAL hsadminng.assumedRoles = '';
|
||||||
|
-- SELECT *
|
||||||
|
SELECT count(*) INTO resultCount
|
||||||
|
FROM unixuser_rv;
|
||||||
|
call expectBetween(resultCount, 20, 50);
|
||||||
|
|
||||||
|
-- hostsharing admin assuming customer role and listing all accessible packages
|
||||||
|
SET SESSION SESSION AUTHORIZATION restricted;
|
||||||
|
SET LOCAL hsadminng.currentUser = 'mike@hostsharing.net';
|
||||||
|
SET LOCAL hsadminng.assumedRoles = 'customer#aaa.admin;customer#aab.admin';
|
||||||
|
-- SELECT *
|
||||||
|
SELECT count(*) INTO resultCount
|
||||||
|
FROM package_rv p;
|
||||||
|
call expectBetween(resultCount, 2, 10);
|
||||||
|
|
||||||
|
-- hostsharing admin assuming two customer admin roles and listing all accessible unixusers
|
||||||
|
SET SESSION SESSION AUTHORIZATION restricted;
|
||||||
|
SET LOCAL hsadminng.currentUser = 'mike@hostsharing.net';
|
||||||
|
SET LOCAL hsadminng.assumedRoles = 'customer#aab.admin;customer#aac.admin';
|
||||||
|
-- SELECT c.prefix, c.reference, uu.*
|
||||||
|
SELECT count(*) INTO resultCount
|
||||||
|
FROM unixuser_rv uu
|
||||||
|
JOIN package_rv p ON p.uuid = uu.packageuuid
|
||||||
|
JOIN customer_rv c ON c.uuid = p.customeruuid;
|
||||||
|
call expectBetween(resultCount, 40, 60);
|
||||||
|
|
||||||
|
-- hostsharing admin assuming two customer admin roles and listing all accessible domains
|
||||||
|
-- ABORT; START TRANSACTION;
|
||||||
|
SET SESSION SESSION AUTHORIZATION restricted;
|
||||||
|
SET LOCAL hsadminng.currentUser = 'mike@hostsharing.net';
|
||||||
|
SET LOCAL hsadminng.assumedRoles = 'customer#aac.admin;customer#aad.admin';
|
||||||
|
-- SELECT p.name, uu.name, dom.name
|
||||||
|
SELECT count(*) INTO resultCount
|
||||||
|
FROM domain_rv dom
|
||||||
|
JOIN unixuser_rv uu ON uu.uuid = dom.unixuseruuid
|
||||||
|
JOIN package_rv p ON p.uuid = uu.packageuuid
|
||||||
|
JOIN customer_rv c ON c.uuid = p.customeruuid;
|
||||||
|
call expectBetween(resultCount, 20, 40);
|
||||||
|
|
||||||
|
-- hostsharing admin assuming two customer admin roles and listing all accessible email addresses
|
||||||
|
-- ABORT; START TRANSACTION;
|
||||||
|
SET SESSION SESSION AUTHORIZATION restricted;
|
||||||
|
SET LOCAL hsadminng.currentUser = 'mike@hostsharing.net';
|
||||||
|
SET LOCAL hsadminng.assumedRoles = 'customer#aae.admin;customer#aaf.admin';
|
||||||
|
-- SELECT c.prefix, p.name as "package", ema.localPart || '@' || dom.name as "email-address"
|
||||||
|
SELECT count(*) INTO resultCount
|
||||||
|
FROM emailaddress_rv ema
|
||||||
|
JOIN domain_rv dom ON dom.uuid = ema.domainuuid
|
||||||
|
JOIN unixuser_rv uu ON uu.uuid = dom.unixuseruuid
|
||||||
|
JOIN package_rv p ON p.uuid = uu.packageuuid
|
||||||
|
JOIN customer_rv c ON c.uuid = p.customeruuid;
|
||||||
|
call expectBetween(resultCount, 100, 300);
|
||||||
|
|
||||||
|
-- ~170ms
|
||||||
|
END; $$;
|
||||||
|
|
||||||
|
/*
|
||||||
|
=== with 7000 customers ===
|
||||||
|
|
||||||
|
1. 7105 vs 801 ms
|
||||||
|
2. 960 vs. 649 ms
|
||||||
|
3. 970 vs. 670 ms
|
||||||
|
|
||||||
|
no count required factor table
|
||||||
|
1 7 000 7 000 1.000 customers
|
||||||
|
2 17 436 15 000 1.162 packages
|
||||||
|
3 174 360 150 000 1.162 unixuser
|
||||||
|
4 105 206 100 000 1.052 domain
|
||||||
|
5 526 030 500 000 1.052 emailaddress
|
||||||
|
|
||||||
|
=== with 10000 customers (+43%) ===
|
||||||
|
|
||||||
|
1. 7491 vs. 1189 ms (-1%)
|
||||||
|
2. 1049 ms (+31%)
|
||||||
|
3. 1028 ms (+53%)
|
||||||
|
in average +9,33%
|
||||||
|
|
||||||
|
no count required factor table
|
||||||
|
1 10 000 7 000 1.429 customers
|
||||||
|
2 24 904 15 000 1.660 packages
|
||||||
|
3 249 040 150 000 1.660 unixuser
|
||||||
|
4 149 946 100 000 1.499 domain
|
||||||
|
5 749 730 500 000 1.499 emailaddress
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
53
sql/examples.sql
Normal file
53
sql/examples.sql
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
-- ========================================================
|
||||||
|
-- First Example Entity with History
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS customer (
|
||||||
|
"id" SERIAL PRIMARY KEY,
|
||||||
|
"reference" int not null unique, -- 10000-99999
|
||||||
|
"prefix" character(3) unique
|
||||||
|
);
|
||||||
|
|
||||||
|
CALL create_historicization('customer');
|
||||||
|
|
||||||
|
|
||||||
|
-- ========================================================
|
||||||
|
-- Second Example Entity with History
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS package_type (
|
||||||
|
"id" serial PRIMARY KEY,
|
||||||
|
"name" character varying(8)
|
||||||
|
);
|
||||||
|
|
||||||
|
CALL create_historicization('package_type');
|
||||||
|
|
||||||
|
-- ========================================================
|
||||||
|
-- Third Example Entity with History
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS package (
|
||||||
|
"id" serial PRIMARY KEY,
|
||||||
|
"name" character varying(5),
|
||||||
|
"customer_id" INTEGER REFERENCES customer(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CALL create_historicization('package');
|
||||||
|
|
||||||
|
|
||||||
|
-- ========================================================
|
||||||
|
-- query historical data
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
ABORT;
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
SET LOCAL hsadminng.currentUser TO 'mih42_customer_aaa';
|
||||||
|
SET LOCAL hsadminng.currentTask TO 'adding customer_aaa';
|
||||||
|
INSERT INTO package (customer_id, name) VALUES (10000, 'aaa00');
|
||||||
|
COMMIT;
|
||||||
|
-- Usage:
|
||||||
|
|
||||||
|
SET hsadminng.timestamp TO '2022-07-12 08:53:27.723315';
|
||||||
|
SET hsadminng.timestamp TO '2022-07-12 11:38:27.723315';
|
||||||
|
SELECT * FROM customer_hv p WHERE prefix = 'aaa';
|
166
sql/historization.sql
Normal file
166
sql/historization.sql
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
|
||||||
|
-- ========================================================
|
||||||
|
-- Historization
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
CREATE TABLE "tx_history" (
|
||||||
|
"tx_id" BIGINT NOT NULL UNIQUE,
|
||||||
|
"tx_timestamp" TIMESTAMP NOT NULL,
|
||||||
|
"user" VARCHAR(64) NOT NULL, -- references postgres user
|
||||||
|
"task" VARCHAR NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TYPE "operation" AS ENUM ('INSERT', 'UPDATE', 'DELETE', 'TRUNCATE');
|
||||||
|
|
||||||
|
-- see https://www.postgresql.org/docs/current/plpgsql-trigger.html
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION historicize()
|
||||||
|
RETURNS trigger
|
||||||
|
LANGUAGE plpgsql STRICT AS $$
|
||||||
|
DECLARE
|
||||||
|
currentUser VARCHAR(64);
|
||||||
|
currentTask varchar;
|
||||||
|
"row" RECORD;
|
||||||
|
"alive" BOOLEAN;
|
||||||
|
"sql" varchar;
|
||||||
|
BEGIN
|
||||||
|
-- determine user_id
|
||||||
|
BEGIN
|
||||||
|
currentUser := current_setting('hsadminng.currentUser');
|
||||||
|
EXCEPTION WHEN OTHERS THEN
|
||||||
|
currentUser := NULL;
|
||||||
|
END;
|
||||||
|
IF (currentUser IS NULL OR currentUser = '') THEN
|
||||||
|
RAISE EXCEPTION 'hsadminng.currentUser must be defined, please use "SET LOCAL ...;"';
|
||||||
|
END IF;
|
||||||
|
RAISE NOTICE 'currentUser: %', currentUser;
|
||||||
|
|
||||||
|
-- determine task
|
||||||
|
currentTask = current_setting('hsadminng.currentTask');
|
||||||
|
IF (currentTask IS NULL OR length(currentTask) < 12) THEN
|
||||||
|
RAISE EXCEPTION 'hsadminng.currentTask (%) must be defined and min 12 characters long, please use "SET LOCAL ...;"', currentTask;
|
||||||
|
END IF;
|
||||||
|
RAISE NOTICE 'currentTask: %', currentTask;
|
||||||
|
|
||||||
|
IF (TG_OP = 'INSERT') OR (TG_OP = 'UPDATE') THEN
|
||||||
|
"row" := NEW;
|
||||||
|
"alive" := TRUE;
|
||||||
|
ELSE -- DELETE or TRUNCATE
|
||||||
|
"row" := OLD;
|
||||||
|
"alive" := FALSE;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
sql := format('INSERT INTO tx_history VALUES (txid_current(), now(), %1L, %2L) ON CONFLICT DO NOTHING', currentUser, currentTask);
|
||||||
|
RAISE NOTICE 'sql: %', sql;
|
||||||
|
EXECUTE sql;
|
||||||
|
sql := format('INSERT INTO %3$I_versions VALUES (DEFAULT, txid_current(), %1$L, %2$L, $1.*)', TG_OP, alive, TG_TABLE_NAME);
|
||||||
|
RAISE NOTICE 'sql: %', sql;
|
||||||
|
EXECUTE sql USING "row";
|
||||||
|
|
||||||
|
RETURN "row";
|
||||||
|
END; $$;
|
||||||
|
|
||||||
|
CREATE OR REPLACE PROCEDURE create_historical_view(baseTable varchar)
|
||||||
|
LANGUAGE plpgsql AS $$
|
||||||
|
DECLARE
|
||||||
|
createTriggerSQL varchar;
|
||||||
|
viewName varchar;
|
||||||
|
versionsTable varchar;
|
||||||
|
createViewSQL varchar;
|
||||||
|
baseCols varchar;
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
viewName = quote_ident(format('%s_hv', baseTable));
|
||||||
|
versionsTable = quote_ident(format('%s_versions', baseTable));
|
||||||
|
baseCols = (SELECT string_agg(quote_ident(column_name), ', ')
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_schema = 'public' AND table_name = baseTable);
|
||||||
|
|
||||||
|
createViewSQL = format(
|
||||||
|
'CREATE OR REPLACE VIEW %1$s AS' ||
|
||||||
|
'(' ||
|
||||||
|
' SELECT %2$s' ||
|
||||||
|
' FROM %3$s' ||
|
||||||
|
' WHERE alive = TRUE' ||
|
||||||
|
' AND version_id IN' ||
|
||||||
|
' (' ||
|
||||||
|
' SELECT max(vt.version_id) AS history_id' ||
|
||||||
|
' FROM %3$s AS vt' ||
|
||||||
|
' JOIN tx_history as txh ON vt.tx_id = txh.tx_id' ||
|
||||||
|
' WHERE txh.tx_timestamp <= current_setting(''hsadminng.timestamp'')::timestamp' ||
|
||||||
|
' GROUP BY id' ||
|
||||||
|
' )' ||
|
||||||
|
')',
|
||||||
|
viewName, baseCols, versionsTable
|
||||||
|
);
|
||||||
|
RAISE NOTICE 'sql: %', createViewSQL;
|
||||||
|
EXECUTE createViewSQL;
|
||||||
|
|
||||||
|
createTriggerSQL = 'CREATE TRIGGER ' || baseTable || '_historicize' ||
|
||||||
|
' AFTER INSERT OR DELETE OR UPDATE ON ' || baseTable ||
|
||||||
|
' FOR EACH ROW EXECUTE PROCEDURE historicize()';
|
||||||
|
RAISE NOTICE 'sql: %', createTriggerSQL;
|
||||||
|
EXECUTE createTriggerSQL;
|
||||||
|
|
||||||
|
END; $$;
|
||||||
|
|
||||||
|
CREATE OR REPLACE PROCEDURE create_historicization(baseTable varchar)
|
||||||
|
LANGUAGE plpgsql AS $$
|
||||||
|
DECLARE
|
||||||
|
createHistTableSql varchar;
|
||||||
|
createTriggerSQL varchar;
|
||||||
|
viewName varchar;
|
||||||
|
versionsTable varchar;
|
||||||
|
createViewSQL varchar;
|
||||||
|
baseCols varchar;
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
-- create the history table
|
||||||
|
createHistTableSql = '' ||
|
||||||
|
'CREATE TABLE ' || baseTable || '_versions (' ||
|
||||||
|
' version_id serial PRIMARY KEY,' ||
|
||||||
|
' tx_id bigint NOT NULL REFERENCES tx_history(tx_id),' ||
|
||||||
|
' trigger_op operation NOT NULL,' ||
|
||||||
|
' alive boolean not null,' ||
|
||||||
|
|
||||||
|
' LIKE ' || baseTable ||
|
||||||
|
' EXCLUDING CONSTRAINTS' ||
|
||||||
|
' EXCLUDING STATISTICS' ||
|
||||||
|
')';
|
||||||
|
RAISE NOTICE 'sql: %', createHistTableSql;
|
||||||
|
EXECUTE createHistTableSql;
|
||||||
|
|
||||||
|
-- create the historical view
|
||||||
|
viewName = quote_ident(format('%s_hv', baseTable));
|
||||||
|
versionsTable = quote_ident(format('%s_versions', baseTable));
|
||||||
|
baseCols = (SELECT string_agg(quote_ident(column_name), ', ')
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_schema = 'public' AND table_name = baseTable);
|
||||||
|
|
||||||
|
createViewSQL = format(
|
||||||
|
'CREATE OR REPLACE VIEW %1$s AS' ||
|
||||||
|
'(' ||
|
||||||
|
' SELECT %2$s' ||
|
||||||
|
' FROM %3$s' ||
|
||||||
|
' WHERE alive = TRUE' ||
|
||||||
|
' AND version_id IN' ||
|
||||||
|
' (' ||
|
||||||
|
' SELECT max(vt.version_id) AS history_id' ||
|
||||||
|
' FROM %3$s AS vt' ||
|
||||||
|
' JOIN tx_history as txh ON vt.tx_id = txh.tx_id' ||
|
||||||
|
' WHERE txh.tx_timestamp <= current_setting(''hsadminng.timestamp'')::timestamp' ||
|
||||||
|
' GROUP BY id' ||
|
||||||
|
' )' ||
|
||||||
|
')',
|
||||||
|
viewName, baseCols, versionsTable
|
||||||
|
);
|
||||||
|
RAISE NOTICE 'sql: %', createViewSQL;
|
||||||
|
EXECUTE createViewSQL;
|
||||||
|
|
||||||
|
createTriggerSQL = 'CREATE TRIGGER ' || baseTable || '_historicize' ||
|
||||||
|
' AFTER INSERT OR DELETE OR UPDATE ON ' || baseTable ||
|
||||||
|
' FOR EACH ROW EXECUTE PROCEDURE historicize()';
|
||||||
|
RAISE NOTICE 'sql: %', createTriggerSQL;
|
||||||
|
EXECUTE createTriggerSQL;
|
||||||
|
|
||||||
|
END; $$;
|
@ -1,105 +0,0 @@
|
|||||||
--
|
|
||||||
-- Historization
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE history (
|
|
||||||
history_id serial PRIMARY KEY,
|
|
||||||
history_transaction bigint NOT NULL UNIQUE,
|
|
||||||
history_timestamp timestamp NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE FUNCTION historicize() RETURNS trigger
|
|
||||||
AS $$
|
|
||||||
BEGIN
|
|
||||||
IF (TG_OP = 'INSERT') OR (TG_OP = 'UPDATE') THEN
|
|
||||||
EXECUTE 'INSERT INTO history VALUES (DEFAULT, txid_current(), now()) ON CONFLICT DO NOTHING';
|
|
||||||
EXECUTE format('INSERT INTO %I_history VALUES (DEFAULT, txid_current(), False, $1.*)', TG_TABLE_NAME) USING NEW;
|
|
||||||
RETURN NEW;
|
|
||||||
ELSE
|
|
||||||
EXECUTE 'INSERT INTO history VALUES (DEFAULT, txid_current(), now()) ON CONFLICT DO NOTHING';
|
|
||||||
EXECUTE format('INSERT INTO %I_history VALUES (DEFAULT, txid_current(), True, $1.*)', TG_TABLE_NAME) USING OLD;
|
|
||||||
RETURN OLD;
|
|
||||||
END IF;
|
|
||||||
END;
|
|
||||||
$$
|
|
||||||
LANGUAGE plpgsql;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Entity with History
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE person (
|
|
||||||
id serial PRIMARY KEY,
|
|
||||||
name character varying(50) NOT NULL UNIQUE,
|
|
||||||
email character varying(50) NOT NULL UNIQUE
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE person_history (
|
|
||||||
history_id serial PRIMARY KEY,
|
|
||||||
history_transaction bigint NOT NULL REFERENCES history(history_transaction),
|
|
||||||
history_tombstone boolean NOT NULL,
|
|
||||||
id integer NOT NULL,
|
|
||||||
name character varying(50) NOT NULL,
|
|
||||||
email character varying(50) NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TRIGGER person_historicize AFTER INSERT OR DELETE OR UPDATE ON person FOR EACH ROW EXECUTE PROCEDURE historicize();
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Sample data
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO person (name, email) VALUES ('michael', 'michael@hierweck.de');
|
|
||||||
INSERT INTO person (name, email) VALUES ('annika', 'annika@hierweck.de');
|
|
||||||
|
|
||||||
UPDATE person SET email='mh@hierweck.de' WHERE name='michael';
|
|
||||||
UPDATE person SET email='ah@hierweck.de' WHERE name='annika';
|
|
||||||
|
|
||||||
DELETE FROM person WHERE name='michael';
|
|
||||||
DELETE FROM person WHERE name='annika';
|
|
||||||
|
|
||||||
INSERT INTO person (name, email) VALUES ('michael', 'michael@hierweck.de');
|
|
||||||
INSERT INTO person (name, email) VALUES ('annika', 'annika@hierweck.de');
|
|
||||||
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO person (name, email) VALUES ('mx', 'mx@hierweck.de');
|
|
||||||
INSERT INTO person (name, email) VALUES ('ax', 'ax@hierweck.de');
|
|
||||||
UPDATE person SET email='mxx@hierweck.de' WHERE name='mx';
|
|
||||||
UPDATE person SET email='axx@hierweck.de' WHERE name='ax';
|
|
||||||
COMMIT;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Approach 1: Function
|
|
||||||
--
|
|
||||||
--
|
|
||||||
-- Usage:
|
|
||||||
--
|
|
||||||
-- SELECT * FROM person_history(12345, 'name');
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION person_history(transaction bigint, VARIADIC groupby text[]) RETURNS TABLE (
|
|
||||||
history_id integer,
|
|
||||||
history_transaction bigint,
|
|
||||||
history_tombstone boolean,
|
|
||||||
id integer,
|
|
||||||
name character varying(50),
|
|
||||||
email character varying(50)
|
|
||||||
)
|
|
||||||
AS $$
|
|
||||||
BEGIN
|
|
||||||
RETURN QUERY EXECUTE format('SELECT * FROM person_history WHERE history_id IN (SELECT max(history_id) AS history_id FROM person_history WHERE history_transaction <= $1 GROUP BY %s)', array_to_string(groupby, ', ')) USING transaction;
|
|
||||||
END;
|
|
||||||
$$
|
|
||||||
LANGUAGE plpgsql;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Approach 2: View
|
|
||||||
--
|
|
||||||
-- Usage:
|
|
||||||
--
|
|
||||||
-- SET history_transaction = 12345;
|
|
||||||
-- SELECT * FROM person_history_view;
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE VIEW person_history_view
|
|
||||||
AS (SELECT * FROM person_history WHERE history_id IN (SELECT max(history_id) AS history_id FROM person_history WHERE history_transaction <= current_setting('history.transaction')::bigint GROUP BY name));
|
|
50
sql/rbac-tests.sql
Normal file
50
sql/rbac-tests.sql
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
-- ========================================================
|
||||||
|
-- Some Tests
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
select isGranted(findRoleId('administrators'), findRoleId('package#aaa00.owner'));
|
||||||
|
select isGranted(findRoleId('package#aaa00.owner'), findRoleId('administrators'));
|
||||||
|
-- call grantRoleToRole(findRoleId('package#aaa00.owner'), findRoleId('administrators'));
|
||||||
|
-- call grantRoleToRole(findRoleId('administrators'), findRoleId('package#aaa00.owner'));
|
||||||
|
|
||||||
|
select count(*)
|
||||||
|
FROM queryAllPermissionsOfSubjectIdForObjectUuids(findRbacUser('sven@hostsharing.net'),
|
||||||
|
ARRAY(select uuid from customer where reference < 1100000));
|
||||||
|
select count(*)
|
||||||
|
FROM queryAllPermissionsOfSubjectId(findRbacUser('sven@hostsharing.net'));
|
||||||
|
select *
|
||||||
|
FROM queryAllPermissionsOfSubjectId(findRbacUser('alex@example.com'));
|
||||||
|
select *
|
||||||
|
FROM queryAllPermissionsOfSubjectId(findRbacUser('rosa@example.com'));
|
||||||
|
|
||||||
|
select *
|
||||||
|
FROM queryAllRbacUsersWithPermissionsFor(findPermissionId('customer',
|
||||||
|
(SELECT uuid FROM RbacObject WHERE objectTable = 'customer' LIMIT 1),
|
||||||
|
'add-package'));
|
||||||
|
select *
|
||||||
|
FROM queryAllRbacUsersWithPermissionsFor(findPermissionId('package',
|
||||||
|
(SELECT uuid FROM RbacObject WHERE objectTable = 'package' LIMIT 1),
|
||||||
|
'delete'));
|
||||||
|
|
||||||
|
DO LANGUAGE plpgsql
|
||||||
|
$$
|
||||||
|
DECLARE
|
||||||
|
userId uuid;
|
||||||
|
result bool;
|
||||||
|
BEGIN
|
||||||
|
userId = findRbacUser('mike@hostsharing.net');
|
||||||
|
result = (SELECT * FROM isPermissionGrantedToSubject(findPermissionId('package', 94928, 'add-package'), userId));
|
||||||
|
IF (result) THEN
|
||||||
|
RAISE EXCEPTION 'expected permission NOT to be granted, but it is';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
result = (SELECT * FROM isPermissionGrantedToSubject(findPermissionId('package', 94928, 'view'), userId));
|
||||||
|
IF (NOT result) THEN
|
||||||
|
RAISE EXCEPTION 'expected permission to be granted, but it is NOT';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
RAISE LOG 'isPermissionGrantedToSubjectId test passed';
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
89
sql/rbac-view-option-experiments.sql
Normal file
89
sql/rbac-view-option-experiments.sql
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
|
||||||
|
-- ========================================================
|
||||||
|
-- Options for SELECT under RBAC rules
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
-- access control via view policy and isPermissionGrantedToSubject - way too slow (33 s 617ms for 1 million rows)
|
||||||
|
SET SESSION AUTHORIZATION DEFAULT;
|
||||||
|
CREATE ROLE admin;
|
||||||
|
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO admin;
|
||||||
|
CREATE ROLE restricted;
|
||||||
|
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO restricted;
|
||||||
|
|
||||||
|
SET SESSION AUTHORIZATION DEFAULT;
|
||||||
|
ALTER TABLE customer DISABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE customer ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE customer FORCE ROW LEVEL SECURITY;
|
||||||
|
DROP POLICY IF EXISTS customer_policy ON customer;
|
||||||
|
CREATE POLICY customer_policy ON customer
|
||||||
|
FOR SELECT
|
||||||
|
TO restricted
|
||||||
|
USING (
|
||||||
|
-- id=1000
|
||||||
|
isPermissionGrantedToSubject(findPermissionId('customer', id, 'view'), currentUserId())
|
||||||
|
);
|
||||||
|
|
||||||
|
SET SESSION AUTHORIZATION restricted;
|
||||||
|
SET hsadminng.currentUser TO 'alex@example.com';
|
||||||
|
SELECT * from customer;
|
||||||
|
|
||||||
|
-- access control via view-rule and isPermissionGrantedToSubject - way too slow (35 s 580 ms for 1 million rows)
|
||||||
|
SET SESSION SESSION AUTHORIZATION DEFAULT;
|
||||||
|
DROP VIEW cust_view;
|
||||||
|
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());
|
||||||
|
SELECT * from cust_view LIMIT 10;
|
||||||
|
|
||||||
|
select queryAllPermissionsOfSubjectId(findRbacUser('mike@hostsharing.net'));
|
||||||
|
|
||||||
|
-- access control via view-rule with join to recursive permissions - really fast (38ms for 1 million rows)
|
||||||
|
SET SESSION SESSION AUTHORIZATION DEFAULT;
|
||||||
|
ALTER TABLE customer ENABLE ROW LEVEL SECURITY;
|
||||||
|
DROP VIEW IF EXISTS cust_view;
|
||||||
|
CREATE OR REPLACE VIEW cust_view AS
|
||||||
|
SELECT *
|
||||||
|
FROM customer;
|
||||||
|
CREATE OR REPLACE RULE "_RETURN" AS
|
||||||
|
ON SELECT TO cust_view
|
||||||
|
DO INSTEAD
|
||||||
|
SELECT c.uuid, c.reference, c.prefix FROM customer AS c
|
||||||
|
JOIN queryAllPermissionsOfSubjectId(currentUserId()) AS p
|
||||||
|
ON p.objectTable='customer' AND p.objectUuid=c.uuid AND p.op in ('*', '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;
|
||||||
|
|
||||||
|
|
||||||
|
-- access control via view with join to recursive permissions - really fast (38ms for 1 million rows)
|
||||||
|
SET SESSION SESSION AUTHORIZATION DEFAULT;
|
||||||
|
ALTER TABLE customer ENABLE ROW LEVEL SECURITY;
|
||||||
|
DROP VIEW IF EXISTS cust_view;
|
||||||
|
CREATE OR REPLACE VIEW cust_view AS
|
||||||
|
SELECT c.uuid, c.reference, c.prefix
|
||||||
|
FROM customer AS c
|
||||||
|
JOIN queryAllPermissionsOfSubjectId(currentUserId()) AS p
|
||||||
|
ON p.objectUuid=c.uuid AND p.op in ('*', 'view');
|
||||||
|
GRANT ALL PRIVILEGES ON cust_view TO restricted;
|
||||||
|
|
||||||
|
SET SESSION SESSION AUTHORIZATION restricted;
|
||||||
|
-- SET hsadminng.currentUser TO 'alex@example.com';
|
||||||
|
SET hsadminng.currentUser TO 'mike@hostsharing.net';
|
||||||
|
-- SET hsadminng.currentUser TO 'aaaaouq@example.com';
|
||||||
|
SELECT * from cust_view where reference=1144150;
|
||||||
|
|
||||||
|
select rr.uuid, rr.type from RbacGrants g
|
||||||
|
join RbacReference RR on g.ascendantUuid = RR.uuid
|
||||||
|
where g.descendantUuid in (
|
||||||
|
select uuid from queryAllPermissionsOfSubjectId(findRbacUser('alex@example.com'))
|
||||||
|
where objectTable='customer' and op in ('*', 'view'));
|
||||||
|
|
||||||
|
call grantRoleToUser(findRoleId('customer#aaa.admin'), findRbacUser('aaaaouq@example.com'));
|
||||||
|
|
||||||
|
select queryAllPermissionsOfSubjectId(findRbacUser('aaaaouq@example.com'));
|
||||||
|
|
2
sql/rbac.sql
Normal file
2
sql/rbac.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
|||||||
# https://docs.docker.com/engine/reference/builder/#dockerignore-file
|
|
||||||
classes/
|
|
||||||
generated-sources/
|
|
||||||
generated-test-sources/
|
|
||||||
h2db/
|
|
||||||
maven-archiver/
|
|
||||||
maven-status/
|
|
||||||
reports/
|
|
||||||
surefire-reports/
|
|
||||||
test-classes/
|
|
||||||
test-results/
|
|
||||||
www/
|
|
||||||
!*.jar
|
|
||||||
!*.war
|
|
@ -1,20 +0,0 @@
|
|||||||
FROM openjdk:8-jre-alpine
|
|
||||||
|
|
||||||
ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS \
|
|
||||||
JHIPSTER_SLEEP=0 \
|
|
||||||
JAVA_OPTS=""
|
|
||||||
|
|
||||||
# Add a jhipster user to run our application so that it doesn't need to run as root
|
|
||||||
RUN adduser -D -s /bin/sh jhipster
|
|
||||||
WORKDIR /home/jhipster
|
|
||||||
|
|
||||||
ADD entrypoint.sh entrypoint.sh
|
|
||||||
RUN chmod 755 entrypoint.sh && chown jhipster:jhipster entrypoint.sh
|
|
||||||
USER jhipster
|
|
||||||
|
|
||||||
ENTRYPOINT ["./entrypoint.sh"]
|
|
||||||
|
|
||||||
EXPOSE 8080
|
|
||||||
|
|
||||||
ADD *.war app.war
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
|||||||
version: '2'
|
|
||||||
services:
|
|
||||||
hsadminng-app:
|
|
||||||
image: hsadminng
|
|
||||||
environment:
|
|
||||||
- _JAVA_OPTIONS=-Xmx512m -Xms256m
|
|
||||||
- SPRING_PROFILES_ACTIVE=prod,swagger
|
|
||||||
- SPRING_DATASOURCE_URL=jdbc:postgresql://hsadminng-postgresql:5432/hsadminNg
|
|
||||||
- JHIPSTER_SLEEP=10 # gives time for the database to boot before the application
|
|
||||||
ports:
|
|
||||||
- 8080:8080
|
|
||||||
hsadminng-postgresql:
|
|
||||||
extends:
|
|
||||||
file: postgresql.yml
|
|
||||||
service: hsadminng-postgresql
|
|
@ -1,4 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
echo "The application will start in ${JHIPSTER_SLEEP}s..." && sleep ${JHIPSTER_SLEEP}
|
|
||||||
exec java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar "${HOME}/app.war" "$@"
|
|
@ -1,15 +0,0 @@
|
|||||||
version: '2'
|
|
||||||
services:
|
|
||||||
jenkins:
|
|
||||||
image: jenkins:latest
|
|
||||||
ports:
|
|
||||||
- 49001:8080
|
|
||||||
- 50000:50000
|
|
||||||
# uncomment for docker in docker
|
|
||||||
#privileged: true
|
|
||||||
#volumes:
|
|
||||||
# enable persistent volume (warning: make sure that the local jenkins_home folder is created)
|
|
||||||
#- ~/volumes/jenkins_home:/var/jenkins_home
|
|
||||||
# mount docker sock and binary for docker in docker (only works on linux)
|
|
||||||
#- /var/run/docker.sock:/var/run/docker.sock
|
|
||||||
#- /usr/bin/docker:/usr/bin/docker
|
|
@ -1,11 +0,0 @@
|
|||||||
version: '2'
|
|
||||||
services:
|
|
||||||
hsadminng-postgresql:
|
|
||||||
image: postgres:10.4
|
|
||||||
# volumes:
|
|
||||||
# - ~/volumes/jhipster/hsadminNg/postgresql/:/var/lib/postgresql/data/
|
|
||||||
environment:
|
|
||||||
- POSTGRES_USER=hsadminNg
|
|
||||||
- POSTGRES_PASSWORD=
|
|
||||||
ports:
|
|
||||||
- 5432:5432
|
|
@ -1,7 +0,0 @@
|
|||||||
version: '2'
|
|
||||||
services:
|
|
||||||
hsadminng-sonar:
|
|
||||||
image: sonarqube:7.1
|
|
||||||
ports:
|
|
||||||
- 9001:9000
|
|
||||||
- 9092:9092
|
|
@ -1,6 +0,0 @@
|
|||||||
version: '2'
|
|
||||||
services:
|
|
||||||
swagger-editor:
|
|
||||||
image: swaggerapi/swagger-editor:latest
|
|
||||||
ports:
|
|
||||||
- 7742:8080
|
|
@ -0,0 +1,13 @@
|
|||||||
|
package net.hostsharing.hsadminng;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class HsadminNgApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(HsadminNgApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
16
src/main/java/net/hostsharing/hsadminng/TestController.java
Normal file
16
src/main/java/net/hostsharing/hsadminng/TestController.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package net.hostsharing.hsadminng;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class TestController {
|
||||||
|
|
||||||
|
@ResponseBody
|
||||||
|
@RequestMapping(value = "/api/ping", method = RequestMethod.GET)
|
||||||
|
public String ping() {
|
||||||
|
return "pong\n";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package net.hostsharing.hsadminng.config;
|
||||||
|
|
||||||
|
import com.vladmihalcea.hibernate.type.array.StringArrayType;
|
||||||
|
import org.hibernate.dialect.PostgreSQL95Dialect;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused") // configured in application.yml
|
||||||
|
public class PostgreSQL95CustomDialect extends PostgreSQL95Dialect {
|
||||||
|
|
||||||
|
public PostgreSQL95CustomDialect() {
|
||||||
|
this.registerHibernateType(2003, StringArrayType.class.getName());
|
||||||
|
this.registerHibernateType(1111, "pg-uuid");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
51
src/main/java/net/hostsharing/hsadminng/context/Context.java
Normal file
51
src/main/java/net/hostsharing/hsadminng/context/Context.java
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package net.hostsharing.hsadminng.context;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
import javax.persistence.PersistenceContext;
|
||||||
|
import javax.transaction.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class Context {
|
||||||
|
|
||||||
|
@PersistenceContext
|
||||||
|
private EntityManager em;
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.MANDATORY)
|
||||||
|
public void setCurrentUser(final String userName) {
|
||||||
|
em.createNativeQuery(
|
||||||
|
String.format(
|
||||||
|
"set local hsadminng.currentUser = '%s';",
|
||||||
|
userName
|
||||||
|
)
|
||||||
|
).executeUpdate();
|
||||||
|
assumeNoSpecialRole();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCurrentUser() {
|
||||||
|
return String.valueOf(em.createNativeQuery("select currentUser()").getSingleResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.MANDATORY)
|
||||||
|
public void assumeRoles(final String roles) {
|
||||||
|
em.createNativeQuery(
|
||||||
|
String.format(
|
||||||
|
"set local hsadminng.assumedRoles = '%s';",
|
||||||
|
roles
|
||||||
|
)
|
||||||
|
).executeUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.MANDATORY)
|
||||||
|
public void assumeNoSpecialRole() {
|
||||||
|
em.createNativeQuery(
|
||||||
|
"set local hsadminng.assumedRoles = '';"
|
||||||
|
).executeUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getAssumedRoles() {
|
||||||
|
return (String[]) em.createNativeQuery("select assumedRoles()").getSingleResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
package net.hostsharing.hsadminng.errors;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.springframework.core.NestedExceptionUtils;
|
||||||
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.orm.jpa.JpaSystemException;
|
||||||
|
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.context.request.WebRequest;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@ControllerAdvice
|
||||||
|
public class RestResponseEntityExceptionHandler
|
||||||
|
extends ResponseEntityExceptionHandler {
|
||||||
|
|
||||||
|
@ExceptionHandler(DataIntegrityViolationException.class)
|
||||||
|
protected ResponseEntity<CustomErrorResponse> handleConflict(
|
||||||
|
final RuntimeException exc, final WebRequest request) {
|
||||||
|
|
||||||
|
return new ResponseEntity<>(
|
||||||
|
new CustomErrorResponse(request.getContextPath(), exc, HttpStatus.CONFLICT), HttpStatus.CONFLICT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(JpaSystemException.class)
|
||||||
|
protected ResponseEntity<CustomErrorResponse> handleJpaExceptions(
|
||||||
|
final RuntimeException exc, final WebRequest request) {
|
||||||
|
|
||||||
|
return new ResponseEntity<>(
|
||||||
|
new CustomErrorResponse(request.getContextPath(), exc, HttpStatus.FORBIDDEN), HttpStatus.FORBIDDEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
class CustomErrorResponse {
|
||||||
|
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd hh:mm:ss")
|
||||||
|
private final LocalDateTime timestamp;
|
||||||
|
|
||||||
|
private final String path;
|
||||||
|
|
||||||
|
private final int status;
|
||||||
|
|
||||||
|
private final String error;
|
||||||
|
|
||||||
|
private final String message;
|
||||||
|
|
||||||
|
public CustomErrorResponse(final String path, final RuntimeException exc, final HttpStatus status) {
|
||||||
|
this.timestamp = LocalDateTime.now();
|
||||||
|
this.path = path;
|
||||||
|
this.status = status.value();
|
||||||
|
this.error = status.getReasonPhrase();
|
||||||
|
this.message = firstLine(NestedExceptionUtils.getMostSpecificCause(exc).getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String firstLine(final String message) {
|
||||||
|
return message.split("\\r|\\n|\\r\\n", 0)[0];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.hscustomer;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.context.Context;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.transaction.Transactional;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
|
||||||
|
public class CustomerController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Context context;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CustomerRepository customerRepository;
|
||||||
|
|
||||||
|
@GetMapping(value = "/api/customers")
|
||||||
|
@Transactional
|
||||||
|
public List<CustomerEntity> listCustomers(
|
||||||
|
@RequestHeader(value = "current-user") String userName,
|
||||||
|
@RequestHeader(value = "assumed-roles", required = false) String assumedRoles,
|
||||||
|
@RequestParam(required = false) String prefix
|
||||||
|
) {
|
||||||
|
context.setCurrentUser(userName);
|
||||||
|
if (assumedRoles != null && !assumedRoles.isBlank()) {
|
||||||
|
context.assumeRoles(assumedRoles);
|
||||||
|
}
|
||||||
|
return customerRepository.findCustomerByOptionalPrefixLike(prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "/api/customers")
|
||||||
|
@Transactional
|
||||||
|
public CustomerEntity addCustomer(
|
||||||
|
@RequestHeader(value = "current-user") String userName,
|
||||||
|
@RequestHeader(value = "assumed-roles", required = false) String assumedRoles,
|
||||||
|
@RequestBody CustomerEntity customer
|
||||||
|
) {
|
||||||
|
context.setCurrentUser(userName);
|
||||||
|
if (assumedRoles != null && !assumedRoles.isBlank()) {
|
||||||
|
context.assumeRoles(assumedRoles);
|
||||||
|
}
|
||||||
|
if (customer.getUuid() == null) {
|
||||||
|
customer.setUuid(UUID.randomUUID());
|
||||||
|
}
|
||||||
|
return customerRepository.save(customer);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.hscustomer;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "customer_rv")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class CustomerEntity {
|
||||||
|
private @Id UUID uuid;
|
||||||
|
private String prefix;
|
||||||
|
private int reference;
|
||||||
|
private @Column(name="adminusername")String adminUserName;
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.hscustomer;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.Repository;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public interface CustomerRepository extends Repository<CustomerEntity, UUID> {
|
||||||
|
|
||||||
|
|
||||||
|
Optional<CustomerEntity> findByUuid(UUID id);
|
||||||
|
|
||||||
|
@Query("SELECT c FROM CustomerEntity c WHERE :prefix is null or c.prefix like concat(:prefix, '%')")
|
||||||
|
List<CustomerEntity> findCustomerByOptionalPrefixLike(@Param("prefix") String prefix);
|
||||||
|
|
||||||
|
CustomerEntity save(final CustomerEntity entity);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.hspackage;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.context.Context;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.transaction.Transactional;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class PackageController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Context context;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PackageRepository packageRepository;
|
||||||
|
|
||||||
|
@RequestMapping(value = "/api/packages", method = RequestMethod.GET)
|
||||||
|
@Transactional
|
||||||
|
public List<PackageEntity> listPackages(
|
||||||
|
@RequestHeader(value = "current-user") String userName,
|
||||||
|
@RequestHeader(value = "assumed-roles", required = false) String assumedRoles,
|
||||||
|
@RequestParam(required = false) String name
|
||||||
|
) {
|
||||||
|
context.setCurrentUser(userName);
|
||||||
|
if (assumedRoles != null && !assumedRoles.isBlank()) {
|
||||||
|
context.assumeRoles(assumedRoles);
|
||||||
|
}
|
||||||
|
return packageRepository.findAllByOptionalNameLike(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.hspackage;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import net.hostsharing.hsadminng.hs.hscustomer.CustomerEntity;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "package_rv")
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class PackageEntity {
|
||||||
|
|
||||||
|
private @Id UUID uuid;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ManyToOne(optional = false)
|
||||||
|
@JoinColumn(name = "customeruuid")
|
||||||
|
private CustomerEntity customer;
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.hspackage;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public interface PackageRepository extends Repository<PackageEntity, UUID> {
|
||||||
|
|
||||||
|
@Query("SELECT p FROM PackageEntity p WHERE :name is null or p.name like concat(:name, '%')")
|
||||||
|
List<PackageEntity> findAllByOptionalNameLike(final String name);
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package net.hostsharing.hsadminng.rbac.rbacrole;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.context.Context;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestHeader;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.transaction.Transactional;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
|
||||||
|
public class RbacRoleController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Context context;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RbacRoleRepository rbacRoleRepository;
|
||||||
|
|
||||||
|
@GetMapping(value = "/api/rbacroles")
|
||||||
|
@Transactional
|
||||||
|
public Iterable<RbacRoleEntity> listCustomers(
|
||||||
|
@RequestHeader(value = "current-user") String userName,
|
||||||
|
@RequestHeader(value = "assumed-roles", required = false) String assumedRoles
|
||||||
|
) {
|
||||||
|
context.setCurrentUser(userName);
|
||||||
|
if (assumedRoles != null && !assumedRoles.isBlank()) {
|
||||||
|
context.assumeRoles(assumedRoles);
|
||||||
|
}
|
||||||
|
return rbacRoleRepository.findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package net.hostsharing.hsadminng.rbac.rbacrole;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
import org.hibernate.annotations.Formula;
|
||||||
|
import org.springframework.data.annotation.Immutable;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "rbacrole_rv")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
@Immutable
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class RbacRoleEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private UUID uuid;
|
||||||
|
|
||||||
|
@Column(name="objectuuid")
|
||||||
|
private UUID objectUuid;
|
||||||
|
|
||||||
|
@Column(name="objecttable")
|
||||||
|
private String objectTable;
|
||||||
|
|
||||||
|
@Column(name="objectidname")
|
||||||
|
private String objectIdName;
|
||||||
|
|
||||||
|
@Column(name="roletype")
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private RbacRoleType roleType;
|
||||||
|
|
||||||
|
@Formula("objectTable||'#'||objectIdName||'.'||roleType")
|
||||||
|
private String roleName;
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package net.hostsharing.hsadminng.rbac.rbacrole;
|
||||||
|
|
||||||
|
import org.springframework.data.repository.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public interface RbacRoleRepository extends Repository<RbacRoleEntity, UUID> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all instances of the type.
|
||||||
|
*
|
||||||
|
* @return all entities
|
||||||
|
*/
|
||||||
|
List<RbacRoleEntity> findAll();
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package net.hostsharing.hsadminng.rbac.rbacrole;
|
||||||
|
|
||||||
|
public enum RbacRoleType {
|
||||||
|
owner, admin, tenant
|
||||||
|
}
|
@ -1,23 +0,0 @@
|
|||||||
// Licensed under Apache-2.0
|
|
||||||
package org.hostsharing.hsadminng;
|
|
||||||
|
|
||||||
import org.hostsharing.hsadminng.config.DefaultProfileUtil;
|
|
||||||
|
|
||||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
|
||||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a helper Java class that provides an alternative to creating a web.xml.
|
|
||||||
* This will be invoked only when the application is deployed to a Servlet container like Tomcat, JBoss etc.
|
|
||||||
*/
|
|
||||||
public class ApplicationWebXml extends SpringBootServletInitializer {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
|
|
||||||
/**
|
|
||||||
* set a default to use when no profile is configured.
|
|
||||||
*/
|
|
||||||
DefaultProfileUtil.addDefaultProfile(application.application());
|
|
||||||
return application.sources(HsadminNgApp.class);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,111 +0,0 @@
|
|||||||
// Licensed under Apache-2.0
|
|
||||||
package org.hostsharing.hsadminng;
|
|
||||||
|
|
||||||
import org.hostsharing.hsadminng.config.ApplicationProperties;
|
|
||||||
import org.hostsharing.hsadminng.config.DefaultProfileUtil;
|
|
||||||
import org.hostsharing.hsadminng.service.accessfilter.Role;
|
|
||||||
|
|
||||||
import io.github.jhipster.config.JHipsterConstants;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.boot.SpringApplication;
|
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
||||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
|
|
||||||
@SpringBootApplication
|
|
||||||
@EnableConfigurationProperties({ LiquibaseProperties.class, ApplicationProperties.class })
|
|
||||||
public class HsadminNgApp {
|
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(HsadminNgApp.class);
|
|
||||||
|
|
||||||
private final Environment env;
|
|
||||||
|
|
||||||
public HsadminNgApp(Environment env) {
|
|
||||||
this.env = env;
|
|
||||||
|
|
||||||
// TODO mhoennig rather use @PostConstruct or something more decentral
|
|
||||||
Role.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes hsadminNg.
|
|
||||||
* <p>
|
|
||||||
* Spring profiles can be configured with a program argument --spring.profiles.active=your-active-profile
|
|
||||||
* <p>
|
|
||||||
* You can find more information on how profiles work with JHipster on
|
|
||||||
* <a href="https://www.jhipster.tech/profiles/">https://www.jhipster.tech/profiles/</a>.
|
|
||||||
*/
|
|
||||||
@PostConstruct
|
|
||||||
public void initApplication() {
|
|
||||||
|
|
||||||
Collection<String> activeProfiles = Arrays.asList(env.getActiveProfiles());
|
|
||||||
if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)
|
|
||||||
&& activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_PRODUCTION)) {
|
|
||||||
log.error(
|
|
||||||
"You have misconfigured your application! It should not run " +
|
|
||||||
"with both the 'dev' and 'prod' profiles at the same time.");
|
|
||||||
}
|
|
||||||
if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)
|
|
||||||
&& activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_CLOUD)) {
|
|
||||||
log.error(
|
|
||||||
"You have misconfigured your application! It should not " +
|
|
||||||
"run with both the 'dev' and 'cloud' profiles at the same time.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main method, used to run the application.
|
|
||||||
*
|
|
||||||
* @param args the command line arguments
|
|
||||||
*/
|
|
||||||
public static void main(String[] args) {
|
|
||||||
SpringApplication app = new SpringApplication(HsadminNgApp.class);
|
|
||||||
DefaultProfileUtil.addDefaultProfile(app);
|
|
||||||
Environment env = app.run(args).getEnvironment();
|
|
||||||
logApplicationStartup(env);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void logApplicationStartup(Environment env) {
|
|
||||||
String protocol = "http";
|
|
||||||
if (env.getProperty("server.ssl.key-store") != null) {
|
|
||||||
protocol = "https";
|
|
||||||
}
|
|
||||||
String serverPort = env.getProperty("server.port");
|
|
||||||
String contextPath = env.getProperty("server.servlet.context-path");
|
|
||||||
if (StringUtils.isBlank(contextPath)) {
|
|
||||||
contextPath = "/";
|
|
||||||
}
|
|
||||||
String hostAddress = "localhost";
|
|
||||||
try {
|
|
||||||
hostAddress = InetAddress.getLocalHost().getHostAddress();
|
|
||||||
} catch (UnknownHostException e) {
|
|
||||||
log.warn("The host name could not be determined, using `localhost` as fallback");
|
|
||||||
}
|
|
||||||
log.info(
|
|
||||||
"\n----------------------------------------------------------\n\t" +
|
|
||||||
"Application '{}' is running! Access URLs:\n\t" +
|
|
||||||
"Local: \t\t{}://localhost:{}{}\n\t" +
|
|
||||||
"External: \t{}://{}:{}{}\n\t" +
|
|
||||||
"Profile(s): \t{}\n----------------------------------------------------------",
|
|
||||||
env.getProperty("spring.application.name"),
|
|
||||||
protocol,
|
|
||||||
serverPort,
|
|
||||||
contextPath,
|
|
||||||
protocol,
|
|
||||||
hostAddress,
|
|
||||||
serverPort,
|
|
||||||
contextPath,
|
|
||||||
env.getActiveProfiles());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,116 +0,0 @@
|
|||||||
// Licensed under Apache-2.0
|
|
||||||
package org.hostsharing.hsadminng.aop.logging;
|
|
||||||
|
|
||||||
import io.github.jhipster.config.JHipsterConstants;
|
|
||||||
|
|
||||||
import org.aspectj.lang.JoinPoint;
|
|
||||||
import org.aspectj.lang.ProceedingJoinPoint;
|
|
||||||
import org.aspectj.lang.annotation.AfterThrowing;
|
|
||||||
import org.aspectj.lang.annotation.Around;
|
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
|
||||||
import org.aspectj.lang.annotation.Pointcut;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Aspect for logging execution of service and repository Spring components.
|
|
||||||
*
|
|
||||||
* By default, it only runs with the "dev" profile.
|
|
||||||
*/
|
|
||||||
@Aspect
|
|
||||||
public class LoggingAspect {
|
|
||||||
|
|
||||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
|
||||||
|
|
||||||
private final Environment env;
|
|
||||||
|
|
||||||
public LoggingAspect(Environment env) {
|
|
||||||
this.env = env;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pointcut that matches all repositories, services and Web REST endpoints.
|
|
||||||
*/
|
|
||||||
@Pointcut("within(@org.springframework.stereotype.Repository *)" +
|
|
||||||
" || within(@org.springframework.stereotype.Service *)" +
|
|
||||||
" || within(@org.springframework.web.bind.annotation.RestController *)")
|
|
||||||
public void springBeanPointcut() {
|
|
||||||
// Method is empty as this is just a Pointcut, the implementations are in the advices.
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pointcut that matches all Spring beans in the application's main packages.
|
|
||||||
*/
|
|
||||||
@Pointcut("within(org.hostsharing.hsadminng.repository..*)" +
|
|
||||||
" || within(org.hostsharing.hsadminng.service..*)" +
|
|
||||||
" || within(org.hostsharing.hsadminng.web.rest..*)")
|
|
||||||
public void applicationPackagePointcut() {
|
|
||||||
// Method is empty as this is just a Pointcut, the implementations are in the advices.
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Advice that logs methods throwing exceptions.
|
|
||||||
*
|
|
||||||
* @param joinPoint join point for advice
|
|
||||||
* @param e exception
|
|
||||||
*/
|
|
||||||
@AfterThrowing(pointcut = "applicationPackagePointcut() && springBeanPointcut()", throwing = "e")
|
|
||||||
public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
|
|
||||||
if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) {
|
|
||||||
log.error(
|
|
||||||
"Exception in {}.{}() with cause = \'{}\' and exception = \'{}\'",
|
|
||||||
joinPoint.getSignature().getDeclaringTypeName(),
|
|
||||||
joinPoint.getSignature().getName(),
|
|
||||||
e.getCause() != null ? e.getCause() : "NULL",
|
|
||||||
e.getMessage(),
|
|
||||||
e);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
log.error(
|
|
||||||
"Exception in {}.{}() with cause = {}",
|
|
||||||
joinPoint.getSignature().getDeclaringTypeName(),
|
|
||||||
joinPoint.getSignature().getName(),
|
|
||||||
e.getCause() != null ? e.getCause() : "NULL");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Advice that logs when a method is entered and exited.
|
|
||||||
*
|
|
||||||
* @param joinPoint join point for advice
|
|
||||||
* @return result
|
|
||||||
* @throws Throwable throws IllegalArgumentException
|
|
||||||
*/
|
|
||||||
@Around("applicationPackagePointcut() && springBeanPointcut()")
|
|
||||||
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
log.debug(
|
|
||||||
"Enter: {}.{}() with argument[s] = {}",
|
|
||||||
joinPoint.getSignature().getDeclaringTypeName(),
|
|
||||||
joinPoint.getSignature().getName(),
|
|
||||||
Arrays.toString(joinPoint.getArgs()));
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Object result = joinPoint.proceed();
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
log.debug(
|
|
||||||
"Exit: {}.{}() with result = {}",
|
|
||||||
joinPoint.getSignature().getDeclaringTypeName(),
|
|
||||||
joinPoint.getSignature().getName(),
|
|
||||||
result);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
log.error(
|
|
||||||
"Illegal argument: {} in {}.{}()",
|
|
||||||
Arrays.toString(joinPoint.getArgs()),
|
|
||||||
joinPoint.getSignature().getDeclaringTypeName(),
|
|
||||||
joinPoint.getSignature().getName());
|
|
||||||
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
// Licensed under Apache-2.0
|
|
||||||
package org.hostsharing.hsadminng.config;
|
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Properties specific to Hsadmin Ng.
|
|
||||||
* <p>
|
|
||||||
* Properties are configured in the application.yml file.
|
|
||||||
* See {@link io.github.jhipster.config.JHipsterProperties} for a good example.
|
|
||||||
*/
|
|
||||||
@ConfigurationProperties(prefix = "application", ignoreUnknownFields = false)
|
|
||||||
public class ApplicationProperties {
|
|
||||||
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
// Licensed under Apache-2.0
|
|
||||||
package org.hostsharing.hsadminng.config;
|
|
||||||
|
|
||||||
import io.github.jhipster.async.ExceptionHandlingAsyncTaskExecutor;
|
|
||||||
import io.github.jhipster.config.JHipsterProperties;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
|
|
||||||
import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.scheduling.annotation.*;
|
|
||||||
import org.springframework.scheduling.annotation.SchedulingConfigurer;
|
|
||||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
|
||||||
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
|
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableAsync
|
|
||||||
@EnableScheduling
|
|
||||||
public class AsyncConfiguration implements AsyncConfigurer, SchedulingConfigurer {
|
|
||||||
|
|
||||||
private final Logger log = LoggerFactory.getLogger(AsyncConfiguration.class);
|
|
||||||
|
|
||||||
private final JHipsterProperties jHipsterProperties;
|
|
||||||
|
|
||||||
public AsyncConfiguration(JHipsterProperties jHipsterProperties) {
|
|
||||||
this.jHipsterProperties = jHipsterProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Bean(name = "taskExecutor")
|
|
||||||
public Executor getAsyncExecutor() {
|
|
||||||
log.debug("Creating Async Task Executor");
|
|
||||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
|
||||||
executor.setCorePoolSize(jHipsterProperties.getAsync().getCorePoolSize());
|
|
||||||
executor.setMaxPoolSize(jHipsterProperties.getAsync().getMaxPoolSize());
|
|
||||||
executor.setQueueCapacity(jHipsterProperties.getAsync().getQueueCapacity());
|
|
||||||
executor.setThreadNamePrefix("hsadmin-ng-Executor-");
|
|
||||||
return new ExceptionHandlingAsyncTaskExecutor(executor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
|
|
||||||
return new SimpleAsyncUncaughtExceptionHandler();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
|
|
||||||
taskRegistrar.setScheduler(scheduledTaskExecutor());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public Executor scheduledTaskExecutor() {
|
|
||||||
return Executors.newScheduledThreadPool(jHipsterProperties.getAsync().getCorePoolSize());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
// Licensed under Apache-2.0
|
|
||||||
package org.hostsharing.hsadminng.config;
|
|
||||||
|
|
||||||
import io.github.jhipster.config.JHipsterProperties;
|
|
||||||
|
|
||||||
import org.ehcache.config.builders.*;
|
|
||||||
import org.ehcache.jsr107.Eh107Configuration;
|
|
||||||
import org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer;
|
|
||||||
import org.springframework.cache.annotation.EnableCaching;
|
|
||||||
import org.springframework.context.annotation.*;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableCaching
|
|
||||||
public class CacheConfiguration {
|
|
||||||
|
|
||||||
private final javax.cache.configuration.Configuration<Object, Object> jcacheConfiguration;
|
|
||||||
|
|
||||||
public CacheConfiguration(JHipsterProperties jHipsterProperties) {
|
|
||||||
JHipsterProperties.Cache.Ehcache ehcache = jHipsterProperties.getCache().getEhcache();
|
|
||||||
|
|
||||||
jcacheConfiguration = Eh107Configuration.fromEhcacheCacheConfiguration(
|
|
||||||
CacheConfigurationBuilder.newCacheConfigurationBuilder(
|
|
||||||
Object.class,
|
|
||||||
Object.class,
|
|
||||||
ResourcePoolsBuilder.heap(ehcache.getMaxEntries()))
|
|
||||||
.withExpiry(
|
|
||||||
ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(ehcache.getTimeToLiveSeconds())))
|
|
||||||
.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public JCacheManagerCustomizer cacheManagerCustomizer() {
|
|
||||||
return cm -> {
|
|
||||||
cm.createCache(org.hostsharing.hsadminng.repository.UserRepository.USERS_BY_LOGIN_CACHE, jcacheConfiguration);
|
|
||||||
cm.createCache(org.hostsharing.hsadminng.repository.UserRepository.USERS_BY_EMAIL_CACHE, jcacheConfiguration);
|
|
||||||
// jhipster-needle-ehcache-add-entry
|
|
||||||
|
|
||||||
cm.createCache(
|
|
||||||
org.hostsharing.hsadminng.repository.UserRoleAssignmentRepository.CURRENT_USER_ROLE_ASSIGNMENTS_CACHE,
|
|
||||||
jcacheConfiguration);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
// Licensed under Apache-2.0
|
|
||||||
package org.hostsharing.hsadminng.config;
|
|
||||||
|
|
||||||
import io.github.jhipster.config.JHipsterConstants;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.cloud.config.java.AbstractCloudConfig;
|
|
||||||
import org.springframework.context.annotation.*;
|
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@Profile(JHipsterConstants.SPRING_PROFILE_CLOUD)
|
|
||||||
public class CloudDatabaseConfiguration extends AbstractCloudConfig {
|
|
||||||
|
|
||||||
private final Logger log = LoggerFactory.getLogger(CloudDatabaseConfiguration.class);
|
|
||||||
|
|
||||||
private static final String CLOUD_CONFIGURATION_HIKARI_PREFIX = "spring.datasource.hikari";
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConfigurationProperties(CLOUD_CONFIGURATION_HIKARI_PREFIX)
|
|
||||||
public DataSource dataSource() {
|
|
||||||
log.info("Configuring JDBC datasource from a cloud provider");
|
|
||||||
return connectionFactory().dataSource();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
// Licensed under Apache-2.0
|
|
||||||
package org.hostsharing.hsadminng.config;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Application constants.
|
|
||||||
*/
|
|
||||||
public final class Constants {
|
|
||||||
|
|
||||||
// Regex for acceptable logins
|
|
||||||
public static final String LOGIN_REGEX = "^[_.@A-Za-z0-9-]*$";
|
|
||||||
|
|
||||||
public static final String SYSTEM_ACCOUNT = "system";
|
|
||||||
public static final String ANONYMOUS_USER = "anonymoususer";
|
|
||||||
public static final String DEFAULT_LANGUAGE = "de";
|
|
||||||
|
|
||||||
private Constants() {
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
// Licensed under Apache-2.0
|
|
||||||
package org.hostsharing.hsadminng.config;
|
|
||||||
|
|
||||||
import io.github.jhipster.config.JHipsterConstants;
|
|
||||||
import io.github.jhipster.config.h2.H2ConfigurationHelper;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.context.annotation.Profile;
|
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
|
||||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
|
||||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableJpaRepositories("org.hostsharing.hsadminng.repository")
|
|
||||||
@EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware")
|
|
||||||
@EnableTransactionManagement
|
|
||||||
public class DatabaseConfiguration {
|
|
||||||
|
|
||||||
private final Logger log = LoggerFactory.getLogger(DatabaseConfiguration.class);
|
|
||||||
|
|
||||||
private final Environment env;
|
|
||||||
|
|
||||||
public DatabaseConfiguration(Environment env) {
|
|
||||||
this.env = env;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open the TCP port for the H2 database, so it is available remotely.
|
|
||||||
*
|
|
||||||
* @return the H2 database TCP server
|
|
||||||
* @throws SQLException if the server failed to start
|
|
||||||
*/
|
|
||||||
@Bean(initMethod = "start", destroyMethod = "stop")
|
|
||||||
@Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)
|
|
||||||
public Object h2TCPServer() throws SQLException {
|
|
||||||
String port = getValidPortForH2();
|
|
||||||
log.debug("H2 database is available on port {}", port);
|
|
||||||
return H2ConfigurationHelper.createServer(port);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getValidPortForH2() {
|
|
||||||
int port = Integer.parseInt(env.getProperty("server.port"));
|
|
||||||
if (port < 10000) {
|
|
||||||
port = 10000 + port;
|
|
||||||
} else {
|
|
||||||
if (port < 63536) {
|
|
||||||
port = port + 2000;
|
|
||||||
} else {
|
|
||||||
port = port - 2000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return String.valueOf(port);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
// Licensed under Apache-2.0
|
|
||||||
package org.hostsharing.hsadminng.config;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.format.FormatterRegistry;
|
|
||||||
import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar;
|
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure the converters to use the ISO format for dates by default.
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
public class DateTimeFormatConfiguration implements WebMvcConfigurer {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addFormatters(FormatterRegistry registry) {
|
|
||||||
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
|
|
||||||
registrar.setUseIsoFormat(true);
|
|
||||||
registrar.registerFormatters(registry);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
// Licensed under Apache-2.0
|
|
||||||
package org.hostsharing.hsadminng.config;
|
|
||||||
|
|
||||||
import io.github.jhipster.config.JHipsterConstants;
|
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility class to load a Spring profile to be used as default
|
|
||||||
* when there is no <code>spring.profiles.active</code> set in the environment or as command line argument.
|
|
||||||
* If the value is not available in <code>application.yml</code> then <code>dev</code> profile will be used as default.
|
|
||||||
*/
|
|
||||||
public final class DefaultProfileUtil {
|
|
||||||
|
|
||||||
private static final String SPRING_PROFILE_DEFAULT = "spring.profiles.default";
|
|
||||||
|
|
||||||
private DefaultProfileUtil() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a default to use when no profile is configured.
|
|
||||||
*
|
|
||||||
* @param app the Spring application
|
|
||||||
*/
|
|
||||||
public static void addDefaultProfile(SpringApplication app) {
|
|
||||||
Map<String, Object> defProperties = new HashMap<>();
|
|
||||||
/*
|
|
||||||
* The default profile to use when no other profiles are defined
|
|
||||||
* This cannot be set in the <code>application.yml</code> file.
|
|
||||||
* See https://github.com/spring-projects/spring-boot/issues/1219
|
|
||||||
*/
|
|
||||||
defProperties.put(SPRING_PROFILE_DEFAULT, JHipsterConstants.SPRING_PROFILE_DEVELOPMENT);
|
|
||||||
app.setDefaultProperties(defProperties);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the profiles that are applied else get default profiles.
|
|
||||||
*
|
|
||||||
* @param env spring environment
|
|
||||||
* @return profiles
|
|
||||||
*/
|
|
||||||
public static String[] getActiveProfiles(Environment env) {
|
|
||||||
String[] profiles = env.getActiveProfiles();
|
|
||||||
if (profiles.length == 0) {
|
|
||||||
return env.getDefaultProfiles();
|
|
||||||
}
|
|
||||||
return profiles;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
// Licensed under Apache-2.0
|
|
||||||
package org.hostsharing.hsadminng.config;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
|
|
||||||
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
|
|
||||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
|
||||||
import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.zalando.problem.ProblemModule;
|
|
||||||
import org.zalando.problem.violations.ConstraintViolationProblemModule;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
public class JacksonConfiguration {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Support for Java date and time API.
|
|
||||||
*
|
|
||||||
* @return the corresponding Jackson module.
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public JavaTimeModule javaTimeModule() {
|
|
||||||
return new JavaTimeModule();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public Jdk8Module jdk8TimeModule() {
|
|
||||||
return new Jdk8Module();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Support for Hibernate types in Jackson.
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public Hibernate5Module hibernate5Module() {
|
|
||||||
return new Hibernate5Module();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Jackson Afterburner module to speed up serialization/deserialization.
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public AfterburnerModule afterburnerModule() {
|
|
||||||
return new AfterburnerModule();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Module for serialization/deserialization of RFC7807 Problem.
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
ProblemModule problemModule() {
|
|
||||||
return new ProblemModule();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Module for serialization/deserialization of ConstraintViolationProblem.
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
ConstraintViolationProblemModule constraintViolationProblemModule() {
|
|
||||||
return new ConstraintViolationProblemModule();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
// Licensed under Apache-2.0
|
|
||||||
package org.hostsharing.hsadminng.config;
|
|
||||||
|
|
||||||
import io.github.jhipster.config.JHipsterConstants;
|
|
||||||
import io.github.jhipster.config.liquibase.AsyncSpringLiquibase;
|
|
||||||
import liquibase.integration.spring.SpringLiquibase;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
|
||||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
import org.springframework.core.task.TaskExecutor;
|
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
public class LiquibaseConfiguration {
|
|
||||||
|
|
||||||
private final Logger log = LoggerFactory.getLogger(LiquibaseConfiguration.class);
|
|
||||||
|
|
||||||
private final Environment env;
|
|
||||||
|
|
||||||
public LiquibaseConfiguration(Environment env) {
|
|
||||||
this.env = env;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public SpringLiquibase liquibase(
|
|
||||||
@Qualifier("taskExecutor") TaskExecutor taskExecutor,
|
|
||||||
DataSource dataSource,
|
|
||||||
LiquibaseProperties liquibaseProperties) {
|
|
||||||
|
|
||||||
// Use liquibase.integration.spring.SpringLiquibase if you don't want Liquibase to start asynchronously
|
|
||||||
SpringLiquibase liquibase = new AsyncSpringLiquibase(taskExecutor, env);
|
|
||||||
liquibase.setDataSource(dataSource);
|
|
||||||
liquibase.setChangeLog("classpath:config/liquibase/master.xml");
|
|
||||||
liquibase.setContexts(liquibaseProperties.getContexts());
|
|
||||||
liquibase.setDefaultSchema(liquibaseProperties.getDefaultSchema());
|
|
||||||
liquibase.setDropFirst(liquibaseProperties.isDropFirst());
|
|
||||||
liquibase.setChangeLogParameters(liquibaseProperties.getParameters());
|
|
||||||
if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_NO_LIQUIBASE)) {
|
|
||||||
liquibase.setShouldRun(false);
|
|
||||||
} else {
|
|
||||||
liquibase.setShouldRun(liquibaseProperties.isEnabled());
|
|
||||||
log.debug("Configuring Liquibase");
|
|
||||||
}
|
|
||||||
return liquibase;
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user