rekursive Entity-Imports and render complex Mermad-Flowcharts (example: Debitor with parterRel+personRel and holderPerspn+anchorPerson each)
This commit is contained in:
parent
54cff5ece9
commit
3e2fa5a6f6
@ -3,8 +3,6 @@ package net.hostsharing.hsadminng.hs.office.bankaccount;
|
||||
import lombok.*;
|
||||
import lombok.experimental.FieldNameConstants;
|
||||
import net.hostsharing.hsadminng.errors.DisplayName;
|
||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
|
||||
import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEntity;
|
||||
import net.hostsharing.hsadminng.persistence.HasUuid;
|
||||
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
|
||||
import net.hostsharing.hsadminng.stringify.Stringify;
|
||||
@ -17,10 +15,8 @@ import jakarta.persistence.Table;
|
||||
import java.util.UUID;
|
||||
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.*;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.fetchedBySql;
|
||||
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
||||
|
||||
@Entity
|
||||
@ -59,7 +55,7 @@ public class HsOfficeBankAccountEntity implements HasUuid, Stringifyable {
|
||||
return holder;
|
||||
}
|
||||
|
||||
public static RbacView hsOfficeBankAccount() {
|
||||
public static RbacView rbac() {
|
||||
// @formatter:off
|
||||
return rbacViewFor("bankAccount", HsOfficeBankAccountEntity.class)
|
||||
.withIdentityView(SQL.query("target.iban || ':' || target.holder"))
|
||||
@ -75,69 +71,4 @@ public class HsOfficeBankAccountEntity implements HasUuid, Stringifyable {
|
||||
.pop();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
public static RbacView hsOfficeDebitor() {
|
||||
// @formatter:off
|
||||
return rbacViewFor("debitor", HsOfficeDebitorEntity.class)
|
||||
.withIdentityView(SQL.query("""
|
||||
SELECT debitor.uuid,
|
||||
'D-' || (SELECT partner.partnerNumber
|
||||
FROM hs_office_partner partner
|
||||
JOIN hs_office_relationship partnerRel
|
||||
ON partnerRel.uuid = partner.partnerRoleUUid AND partnerRel.relType = 'PARTNER'
|
||||
JOIN hs_office_relationship debitorRel
|
||||
ON debitorRel.relAnchorUuid = partnerRel.relHolderUuid AND partnerRel.relType = 'ACCOUNTING'
|
||||
WHERE debitorRel.uuid = debitor.debitorRelUuid)
|
||||
|| to_char(debitorNumberSuffix, 'fm00')
|
||||
from hs_office_debitor as debitor;
|
||||
"""))
|
||||
.withUpdatableColumns(
|
||||
"debitorRel",
|
||||
"billable",
|
||||
"billingContactUuid",
|
||||
"refundBankAccountUuid",
|
||||
"vatId",
|
||||
"vatCountryCode",
|
||||
"vatBusiness",
|
||||
"vatreversecharge",
|
||||
"defaultPrefix" /* TODO: do we want that updatable? */ )
|
||||
.createPermission(custom("new-debitor")).grantedTo("global", ADMIN).pop()
|
||||
|
||||
.defineProxyEntityAlias("debitorRel", HsOfficeRelationshipEntity.class, fetchedBySql("""
|
||||
SELECT *
|
||||
FROM hs_office_relationship AS r
|
||||
WHERE r.relType = 'ACCOUNTING' AND r.relHolderUuid = ${REF}.debitorRelUuid;
|
||||
"""),
|
||||
dependsOnColumn("debitorRelUuid"))
|
||||
.createPermission(ALL).grantedTo("debitorRel", OWNER).pop()
|
||||
.createPermission(EDIT).grantedTo("debitorRel", ADMIN).pop()
|
||||
.createPermission(VIEW).grantedTo("debitorRel", TENANT).pop()
|
||||
|
||||
.defineEntityAlias("refundBankAccount", HsOfficeBankAccountEntity.class, fetchedBySql("""
|
||||
SELECT *
|
||||
FROM hs_office_relationship AS r
|
||||
WHERE r.relType = 'ACCOUNTING' AND r.relHolderUuid = ${REF}.debitorRelUuid;
|
||||
"""),
|
||||
dependsOnColumn("bankAccountUuid"))
|
||||
.importRbacViewAs("refundBankAccount", HsOfficeBankAccountEntity.hsOfficeBankAccount())
|
||||
.toRole("refundBankAccount", ADMIN).grantRole("debitorRel", AGENT)
|
||||
.toRole("debitorRel", AGENT).grantRole("refundBankAccount", REFERRER)
|
||||
|
||||
.defineEntityAlias("partnerRel", HsOfficeRelationshipEntity.class, fetchedBySql("""
|
||||
SELECT *
|
||||
FROM hs_office_relationship AS partnerRel
|
||||
WHERE ${debitorRel}.relAnchorUuid = partnerRel.relHolderUuid;
|
||||
"""),
|
||||
dependsOnColumn("debitorRelUuid"))
|
||||
.toRole("partnerRel", ADMIN).grantRole("debitorRel", ADMIN)
|
||||
.toRole("partnerRel", AGENT).grantRole("debitorRel", AGENT)
|
||||
.toRole("debitorRel", AGENT).grantRole("partnerRel", TENANT)
|
||||
.declareEntityAliases("partnerPerson", "operationalPerson")
|
||||
.forExampleRole("partnerPerson", ADMIN).wouldBeGrantedTo("partnerRel", ADMIN)
|
||||
.forExampleRole("operationalPerson", ADMIN).wouldBeGrantedTo("partnerRel", ADMIN)
|
||||
.forExampleRole("partnerRel", TENANT).wouldBeGrantedTo("partnerPerson", REFERRER);
|
||||
|
||||
|
||||
// @formatter:on
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,10 @@ import lombok.*;
|
||||
import net.hostsharing.hsadminng.errors.DisplayName;
|
||||
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity;
|
||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
|
||||
import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEntity;
|
||||
import net.hostsharing.hsadminng.persistence.HasUuid;
|
||||
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
|
||||
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
|
||||
import net.hostsharing.hsadminng.stringify.Stringify;
|
||||
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
@ -14,6 +16,13 @@ import jakarta.persistence.*;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.VIEW;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.REFERRER;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.fetchedBySql;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
|
||||
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
||||
|
||||
@Entity
|
||||
@ -97,4 +106,69 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
|
||||
public String toShortString() {
|
||||
return DEBITOR_NUMBER_TAG + getDebitorNumberString();
|
||||
}
|
||||
|
||||
public static RbacView rbac() {
|
||||
// @formatter:off
|
||||
return rbacViewFor("debitor", HsOfficeDebitorEntity.class)
|
||||
.withIdentityView(RbacView.SQL.query("""
|
||||
SELECT debitor.uuid,
|
||||
'D-' || (SELECT partner.partnerNumber
|
||||
FROM hs_office_partner partner
|
||||
JOIN hs_office_relationship partnerRel
|
||||
ON partnerRel.uuid = partner.partnerRoleUUid AND partnerRel.relType = 'PARTNER'
|
||||
JOIN hs_office_relationship debitorRel
|
||||
ON debitorRel.relAnchorUuid = partnerRel.relHolderUuid AND partnerRel.relType = 'ACCOUNTING'
|
||||
WHERE debitorRel.uuid = debitor.debitorRelUuid)
|
||||
|| to_char(debitorNumberSuffix, 'fm00')
|
||||
from hs_office_debitor as debitor;
|
||||
"""))
|
||||
.withUpdatableColumns(
|
||||
"debitorRel",
|
||||
"billable",
|
||||
"billingContactUuid",
|
||||
"refundBankAccountUuid",
|
||||
"vatId",
|
||||
"vatCountryCode",
|
||||
"vatBusiness",
|
||||
"vatReverseCharge",
|
||||
"defaultPrefix" /* TODO: do we want that updatable? */ )
|
||||
.createPermission(custom("new-debitor")).grantedTo("global", ADMIN).pop()
|
||||
|
||||
.importProxyEntity("debitorRel", HsOfficeRelationshipEntity.class,
|
||||
fetchedBySql("""
|
||||
SELECT *
|
||||
FROM hs_office_relationship AS r
|
||||
WHERE r.relType = 'ACCOUNTING' AND r.relHolderUuid = ${REF}.debitorRelUuid;
|
||||
"""),
|
||||
dependsOnColumn("debitorRelUuid"))
|
||||
.createPermission(ALL).grantedTo("debitorRel", OWNER).pop()
|
||||
.createPermission(EDIT).grantedTo("debitorRel", ADMIN).pop()
|
||||
.createPermission(VIEW).grantedTo("debitorRel", TENANT).pop()
|
||||
|
||||
.importEntityAlias("refundBankAccount", HsOfficeBankAccountEntity.class,
|
||||
fetchedBySql("""
|
||||
SELECT *
|
||||
FROM hs_office_relationship AS r
|
||||
WHERE r.relType = 'ACCOUNTING' AND r.relHolderUuid = ${REF}.debitorRelUuid;
|
||||
"""),
|
||||
dependsOnColumn("bankAccountUuid"))
|
||||
.toRole("refundBankAccount", ADMIN).grantRole("debitorRel", AGENT)
|
||||
.toRole("debitorRel", AGENT).grantRole("refundBankAccount", REFERRER)
|
||||
|
||||
.importEntityAlias("partnerRel", HsOfficeRelationshipEntity.class,
|
||||
fetchedBySql("""
|
||||
SELECT *
|
||||
FROM hs_office_relationship AS partnerRel
|
||||
WHERE ${debitorRel}.relAnchorUuid = partnerRel.relHolderUuid;
|
||||
"""),
|
||||
dependsOnColumn("debitorRelUuid"))
|
||||
.toRole("partnerRel", ADMIN).grantRole("debitorRel", ADMIN)
|
||||
.toRole("partnerRel", AGENT).grantRole("debitorRel", AGENT)
|
||||
.toRole("debitorRel", AGENT).grantRole("partnerRel", TENANT)
|
||||
.declarePlaceholderEntityAliases("partnerPerson", "operationalPerson")
|
||||
.forExampleRole("partnerPerson", ADMIN).wouldBeGrantedTo("partnerRel", ADMIN)
|
||||
.forExampleRole("operationalPerson", ADMIN).wouldBeGrantedTo("partnerRel", ADMIN)
|
||||
.forExampleRole("partnerRel", TENANT).wouldBeGrantedTo("partnerPerson", REFERRER);
|
||||
// @formatter:on
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import lombok.*;
|
||||
import lombok.experimental.FieldNameConstants;
|
||||
import net.hostsharing.hsadminng.errors.DisplayName;
|
||||
import net.hostsharing.hsadminng.persistence.HasUuid;
|
||||
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
|
||||
import net.hostsharing.hsadminng.stringify.Stringify;
|
||||
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -11,6 +12,11 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import jakarta.persistence.*;
|
||||
import java.util.UUID;
|
||||
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.GLOBAL;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.query;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
|
||||
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
||||
|
||||
@Entity
|
||||
@ -56,4 +62,21 @@ public class HsOfficePersonEntity implements HasUuid, Stringifyable {
|
||||
return personType + " " +
|
||||
(!StringUtils.isEmpty(tradeName) ? tradeName : (familyName + ", " + givenName));
|
||||
}
|
||||
|
||||
public static RbacView rbac() {
|
||||
// @formatter:off
|
||||
return rbacViewFor("person", HsOfficePersonEntity.class)
|
||||
.withIdentityView(query("concat(target.tradeName, target.familyName, target.givenName)"))
|
||||
.withUpdatableColumns("personType", "tradeName", "givenName", "familyName")
|
||||
.createRole(OWNER)
|
||||
.withPermission(ALL)
|
||||
.withCurrentUserAsOwner()
|
||||
.withIncomingSuperRole(GLOBAL, ADMIN)
|
||||
.createSubRole(ADMIN)
|
||||
.withPermission(EDIT)
|
||||
.createSubRole(REFERRER)
|
||||
.withPermission(VIEW)
|
||||
.pop();
|
||||
// @formatter:on
|
||||
}
|
||||
}
|
||||
|
@ -5,12 +5,20 @@ import lombok.experimental.FieldNameConstants;
|
||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
|
||||
import net.hostsharing.hsadminng.persistence.HasUuid;
|
||||
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity;
|
||||
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
|
||||
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL;
|
||||
import net.hostsharing.hsadminng.stringify.Stringify;
|
||||
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.util.UUID;
|
||||
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.GLOBAL;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.fetchedBySql;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
|
||||
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
||||
|
||||
@Entity
|
||||
@ -67,4 +75,34 @@ public class HsOfficeRelationshipEntity implements HasUuid, Stringifyable {
|
||||
public String toShortString() {
|
||||
return toShortString.apply(this);
|
||||
}
|
||||
|
||||
public static RbacView rbac() {
|
||||
// @formatter:off
|
||||
return rbacViewFor("relationship", HsOfficeRelationshipEntity.class)
|
||||
.withIdentityView(SQL.query("""
|
||||
(select idName from hs_office_person_iv p where p.uuid = target.relAnchorUuid)
|
||||
|| '-with-' || target.relType || '-'
|
||||
|| (select idName from hs_office_person_iv p where p.uuid = target.relHolderUuid)
|
||||
"""))
|
||||
.withUpdatableColumns("contactUuid")
|
||||
.importEntityAlias("anchorPerson", HsOfficePersonEntity.class,
|
||||
fetchedBySql("select * from hs_office_person as p where p.uuid = ${REF}.relAnchorUuid"),
|
||||
dependsOnColumn("relAnchorUuid"))
|
||||
.importEntityAlias("holderPerson", HsOfficePersonEntity.class,
|
||||
fetchedBySql("select * from hs_office_person as p where p.uuid = ${REF}.relHolderUuid"),
|
||||
dependsOnColumn("relHolderUuid"))
|
||||
.createRole(OWNER)
|
||||
.withCurrentUserAsOwner()
|
||||
.withPermission(ALL)
|
||||
.withIncomingSuperRole(GLOBAL, ADMIN)
|
||||
.withIncomingSuperRole("anchorPerson", ADMIN)
|
||||
.createSubRole(ADMIN)
|
||||
.withPermission(EDIT)
|
||||
.createSubRole(AGENT)
|
||||
.withIncomingSuperRole("holderPerson", ADMIN)
|
||||
.createSubRole(TENANT)
|
||||
.withPermission(VIEW)
|
||||
.pop();
|
||||
// @formatter:on
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEnti
|
||||
import net.hostsharing.hsadminng.persistence.HasUuid;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.*;
|
||||
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
|
||||
@ -36,11 +37,11 @@ public class RbacView {
|
||||
private SQL identityViewSqlQuery;
|
||||
private EntityAlias entityAliasProxy;
|
||||
|
||||
public static <E extends HasUuid> RbacView rbacViewFor(final String alias, final Class entityClass) {
|
||||
public static <E extends HasUuid> RbacView rbacViewFor(final String alias, final Class<? extends HasUuid> entityClass) {
|
||||
return new RbacView(alias, entityClass);
|
||||
}
|
||||
|
||||
RbacView(final String alias, final Class entityClass) {
|
||||
RbacView(final String alias, final Class<? extends HasUuid> entityClass) {
|
||||
entityAlias = new EntityAlias(alias, entityClass);
|
||||
entityAliases.put(alias, entityAlias);
|
||||
new RbacUserReference(CREATOR);
|
||||
@ -71,31 +72,53 @@ public class RbacView {
|
||||
return permDef;
|
||||
}
|
||||
|
||||
public <EC extends HasUuid> RbacView declareEntityAliases(final String... aliasNames) {
|
||||
public <EC extends HasUuid> RbacView declarePlaceholderEntityAliases(final String... aliasNames) {
|
||||
for ( String alias: aliasNames ) {
|
||||
entityAliases.put(alias, new EntityAlias(alias));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public <EC extends HasUuid> RbacView defineProxyEntityAlias(
|
||||
public <EC extends HasUuid> RbacView importProxyEntity(
|
||||
final String aliasName, final Class entityClass, final SQL fetchSql, final Column dependsOnColum) {
|
||||
entityAliasProxy = new EntityAlias(aliasName, entityClass, fetchSql, dependsOnColum);
|
||||
entityAliases.put(aliasName, entityAliasProxy);
|
||||
if ( entityAliasProxy != null ) {
|
||||
throw new IllegalStateException("there is already an entityAliasProxy: " + entityAliasProxy);
|
||||
}
|
||||
entityAliasProxy = importEntityAliasImpl(aliasName, entityClass, fetchSql, dependsOnColum);
|
||||
return this;
|
||||
}
|
||||
|
||||
public <EC extends HasUuid> RbacView defineEntityAlias(
|
||||
public RbacView importEntityAlias(
|
||||
final String aliasName, final Class entityClass, final SQL fetchSql, final Column dependsOnColum) {
|
||||
entityAliases.put(aliasName, new EntityAlias(aliasName, entityClass, fetchSql, dependsOnColum));
|
||||
importEntityAliasImpl(aliasName, entityClass, fetchSql, dependsOnColum);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RbacView importRbacViewAs(final String aliasName, final RbacView importedRbacView) {
|
||||
private EntityAlias importEntityAliasImpl(final String aliasName, final Class entityClass, final SQL fetchSql, final Column dependsOnColum) {
|
||||
final var entityAlias = new EntityAlias(aliasName, entityClass, fetchSql, dependsOnColum);
|
||||
entityAliases.put(aliasName, entityAlias);
|
||||
try {
|
||||
importAsAlias(aliasName, rbacDefinition(entityClass));
|
||||
} catch ( final Exception exc) {
|
||||
new RuntimeException("cannot import entity: " + entityClass, exc);
|
||||
}
|
||||
return entityAlias;
|
||||
}
|
||||
|
||||
private static RbacView rbacDefinition(final Class<? extends HasUuid> entityClass)
|
||||
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
|
||||
return (RbacView) entityClass.getMethod("rbac").invoke(null);
|
||||
}
|
||||
|
||||
private RbacView importAsAlias(final String aliasName, final RbacView importedRbacView) {
|
||||
final var mapper = new AliasNameMapper(importedRbacView, aliasName);
|
||||
importedRbacView.getEntityAliases().values().forEach(entityAlias -> {
|
||||
new EntityAlias( mapper.map(entityAlias.aliasName), entityAlias.entityClass);
|
||||
});
|
||||
importedRbacView.getEntityAliases().values().stream()
|
||||
.filter(entityAlias -> !importedRbacView.isMainEntityAlias(entityAlias))
|
||||
.filter(entityAlias -> !entityAlias.isGlobal())
|
||||
.forEach(entityAlias -> {
|
||||
final String mappedAliasName = mapper.map(entityAlias.aliasName);
|
||||
entityAliases.put(mappedAliasName, new EntityAlias(mappedAliasName, entityAlias.entityClass));
|
||||
});
|
||||
importedRbacView.getRoleDefs().forEach(roleDef -> {
|
||||
new RbacRoleDefinition( findEntityAlias(mapper.map(roleDef.entityAlias.aliasName)), roleDef.role);
|
||||
});
|
||||
@ -120,15 +143,15 @@ public class RbacView {
|
||||
|
||||
|
||||
private RbacGrantDefinition grantRoleToCurrentUser(final RbacRoleDefinition roleDefinition) {
|
||||
return new RbacGrantDefinition(roleDefinition, currentUser());
|
||||
return new RbacGrantDefinition(roleDefinition, currentUser()).toCreate();
|
||||
}
|
||||
|
||||
private RbacGrantDefinition grantPermissionToRole(final RbacPermissionDefinition permDef , final RbacRoleDefinition roleDef) {
|
||||
return new RbacGrantDefinition(permDef, roleDef);
|
||||
return new RbacGrantDefinition(permDef, roleDef).toCreate();
|
||||
}
|
||||
|
||||
private RbacGrantDefinition grantSubRoleToSuperRole(final RbacRoleDefinition subRoleDefinition, final RbacRoleDefinition superRoleDefinition) {
|
||||
return new RbacGrantDefinition(subRoleDefinition, superRoleDefinition);
|
||||
return new RbacGrantDefinition(subRoleDefinition, superRoleDefinition).toCreate();
|
||||
}
|
||||
|
||||
boolean isMainEntityAlias(final EntityAlias entityAlias) {
|
||||
@ -148,7 +171,7 @@ public class RbacView {
|
||||
}
|
||||
|
||||
public RbacView grantRole(final String entityAlias, final Role role) {
|
||||
new RbacGrantDefinition(findRbacRole(entityAlias, role), superRoleDef);
|
||||
new RbacGrantDefinition(findRbacRole(entityAlias, role), superRoleDef).toCreate();
|
||||
return RbacView.this;
|
||||
}
|
||||
|
||||
@ -161,6 +184,7 @@ public class RbacView {
|
||||
private final RbacRoleDefinition superRoleDef;
|
||||
private final RbacRoleDefinition subRoleDef;
|
||||
private final RbacPermissionDefinition permDef;
|
||||
private boolean toCreate;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
@ -203,7 +227,16 @@ public class RbacView {
|
||||
|
||||
boolean isAssumed() {
|
||||
// TODO: not implemented yet
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean isToCreate() {
|
||||
return toCreate;
|
||||
}
|
||||
|
||||
RbacGrantDefinition toCreate() {
|
||||
toCreate = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public enum GrantType {
|
||||
@ -262,7 +295,7 @@ public class RbacView {
|
||||
}
|
||||
|
||||
public RbacPermissionDefinition grantedTo(final String entityAlias, final Role role) {
|
||||
new RbacGrantDefinition(this, findRbacRole(entityAlias, role) );
|
||||
new RbacGrantDefinition(this, findRbacRole(entityAlias, role) ).toCreate();
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -309,7 +342,7 @@ public class RbacView {
|
||||
|
||||
public RbacRoleDefinition createSubRole(final Role role) {
|
||||
final var roleDef = findRbacRole(entityAlias, role).toCreate();
|
||||
new RbacGrantDefinition(roleDef, this);
|
||||
new RbacGrantDefinition(roleDef, this).toCreate();
|
||||
return roleDef;
|
||||
}
|
||||
|
||||
@ -346,7 +379,7 @@ public class RbacView {
|
||||
}
|
||||
}
|
||||
|
||||
private EntityAlias findEntityAlias(final String aliasName) {
|
||||
EntityAlias findEntityAlias(final String aliasName) {
|
||||
final var found = entityAliases.get(aliasName);
|
||||
if ( found == null ) {
|
||||
throw new IllegalArgumentException("entityAlias not found: " + aliasName);
|
||||
@ -354,7 +387,7 @@ public class RbacView {
|
||||
return found;
|
||||
}
|
||||
|
||||
public RbacRoleDefinition findRbacRole(final EntityAlias entityAlias, final Role role) {
|
||||
RbacRoleDefinition findRbacRole(final EntityAlias entityAlias, final Role role) {
|
||||
return roleDefs.stream()
|
||||
.filter(r -> r.getEntityAlias() == entityAlias && r.getRole().equals(role))
|
||||
.findFirst()
|
||||
@ -367,17 +400,21 @@ public class RbacView {
|
||||
|
||||
record EntityAlias(String aliasName, Class<? extends HasUuid> entityClass, SQL fetchSql, Column dependsOnColum) {
|
||||
|
||||
public EntityAlias(final String aliasName) {
|
||||
this(aliasName, null, null, null);
|
||||
}
|
||||
public EntityAlias(final String aliasName) {
|
||||
this(aliasName, null, null, null);
|
||||
}
|
||||
|
||||
public EntityAlias(final String aliasName, final Class<? extends HasUuid> entityClass) {
|
||||
this(aliasName, entityClass, null, null);
|
||||
}
|
||||
public EntityAlias(final String aliasName, final Class<? extends HasUuid> entityClass) {
|
||||
this(aliasName, entityClass, null, null);
|
||||
}
|
||||
|
||||
boolean isGlobal() {
|
||||
return aliasName().equals("global");
|
||||
}
|
||||
|
||||
boolean isPlaceholder() {
|
||||
return entityClass == null;
|
||||
}
|
||||
}
|
||||
|
||||
public record Role(String roleName) {
|
||||
@ -389,7 +426,7 @@ public class RbacView {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "." + roleName;
|
||||
return ":" + roleName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -409,7 +446,7 @@ public class RbacView {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "." + permission;
|
||||
return ":" + permission;
|
||||
}
|
||||
}
|
||||
|
||||
@ -457,7 +494,10 @@ public class RbacView {
|
||||
if (originalAliasName.equals(importedRbacView.entityAlias.aliasName) ) {
|
||||
return outerAliasName;
|
||||
}
|
||||
return originalAliasName;
|
||||
if (originalAliasName.equals("global") ) {
|
||||
return originalAliasName;
|
||||
}
|
||||
return outerAliasName + "." + originalAliasName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package net.hostsharing.hsadminng.rbac.rbacdef;
|
||||
|
||||
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity;
|
||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -11,7 +11,8 @@ import static java.util.stream.Collectors.joining;
|
||||
|
||||
public class RbacViewMermaidFlowchart {
|
||||
|
||||
|
||||
public static final String HOSTSHARING_ORANGE = "#dd4901";
|
||||
public static final String HOSTSHARING_LIGHTBLUE = "#99bcdb";
|
||||
private final RbacView rbacDef;
|
||||
private final StringBuilder flowchart = new StringBuilder();
|
||||
|
||||
@ -21,38 +22,28 @@ public class RbacViewMermaidFlowchart {
|
||||
### rbac %{entityAlias} %{timestamp}
|
||||
|
||||
```mermaid
|
||||
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||
flowchart TB
|
||||
|
||||
"""
|
||||
.replace("%{entityAlias}", rbacDef.getEntityAlias().aliasName())
|
||||
.replace("%{timestamp}", LocalDateTime.now().toString()));
|
||||
renderSubgraphGlobal();
|
||||
renderEntitySubgraphs();
|
||||
renderGrants();
|
||||
flowchart.append("```");
|
||||
}
|
||||
|
||||
void renderSubgraphGlobal() {
|
||||
flowchart.append("""
|
||||
subgraph global
|
||||
style global fill: lightgray
|
||||
|
||||
role:global.admin[global.admin]
|
||||
end
|
||||
""");
|
||||
}
|
||||
|
||||
private void renderEntitySubgraphs() {
|
||||
rbacDef.getEntityAliases().values().stream()
|
||||
.filter(entityAlias -> !rbacDef.isEntityAliasProxy(entityAlias))
|
||||
.filter(entityAlias -> !entityAlias.isPlaceholder())
|
||||
.forEach(this::renderEntitySubgraph);
|
||||
}
|
||||
|
||||
private void renderEntitySubgraph(final RbacView.EntityAlias entity) {
|
||||
final var color = rbacDef.isMainEntityAlias(entity) ? "lightgreen" : "lightgray";
|
||||
final var color = rbacDef.isMainEntityAlias(entity) ? HOSTSHARING_ORANGE : HOSTSHARING_LIGHTBLUE;
|
||||
flowchart.append("""
|
||||
|
||||
subgraph %{aliasName}
|
||||
subgraph %{aliasName}["`**%{aliasName}**`"]
|
||||
direction TB
|
||||
style %{aliasName} fill: %{color}
|
||||
|
||||
@ -98,13 +89,16 @@ public class RbacViewMermaidFlowchart {
|
||||
}
|
||||
|
||||
private String grantDef(final RbacView.RbacGrantDefinition grant) {
|
||||
final var arrow = grant.isToCreate()
|
||||
? grant.isAssumed() ? " ==> " : " == // ==> "
|
||||
: grant.isAssumed() ? " -.-> " : " -.- // -.-> ";
|
||||
return switch (grant.grantType()) {
|
||||
case USER_TO_ROLE ->
|
||||
// TODO: other user types not implemented yet
|
||||
"user:creator" + (grant.isAssumed() ? " -.-> " : " --> ") + roleId(grant.getSubRoleDef());
|
||||
"user:creator" + arrow + roleId(grant.getSubRoleDef());
|
||||
case ROLE_TO_ROLE ->
|
||||
roleId(grant.getSuperRoleDef()) + (grant.isAssumed() ? " -.-> " : " --> ") + roleId(grant.getSubRoleDef());
|
||||
case ROLE_TO_PERM -> roleId(grant.getSuperRoleDef()) + " --> " + permId(grant.getPermDef());
|
||||
roleId(grant.getSuperRoleDef()) + arrow + roleId(grant.getSubRoleDef());
|
||||
case ROLE_TO_PERM -> roleId(grant.getSuperRoleDef()) + arrow + permId(grant.getPermDef());
|
||||
};
|
||||
}
|
||||
|
||||
@ -131,14 +125,20 @@ public class RbacViewMermaidFlowchart {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
|
||||
Files.writeString(
|
||||
Paths.get("doc", "hsOfficeBankAccount.md"),
|
||||
new RbacViewMermaidFlowchart(HsOfficeBankAccountEntity.hsOfficeBankAccount()).toString(),
|
||||
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
// Files.writeString(
|
||||
// Paths.get("doc", "hsOfficeRelationship.md"),
|
||||
// new RbacViewMermaidFlowchart(HsOfficeRelationshipEntity.rbac()).toString(),
|
||||
// StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
//
|
||||
//
|
||||
// Files.writeString(
|
||||
// Paths.get("doc", "hsOfficeBankAccount.md"),
|
||||
// new RbacViewMermaidFlowchart(HsOfficeBankAccountEntity.rbac()).toString(),
|
||||
// StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
|
||||
Files.writeString(
|
||||
Paths.get("doc", "hsOfficeDebitor.md"),
|
||||
new RbacViewMermaidFlowchart(HsOfficeBankAccountEntity.hsOfficeDebitor()).toString(),
|
||||
new RbacViewMermaidFlowchart(HsOfficeDebitorEntity.rbac()).toString(),
|
||||
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ public static void main(String[] args) throws IOException {
|
||||
|
||||
Files.writeString(
|
||||
Paths.get("doc", "hsOfficeBankAccount.sql"),
|
||||
new RbacViewPostgresGenerator(HsOfficeBankAccountEntity.hsOfficeBankAccount()).toString(),
|
||||
new RbacViewPostgresGenerator(HsOfficeBankAccountEntity.rbac()).toString(),
|
||||
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user