RBAC Diagram+PostgreSQL Generator #21

Merged
hsh-michaelhoennig merged 54 commits from experimental-rbacview-generator into master 2024-03-11 12:30:44 +01:00
7 changed files with 125 additions and 18 deletions
Showing only changes of commit fa15378fd2 - Show all commits

View File

@ -85,6 +85,8 @@ public class HsOfficeRelationshipEntity implements HasUuid, Stringifyable {
|| '-with-' || target.relType || '-'
|| (select idName from hs_office_person_iv p where p.uuid = relHolderUuid)
"""))
.withRestrictedViewOrderedBy(SQL.expression(
"(select idName from hs_office_person_iv p where p.uuid = target.relHolderUuid)"))
.withUpdatableColumns("contactUuid")
.importEntityAlias("anchorPerson", HsOfficePersonEntity.class,
dependsOnColumn("relAnchorUuid"),

View File

@ -0,0 +1,34 @@
package net.hostsharing.hsadminng.rbac.rbacdef;
import static net.hostsharing.hsadminng.rbac.rbacdef.StringWriter.with;
public class RbacIdentityViewGenerator {
private final RbacView rbacDef;
private final String liquibaseTagPrefix;
private final String simpleEntityVarName;
private final String rawTableName;
public RbacIdentityViewGenerator(final RbacView rbacDef, final String liquibaseTagPrefix) {
this.rbacDef = rbacDef;
this.liquibaseTagPrefix = liquibaseTagPrefix;
this.simpleEntityVarName = rbacDef.getRootEntityAlias().simpleName();
this.rawTableName = rbacDef.getRootEntityAlias().getRawTableName();
}
void generateTo(final StringWriter plPgSql) {
plPgSql.writeLn("""
-- ============================================================================
--changeset ${liquibaseTagPrefix}-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
call generateRbacIdentityView('${rawTableName}', $idName$
${identityViewSqlPart}
$idName$);
--//
""",
with("liquibaseTagPrefix", liquibaseTagPrefix),
with("identityViewSqlPart", rbacDef.getIdentityViewSqlQuery().sql), // TODO: other part types
with("rawTableName", rawTableName));
}
}

View File

@ -0,0 +1,41 @@
package net.hostsharing.hsadminng.rbac.rbacdef;
import static java.util.stream.Collectors.joining;
import static net.hostsharing.hsadminng.rbac.rbacdef.StringWriter.with;
public class RbacRestrictedViewGenerator {
private final RbacView rbacDef;
private final String liquibaseTagPrefix;
private final String simpleEntityVarName;
private final String rawTableName;
public RbacRestrictedViewGenerator(final RbacView rbacDef, final String liquibaseTagPrefix) {
this.rbacDef = rbacDef;
this.liquibaseTagPrefix = liquibaseTagPrefix;
this.simpleEntityVarName = rbacDef.getRootEntityAlias().simpleName();
this.rawTableName = rbacDef.getRootEntityAlias().getRawTableName();
}
void generateTo(final StringWriter plPgSql) {
plPgSql.writeLn("""
-- ============================================================================
--changeset ${liquibaseTagPrefix}-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
call generateRbacRestrictedView('${rawTableName}',
'${orderBy}',
$updates$
${updates}
$updates$);
--//
""",
with("liquibaseTagPrefix", liquibaseTagPrefix),
with("orderBy", rbacDef.getOrderBySqlExpression().sql),
with("updates", rbacDef.getUpdatableColumns().stream()
.map(c -> c + " = new." + c)
.collect(joining("\n"))),
with("rawTableName", rawTableName));
}
}

View File

@ -0,0 +1,31 @@
package net.hostsharing.hsadminng.rbac.rbacdef;
import static net.hostsharing.hsadminng.rbac.rbacdef.StringWriter.with;
public class RbacRoleDescriptorsGenerator {
private final String liquibaseTagPrefix;
private final String simpleEntityVarName;
private final String rawTableName;
public RbacRoleDescriptorsGenerator(final RbacView rbacDef, final String liquibaseTagPrefix) {
this.liquibaseTagPrefix = liquibaseTagPrefix;
this.simpleEntityVarName = rbacDef.getRootEntityAlias().simpleName();
this.rawTableName = rbacDef.getRootEntityAlias().getRawTableName();
}
void generateTo(final StringWriter plPgSql) {
plPgSql.writeLn("""
-- ============================================================================
--changeset ${liquibaseTagPrefix}-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
call generateRbacRoleDescriptors('${simpleEntityVarName}', '${rawTableName}');
--//
""",
with("liquibaseTagPrefix", liquibaseTagPrefix),
with("simpleEntityVarName", simpleEntityVarName),
with("rawTableName", rawTableName));
}
}

View File

@ -27,7 +27,6 @@ public class RbacView {
public static final String GLOBAL = "global";
public static final String OUTPUT_BASEDIR = "src/main/resources/db/changelog";
private final EntityAlias rootEntityAlias;
private final Set<RbacUserReference> userDefs = new LinkedHashSet<>();
@ -47,6 +46,7 @@ public class RbacView {
private final Set<RbacGrantDefinition> grantDefs = new LinkedHashSet<>();
private SQL identityViewSqlQuery;
private SQL orderBySqlExpression;
private EntityAlias rootEntityAliasProxy;
private RbacRoleDefinition previousRoleDef;
@ -70,6 +70,11 @@ public class RbacView {
return this;
}
public RbacView withRestrictedViewOrderedBy(final SQL orderBySqlExpression) {
this.orderBySqlExpression = orderBySqlExpression;
return this;
}
public RbacView createRole(final Role role, final Consumer<RbacRoleDefinition> with) {
final RbacRoleDefinition newRoleDef = findRbacRole(rootEntityAlias, role).toCreate();
with.accept(newRoleDef);
@ -619,11 +624,17 @@ public class RbacView {
return new SQL(projection, Part.SQL_PROJECTION);
}
public static SQL expression(final String sqlExpression) {
// TODO: validate
return new SQL(sqlExpression, Part.SQL_EXPRESSION);
}
enum Part {
NOOP,
SQL_QUERY,
AUTO_FETCH,
SQL_PROJECTION
SQL_PROJECTION,
SQL_EXPRESSION
}
final String sql;

View File

@ -4,7 +4,6 @@ import lombok.SneakyThrows;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.time.LocalDateTime;
@ -13,7 +12,6 @@ import static net.hostsharing.hsadminng.rbac.rbacdef.StringWriter.with;
public class RbacViewPostgresGenerator {
private final RbacView rbacDef;
private final String liqibaseTagPrefix;
private final StringWriter plPgSql = new StringWriter();
@ -29,7 +27,11 @@ public class RbacViewPostgresGenerator {
with("timestamp", LocalDateTime.now().toString()),
with("ref", NEW.name()));
new RbacObjectGenerator(rbacDef, liqibaseTagPrefix).generateTo(plPgSql);
new RbacRoleDescriptorsGenerator(rbacDef, liqibaseTagPrefix).generateTo(plPgSql);
new RolesGrantsAndPermissionsGenerator(rbacDef, liqibaseTagPrefix).generateTo(plPgSql);
new RbacIdentityViewGenerator(rbacDef, liqibaseTagPrefix).generateTo(plPgSql);
new RbacRestrictedViewGenerator(rbacDef, liqibaseTagPrefix).generateTo(plPgSql);
}
@Override
@ -37,17 +39,6 @@ public class RbacViewPostgresGenerator {
return plPgSql.toString();
}
@SneakyThrows
private static void generatePostgres(final RbacView rbac) {
final Path outputPath = Paths.get("doc", rbac.getRootEntityAlias().simpleName() + ".sql");
Files.writeString(
outputPath,
new RbacViewPostgresGenerator(rbac).toString(),
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
System.out.println(outputPath.toAbsolutePath());
}
@SneakyThrows
public void generateToChangeLog(final Path outputPath) {
Files.writeString(

View File

@ -22,7 +22,6 @@ class RolesGrantsAndPermissionsGenerator {
private final RbacView rbacDef;
private final Set<RbacView.RbacGrantDefinition> rbacGrants = new HashSet<>();
private final String liquibaseTagPrefix;
private final Class<?> entityClass;
private final String simpleEntityName;
private final String simpleEntityVarName;
private final String rawTableName;
@ -34,7 +33,6 @@ class RolesGrantsAndPermissionsGenerator {
.collect(toSet()));
this.liquibaseTagPrefix = liquibaseTagPrefix;
entityClass = rbacDef.getRootEntityAlias().entityClass();
simpleEntityVarName = rbacDef.getRootEntityAlias().simpleName();
simpleEntityName = capitalize(simpleEntityVarName);
rawTableName = rbacDef.getRootEntityAlias().getRawTableName();
@ -452,7 +450,6 @@ class RolesGrantsAndPermissionsGenerator {
on ${rawTableName}
for each row
execute procedure updateTriggerFor${simpleEntityName}_tf();
--//
"""
.replace("${simpleEntityName}", simpleEntityName)
.replace("${rawTableName}", rawTableName)