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 || '-' || '-with-' || target.relType || '-'
|| (select idName from hs_office_person_iv p where p.uuid = relHolderUuid) || (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") .withUpdatableColumns("contactUuid")
.importEntityAlias("anchorPerson", HsOfficePersonEntity.class, .importEntityAlias("anchorPerson", HsOfficePersonEntity.class,
dependsOnColumn("relAnchorUuid"), 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 GLOBAL = "global";
public static final String OUTPUT_BASEDIR = "src/main/resources/db/changelog"; public static final String OUTPUT_BASEDIR = "src/main/resources/db/changelog";
private final EntityAlias rootEntityAlias; private final EntityAlias rootEntityAlias;
private final Set<RbacUserReference> userDefs = new LinkedHashSet<>(); private final Set<RbacUserReference> userDefs = new LinkedHashSet<>();
@ -47,6 +46,7 @@ public class RbacView {
private final Set<RbacGrantDefinition> grantDefs = new LinkedHashSet<>(); private final Set<RbacGrantDefinition> grantDefs = new LinkedHashSet<>();
private SQL identityViewSqlQuery; private SQL identityViewSqlQuery;
private SQL orderBySqlExpression;
private EntityAlias rootEntityAliasProxy; private EntityAlias rootEntityAliasProxy;
private RbacRoleDefinition previousRoleDef; private RbacRoleDefinition previousRoleDef;
@ -70,6 +70,11 @@ public class RbacView {
return this; return this;
} }
public RbacView withRestrictedViewOrderedBy(final SQL orderBySqlExpression) {
this.orderBySqlExpression = orderBySqlExpression;
return this;
}
public RbacView createRole(final Role role, final Consumer<RbacRoleDefinition> with) { public RbacView createRole(final Role role, final Consumer<RbacRoleDefinition> with) {
final RbacRoleDefinition newRoleDef = findRbacRole(rootEntityAlias, role).toCreate(); final RbacRoleDefinition newRoleDef = findRbacRole(rootEntityAlias, role).toCreate();
with.accept(newRoleDef); with.accept(newRoleDef);
@ -619,11 +624,17 @@ public class RbacView {
return new SQL(projection, Part.SQL_PROJECTION); 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 { enum Part {
NOOP, NOOP,
SQL_QUERY, SQL_QUERY,
AUTO_FETCH, AUTO_FETCH,
SQL_PROJECTION SQL_PROJECTION,
SQL_EXPRESSION
} }
final String sql; final String sql;

View File

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

View File

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