Compare commits

..

No commits in common. "e521c3c9c307a0f73a93c19995c530322bf4d3da" and "12010b4dae68f1fe96fbc0ddb72459943b9edf50" have entirely different histories.

7 changed files with 56 additions and 160 deletions

View File

@ -130,7 +130,7 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
"vatBusiness", "vatBusiness",
"vatReverseCharge", "vatReverseCharge",
"defaultPrefix" /* TODO: do we want that updatable? */) "defaultPrefix" /* TODO: do we want that updatable? */)
.createPermission(custom("new-debitor")).grantedTo("global", ADMIN) .createPermission(custom("new-debitor")).grantedTo("global", ADMIN).pop()
.importRootEntityAliasProxy("debitorRel", HsOfficeRelationshipEntity.class, .importRootEntityAliasProxy("debitorRel", HsOfficeRelationshipEntity.class,
fetchedBySql(""" fetchedBySql("""
@ -139,9 +139,9 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
WHERE r.relType = 'ACCOUNTING' AND r.relHolderUuid = ${REF}.debitorRelUuid WHERE r.relType = 'ACCOUNTING' AND r.relHolderUuid = ${REF}.debitorRelUuid
"""), """),
dependsOnColumn("debitorRelUuid")) dependsOnColumn("debitorRelUuid"))
.createPermission(ALL).grantedTo("debitorRel", OWNER) .createPermission(ALL).grantedTo("debitorRel", OWNER).pop()
.createPermission(EDIT).grantedTo("debitorRel", ADMIN) .createPermission(EDIT).grantedTo("debitorRel", ADMIN).pop()
.createPermission(VIEW).grantedTo("debitorRel", TENANT) .createPermission(VIEW).grantedTo("debitorRel", TENANT).pop()
.importEntityAlias("refundBankAccount", HsOfficeBankAccountEntity.class, .importEntityAlias("refundBankAccount", HsOfficeBankAccountEntity.class,
fetchedBySql(""" fetchedBySql("""

View File

@ -2,9 +2,7 @@ package net.hostsharing.hsadminng.hs.office.partner;
import lombok.*; import lombok.*;
import net.hostsharing.hsadminng.errors.DisplayName; import net.hostsharing.hsadminng.errors.DisplayName;
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.stringify.Stringify; import net.hostsharing.hsadminng.stringify.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.stringify.Stringifyable;
@ -12,11 +10,6 @@ import jakarta.persistence.*;
import java.time.LocalDate; import java.time.LocalDate;
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.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
@ -62,41 +55,6 @@ public class HsOfficePartnerDetailsEntity implements HasUuid, Stringifyable {
return registrationNumber != null ? registrationNumber return registrationNumber != null ? registrationNumber
: birthName != null ? birthName : birthName != null ? birthName
: birthday != null ? birthday.toString() : birthday != null ? birthday.toString()
: dateOfDeath != null ? dateOfDeath.toString() : dateOfDeath != null ? dateOfDeath.toString() : "<empty details>";
: "<empty details>";
}
public static RbacView rbac() {
return rbacViewFor("partnerDetails", HsOfficePartnerDetailsEntity.class)
.withIdentityView(RbacView.SQL.query("""
SELECT partner_iv.idName || '-details'
FROM hs_office_partner_details AS partnerDetails
JOIN hs_office_partner partner ON partner.detailsUuid = partnerDetails.uuid
JOIN hs_office_partner_iv partner_iv ON partner_iv.uuid = partner.uuid
"""))
.withUpdatableColumns(
"registrationOffice",
"registrationNumber",
"birthPlace",
"birthName",
"birthday",
"dateOfDeath")
.createPermission(custom("new-partner-details")).grantedTo("global", ADMIN)
.importRootEntityAliasProxy("partnerRel", HsOfficeRelationshipEntity.class,
fetchedBySql("""
SELECT partnerRel.*
FROM hs_office_relationship AS partnerRel
JOIN hs_office_partner AS partner
ON partner.detailsUuid = ${ref}.uuid
WHERE partnerRel.uuid = partner.partnerRoleUuid
"""),
dependsOnColumn("partnerRoleUuid"))
// The grants are defined in HsOfficePartnerEntity.rbac()
// because they have to be changed when its partnerRel changes,
// not when anything in partner details changes.
;
} }
} }

