RBAC Diagram+PostgreSQL Generator #21
@ -3,8 +3,6 @@ package net.hostsharing.hsadminng.hs.office.bankaccount;
|
|||||||
import lombok.*;
|
import lombok.*;
|
||||||
import lombok.experimental.FieldNameConstants;
|
import lombok.experimental.FieldNameConstants;
|
||||||
import net.hostsharing.hsadminng.errors.DisplayName;
|
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.persistence.HasUuid;
|
||||||
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
|
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
|
||||||
import net.hostsharing.hsadminng.stringify.Stringify;
|
import net.hostsharing.hsadminng.stringify.Stringify;
|
||||||
@ -17,10 +15,8 @@ import jakarta.persistence.Table;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.*;
|
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.Permission.*;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
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;
|
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@ -59,7 +55,7 @@ public class HsOfficeBankAccountEntity implements HasUuid, Stringifyable {
|
|||||||
return holder;
|
return holder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RbacView hsOfficeBankAccount() {
|
public static RbacView rbac() {
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
return rbacViewFor("bankAccount", HsOfficeBankAccountEntity.class)
|
return rbacViewFor("bankAccount", HsOfficeBankAccountEntity.class)
|
||||||
.withIdentityView(SQL.query("target.iban || ':' || target.holder"))
|
.withIdentityView(SQL.query("target.iban || ':' || target.holder"))
|
||||||
@ -75,69 +71,4 @@ public class HsOfficeBankAccountEntity implements HasUuid, Stringifyable {
|
|||||||
.pop();
|
.pop();
|
||||||
// @formatter:on
|
// @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.errors.DisplayName;
|
||||||
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity;
|
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity;
|
||||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
|
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.persistence.HasUuid;
|
||||||
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
|
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.Stringify;
|
||||||
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
||||||
import org.hibernate.annotations.GenericGenerator;
|
import org.hibernate.annotations.GenericGenerator;
|
||||||
@ -14,6 +16,13 @@ import jakarta.persistence.*;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
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;
|
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@ -97,4 +106,69 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
|
|||||||
public String toShortString() {
|
public String toShortString() {
|
||||||
return DEBITOR_NUMBER_TAG + getDebitorNumberString();
|
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 lombok.experimental.FieldNameConstants;
|
||||||
import net.hostsharing.hsadminng.errors.DisplayName;
|
import net.hostsharing.hsadminng.errors.DisplayName;
|
||||||
import net.hostsharing.hsadminng.persistence.HasUuid;
|
import net.hostsharing.hsadminng.persistence.HasUuid;
|
||||||
|
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
|
||||||
import net.hostsharing.hsadminng.stringify.Stringify;
|
import net.hostsharing.hsadminng.stringify.Stringify;
|
||||||
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@ -11,6 +12,11 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import java.util.UUID;
|
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;
|
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@ -56,4 +62,21 @@ public class HsOfficePersonEntity implements HasUuid, Stringifyable {
|
|||||||
return personType + " " +
|
return personType + " " +
|
||||||
(!StringUtils.isEmpty(tradeName) ? tradeName : (familyName + ", " + givenName));
|
(!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.hs.office.contact.HsOfficeContactEntity;
|
||||||
import net.hostsharing.hsadminng.persistence.HasUuid;
|
import net.hostsharing.hsadminng.persistence.HasUuid;
|
||||||
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity;
|
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.Stringify;
|
||||||
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import java.util.UUID;
|
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;
|
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@ -67,4 +75,34 @@ public class HsOfficeRelationshipEntity implements HasUuid, Stringifyable {
|
|||||||
public String toShortString() {
|
public String toShortString() {
|
||||||
return toShortString.apply(this);
|
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 net.hostsharing.hsadminng.persistence.HasUuid;
|
||||||
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
|
||||||
@ -36,11 +37,11 @@ public class RbacView {
|
|||||||
private SQL identityViewSqlQuery;
|
private SQL identityViewSqlQuery;
|
||||||
private EntityAlias entityAliasProxy;
|
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);
|
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);
|
entityAlias = new EntityAlias(alias, entityClass);
|
||||||
entityAliases.put(alias, entityAlias);
|
entityAliases.put(alias, entityAlias);
|
||||||
new RbacUserReference(CREATOR);
|
new RbacUserReference(CREATOR);
|
||||||
@ -71,31 +72,53 @@ public class RbacView {
|
|||||||
return permDef;
|
return permDef;
|
||||||
}
|
}
|
||||||
|
|
||||||
public <EC extends HasUuid> RbacView declareEntityAliases(final String... aliasNames) {
|
public <EC extends HasUuid> RbacView declarePlaceholderEntityAliases(final String... aliasNames) {
|
||||||
for ( String alias: aliasNames ) {
|
for ( String alias: aliasNames ) {
|
||||||
entityAliases.put(alias, new EntityAlias(alias));
|
entityAliases.put(alias, new EntityAlias(alias));
|
||||||
}
|
}
|
||||||
return this;
|
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) {
|
final String aliasName, final Class entityClass, final SQL fetchSql, final Column dependsOnColum) {
|
||||||
entityAliasProxy = new EntityAlias(aliasName, entityClass, fetchSql, dependsOnColum);
|
if ( entityAliasProxy != null ) {
|
||||||
entityAliases.put(aliasName, entityAliasProxy);
|
throw new IllegalStateException("there is already an entityAliasProxy: " + entityAliasProxy);
|
||||||
|
}
|
||||||
|
entityAliasProxy = importEntityAliasImpl(aliasName, entityClass, fetchSql, dependsOnColum);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public <EC extends HasUuid> RbacView defineEntityAlias(
|
public RbacView importEntityAlias(
|
||||||
final String aliasName, final Class entityClass, final SQL fetchSql, final Column dependsOnColum) {
|
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;
|
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);
|
final var mapper = new AliasNameMapper(importedRbacView, aliasName);
|
||||||
importedRbacView.getEntityAliases().values().forEach(entityAlias -> {
|
importedRbacView.getEntityAliases().values().stream()
|
||||||
new EntityAlias( mapper.map(entityAlias.aliasName), entityAlias.entityClass);
|
.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 -> {
|
importedRbacView.getRoleDefs().forEach(roleDef -> {
|
||||||
new RbacRoleDefinition( findEntityAlias(mapper.map(roleDef.entityAlias.aliasName)), roleDef.role);
|
new RbacRoleDefinition( findEntityAlias(mapper.map(roleDef.entityAlias.aliasName)), roleDef.role);
|
||||||
});
|
});
|
||||||
@ -120,15 +143,15 @@ public class RbacView {
|
|||||||
|
|
||||||
|
|
||||||
private RbacGrantDefinition grantRoleToCurrentUser(final RbacRoleDefinition roleDefinition) {
|
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) {
|
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) {
|
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) {
|
boolean isMainEntityAlias(final EntityAlias entityAlias) {
|
||||||
@ -148,7 +171,7 @@ public class RbacView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public RbacView grantRole(final String entityAlias, final Role role) {
|
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;
|
return RbacView.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,6 +184,7 @@ public class RbacView {
|
|||||||
private final RbacRoleDefinition superRoleDef;
|
private final RbacRoleDefinition superRoleDef;
|
||||||
private final RbacRoleDefinition subRoleDef;
|
private final RbacRoleDefinition subRoleDef;
|
||||||
private final RbacPermissionDefinition permDef;
|
private final RbacPermissionDefinition permDef;
|
||||||
|
private boolean toCreate;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
@ -203,7 +227,16 @@ public class RbacView {
|
|||||||
|
|
||||||
boolean isAssumed() {
|
boolean isAssumed() {
|
||||||
// TODO: not implemented yet
|
// TODO: not implemented yet
|
||||||
return false;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isToCreate() {
|
||||||
|
return toCreate;
|
||||||
|
}
|
||||||
|
|
||||||
|
RbacGrantDefinition toCreate() {
|
||||||
|
toCreate = true;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum GrantType {
|
public enum GrantType {
|
||||||
@ -262,7 +295,7 @@ public class RbacView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public RbacPermissionDefinition grantedTo(final String entityAlias, final Role role) {
|
public RbacPermissionDefinition grantedTo(final String entityAlias, final Role role) {
|
||||||
new RbacGrantDefinition(this, findRbacRole(entityAlias, role) );
|
new RbacGrantDefinition(this, findRbacRole(entityAlias, role) ).toCreate();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,7 +342,7 @@ public class RbacView {
|
|||||||
|
|
||||||
public RbacRoleDefinition createSubRole(final Role role) {
|
public RbacRoleDefinition createSubRole(final Role role) {
|
||||||
final var roleDef = findRbacRole(entityAlias, role).toCreate();
|
final var roleDef = findRbacRole(entityAlias, role).toCreate();
|
||||||
new RbacGrantDefinition(roleDef, this);
|
new RbacGrantDefinition(roleDef, this).toCreate();
|
||||||
return roleDef;
|
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);
|
final var found = entityAliases.get(aliasName);
|
||||||
if ( found == null ) {
|
if ( found == null ) {
|
||||||
throw new IllegalArgumentException("entityAlias not found: " + aliasName);
|
throw new IllegalArgumentException("entityAlias not found: " + aliasName);
|
||||||
@ -354,7 +387,7 @@ public class RbacView {
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RbacRoleDefinition findRbacRole(final EntityAlias entityAlias, final Role role) {
|
RbacRoleDefinition findRbacRole(final EntityAlias entityAlias, final Role role) {
|
||||||
return roleDefs.stream()
|
return roleDefs.stream()
|
||||||
.filter(r -> r.getEntityAlias() == entityAlias && r.getRole().equals(role))
|
.filter(r -> r.getEntityAlias() == entityAlias && r.getRole().equals(role))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
@ -367,17 +400,21 @@ public class RbacView {
|
|||||||
|
|
||||||
record EntityAlias(String aliasName, Class<? extends HasUuid> entityClass, SQL fetchSql, Column dependsOnColum) {
|
record EntityAlias(String aliasName, Class<? extends HasUuid> entityClass, SQL fetchSql, Column dependsOnColum) {
|
||||||
|
|
||||||
public EntityAlias(final String aliasName) {
|
public EntityAlias(final String aliasName) {
|
||||||
this(aliasName, null, null, null);
|
this(aliasName, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntityAlias(final String aliasName, final Class<? extends HasUuid> entityClass) {
|
public EntityAlias(final String aliasName, final Class<? extends HasUuid> entityClass) {
|
||||||
this(aliasName, entityClass, null, null);
|
this(aliasName, entityClass, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isGlobal() {
|
boolean isGlobal() {
|
||||||
return aliasName().equals("global");
|
return aliasName().equals("global");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isPlaceholder() {
|
||||||
|
return entityClass == null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public record Role(String roleName) {
|
public record Role(String roleName) {
|
||||||
@ -389,7 +426,7 @@ public class RbacView {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "." + roleName;
|
return ":" + roleName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -409,7 +446,7 @@ public class RbacView {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "." + permission;
|
return ":" + permission;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -457,7 +494,10 @@ public class RbacView {
|
|||||||
if (originalAliasName.equals(importedRbacView.entityAlias.aliasName) ) {
|
if (originalAliasName.equals(importedRbacView.entityAlias.aliasName) ) {
|
||||||
return outerAliasName;
|
return outerAliasName;
|
||||||
}
|
}
|
||||||
return originalAliasName;
|
if (originalAliasName.equals("global") ) {
|
||||||
|
return originalAliasName;
|
||||||
|
}
|
||||||
|
return outerAliasName + "." + originalAliasName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package net.hostsharing.hsadminng.rbac.rbacdef;
|
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 org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -11,7 +11,8 @@ import static java.util.stream.Collectors.joining;
|
|||||||
|
|
||||||
public class RbacViewMermaidFlowchart {
|
public class RbacViewMermaidFlowchart {
|
||||||
|
|
||||||
|
public static final String HOSTSHARING_ORANGE = "#dd4901";
|
||||||
|
public static final String HOSTSHARING_LIGHTBLUE = "#99bcdb";
|
||||||
private final RbacView rbacDef;
|
private final RbacView rbacDef;
|
||||||
private final StringBuilder flowchart = new StringBuilder();
|
private final StringBuilder flowchart = new StringBuilder();
|
||||||
|
|
||||||
@ -21,38 +22,28 @@ public class RbacViewMermaidFlowchart {
|
|||||||
### rbac %{entityAlias} %{timestamp}
|
### rbac %{entityAlias} %{timestamp}
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
|
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||||
flowchart TB
|
flowchart TB
|
||||||
|
|
||||||
"""
|
"""
|
||||||
.replace("%{entityAlias}", rbacDef.getEntityAlias().aliasName())
|
.replace("%{entityAlias}", rbacDef.getEntityAlias().aliasName())
|
||||||
.replace("%{timestamp}", LocalDateTime.now().toString()));
|
.replace("%{timestamp}", LocalDateTime.now().toString()));
|
||||||
renderSubgraphGlobal();
|
|
||||||
renderEntitySubgraphs();
|
renderEntitySubgraphs();
|
||||||
renderGrants();
|
renderGrants();
|
||||||
flowchart.append("```");
|
flowchart.append("```");
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderSubgraphGlobal() {
|
|
||||||
flowchart.append("""
|
|
||||||
subgraph global
|
|
||||||
style global fill: lightgray
|
|
||||||
|
|
||||||
role:global.admin[global.admin]
|
|
||||||
end
|
|
||||||
""");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void renderEntitySubgraphs() {
|
private void renderEntitySubgraphs() {
|
||||||
rbacDef.getEntityAliases().values().stream()
|
rbacDef.getEntityAliases().values().stream()
|
||||||
.filter(entityAlias -> !rbacDef.isEntityAliasProxy(entityAlias))
|
.filter(entityAlias -> !rbacDef.isEntityAliasProxy(entityAlias))
|
||||||
|
.filter(entityAlias -> !entityAlias.isPlaceholder())
|
||||||
.forEach(this::renderEntitySubgraph);
|
.forEach(this::renderEntitySubgraph);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderEntitySubgraph(final RbacView.EntityAlias entity) {
|
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("""
|
flowchart.append("""
|
||||||
|
|
||||||
subgraph %{aliasName}
|
subgraph %{aliasName}["`**%{aliasName}**`"]
|
||||||
direction TB
|
direction TB
|
||||||
style %{aliasName} fill: %{color}
|
style %{aliasName} fill: %{color}
|
||||||
|
|
||||||
@ -98,13 +89,16 @@ public class RbacViewMermaidFlowchart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String grantDef(final RbacView.RbacGrantDefinition grant) {
|
private String grantDef(final RbacView.RbacGrantDefinition grant) {
|
||||||
|
final var arrow = grant.isToCreate()
|
||||||
|
? grant.isAssumed() ? " ==> " : " == // ==> "
|
||||||
|
: grant.isAssumed() ? " -.-> " : " -.- // -.-> ";
|
||||||
return switch (grant.grantType()) {
|
return switch (grant.grantType()) {
|
||||||
case USER_TO_ROLE ->
|
case USER_TO_ROLE ->
|
||||||
// TODO: other user types not implemented yet
|
// TODO: other user types not implemented yet
|
||||||
"user:creator" + (grant.isAssumed() ? " -.-> " : " --> ") + roleId(grant.getSubRoleDef());
|
"user:creator" + arrow + roleId(grant.getSubRoleDef());
|
||||||
case ROLE_TO_ROLE ->
|
case ROLE_TO_ROLE ->
|
||||||
roleId(grant.getSuperRoleDef()) + (grant.isAssumed() ? " -.-> " : " --> ") + roleId(grant.getSubRoleDef());
|
roleId(grant.getSuperRoleDef()) + arrow + roleId(grant.getSubRoleDef());
|
||||||
case ROLE_TO_PERM -> roleId(grant.getSuperRoleDef()) + " --> " + permId(grant.getPermDef());
|
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 {
|
public static void main(String[] args) throws IOException {
|
||||||
|
|
||||||
Files.writeString(
|
// Files.writeString(
|
||||||
Paths.get("doc", "hsOfficeBankAccount.md"),
|
// Paths.get("doc", "hsOfficeRelationship.md"),
|
||||||
new RbacViewMermaidFlowchart(HsOfficeBankAccountEntity.hsOfficeBankAccount()).toString(),
|
// new RbacViewMermaidFlowchart(HsOfficeRelationshipEntity.rbac()).toString(),
|
||||||
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
// StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Files.writeString(
|
||||||
|
// Paths.get("doc", "hsOfficeBankAccount.md"),
|
||||||
|
// new RbacViewMermaidFlowchart(HsOfficeBankAccountEntity.rbac()).toString(),
|
||||||
|
// StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||||
|
|
||||||
Files.writeString(
|
Files.writeString(
|
||||||
Paths.get("doc", "hsOfficeDebitor.md"),
|
Paths.get("doc", "hsOfficeDebitor.md"),
|
||||||
new RbacViewMermaidFlowchart(HsOfficeBankAccountEntity.hsOfficeDebitor()).toString(),
|
new RbacViewMermaidFlowchart(HsOfficeDebitorEntity.rbac()).toString(),
|
||||||
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ public static void main(String[] args) throws IOException {
|
|||||||
|
|
||||||
Files.writeString(
|
Files.writeString(
|
||||||
Paths.get("doc", "hsOfficeBankAccount.sql"),
|
Paths.get("doc", "hsOfficeBankAccount.sql"),
|
||||||
new RbacViewPostgresGenerator(HsOfficeBankAccountEntity.hsOfficeBankAccount()).toString(),
|
new RbacViewPostgresGenerator(HsOfficeBankAccountEntity.rbac()).toString(),
|
||||||
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user