diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipEntity.java index 82356e28..72185b64 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipEntity.java @@ -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"), diff --git a/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacIdentityViewGenerator.java b/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacIdentityViewGenerator.java new file mode 100644 index 00000000..ed51061b --- /dev/null +++ b/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacIdentityViewGenerator.java @@ -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)); + } +} diff --git a/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacRestrictedViewGenerator.java b/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacRestrictedViewGenerator.java new file mode 100644 index 00000000..3755b20f --- /dev/null +++ b/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacRestrictedViewGenerator.java @@ -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)); + } +} diff --git a/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacRoleDescriptorsGenerator.java b/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacRoleDescriptorsGenerator.java new file mode 100644 index 00000000..661f9091 --- /dev/null +++ b/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacRoleDescriptorsGenerator.java @@ -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)); + } +} diff --git a/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacView.java b/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacView.java index f193903d..b60a1d29 100644 --- a/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacView.java +++ b/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacView.java @@ -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 userDefs = new LinkedHashSet<>(); @@ -47,6 +46,7 @@ public class RbacView { private final Set 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 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; diff --git a/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacViewPostgresGenerator.java b/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacViewPostgresGenerator.java index 5a4fdd48..11c2dc8c 100644 --- a/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacViewPostgresGenerator.java +++ b/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacViewPostgresGenerator.java @@ -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( diff --git a/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RolesGrantsAndPermissionsGenerator.java b/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RolesGrantsAndPermissionsGenerator.java index 199cef9d..7f44c84c 100644 --- a/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RolesGrantsAndPermissionsGenerator.java +++ b/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RolesGrantsAndPermissionsGenerator.java @@ -22,7 +22,6 @@ class RolesGrantsAndPermissionsGenerator { private final RbacView rbacDef; private final Set 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)