View File

@ -7,15 +7,12 @@ 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.hs.office.relationship.HsOfficeRelationshipEntity; import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEntity;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView; import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacViewMermaidFlowchart;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacViewPostgresGenerator;
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.NotFound; import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction; import org.hibernate.annotations.NotFoundAction;
import jakarta.persistence.*; import jakarta.persistence.*;
import java.io.IOException;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
@ -82,36 +79,23 @@ public class HsOfficePartnerEntity implements Stringifyable, HasUuid {
public static RbacView rbac() { public static RbacView rbac() {
return rbacViewFor("partner", HsOfficePartnerEntity.class) return rbacViewFor("partner", HsOfficePartnerEntity.class)
.withIdentityView(RbacView.SQL.query(""" .withIdentityView(RbacView.SQL.query("""
SELECT partner.partnerNumber SELECT partner.partnerNumber
|| ':' || (SELECT idName FROM hs_office_person_iv p WHERE p.uuid = partner.personuuid) || ':' || (SELECT idName FROM hs_office_person_iv p WHERE p.uuid = partner.personuuid)
|| '-' || (SELECT idName FROM hs_office_contact_iv c WHERE c.uuid = partner.contactuuid) || '-' || (SELECT idName FROM hs_office_contact_iv c WHERE c.uuid = partner.contactuuid)
FROM hs_office_partner AD partner FROM hs_office_partner AD partner
$idName$)
""")) """))
.withUpdatableColumns( .withUpdatableColumns(
"partnerRoleUuid", "partnerRoleUuid",
"personUuid", "personUuid",
"contactUuid") "contactUuid")
.createPermission(custom("new-partner")).grantedTo("global", ADMIN) .createPermission(custom("new-partner")).grantedTo("global", ADMIN).pop()
.importRootEntityAliasProxy("partnerRel", HsOfficeRelationshipEntity.class, .importRootEntityAliasProxy("partnerRel", HsOfficeRelationshipEntity.class,
fetchedBySql("SELECT * FROM hs_office_relationship AS r WHERE r.uuid = ${ref}.partnerRoleUuid"), fetchedBySql("SELECT * FROM hs_office_relationship AS r WHERE r.uuid = ${ref}.partnerRoleUuid"),
dependsOnColumn("partnerRelUuid")) dependsOnColumn("partnerRelUuid"))
.createPermission(ALL).grantedTo("partnerRel", ADMIN) .createPermission(ALL).grantedTo("partnerRel", ADMIN).pop()
.createPermission(EDIT).grantedTo("partnerRel", AGENT) .createPermission(EDIT).grantedTo("partnerRel", AGENT).pop()
.createPermission(VIEW).grantedTo("partnerRel", TENANT) .createPermission(VIEW).grantedTo("partnerRel", TENANT).pop();
.importSubEntityAlias("partnerDetails", HsOfficePartnerDetailsEntity.class,
fetchedBySql("SELECT * FROM hs_office_partner_details AS d WHERE d.uuid = ${ref}.detailsUuid"),
dependsOnColumn("detailsUuid"))
.createPermission("partnerDetails", ALL).grantedTo("partnerRel", ADMIN)
.createPermission("partnerDetails", EDIT).grantedTo("partnerRel", AGENT)
.createPermission("partnerDetails", VIEW).grantedTo("partnerRel", AGENT);
} }
public static void main(String[] args) throws IOException {
final RbacView rbac = HsOfficePartnerEntity.rbac();
new RbacViewMermaidFlowchart(rbac).generateToMarkdownFile();
new RbacViewPostgresGenerator(rbac).generateToChangeLog("233-hs-office-partner-rbac.sql");
}
} }

View File

