RBAC Diagram+PostgreSQL Generator #21
@ -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"),
|
||||||
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
@ -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(
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user