frame for update trigger

This commit is contained in:
Michael Hoennig 2024-02-28 16:53:11 +01:00
parent fef6e1c01c
commit 5276471adb
3 changed files with 78 additions and 9 deletions

View File

@ -105,17 +105,19 @@ public class HsOfficeSepaMandateEntity implements Stringifyable, HasUuid {
.createRole(OWNER, (with) -> { .createRole(OWNER, (with) -> {
with.owningUser(CREATOR); with.owningUser(CREATOR);
with.incomingSuperRole(GLOBAL, ADMIN); with.incomingSuperRole(GLOBAL, ADMIN);
with.outgoingSubRole("bankAccount", REFERRER);
with.permission(ALL); with.permission(ALL);
}) })
.createSubRole(ADMIN, (with) -> { .createSubRole(ADMIN, (with) -> {
with.permission(EDIT); with.permission(EDIT);
}) })
.createSubRole(AGENT, (with) -> { .createSubRole(AGENT, (with) -> {
with.outgoingSubRole("bankAccount", REFERRER);
with.outgoingSubRole("debitorRel", AGENT); with.outgoingSubRole("debitorRel", AGENT);
}) })
.createSubRole(REFERRER, (with) -> { .createSubRole(REFERRER, (with) -> {
with.incomingSuperRole("bankAccount", ADMIN);
with.incomingSuperRole("debitorRel", AGENT); with.incomingSuperRole("debitorRel", AGENT);
with.outgoingSubRole("debitorRel", TENANT);
with.permission(VIEW); with.permission(VIEW);
}); });
} }

View File

@ -13,6 +13,7 @@ import jakarta.validation.constraints.NotNull;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.*; import java.util.*;
import static java.util.Optional.ofNullable;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.autoFetched; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.autoFetched;
import static org.apache.commons.lang3.StringUtils.uncapitalize; import static org.apache.commons.lang3.StringUtils.uncapitalize;
@ -300,6 +301,18 @@ public class RbacView {
return this; return this;
} }
boolean dependsOnColumn(final String columnName) {
return dependsRoleDefOnColumnName(this.superRoleDef, columnName)
|| dependsRoleDefOnColumnName(this.subRoleDef, columnName);
}
private Boolean dependsRoleDefOnColumnName(final RbacRoleDefinition superRoleDef, final String columnName) {
return ofNullable(superRoleDef)
.map(r -> r.getEntityAlias().dependsOnColum())
.map(d -> columnName.equals(d.column))
.orElse(false);
}
public enum GrantType { public enum GrantType {
ROLE_TO_USER, ROLE_TO_USER,
ROLE_TO_ROLE, ROLE_TO_ROLE,

View File

@ -4,10 +4,12 @@ import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacPermissionDefinition;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import static java.util.stream.Collectors.*; import static java.util.stream.Collectors.*;
import static net.hostsharing.hsadminng.rbac.rbacdef.PostgresTriggerReference.NEW; import static net.hostsharing.hsadminng.rbac.rbacdef.PostgresTriggerReference.NEW;
import static net.hostsharing.hsadminng.rbac.rbacdef.PostgresTriggerReference.OLD;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacGrantDefinition.GrantType.*; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacGrantDefinition.GrantType.*;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.getRawTableName; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.getRawTableName;
@ -79,12 +81,19 @@ class RolesGrantsAndPermissionsGenerator {
}); });
}); });
plPgSql.writeLn(""" plPgSql.indented(() -> {
begin plPgSql.writeLn("begin");
if TG_OP <> 'INSERT' then generateCreateRolesAndGrantsAfterInsert(plPgSql);
raise exception 'invalid usage of TRIGGER AFTER INSERT function'; generateUpdateRolesAndGrantsAfterUpdate(plPgSql);
end if; plPgSql.ensureEmptyLine();
"""); plPgSql.writeLn("end; $$;");
});
plPgSql.writeLn();
}
private void generateCreateRolesAndGrantsAfterInsert(final StringWriter plPgSql) {
plPgSql.ensureEmptyLine();
plPgSql.writeLn("if TG_OP = 'INSERT' then");
plPgSql.indented(() -> { plPgSql.indented(() -> {
@ -106,8 +115,53 @@ class RolesGrantsAndPermissionsGenerator {
generateGrants(plPgSql, PERM_TO_ROLE); generateGrants(plPgSql, PERM_TO_ROLE);
}); });
plPgSql.writeLn("end; $$;"); plPgSql.writeLn("end if;");
}
private void generateUpdateRolesAndGrantsAfterUpdate(final StringWriter plPgSql) {
plPgSql.ensureEmptyLine();
plPgSql.writeLn("if TG_OP = 'UPDATE' then");
plPgSql.indented(() -> {
rbacDef.getEntityAliases().values().stream()
.filter(ea -> !rbacDef.isRootEntityAlias(ea))
.filter(ea -> ea.fetchSql() != null)
.forEach(ea -> {
plPgSql.writeLn( ea.fetchSql().sql.replace("${ref}", OLD.name()) + " into " + entityRefVar(OLD, ea) + ";");
});
rbacDef.getEntityAliases().values().stream()
.map(RbacView.EntityAlias::dependsOnColum)
.filter(Objects::nonNull)
.filter(this::isUpdatable)
.map(c -> c.column)
.sorted()
.distinct()
.forEach(columnName -> {
plPgSql.writeLn(); plPgSql.writeLn();
plPgSql.writeLn("if NEW." + columnName + " <> OLD." + columnName + " then");
plPgSql.indented(() -> {
updateGrantsDependingOn(plPgSql, columnName);
});
plPgSql.writeLn("end if;");
});
});
plPgSql.writeLn("end if;");
}
private boolean isUpdatable(final RbacView.Column c) {
return rbacDef.getUpdatableColumns().contains(c);
}
private void updateGrantsDependingOn(final StringWriter plPgSql, final String columnName) {
rbacDef.getGrantDefs().stream()
.filter(RbacView.RbacGrantDefinition::isToCreate)
.filter(g -> g.dependsOnColumn(columnName))
.forEach(g -> {
plPgSql.writeLn("-- TODO: " + g);
});
} }
private void generateGrants(final StringWriter plPgSql, final RbacView.RbacGrantDefinition.GrantType grantType) { private void generateGrants(final StringWriter plPgSql, final RbacView.RbacGrantDefinition.GrantType grantType) {