@ -4,7 +4,7 @@ import java.util.function.Consumer;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import net.hostsharing.hsadminng.persistence.HasUuid; import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEntity;
import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject; import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
@ -88,10 +88,6 @@ public class RbacView {
return createPermission(rootEntityAlias, permission); return createPermission(rootEntityAlias, permission);
} }
public RbacPermissionDefinition createPermission(final String entityAliasName, final Permission permission) {
return createPermission(findEntityAlias(entityAliasName), permission);
}
private RbacPermissionDefinition createPermission(final EntityAlias entityAlias, final Permission permission) { private RbacPermissionDefinition createPermission(final EntityAlias entityAlias, final Permission permission) {
final RbacPermissionDefinition permDef = new RbacPermissionDefinition(entityAlias, permission, true); final RbacPermissionDefinition permDef = new RbacPermissionDefinition(entityAlias, permission, true);
permDefs.add(permDef); permDefs.add(permDef);
@ -106,37 +102,27 @@ public class RbacView {
} }
public <EC extends RbacObject> RbacView importRootEntityAliasProxy( public <EC extends RbacObject> RbacView importRootEntityAliasProxy(
final String aliasName, final Class<? extends HasUuid> entityClass, final SQL fetchSql, final Column dependsOnColum) { final String aliasName, final Class entityClass, final SQL fetchSql, final Column dependsOnColum) {
if ( rootEntityAliasProxy != null ) { if ( rootEntityAliasProxy != null ) {
throw new IllegalStateException("there is already an entityAliasProxy: " + rootEntityAliasProxy); throw new IllegalStateException("there is already an entityAliasProxy: " + rootEntityAliasProxy);
} }
rootEntityAliasProxy = importEntityAliasImpl(aliasName, entityClass, fetchSql, dependsOnColum, false); rootEntityAliasProxy = importEntityAliasImpl(aliasName, entityClass, fetchSql, dependsOnColum);
return this;
}
public RbacView importSubEntityAlias(
final String aliasName, final Class<? extends HasUuid> entityClass,
final SQL fetchSql, final Column dependsOnColum) {
importEntityAliasImpl(aliasName, entityClass, fetchSql, dependsOnColum, true);
return this; return this;
} }
public RbacView importEntityAlias( public RbacView importEntityAlias(
final String aliasName, final Class<? extends HasUuid> entityClass, final String aliasName, final Class entityClass, final SQL fetchSql, final Column dependsOnColum) {
final SQL fetchSql, final Column dependsOnColum) { importEntityAliasImpl(aliasName, entityClass, fetchSql, dependsOnColum);
importEntityAliasImpl(aliasName, entityClass, fetchSql, dependsOnColum, false);
return this; return this;
} }
private EntityAlias importEntityAliasImpl( private EntityAlias importEntityAliasImpl(final String aliasName, final Class entityClass, final SQL fetchSql, final Column dependsOnColum) {
final String aliasName, final Class<? extends HasUuid> entityClass, final var entityAlias = new EntityAlias(aliasName, entityClass, fetchSql, dependsOnColum);
final SQL fetchSql, final Column dependsOnColum, boolean asSubEntity) {
final var entityAlias = new EntityAlias(aliasName, entityClass, fetchSql, dependsOnColum, asSubEntity);
entityAliases.put(aliasName, entityAlias); entityAliases.put(aliasName, entityAlias);
try { try {
importAsAlias(aliasName, rbacDefinition(entityClass), asSubEntity); importAsAlias(aliasName, rbacDefinition(entityClass));
} catch ( final ReflectiveOperationException exc) { } catch ( final Exception exc) {
throw new RuntimeException("cannot import entity: " + entityClass, exc); new RuntimeException("cannot import entity: " + entityClass, exc);
} }
return entityAlias; return entityAlias;
} }
@ -146,13 +132,11 @@ public class RbacView {
return (RbacView) entityClass.getMethod("rbac").invoke(null); return (RbacView) entityClass.getMethod("rbac").invoke(null);
} }
private RbacView importAsAlias(final String aliasName, final RbacView importedRbacView, final boolean asSubEntity) { private RbacView importAsAlias(final String aliasName, final RbacView importedRbacView) {
final var mapper = new AliasNameMapper(importedRbacView, aliasName, final var mapper = new AliasNameMapper(importedRbacView, aliasName);
asSubEntity ? entityAliases.keySet() : null);
importedRbacView.getEntityAliases().values().stream() importedRbacView.getEntityAliases().values().stream()
.filter(entityAlias -> !importedRbacView.isRootEntityAlias(entityAlias)) .filter(entityAlias -> !importedRbacView.isRootEntityAlias(entityAlias))
.filter(entityAlias -> !entityAlias.isGlobal()) .filter(entityAlias -> !entityAlias.isGlobal())
.filter(entityAlias -> !asSubEntity || !entityAliases.containsKey(entityAlias.aliasName))
.forEach(entityAlias -> { .forEach(entityAlias -> {
final String mappedAliasName = mapper.map(entityAlias.aliasName); final String mappedAliasName = mapper.map(entityAlias.aliasName);
entityAliases.put(mappedAliasName, new EntityAlias(mappedAliasName, entityAlias.entityClass)); entityAliases.put(mappedAliasName, new EntityAlias(mappedAliasName, entityAlias.entityClass));
@ -317,17 +301,28 @@ public class RbacView {
final Permission permission; final Permission permission;
final boolean toCreate; final boolean toCreate;
private RbacPermissionDefinition(final EntityAlias entityAlias, final Permission permission, final boolean toCreate) { public RbacPermissionDefinition(final EntityAlias entityAlias, final Permission permission, final boolean toCreate) {
this.entityAlias = entityAlias; this.entityAlias = entityAlias;
this.permission = permission; this.permission = permission;
this.toCreate = toCreate; this.toCreate = toCreate;
} }
public RbacView grantedTo(final String entityAlias, final Role role) { public RbacView pop() {
findOrCreateGrantDef(this, findRbacRole(entityAlias, role) ).toCreate();
return RbacView.this; return RbacView.this;
} }
public RbacPermissionDefinition withIncomingSuperRole(
final Class<HsOfficeRelationshipEntity> hsOfficeRelationshipEntityClass,
final Role owner) {
return this;
}
public RbacPermissionDefinition grantedTo(final String entityAlias, final Role role) {
findOrCreateGrantDef(this, findRbacRole(entityAlias, role) ).toCreate();
return this;
}
@Override @Override
public String toString() { public String toString() {
return "perm:" + entityAlias.aliasName + permission; return "perm:" + entityAlias.aliasName + permission;
@ -445,14 +440,14 @@ public class RbacView {
.orElseGet(() -> new RbacGrantDefinition(subRoleDefinition, superRoleDefinition)); .orElseGet(() -> new RbacGrantDefinition(subRoleDefinition, superRoleDefinition));
} }
record EntityAlias(String aliasName, Class<? extends RbacObject> entityClass, SQL fetchSql, Column dependsOnColum, boolean isSubEntity) { record EntityAlias(String aliasName, Class<? extends RbacObject> entityClass, SQL fetchSql, Column dependsOnColum) {
public EntityAlias(final String aliasName) { public EntityAlias(final String aliasName) {
this(aliasName, null, null, null, false); this(aliasName, null, null, null);
} }
public EntityAlias(final String aliasName, final Class<? extends RbacObject> entityClass) { public EntityAlias(final String aliasName, final Class<? extends RbacObject> entityClass) {
this(aliasName, entityClass, null, null, false); this(aliasName, entityClass, null, null);
} }
boolean isGlobal() { boolean isGlobal() {
@ -463,6 +458,8 @@ public class RbacView {
return entityClass == null; return entityClass == null;
} }
private String withoutEntitySuffix(final String simpleEntityName) { private String withoutEntitySuffix(final String simpleEntityName) {
return simpleEntityName.substring(0, simpleEntityName.length()-"Entity".length()); return simpleEntityName.substring(0, simpleEntityName.length()-"Entity".length());
} }
@ -509,27 +506,14 @@ public class RbacView {
public static class SQL { public static class SQL {
/**
* DSL methid to specify an SQL SELECT expression which fetches the related entity,
* using the reference `${ref}` of the root entity.
* `${ref}` is going to be replaced by either `NEW` or `OLD` of the trigger function.
* `into ...` will be added with a variable name prefixed with either `new` or `old`.
*
* @param sql an SQL SELECT expression (not ending with ';)
* @return the wrapped SQL expression
*/
public static SQL fetchedBySql(final String sql) { public static SQL fetchedBySql(final String sql) {
validateExpression(sql);
return new SQL(sql); return new SQL(sql);
} }
/** Generic DSL method to specify an SQL SELECT expression.
*
* @param sql an SQL SELECT expression (not ending with ';)
* @return the wrapped SQL expression
*/
public static SQL query(final String sql) { public static SQL query(final String sql) {
validateExpression(sql); if (sql.matches(";[ \t]*$")) {
throw new IllegalArgumentException("SQL expression must not end with ';': " + sql);
}
return new SQL(sql); return new SQL(sql);
} }
@ -538,12 +522,6 @@ public class RbacView {
private SQL(final String sql) { private SQL(final String sql) {
this.sql = sql; this.sql = sql;
} }
private static void validateExpression(final String sql) {
if (sql.matches(";[ \t]*$")) {
throw new IllegalArgumentException("SQL expression must not end with ';': " + sql);
}
}
} }
public static class Column { public static class Column {
@ -564,21 +542,18 @@ public class RbacView {
private final RbacView importedRbacView; private final RbacView importedRbacView;
private final String outerAliasName; private final String outerAliasName;
private final Set<String> outerAliasNames; AliasNameMapper(final RbacView importedRbacView, final String outerAliasName) {
AliasNameMapper(final RbacView importedRbacView, final String outerAliasName, final Set<String> outerAliasNames) {
this.importedRbacView = importedRbacView; this.importedRbacView = importedRbacView;
this.outerAliasName = outerAliasName; this.outerAliasName = outerAliasName;
this.outerAliasNames = (outerAliasNames == null) ? Collections.emptySet() : outerAliasNames;
} }
String map(final String originalAliasName) { String map(final String originalAliasName) {
if (outerAliasNames.contains(originalAliasName) || originalAliasName.equals("global")) {
return originalAliasName;
}
if (originalAliasName.equals(importedRbacView.rootEntityAlias.aliasName) ) { if (originalAliasName.equals(importedRbacView.rootEntityAlias.aliasName) ) {
return outerAliasName; return outerAliasName;
} }
if (originalAliasName.equals("global") ) {
return originalAliasName;
}
return outerAliasName + "." + originalAliasName; return outerAliasName + "." + originalAliasName;
} }
} }

View File

@ -2,7 +2,6 @@ package net.hostsharing.hsadminng.rbac.rbacdef;
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity; import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity;
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity; import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerDetailsEntity;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity; import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEntity; import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEntity;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -17,7 +16,6 @@ import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacGrantDefinitio
public class RbacViewMermaidFlowchart { public class RbacViewMermaidFlowchart {
public static final String HOSTSHARING_ORANGE = "#dd4901"; public static final String HOSTSHARING_ORANGE = "#dd4901";
public static final String HOSTSHARING_ORANGE_LIGHT = "#feb28c";
public static final String HOSTSHARING_LIGHTBLUE = "#99bcdb"; public static final String HOSTSHARING_LIGHTBLUE = "#99bcdb";
private final RbacView rbacDef; private final RbacView rbacDef;
private final StringWriter flowchart = new StringWriter(); private final StringWriter flowchart = new StringWriter();
@ -39,9 +37,7 @@ public class RbacViewMermaidFlowchart {
} }
private void renderEntitySubgraph(final RbacView.EntityAlias entity) { private void renderEntitySubgraph(final RbacView.EntityAlias entity) {
final var color = rbacDef.isRootEntityAlias(entity) ? HOSTSHARING_ORANGE final var color = rbacDef.isRootEntityAlias(entity) ? HOSTSHARING_ORANGE : HOSTSHARING_LIGHTBLUE;
: entity.isSubEntity() ? HOSTSHARING_ORANGE_LIGHT
: HOSTSHARING_LIGHTBLUE;
flowchart.writeLn(""" flowchart.writeLn("""
subgraph %{aliasName}["`**%{aliasName}**`"] subgraph %{aliasName}["`**%{aliasName}**`"]
direction TB direction TB
@ -146,7 +142,7 @@ public class RbacViewMermaidFlowchart {
return flowchart.toString(); return flowchart.toString();
} }
public void generateToMarkdownFile() throws IOException { void generateToMarkdownFile() throws IOException {
final Path path = Paths.get("doc", rbacDef.getRootEntityAlias().simpleName() + ".md"); final Path path = Paths.get("doc", rbacDef.getRootEntityAlias().simpleName() + ".md");
Files.writeString( Files.writeString(
path, path,
@ -168,7 +164,6 @@ public class RbacViewMermaidFlowchart {
new RbacViewMermaidFlowchart(HsOfficeBankAccountEntity.rbac()).generateToMarkdownFile(); new RbacViewMermaidFlowchart(HsOfficeBankAccountEntity.rbac()).generateToMarkdownFile();
new RbacViewMermaidFlowchart(HsOfficeRelationshipEntity.rbac()).generateToMarkdownFile(); new RbacViewMermaidFlowchart(HsOfficeRelationshipEntity.rbac()).generateToMarkdownFile();
new RbacViewMermaidFlowchart(HsOfficePartnerEntity.rbac()).generateToMarkdownFile(); new RbacViewMermaidFlowchart(HsOfficePartnerEntity.rbac()).generateToMarkdownFile();
new RbacViewMermaidFlowchart(HsOfficePartnerDetailsEntity.rbac()).generateToMarkdownFile();
new RbacViewMermaidFlowchart(HsOfficeDebitorEntity.rbac()).generateToMarkdownFile(); new RbacViewMermaidFlowchart(HsOfficeDebitorEntity.rbac()).generateToMarkdownFile();
} }
} }

View File

@ -24,9 +24,8 @@ public class RbacViewPostgresGenerator {
liqibaseTagPrefix = rbacDef.getRootEntityAlias().entityClass().getSimpleName(); liqibaseTagPrefix = rbacDef.getRootEntityAlias().entityClass().getSimpleName();
plPgSql.writeLn(""" plPgSql.writeLn("""
--liquibase formatted sql --liquibase formatted sql
-- This code generated was by ${generator} at %{timestamp}. -- generated at: %{timestamp}
""" """
.replace("${generator}", getClass().getSimpleName())
.replace("%{timestamp}", LocalDateTime.now().toString())); .replace("%{timestamp}", LocalDateTime.now().toString()));
new RolesGrantsAndPermissionsGenerator(rbacDef, liqibaseTagPrefix).generateTo(plPgSql); new RolesGrantsAndPermissionsGenerator(rbacDef, liqibaseTagPrefix).generateTo(plPgSql);
@ -47,16 +46,6 @@ public class RbacViewPostgresGenerator {
System.out.println(outputPath.toAbsolutePath()); System.out.println(outputPath.toAbsolutePath());
} }
public void generateToChangeLog(final String fileName) throws IOException {
final Path outputPath = Path.of("src/main/resources/db/changelog", fileName);
Files.writeString(
outputPath,
toString(),
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING);
System.out.println(outputPath.toAbsolutePath());
}
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
generatePostgres(HsOfficeRelationshipEntity.rbac()); generatePostgres(HsOfficeRelationshipEntity.rbac());
generatePostgres(HsOfficePartnerEntity.rbac()); generatePostgres(HsOfficePartnerEntity.rbac());

View File

@ -98,7 +98,6 @@ class RolesGrantsAndPermissionsGenerator {
createRolesWithGrantsSql(plPgSql, REFERRER); createRolesWithGrantsSql(plPgSql, REFERRER);
plPgSql.writeLn(); plPgSql.writeLn();
// TODO: we need to group and sort the grants, similar to the Flowchart generator
rbacGrants.forEach(g -> plPgSql.writeLn(generateGrant(g))); rbacGrants.forEach(g -> plPgSql.writeLn(generateGrant(g)));
plPgSql.writeLn("return NEW;"); plPgSql.writeLn("return NEW;");
@ -124,14 +123,10 @@ class RolesGrantsAndPermissionsGenerator {
return "createPermissions(${entityRef}.uuid, array ['${perm}']" return "createPermissions(${entityRef}.uuid, array ['${perm}']"
.replace("${entityRef}", rbacDef.isRootEntityAlias(permDef.entityAlias) .replace("${entityRef}", rbacDef.isRootEntityAlias(permDef.entityAlias)
? ref.name() ? ref.name()
: refVarName(ref, permDef.entityAlias)) : "not implemented yet" ) // TODO
.replace("${perm}", permDef.permission.permission()); .replace("${perm}", permDef.permission.permission());
} }
private String refVarName(final PostgresTriggerReference ref, final RbacView.EntityAlias entityAlias) {
return ref.name().toLowerCase() + capitalize(entityAlias.aliasName());
}
private String getRawTableName(final Class<?> entityClass) { private String getRawTableName(final Class<?> entityClass) {
return withoutRvSuffix(entityClass.getAnnotation(Table.class).name()); return withoutRvSuffix(entityClass.getAnnotation(Table.class).name());
} }