Compare commits
3 Commits
92086d8634
...
b9706ee4c3
Author | SHA1 | Date | |
---|---|---|---|
|
b9706ee4c3 | ||
|
c80dfc2fa8 | ||
|
001ab652c7 |
@ -102,16 +102,16 @@ public class HsOfficePartnerEntity implements Stringifyable, RbacObject {
|
|||||||
usingDefaultCase(),
|
usingDefaultCase(),
|
||||||
directlyFetchedByDependsOnColumn(),
|
directlyFetchedByDependsOnColumn(),
|
||||||
dependsOnColumn("partnerRelUuid"))
|
dependsOnColumn("partnerRelUuid"))
|
||||||
.createPermission(DELETE).grantedTo("partnerRel", ADMIN)
|
.createPermission(DELETE).grantedTo("partnerRel", OWNER)
|
||||||
.createPermission(UPDATE).grantedTo("partnerRel", AGENT)
|
.createPermission(UPDATE).grantedTo("partnerRel", ADMIN)
|
||||||
.createPermission(SELECT).grantedTo("partnerRel", TENANT)
|
.createPermission(SELECT).grantedTo("partnerRel", TENANT)
|
||||||
|
|
||||||
.importSubEntityAlias("partnerDetails", HsOfficePartnerDetailsEntity.class,
|
.importSubEntityAlias("partnerDetails", HsOfficePartnerDetailsEntity.class,
|
||||||
directlyFetchedByDependsOnColumn(),
|
directlyFetchedByDependsOnColumn(),
|
||||||
dependsOnColumn("detailsUuid"))
|
dependsOnColumn("detailsUuid"))
|
||||||
.createPermission("partnerDetails", DELETE).grantedTo("partnerRel", ADMIN)
|
.createPermission("partnerDetails", DELETE).grantedTo("partnerRel", OWNER)
|
||||||
.createPermission("partnerDetails", UPDATE).grantedTo("partnerRel", AGENT)
|
.createPermission("partnerDetails", UPDATE).grantedTo("partnerRel", AGENT)
|
||||||
.createPermission("partnerDetails", SELECT).grantedTo("partnerRel", AGENT);
|
.createPermission("partnerDetails", SELECT).grantedTo("partnerRel", AGENT); // not TENANT!
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
|
@ -16,6 +16,8 @@ import java.io.IOException;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.*;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.*;
|
||||||
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.CaseDef.inCaseOf;
|
||||||
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.CaseDef.inOtherCases;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Nullable.NOT_NULL;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Nullable.NOT_NULL;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
|
||||||
@ -110,14 +112,13 @@ public class HsOfficeRelationEntity implements RbacObject, Stringifyable {
|
|||||||
with.permission(DELETE);
|
with.permission(DELETE);
|
||||||
})
|
})
|
||||||
.createSubRole(ADMIN, (with) -> {
|
.createSubRole(ADMIN, (with) -> {
|
||||||
with.incomingSuperRole("anchorPerson", ADMIN);
|
|
||||||
with.outgoingSubRole("anchorPerson", OWNER);
|
with.outgoingSubRole("anchorPerson", OWNER);
|
||||||
with.permission(UPDATE);
|
with.permission(UPDATE);
|
||||||
})
|
})
|
||||||
.createSubRole(AGENT, (with) -> {
|
.createSubRole(AGENT, (with) -> {
|
||||||
|
with.incomingSuperRole("anchorPerson", ADMIN);
|
||||||
})
|
})
|
||||||
.createSubRole(TENANT, (with) -> {
|
.createSubRole(TENANT, (with) -> {
|
||||||
with.incomingSuperRole("holderPerson", ADMIN);
|
|
||||||
with.incomingSuperRole("contact", ADMIN);
|
with.incomingSuperRole("contact", ADMIN);
|
||||||
with.outgoingSubRole("anchorPerson", REFERRER);
|
with.outgoingSubRole("anchorPerson", REFERRER);
|
||||||
with.outgoingSubRole("holderPerson", REFERRER);
|
with.outgoingSubRole("holderPerson", REFERRER);
|
||||||
@ -125,22 +126,25 @@ public class HsOfficeRelationEntity implements RbacObject, Stringifyable {
|
|||||||
with.permission(SELECT);
|
with.permission(SELECT);
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
//FIXME: .inCaseOf("DEBITOR")
|
// inCaseOf("DEBITOR", then -> {}), TODO.spec: needs to be defined
|
||||||
inOtherCases(then -> {
|
inOtherCases(then -> {
|
||||||
then.createRole(OWNER, (with) -> {
|
then.createRole(OWNER, (with) -> {
|
||||||
with.owningUser(CREATOR);
|
with.owningUser(CREATOR);
|
||||||
with.incomingSuperRole(GLOBAL, ADMIN);
|
with.incomingSuperRole(GLOBAL, ADMIN);
|
||||||
|
with.incomingSuperRole("anchorPerson", ADMIN);
|
||||||
with.permission(DELETE);
|
with.permission(DELETE);
|
||||||
})
|
})
|
||||||
.createSubRole(ADMIN, (with) -> {
|
.createSubRole(ADMIN, (with) -> {
|
||||||
with.incomingSuperRole("anchorPerson", ADMIN);
|
|
||||||
with.permission(UPDATE);
|
with.permission(UPDATE);
|
||||||
})
|
})
|
||||||
.createSubRole(AGENT, (with) -> {
|
.createSubRole(AGENT, (with) -> {
|
||||||
|
// TODO.spec: we need relation:PROXY, to allow changing the relation contact.
|
||||||
|
// the alternative would be to move this to the relation:ADMIN role,
|
||||||
|
// but then the partner holder person could update the partner relation itself,
|
||||||
|
// see partner entity.
|
||||||
with.incomingSuperRole("holderPerson", ADMIN);
|
with.incomingSuperRole("holderPerson", ADMIN);
|
||||||
})
|
})
|
||||||
.createSubRole(TENANT, (with) -> {
|
.createSubRole(TENANT, (with) -> {
|
||||||
with.incomingSuperRole("holderPerson", ADMIN);
|
|
||||||
with.incomingSuperRole("contact", ADMIN);
|
with.incomingSuperRole("contact", ADMIN);
|
||||||
with.outgoingSubRole("anchorPerson", REFERRER);
|
with.outgoingSubRole("anchorPerson", REFERRER);
|
||||||
with.outgoingSubRole("holderPerson", REFERRER);
|
with.outgoingSubRole("holderPerson", REFERRER);
|
||||||
|
@ -26,14 +26,18 @@ import java.lang.reflect.Method;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static java.lang.reflect.Modifier.isStatic;
|
import static java.lang.reflect.Modifier.isStatic;
|
||||||
import static java.util.Arrays.stream;
|
import static java.util.Arrays.stream;
|
||||||
import static java.util.Optional.ofNullable;
|
import static java.util.Optional.ofNullable;
|
||||||
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.ColumnValue.usingDefaultCase;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Nullable.NOT_NULL;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Nullable.NOT_NULL;
|
||||||
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacGrantDefinition.GrantType.PERM_TO_ROLE;
|
||||||
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.Part.AUTO_FETCH;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.Part.AUTO_FETCH;
|
||||||
|
import static org.apache.commons.collections4.SetUtils.hashSet;
|
||||||
import static org.apache.commons.lang3.StringUtils.uncapitalize;
|
import static org.apache.commons.lang3.StringUtils.uncapitalize;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ -60,14 +64,17 @@ public class RbacView {
|
|||||||
};
|
};
|
||||||
private final Set<String> updatableColumns = new LinkedHashSet<>();
|
private final Set<String> updatableColumns = new LinkedHashSet<>();
|
||||||
private final Set<RbacGrantDefinition> grantDefs = new LinkedHashSet<>();
|
private final Set<RbacGrantDefinition> grantDefs = new LinkedHashSet<>();
|
||||||
|
private final Set<CaseDef> allCases = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
private String discriminatorColumName;
|
||||||
|
private CaseDef processingCase;
|
||||||
private SQL identityViewSqlQuery;
|
private SQL identityViewSqlQuery;
|
||||||
private SQL orderBySqlExpression;
|
private SQL orderBySqlExpression;
|
||||||
private EntityAlias rootEntityAliasProxy;
|
private EntityAlias rootEntityAliasProxy;
|
||||||
private RbacRoleDefinition previousRoleDef;
|
private RbacRoleDefinition previousRoleDef;
|
||||||
private final Map<String, String> cases = new HashMap<>() {
|
private final Map<String, CaseDef> cases = new LinkedHashMap<>() {
|
||||||
@Override
|
@Override
|
||||||
public String put(final String key, final String value) {
|
public CaseDef put(final String key, final CaseDef value) {
|
||||||
if (containsKey(key)) {
|
if (containsKey(key)) {
|
||||||
throw new IllegalArgumentException("duplicate case: " + key);
|
throw new IllegalArgumentException("duplicate case: " + key);
|
||||||
}
|
}
|
||||||
@ -247,7 +254,11 @@ public class RbacView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private RbacPermissionDefinition createPermission(final EntityAlias entityAlias, final Permission permission) {
|
private RbacPermissionDefinition createPermission(final EntityAlias entityAlias, final Permission permission) {
|
||||||
return new RbacPermissionDefinition(entityAlias, permission, null, true);
|
return permDefs.stream()
|
||||||
|
.filter(p -> p.permission == permission && p.entityAlias == entityAlias)
|
||||||
|
.findFirst()
|
||||||
|
// .map(g -> g.forCase(processingCase)) TODO: not implemented case dependent
|
||||||
|
.orElseGet(() -> new RbacPermissionDefinition(entityAlias, permission, null, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public <EC extends RbacObject> RbacView declarePlaceholderEntityAliases(final String... aliasNames) {
|
public <EC extends RbacObject> RbacView declarePlaceholderEntityAliases(final String... aliasNames) {
|
||||||
@ -292,7 +303,7 @@ public class RbacView {
|
|||||||
if (rootEntityAliasProxy != null) {
|
if (rootEntityAliasProxy != null) {
|
||||||
throw new IllegalStateException("there is already an entityAliasProxy: " + rootEntityAliasProxy);
|
throw new IllegalStateException("there is already an entityAliasProxy: " + rootEntityAliasProxy);
|
||||||
}
|
}
|
||||||
rootEntityAliasProxy = importEntityAliasImpl(aliasName, entityClass, fetchSql, dependsOnColum, false, NOT_NULL);
|
rootEntityAliasProxy = importEntityAliasImpl(aliasName, entityClass, forCase, fetchSql, dependsOnColum, false, NOT_NULL);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,7 +322,7 @@ public class RbacView {
|
|||||||
public RbacView importSubEntityAlias(
|
public RbacView importSubEntityAlias(
|
||||||
final String aliasName, final Class<? extends RbacObject> entityClass,
|
final String aliasName, final Class<? extends RbacObject> entityClass,
|
||||||
final SQL fetchSql, final Column dependsOnColum) {
|
final SQL fetchSql, final Column dependsOnColum) {
|
||||||
importEntityAliasImpl(aliasName, entityClass, fetchSql, dependsOnColum, true, NOT_NULL);
|
importEntityAliasImpl(aliasName, entityClass, usingDefaultCase(), fetchSql, dependsOnColum, true, NOT_NULL);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,17 +356,17 @@ public class RbacView {
|
|||||||
public RbacView importEntityAlias(
|
public RbacView importEntityAlias(
|
||||||
final String aliasName, final Class<? extends RbacObject> entityClass,
|
final String aliasName, final Class<? extends RbacObject> entityClass,
|
||||||
final Column dependsOnColum, final SQL fetchSql, final Nullable nullable) {
|
final Column dependsOnColum, final SQL fetchSql, final Nullable nullable) {
|
||||||
importEntityAliasImpl(aliasName, entityClass, fetchSql, dependsOnColum, false, nullable);
|
importEntityAliasImpl(aliasName, entityClass, usingDefaultCase(), fetchSql, dependsOnColum, false, nullable);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private EntityAlias importEntityAliasImpl(
|
private EntityAlias importEntityAliasImpl(
|
||||||
final String aliasName, final Class<? extends RbacObject> entityClass,
|
final String aliasName, final Class<? extends RbacObject> entityClass, final ColumnValue forCase,
|
||||||
final SQL fetchSql, final Column dependsOnColum, boolean asSubEntity, final Nullable nullable) {
|
final SQL fetchSql, final Column dependsOnColum, boolean asSubEntity, final Nullable nullable) {
|
||||||
final var entityAlias = new EntityAlias(aliasName, entityClass, fetchSql, dependsOnColum, asSubEntity, nullable);
|
final var entityAlias = new EntityAlias(aliasName, entityClass, fetchSql, dependsOnColum, asSubEntity, nullable);
|
||||||
entityAliases.put(aliasName, entityAlias);
|
entityAliases.put(aliasName, entityAlias);
|
||||||
try {
|
try {
|
||||||
importAsAlias(aliasName, rbacDefinition(entityClass), asSubEntity);
|
importAsAlias(aliasName, rbacDefinition(entityClass), forCase, asSubEntity);
|
||||||
} catch (final ReflectiveOperationException exc) {
|
} catch (final ReflectiveOperationException exc) {
|
||||||
throw new RuntimeException("cannot import entity: " + entityClass, exc);
|
throw new RuntimeException("cannot import entity: " + entityClass, exc);
|
||||||
}
|
}
|
||||||
@ -367,7 +378,7 @@ public class RbacView {
|
|||||||
return (RbacView) entityClass.getMethod("rbac").invoke(null);
|
return (RbacView) entityClass.getMethod("rbac").invoke(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private RbacView importAsAlias(final String aliasName, final RbacView importedRbacView, final boolean asSubEntity) {
|
private RbacView importAsAlias(final String aliasName, final RbacView importedRbacView, final ColumnValue forCase, final boolean asSubEntity) {
|
||||||
final var mapper = new AliasNameMapper(importedRbacView, aliasName,
|
final var mapper = new AliasNameMapper(importedRbacView, aliasName,
|
||||||
asSubEntity ? entityAliases.keySet() : null);
|
asSubEntity ? entityAliases.keySet() : null);
|
||||||
importedRbacView.getEntityAliases().values().stream()
|
importedRbacView.getEntityAliases().values().stream()
|
||||||
@ -382,7 +393,8 @@ public class RbacView {
|
|||||||
new RbacRoleDefinition(findEntityAlias(mapper.map(roleDef.entityAlias.aliasName)), roleDef.role);
|
new RbacRoleDefinition(findEntityAlias(mapper.map(roleDef.entityAlias.aliasName)), roleDef.role);
|
||||||
});
|
});
|
||||||
importedRbacView.getGrantDefs().forEach(grantDef -> {
|
importedRbacView.getGrantDefs().forEach(grantDef -> {
|
||||||
if (grantDef.grantType() == RbacGrantDefinition.GrantType.ROLE_TO_ROLE) {
|
if ( grantDef.grantType() == RbacGrantDefinition.GrantType.ROLE_TO_ROLE &&
|
||||||
|
grantDef.matchesCase(forCase) ) {
|
||||||
final var importedGrantDef = findOrCreateGrantDef(
|
final var importedGrantDef = findOrCreateGrantDef(
|
||||||
findRbacRole(
|
findRbacRole(
|
||||||
mapper.map(grantDef.getSubRoleDef().entityAlias.aliasName),
|
mapper.map(grantDef.getSubRoleDef().entityAlias.aliasName),
|
||||||
@ -400,8 +412,15 @@ public class RbacView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public RbacView switchOnColumn(final String discriminatorColumName, final CaseDef... caseDefs) {
|
public RbacView switchOnColumn(final String discriminatorColumName, final CaseDef... caseDefs) {
|
||||||
|
this.discriminatorColumName = discriminatorColumName;
|
||||||
|
allCases.addAll(stream(caseDefs).toList());
|
||||||
|
|
||||||
// FIXME: currently only the default case is executed
|
// FIXME: currently only the default case is executed
|
||||||
stream(caseDefs).filter(caseDef -> caseDef.val == null).findAny().orElseThrow().def.accept(this);
|
stream(caseDefs).forEach(caseDef -> {
|
||||||
|
this.processingCase = caseDef;
|
||||||
|
caseDef.def.accept(this);
|
||||||
|
this.processingCase = null;
|
||||||
|
});
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -463,7 +482,15 @@ public class RbacView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void generateWithBaseFileName(final String baseFileName) {
|
public void generateWithBaseFileName(final String baseFileName) {
|
||||||
new RbacViewMermaidFlowchartGenerator(this).generateToMarkdownFile(Path.of(OUTPUT_BASEDIR, baseFileName + ".md"));
|
if (allCases.size() > 1) {
|
||||||
|
allCases.forEach(caseDef -> {
|
||||||
|
final var fileName = baseFileName + (caseDef.isDefaultCase() ? "" : "-" + caseDef.val) + ".md";
|
||||||
|
new RbacViewMermaidFlowchartGenerator(this, caseDef)
|
||||||
|
.generateToMarkdownFile(Path.of(OUTPUT_BASEDIR, fileName));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
new RbacViewMermaidFlowchartGenerator(this).generateToMarkdownFile(Path.of(OUTPUT_BASEDIR, baseFileName + ".md"));
|
||||||
|
}
|
||||||
new RbacViewPostgresGenerator(this).generateToChangeLog(Path.of(OUTPUT_BASEDIR, baseFileName + ".sql"));
|
new RbacViewPostgresGenerator(this).generateToChangeLog(Path.of(OUTPUT_BASEDIR, baseFileName + ".sql"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -488,25 +515,6 @@ public class RbacView {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class CaseDef {
|
|
||||||
|
|
||||||
private final String val;
|
|
||||||
private final Consumer<RbacView> def;
|
|
||||||
|
|
||||||
public CaseDef(final String discriminatorColumnValue, final Consumer<RbacView> def) {
|
|
||||||
this.val = discriminatorColumnValue;
|
|
||||||
this.def = def;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CaseDef inCaseOf(final String discriminatorColumnValue, final Consumer<RbacView> def) {
|
|
||||||
return new CaseDef(discriminatorColumnValue, def);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CaseDef inOtherCases(final Consumer<RbacView> def) {
|
|
||||||
return new CaseDef(null, def);
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Nullable {
|
public enum Nullable {
|
||||||
NOT_NULL, // DEFAULT
|
NOT_NULL, // DEFAULT
|
||||||
NULLABLE
|
NULLABLE
|
||||||
@ -522,26 +530,28 @@ public class RbacView {
|
|||||||
private final RbacPermissionDefinition permDef;
|
private final RbacPermissionDefinition permDef;
|
||||||
private boolean assumed = true;
|
private boolean assumed = true;
|
||||||
private boolean toCreate = false;
|
private boolean toCreate = false;
|
||||||
private String onlyInCaseOf;
|
private Set<CaseDef> forCases = new HashSet<>();
|
||||||
private String exceptInCaseOf;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
final var arrow = isConditional()
|
final var arrow = isAssumed() ? " --> " : " -- // --> ";
|
||||||
? (isAssumed() ? " -- ?? --> " : " -- ?//? --> ")
|
final var grant = switch (grantType()) {
|
||||||
: (isAssumed() ? " --> " : " -- // --> ");
|
|
||||||
return switch (grantType()) {
|
|
||||||
case ROLE_TO_USER -> userDef.toString() + arrow + subRoleDef.toString();
|
case ROLE_TO_USER -> userDef.toString() + arrow + subRoleDef.toString();
|
||||||
case ROLE_TO_ROLE -> superRoleDef + arrow + subRoleDef;
|
case ROLE_TO_ROLE -> superRoleDef + arrow + subRoleDef;
|
||||||
case PERM_TO_ROLE -> superRoleDef + arrow + permDef;
|
case PERM_TO_ROLE -> superRoleDef + arrow + permDef;
|
||||||
};
|
};
|
||||||
|
final var condition = isConditional()
|
||||||
|
? (" (" +forCases.stream().map(CaseDef::toString).collect(Collectors.joining("||")) + ")")
|
||||||
|
: "";
|
||||||
|
return grant + condition;
|
||||||
}
|
}
|
||||||
|
|
||||||
RbacGrantDefinition(final RbacRoleDefinition subRoleDef, final RbacRoleDefinition superRoleDef) {
|
RbacGrantDefinition(final RbacRoleDefinition subRoleDef, final RbacRoleDefinition superRoleDef, final CaseDef forCase) {
|
||||||
this.userDef = null;
|
this.userDef = null;
|
||||||
this.subRoleDef = subRoleDef;
|
this.subRoleDef = subRoleDef;
|
||||||
this.superRoleDef = superRoleDef;
|
this.superRoleDef = superRoleDef;
|
||||||
this.permDef = null;
|
this.permDef = null;
|
||||||
|
this.forCases = forCase != null ? hashSet(forCase) : null;
|
||||||
register(this);
|
register(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -567,7 +577,7 @@ public class RbacView {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
GrantType grantType() {
|
GrantType grantType() {
|
||||||
return permDef != null ? GrantType.PERM_TO_ROLE
|
return permDef != null ? PERM_TO_ROLE
|
||||||
: userDef != null ? GrantType.ROLE_TO_USER
|
: userDef != null ? GrantType.ROLE_TO_USER
|
||||||
: GrantType.ROLE_TO_ROLE;
|
: GrantType.ROLE_TO_ROLE;
|
||||||
}
|
}
|
||||||
@ -576,8 +586,31 @@ public class RbacView {
|
|||||||
return assumed;
|
return assumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RbacGrantDefinition forCase(final CaseDef processingCase) {
|
||||||
|
forCases.add(processingCase);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
boolean isConditional() {
|
boolean isConditional() {
|
||||||
return onlyInCaseOf != null;
|
return forCases != null && !forCases.isEmpty() && forCases.size()<allCases.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean matchesCase(final ColumnValue requestedCase) {
|
||||||
|
if (forCases == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
final var noCasesDefined = forCases.isEmpty();
|
||||||
|
final var generateForAllCases = requestedCase == null;
|
||||||
|
final boolean isGrantedForRequestedCase = forCases.stream().anyMatch(c -> c.isCase(requestedCase));
|
||||||
|
return noCasesDefined || generateForAllCases || isGrantedForRequestedCase;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean matchesCase(final CaseDef requestedCase) {
|
||||||
|
final var noCasesDefined = forCases.isEmpty();
|
||||||
|
final var generateForAllCases = requestedCase == null;
|
||||||
|
final boolean isGrantedForRequestedCase = forCases.contains(requestedCase);
|
||||||
|
return noCasesDefined || generateForAllCases || isGrantedForRequestedCase;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isToCreate() {
|
boolean isToCreate() {
|
||||||
@ -606,17 +639,6 @@ public class RbacView {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RbacGrantDefinition onlyInCaseOf(final String caseName) {
|
|
||||||
this.onlyInCaseOf = caseName;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public RbacGrantDefinition exceptInCaseOf(final String caseName) {
|
|
||||||
this.exceptInCaseOf = caseName;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum GrantType {
|
public enum GrantType {
|
||||||
ROLE_TO_USER,
|
ROLE_TO_USER,
|
||||||
ROLE_TO_ROLE,
|
ROLE_TO_ROLE,
|
||||||
@ -840,7 +862,7 @@ public class RbacView {
|
|||||||
|
|
||||||
private RbacGrantDefinition findOrCreateGrantDef(final RbacPermissionDefinition permDef, final RbacRoleDefinition roleDef) {
|
private RbacGrantDefinition findOrCreateGrantDef(final RbacPermissionDefinition permDef, final RbacRoleDefinition roleDef) {
|
||||||
return grantDefs.stream()
|
return grantDefs.stream()
|
||||||
.filter(g -> g.permDef == permDef && g.subRoleDef == roleDef)
|
.filter(g -> g.permDef == permDef && g.superRoleDef == roleDef)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElseGet(() -> new RbacGrantDefinition(permDef, roleDef));
|
.orElseGet(() -> new RbacGrantDefinition(permDef, roleDef));
|
||||||
}
|
}
|
||||||
@ -848,10 +870,12 @@ public class RbacView {
|
|||||||
private RbacGrantDefinition findOrCreateGrantDef(
|
private RbacGrantDefinition findOrCreateGrantDef(
|
||||||
final RbacRoleDefinition subRoleDefinition,
|
final RbacRoleDefinition subRoleDefinition,
|
||||||
final RbacRoleDefinition superRoleDefinition) {
|
final RbacRoleDefinition superRoleDefinition) {
|
||||||
return grantDefs.stream()
|
final var distinctGrantDef = grantDefs.stream()
|
||||||
.filter(g -> g.subRoleDef == subRoleDefinition && g.superRoleDef == superRoleDefinition)
|
.filter(g -> g.subRoleDef == subRoleDefinition && g.superRoleDef == superRoleDefinition)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElseGet(() -> new RbacGrantDefinition(subRoleDefinition, superRoleDefinition));
|
.map(g -> g.forCase(processingCase))
|
||||||
|
.orElseGet(() -> new RbacGrantDefinition(subRoleDefinition, superRoleDefinition, processingCase));
|
||||||
|
return distinctGrantDef;
|
||||||
}
|
}
|
||||||
|
|
||||||
record EntityAlias(String aliasName, Class<? extends RbacObject> entityClass, SQL fetchSql, Column dependsOnColum, boolean isSubEntity, Nullable nullable) {
|
record EntityAlias(String aliasName, Class<? extends RbacObject> entityClass, SQL fetchSql, Column dependsOnColum, boolean isSubEntity, Nullable nullable) {
|
||||||
@ -1109,6 +1133,56 @@ public class RbacView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class CaseDef {
|
||||||
|
|
||||||
|
final String val;
|
||||||
|
final Consumer<RbacView> def;
|
||||||
|
|
||||||
|
private CaseDef(final String discriminatorColumnValue, final Consumer<RbacView> def) {
|
||||||
|
this.val = discriminatorColumnValue;
|
||||||
|
this.def = def;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static CaseDef inCaseOf(final String discriminatorColumnValue, final Consumer<RbacView> def) {
|
||||||
|
return new CaseDef(discriminatorColumnValue, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CaseDef inOtherCases(final Consumer<RbacView> def) {
|
||||||
|
return new CaseDef(null, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return ofNullable(val).map(String::hashCode).orElse(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object other) {
|
||||||
|
if (this == other)
|
||||||
|
return true;
|
||||||
|
if (other == null || getClass() != other.getClass())
|
||||||
|
return false;
|
||||||
|
final CaseDef caseDef = (CaseDef) other;
|
||||||
|
return Objects.equals(val, caseDef.val);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isDefaultCase() {
|
||||||
|
return val == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return isDefaultCase()
|
||||||
|
? "inOtherCases"
|
||||||
|
: "inCaseOf:" + val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCase(final ColumnValue requestedCase) {
|
||||||
|
return Objects.equals(requestedCase.value, this.val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void generateRbacView(final Class<? extends RbacObject> c) {
|
private static void generateRbacView(final Class<? extends RbacObject> c) {
|
||||||
final Method mainMethod = stream(c.getMethods()).filter(
|
final Method mainMethod = stream(c.getMethods()).filter(
|
||||||
m -> isStatic(m.getModifiers()) && m.getName().equals("main")
|
m -> isStatic(m.getModifiers()) && m.getName().equals("main")
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.hostsharing.hsadminng.rbac.rbacdef;
|
package net.hostsharing.hsadminng.rbac.rbacdef;
|
||||||
|
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
|
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.CaseDef;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
@ -15,10 +16,13 @@ public class RbacViewMermaidFlowchartGenerator {
|
|||||||
public static final String HOSTSHARING_DARK_BLUE = "#274d6e";
|
public static final String HOSTSHARING_DARK_BLUE = "#274d6e";
|
||||||
public static final String HOSTSHARING_LIGHT_BLUE = "#99bcdb";
|
public static final String HOSTSHARING_LIGHT_BLUE = "#99bcdb";
|
||||||
private final RbacView rbacDef;
|
private final RbacView rbacDef;
|
||||||
|
|
||||||
|
private final CaseDef forCase;
|
||||||
private final StringWriter flowchart = new StringWriter();
|
private final StringWriter flowchart = new StringWriter();
|
||||||
|
|
||||||
public RbacViewMermaidFlowchartGenerator(final RbacView rbacDef) {
|
public RbacViewMermaidFlowchartGenerator(final RbacView rbacDef, final CaseDef forCase) {
|
||||||
this.rbacDef = rbacDef;
|
this.rbacDef = rbacDef;
|
||||||
|
this.forCase = forCase;
|
||||||
flowchart.writeLn("""
|
flowchart.writeLn("""
|
||||||
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||||
flowchart TB
|
flowchart TB
|
||||||
@ -26,6 +30,10 @@ public class RbacViewMermaidFlowchartGenerator {
|
|||||||
renderEntitySubgraphs();
|
renderEntitySubgraphs();
|
||||||
renderGrants();
|
renderGrants();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RbacViewMermaidFlowchartGenerator(final RbacView rbacDef) {
|
||||||
|
this(rbacDef, null);
|
||||||
|
}
|
||||||
private void renderEntitySubgraphs() {
|
private void renderEntitySubgraphs() {
|
||||||
rbacDef.getEntityAliases().values().stream()
|
rbacDef.getEntityAliases().values().stream()
|
||||||
.filter(entityAlias -> !rbacDef.isEntityAliasProxy(entityAlias))
|
.filter(entityAlias -> !rbacDef.isEntityAliasProxy(entityAlias))
|
||||||
@ -99,6 +107,7 @@ public class RbacViewMermaidFlowchartGenerator {
|
|||||||
private void renderGrants(final RbacView.RbacGrantDefinition.GrantType grantType, final String comment) {
|
private void renderGrants(final RbacView.RbacGrantDefinition.GrantType grantType, final String comment) {
|
||||||
final var grantsOfRequestedType = rbacDef.getGrantDefs().stream()
|
final var grantsOfRequestedType = rbacDef.getGrantDefs().stream()
|
||||||
.filter(g -> g.grantType() == grantType)
|
.filter(g -> g.grantType() == grantType)
|
||||||
|
.filter(this::isToBeRenderedInThisGraph)
|
||||||
.toList();
|
.toList();
|
||||||
if ( !grantsOfRequestedType.isEmpty()) {
|
if ( !grantsOfRequestedType.isEmpty()) {
|
||||||
flowchart.ensureSingleEmptyLine();
|
flowchart.ensureSingleEmptyLine();
|
||||||
@ -107,12 +116,19 @@ public class RbacViewMermaidFlowchartGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isToBeRenderedInThisGraph(final RbacView.RbacGrantDefinition g) {
|
||||||
|
if ( g.grantType() != ROLE_TO_ROLE )
|
||||||
|
return true;
|
||||||
|
if ( forCase == null && !g.isConditional() )
|
||||||
|
return true;
|
||||||
|
final var isToBeRenderedInThisGraph = g.getForCases() == null || g.getForCases().contains(forCase);
|
||||||
|
return isToBeRenderedInThisGraph;
|
||||||
|
}
|
||||||
|
|
||||||
private String grantDef(final RbacView.RbacGrantDefinition grant) {
|
private String grantDef(final RbacView.RbacGrantDefinition grant) {
|
||||||
final var arrow = (grant.isToCreate() ? " ==>" : " -.->")
|
final var arrow = (grant.isToCreate() ? " ==>" : " -.->")
|
||||||
+ (grant.isConditional()
|
+ (grant.isAssumed() ? " " : "|XX| ");
|
||||||
? (grant.isAssumed() ? " |??| " : "|?XX?| ")
|
final var grantDef = switch (grant.grantType()) {
|
||||||
: (grant.isAssumed() ? " " : "|XX| "));
|
|
||||||
return switch (grant.grantType()) {
|
|
||||||
case ROLE_TO_USER ->
|
case ROLE_TO_USER ->
|
||||||
// TODO: other user types not implemented yet
|
// TODO: other user types not implemented yet
|
||||||
"user:creator" + arrow + roleId(grant.getSubRoleDef());
|
"user:creator" + arrow + roleId(grant.getSubRoleDef());
|
||||||
@ -120,6 +136,7 @@ public class RbacViewMermaidFlowchartGenerator {
|
|||||||
roleId(grant.getSuperRoleDef()) + arrow + roleId(grant.getSubRoleDef());
|
roleId(grant.getSuperRoleDef()) + arrow + roleId(grant.getSubRoleDef());
|
||||||
case PERM_TO_ROLE -> roleId(grant.getSuperRoleDef()) + arrow + permId(grant.getPermDef());
|
case PERM_TO_ROLE -> roleId(grant.getSuperRoleDef()) + arrow + permId(grant.getPermDef());
|
||||||
};
|
};
|
||||||
|
return grantDef;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String permDef(final RbacView.RbacPermissionDefinition perm) {
|
private String permDef(final RbacView.RbacPermissionDefinition perm) {
|
||||||
@ -148,16 +165,16 @@ public class RbacViewMermaidFlowchartGenerator {
|
|||||||
Files.writeString(
|
Files.writeString(
|
||||||
path,
|
path,
|
||||||
"""
|
"""
|
||||||
### rbac %{entityAlias}
|
### rbac %{entityAlias}
|
||||||
|
|
||||||
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
%{flowchart}
|
%{flowchart}
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
.replace("%{entityAlias}", rbacDef.getRootEntityAlias().aliasName())
|
.replace("%{entityAlias}", rbacDef.getRootEntityAlias().aliasName())
|
||||||
.replace("%{flowchart}", flowchart.toString()),
|
.replace("%{flowchart}", flowchart.toString()),
|
||||||
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||||
System.out.println("Markdown-File: " + path.toAbsolutePath());
|
System.out.println("Markdown-File: " + path.toAbsolutePath());
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
package net.hostsharing.hsadminng.rbac.rbacdef;
|
package net.hostsharing.hsadminng.rbac.rbacdef;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.CaseDef;
|
||||||
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacGrantDefinition;
|
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacGrantDefinition;
|
||||||
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacPermissionDefinition;
|
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.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static java.util.Optional.ofNullable;
|
import static java.util.Optional.ofNullable;
|
||||||
@ -189,7 +191,25 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
createRolesWithGrantsSql(plPgSql, REFERRER);
|
createRolesWithGrantsSql(plPgSql, REFERRER);
|
||||||
|
|
||||||
generateGrants(plPgSql, ROLE_TO_USER);
|
generateGrants(plPgSql, ROLE_TO_USER);
|
||||||
|
|
||||||
generateGrants(plPgSql, ROLE_TO_ROLE);
|
generateGrants(plPgSql, ROLE_TO_ROLE);
|
||||||
|
if (!rbacDef.getAllCases().isEmpty()) {
|
||||||
|
plPgSql.writeLn();
|
||||||
|
final var ifOrElsIf = new AtomicReference<>("IF ");
|
||||||
|
rbacDef.getAllCases().forEach(caseDef -> {
|
||||||
|
if (caseDef.val != null) {
|
||||||
|
plPgSql.writeLn(ifOrElsIf + "NEW." + rbacDef.getDiscriminatorColumName() + " = '" + caseDef.val + "' THEN");
|
||||||
|
} else {
|
||||||
|
plPgSql.writeLn("ELSE");
|
||||||
|
}
|
||||||
|
plPgSql.indented(() -> {
|
||||||
|
generateGrants(plPgSql, ROLE_TO_ROLE, caseDef);
|
||||||
|
});
|
||||||
|
ifOrElsIf.set("ELSIF ");
|
||||||
|
});
|
||||||
|
plPgSql.writeLn("END IF;");
|
||||||
|
}
|
||||||
|
|
||||||
generateGrants(plPgSql, PERM_TO_ROLE);
|
generateGrants(plPgSql, PERM_TO_ROLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,9 +287,19 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
return isInsertPermissionGrant;
|
return isInsertPermissionGrant;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void generateGrants(final StringWriter plPgSql, final RbacGrantDefinition.GrantType grantType, final CaseDef caseDef) {
|
||||||
|
rbacGrants.stream()
|
||||||
|
.filter(g -> g.matchesCase(caseDef))
|
||||||
|
.filter(g -> g.grantType() == grantType)
|
||||||
|
.map(this::generateGrant)
|
||||||
|
.sorted()
|
||||||
|
.forEach(text -> plPgSql.writeLn(text, with("ref", NEW.name())));
|
||||||
|
}
|
||||||
|
|
||||||
private void generateGrants(final StringWriter plPgSql, final RbacGrantDefinition.GrantType grantType) {
|
private void generateGrants(final StringWriter plPgSql, final RbacGrantDefinition.GrantType grantType) {
|
||||||
plPgSql.ensureSingleEmptyLine();
|
plPgSql.ensureSingleEmptyLine();
|
||||||
rbacGrants.stream()
|
rbacGrants.stream()
|
||||||
|
.filter(g -> !g.isConditional())
|
||||||
.filter(g -> g.grantType() == grantType)
|
.filter(g -> g.grantType() == grantType)
|
||||||
.map(this::generateGrant)
|
.map(this::generateGrant)
|
||||||
.sorted()
|
.sorted()
|
||||||
@ -302,7 +332,7 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
.replace("${superRoleRef}", roleRef(NEW, grantDef.getSuperRoleDef()));
|
.replace("${superRoleRef}", roleRef(NEW, grantDef.getSuperRoleDef()));
|
||||||
};
|
};
|
||||||
// if (grantDef.isConditional()) {
|
// if (grantDef.isConditional()) {
|
||||||
// return "if " + grantDef.getOnlyInCaseOf() + " then\n"
|
// return "if " + grantDef.generateCondition() + " then\n"
|
||||||
// + " " + grantSql + "\n"
|
// + " " + grantSql + "\n"
|
||||||
// + "end if;";
|
// + "end if;";
|
||||||
// }
|
// }
|
||||||
@ -371,11 +401,8 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
.replace("${roleSuffix}", capitalize(role.name())));
|
.replace("${roleSuffix}", capitalize(role.name())));
|
||||||
|
|
||||||
generatePermissionsForRole(plPgSql, role);
|
generatePermissionsForRole(plPgSql, role);
|
||||||
|
|
||||||
generateIncomingSuperRolesForRole(plPgSql, role);
|
generateIncomingSuperRolesForRole(plPgSql, role);
|
||||||
|
|
||||||
generateOutgoingSubRolesForRole(plPgSql, role);
|
generateOutgoingSubRolesForRole(plPgSql, role);
|
||||||
|
|
||||||
generateUserGrantsForRole(plPgSql, role);
|
generateUserGrantsForRole(plPgSql, role);
|
||||||
|
|
||||||
plPgSql.chopTail(",\n");
|
plPgSql.chopTail(",\n");
|
||||||
|
@ -0,0 +1,102 @@
|
|||||||
|
### rbac relation
|
||||||
|
|
||||||
|
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||||
|
flowchart TB
|
||||||
|
|
||||||
|
subgraph holderPerson["`**holderPerson**`"]
|
||||||
|
direction TB
|
||||||
|
style holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
|
subgraph holderPerson:roles[ ]
|
||||||
|
style holderPerson:roles fill:#99bcdb,stroke:white
|
||||||
|
|
||||||
|
role:holderPerson:OWNER[[holderPerson:OWNER]]
|
||||||
|
role:holderPerson:ADMIN[[holderPerson:ADMIN]]
|
||||||
|
role:holderPerson:REFERRER[[holderPerson:REFERRER]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph anchorPerson["`**anchorPerson**`"]
|
||||||
|
direction TB
|
||||||
|
style anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
|
subgraph anchorPerson:roles[ ]
|
||||||
|
style anchorPerson:roles fill:#99bcdb,stroke:white
|
||||||
|
|
||||||
|
role:anchorPerson:OWNER[[anchorPerson:OWNER]]
|
||||||
|
role:anchorPerson:ADMIN[[anchorPerson:ADMIN]]
|
||||||
|
role:anchorPerson:REFERRER[[anchorPerson:REFERRER]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph contact["`**contact**`"]
|
||||||
|
direction TB
|
||||||
|
style contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
|
subgraph contact:roles[ ]
|
||||||
|
style contact:roles fill:#99bcdb,stroke:white
|
||||||
|
|
||||||
|
role:contact:OWNER[[contact:OWNER]]
|
||||||
|
role:contact:ADMIN[[contact:ADMIN]]
|
||||||
|
role:contact:REFERRER[[contact:REFERRER]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph relation["`**relation**`"]
|
||||||
|
direction TB
|
||||||
|
style relation fill:#dd4901,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
|
subgraph relation:roles[ ]
|
||||||
|
style relation:roles fill:#dd4901,stroke:white
|
||||||
|
|
||||||
|
role:relation:OWNER[[relation:OWNER]]
|
||||||
|
role:relation:ADMIN[[relation:ADMIN]]
|
||||||
|
role:relation:AGENT[[relation:AGENT]]
|
||||||
|
role:relation:TENANT[[relation:TENANT]]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph relation:permissions[ ]
|
||||||
|
style relation:permissions fill:#dd4901,stroke:white
|
||||||
|
|
||||||
|
perm:relation:DELETE{{relation:DELETE}}
|
||||||
|
perm:relation:UPDATE{{relation:UPDATE}}
|
||||||
|
perm:relation:SELECT{{relation:SELECT}}
|
||||||
|
perm:relation:INSERT{{relation:INSERT}}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
%% granting roles to users
|
||||||
|
user:creator ==> role:relation:OWNER
|
||||||
|
|
||||||
|
%% granting roles to roles
|
||||||
|
role:global:ADMIN -.-> role:anchorPerson:OWNER
|
||||||
|
role:anchorPerson:OWNER -.-> role:anchorPerson:ADMIN
|
||||||
|
role:anchorPerson:ADMIN -.-> role:anchorPerson:REFERRER
|
||||||
|
role:global:ADMIN -.-> role:holderPerson:OWNER
|
||||||
|
role:holderPerson:OWNER -.-> role:holderPerson:ADMIN
|
||||||
|
role:holderPerson:ADMIN -.-> role:holderPerson:REFERRER
|
||||||
|
role:global:ADMIN -.-> role:contact:OWNER
|
||||||
|
role:contact:OWNER -.-> role:contact:ADMIN
|
||||||
|
role:contact:ADMIN -.-> role:contact:REFERRER
|
||||||
|
role:global:ADMIN ==> role:relation:OWNER
|
||||||
|
role:holderPerson:ADMIN ==> role:relation:OWNER
|
||||||
|
role:relation:OWNER ==> role:relation:ADMIN
|
||||||
|
role:relation:ADMIN ==> role:anchorPerson:OWNER
|
||||||
|
role:relation:ADMIN ==> role:relation:AGENT
|
||||||
|
role:anchorPerson:ADMIN ==> role:relation:AGENT
|
||||||
|
role:relation:AGENT ==> role:relation:TENANT
|
||||||
|
role:contact:ADMIN ==> role:relation:TENANT
|
||||||
|
role:relation:TENANT ==> role:anchorPerson:REFERRER
|
||||||
|
role:relation:TENANT ==> role:holderPerson:REFERRER
|
||||||
|
role:relation:TENANT ==> role:contact:REFERRER
|
||||||
|
|
||||||
|
%% granting permissions to roles
|
||||||
|
role:relation:OWNER ==> perm:relation:DELETE
|
||||||
|
role:relation:ADMIN ==> perm:relation:UPDATE
|
||||||
|
role:relation:TENANT ==> perm:relation:SELECT
|
||||||
|
role:anchorPerson:ADMIN ==> perm:relation:INSERT
|
||||||
|
|
||||||
|
```
|
@ -83,15 +83,14 @@ role:contact:OWNER -.-> role:contact:ADMIN
|
|||||||
role:contact:ADMIN -.-> role:contact:REFERRER
|
role:contact:ADMIN -.-> role:contact:REFERRER
|
||||||
role:global:ADMIN ==> role:relation:OWNER
|
role:global:ADMIN ==> role:relation:OWNER
|
||||||
role:relation:OWNER ==> role:relation:ADMIN
|
role:relation:OWNER ==> role:relation:ADMIN
|
||||||
role:anchorPerson:ADMIN ==> role:relation:ADMIN
|
|
||||||
role:relation:ADMIN ==> role:relation:AGENT
|
role:relation:ADMIN ==> role:relation:AGENT
|
||||||
role:holderPerson:ADMIN ==> role:relation:AGENT
|
|
||||||
role:relation:AGENT ==> role:relation:TENANT
|
role:relation:AGENT ==> role:relation:TENANT
|
||||||
role:holderPerson:ADMIN ==> role:relation:TENANT
|
|
||||||
role:contact:ADMIN ==> role:relation:TENANT
|
role:contact:ADMIN ==> role:relation:TENANT
|
||||||
role:relation:TENANT ==> role:anchorPerson:REFERRER
|
role:relation:TENANT ==> role:anchorPerson:REFERRER
|
||||||
role:relation:TENANT ==> role:holderPerson:REFERRER
|
role:relation:TENANT ==> role:holderPerson:REFERRER
|
||||||
role:relation:TENANT ==> role:contact:REFERRER
|
role:relation:TENANT ==> role:contact:REFERRER
|
||||||
|
role:anchorPerson:ADMIN ==> role:relation:OWNER
|
||||||
|
role:holderPerson:ADMIN ==> role:relation:AGENT
|
||||||
|
|
||||||
%% granting permissions to roles
|
%% granting permissions to roles
|
||||||
role:relation:OWNER ==> perm:relation:DELETE
|
role:relation:OWNER ==> perm:relation:DELETE
|
||||||
|
@ -57,16 +57,12 @@ begin
|
|||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficeRelationADMIN(NEW),
|
hsOfficeRelationADMIN(NEW),
|
||||||
permissions => array['UPDATE'],
|
permissions => array['UPDATE'],
|
||||||
incomingSuperRoles => array[
|
incomingSuperRoles => array[hsOfficeRelationOWNER(NEW)]
|
||||||
hsOfficePersonADMIN(newAnchorPerson),
|
|
||||||
hsOfficeRelationOWNER(NEW)]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficeRelationAGENT(NEW),
|
hsOfficeRelationAGENT(NEW),
|
||||||
incomingSuperRoles => array[
|
incomingSuperRoles => array[hsOfficeRelationADMIN(NEW)]
|
||||||
hsOfficePersonADMIN(newHolderPerson),
|
|
||||||
hsOfficeRelationADMIN(NEW)]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
@ -74,7 +70,6 @@ begin
|
|||||||
permissions => array['SELECT'],
|
permissions => array['SELECT'],
|
||||||
incomingSuperRoles => array[
|
incomingSuperRoles => array[
|
||||||
hsOfficeContactADMIN(newContact),
|
hsOfficeContactADMIN(newContact),
|
||||||
hsOfficePersonADMIN(newHolderPerson),
|
|
||||||
hsOfficeRelationAGENT(NEW)],
|
hsOfficeRelationAGENT(NEW)],
|
||||||
outgoingSubRoles => array[
|
outgoingSubRoles => array[
|
||||||
hsOfficeContactREFERRER(newContact),
|
hsOfficeContactREFERRER(newContact),
|
||||||
@ -82,6 +77,15 @@ begin
|
|||||||
hsOfficePersonREFERRER(newHolderPerson)]
|
hsOfficePersonREFERRER(newHolderPerson)]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
IF NEW.type = 'REPRESENTATIVE' THEN
|
||||||
|
call grantRoleToRole(hsOfficePersonOWNER(newAnchorPerson), hsOfficeRelationADMIN(NEW));
|
||||||
|
call grantRoleToRole(hsOfficeRelationAGENT(NEW), hsOfficePersonADMIN(newAnchorPerson));
|
||||||
|
call grantRoleToRole(hsOfficeRelationOWNER(NEW), hsOfficePersonADMIN(newHolderPerson));
|
||||||
|
ELSE
|
||||||
|
call grantRoleToRole(hsOfficeRelationAGENT(NEW), hsOfficePersonADMIN(newHolderPerson));
|
||||||
|
call grantRoleToRole(hsOfficeRelationOWNER(NEW), hsOfficePersonADMIN(newAnchorPerson));
|
||||||
|
END IF;
|
||||||
|
|
||||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
@ -118,48 +122,12 @@ create or replace procedure updateRbacRulesForHsOfficeRelation(
|
|||||||
NEW hs_office_relation
|
NEW hs_office_relation
|
||||||
)
|
)
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
|
|
||||||
declare
|
|
||||||
oldHolderPerson hs_office_person;
|
|
||||||
newHolderPerson hs_office_person;
|
|
||||||
oldAnchorPerson hs_office_person;
|
|
||||||
newAnchorPerson hs_office_person;
|
|
||||||
oldContact hs_office_contact;
|
|
||||||
newContact hs_office_contact;
|
|
||||||
|
|
||||||
begin
|
begin
|
||||||
call enterTriggerForObjectUuid(NEW.uuid);
|
|
||||||
|
|
||||||
SELECT * FROM hs_office_person WHERE uuid = OLD.holderUuid INTO oldHolderPerson;
|
|
||||||
assert oldHolderPerson.uuid is not null, format('oldHolderPerson must not be null for OLD.holderUuid = %s', OLD.holderUuid);
|
|
||||||
|
|
||||||
SELECT * FROM hs_office_person WHERE uuid = NEW.holderUuid INTO newHolderPerson;
|
|
||||||
assert newHolderPerson.uuid is not null, format('newHolderPerson must not be null for NEW.holderUuid = %s', NEW.holderUuid);
|
|
||||||
|
|
||||||
SELECT * FROM hs_office_person WHERE uuid = OLD.anchorUuid INTO oldAnchorPerson;
|
|
||||||
assert oldAnchorPerson.uuid is not null, format('oldAnchorPerson must not be null for OLD.anchorUuid = %s', OLD.anchorUuid);
|
|
||||||
|
|
||||||
SELECT * FROM hs_office_person WHERE uuid = NEW.anchorUuid INTO newAnchorPerson;
|
|
||||||
assert newAnchorPerson.uuid is not null, format('newAnchorPerson must not be null for NEW.anchorUuid = %s', NEW.anchorUuid);
|
|
||||||
|
|
||||||
SELECT * FROM hs_office_contact WHERE uuid = OLD.contactUuid INTO oldContact;
|
|
||||||
assert oldContact.uuid is not null, format('oldContact must not be null for OLD.contactUuid = %s', OLD.contactUuid);
|
|
||||||
|
|
||||||
SELECT * FROM hs_office_contact WHERE uuid = NEW.contactUuid INTO newContact;
|
|
||||||
assert newContact.uuid is not null, format('newContact must not be null for NEW.contactUuid = %s', NEW.contactUuid);
|
|
||||||
|
|
||||||
|
|
||||||
if NEW.contactUuid <> OLD.contactUuid then
|
|
||||||
|
|
||||||
call revokeRoleFromRole(hsOfficeRelationTENANT(OLD), hsOfficeContactADMIN(oldContact));
|
|
||||||
call grantRoleToRole(hsOfficeRelationTENANT(NEW), hsOfficeContactADMIN(newContact));
|
|
||||||
|
|
||||||
call revokeRoleFromRole(hsOfficeContactREFERRER(oldContact), hsOfficeRelationTENANT(OLD));
|
|
||||||
call grantRoleToRole(hsOfficeContactREFERRER(newContact), hsOfficeRelationTENANT(NEW));
|
|
||||||
|
|
||||||
|
if NEW.contactUuid is distinct from OLD.contactUuid then
|
||||||
|
delete from rbacgrants g where g.grantedbytriggerof = OLD.uuid;
|
||||||
|
call buildRbacSystemForHsOfficeRelation(NEW);
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -98,22 +98,21 @@ role:partnerRel.contact:OWNER -.-> role:partnerRel.contact:ADMIN
|
|||||||
role:partnerRel.contact:ADMIN -.-> role:partnerRel.contact:REFERRER
|
role:partnerRel.contact:ADMIN -.-> role:partnerRel.contact:REFERRER
|
||||||
role:global:ADMIN -.-> role:partnerRel:OWNER
|
role:global:ADMIN -.-> role:partnerRel:OWNER
|
||||||
role:partnerRel:OWNER -.-> role:partnerRel:ADMIN
|
role:partnerRel:OWNER -.-> role:partnerRel:ADMIN
|
||||||
role:partnerRel.anchorPerson:ADMIN -.-> role:partnerRel:ADMIN
|
|
||||||
role:partnerRel:ADMIN -.-> role:partnerRel:AGENT
|
role:partnerRel:ADMIN -.-> role:partnerRel:AGENT
|
||||||
role:partnerRel.holderPerson:ADMIN -.-> role:partnerRel:AGENT
|
|
||||||
role:partnerRel:AGENT -.-> role:partnerRel:TENANT
|
role:partnerRel:AGENT -.-> role:partnerRel:TENANT
|
||||||
role:partnerRel.holderPerson:ADMIN -.-> role:partnerRel:TENANT
|
|
||||||
role:partnerRel.contact:ADMIN -.-> role:partnerRel:TENANT
|
role:partnerRel.contact:ADMIN -.-> role:partnerRel:TENANT
|
||||||
role:partnerRel:TENANT -.-> role:partnerRel.anchorPerson:REFERRER
|
role:partnerRel:TENANT -.-> role:partnerRel.anchorPerson:REFERRER
|
||||||
role:partnerRel:TENANT -.-> role:partnerRel.holderPerson:REFERRER
|
role:partnerRel:TENANT -.-> role:partnerRel.holderPerson:REFERRER
|
||||||
role:partnerRel:TENANT -.-> role:partnerRel.contact:REFERRER
|
role:partnerRel:TENANT -.-> role:partnerRel.contact:REFERRER
|
||||||
|
role:partnerRel.anchorPerson:ADMIN -.-> role:partnerRel:OWNER
|
||||||
|
role:partnerRel.holderPerson:ADMIN -.-> role:partnerRel:AGENT
|
||||||
|
|
||||||
%% granting permissions to roles
|
%% granting permissions to roles
|
||||||
role:global:ADMIN ==> perm:partner:INSERT
|
role:global:ADMIN ==> perm:partner:INSERT
|
||||||
role:partnerRel:ADMIN ==> perm:partner:DELETE
|
role:partnerRel:OWNER ==> perm:partner:DELETE
|
||||||
role:partnerRel:AGENT ==> perm:partner:UPDATE
|
role:partnerRel:ADMIN ==> perm:partner:UPDATE
|
||||||
role:partnerRel:TENANT ==> perm:partner:SELECT
|
role:partnerRel:TENANT ==> perm:partner:SELECT
|
||||||
role:partnerRel:ADMIN ==> perm:partnerDetails:DELETE
|
role:partnerRel:OWNER ==> perm:partnerDetails:DELETE
|
||||||
role:partnerRel:AGENT ==> perm:partnerDetails:UPDATE
|
role:partnerRel:AGENT ==> perm:partnerDetails:UPDATE
|
||||||
role:partnerRel:AGENT ==> perm:partnerDetails:SELECT
|
role:partnerRel:AGENT ==> perm:partnerDetails:SELECT
|
||||||
|
|
||||||
|
@ -42,10 +42,10 @@ begin
|
|||||||
SELECT * FROM hs_office_partner_details WHERE uuid = NEW.detailsUuid INTO newPartnerDetails;
|
SELECT * FROM hs_office_partner_details WHERE uuid = NEW.detailsUuid INTO newPartnerDetails;
|
||||||
assert newPartnerDetails.uuid is not null, format('newPartnerDetails must not be null for NEW.detailsUuid = %s', NEW.detailsUuid);
|
assert newPartnerDetails.uuid is not null, format('newPartnerDetails must not be null for NEW.detailsUuid = %s', NEW.detailsUuid);
|
||||||
|
|
||||||
call grantPermissionToRole(createPermission(NEW.uuid, 'DELETE'), hsOfficeRelationADMIN(newPartnerRel));
|
call grantPermissionToRole(createPermission(NEW.uuid, 'DELETE'), hsOfficeRelationOWNER(newPartnerRel));
|
||||||
call grantPermissionToRole(createPermission(NEW.uuid, 'SELECT'), hsOfficeRelationTENANT(newPartnerRel));
|
call grantPermissionToRole(createPermission(NEW.uuid, 'SELECT'), hsOfficeRelationTENANT(newPartnerRel));
|
||||||
call grantPermissionToRole(createPermission(NEW.uuid, 'UPDATE'), hsOfficeRelationAGENT(newPartnerRel));
|
call grantPermissionToRole(createPermission(NEW.uuid, 'UPDATE'), hsOfficeRelationADMIN(newPartnerRel));
|
||||||
call grantPermissionToRole(createPermission(newPartnerDetails.uuid, 'DELETE'), hsOfficeRelationADMIN(newPartnerRel));
|
call grantPermissionToRole(createPermission(newPartnerDetails.uuid, 'DELETE'), hsOfficeRelationOWNER(newPartnerRel));
|
||||||
call grantPermissionToRole(createPermission(newPartnerDetails.uuid, 'SELECT'), hsOfficeRelationAGENT(newPartnerRel));
|
call grantPermissionToRole(createPermission(newPartnerDetails.uuid, 'SELECT'), hsOfficeRelationAGENT(newPartnerRel));
|
||||||
call grantPermissionToRole(createPermission(newPartnerDetails.uuid, 'UPDATE'), hsOfficeRelationAGENT(newPartnerRel));
|
call grantPermissionToRole(createPermission(newPartnerDetails.uuid, 'UPDATE'), hsOfficeRelationAGENT(newPartnerRel));
|
||||||
|
|
||||||
@ -110,17 +110,17 @@ begin
|
|||||||
|
|
||||||
if NEW.partnerRelUuid <> OLD.partnerRelUuid then
|
if NEW.partnerRelUuid <> OLD.partnerRelUuid then
|
||||||
|
|
||||||
call revokePermissionFromRole(getPermissionId(OLD.uuid, 'DELETE'), hsOfficeRelationADMIN(oldPartnerRel));
|
call revokePermissionFromRole(getPermissionId(OLD.uuid, 'DELETE'), hsOfficeRelationOWNER(oldPartnerRel));
|
||||||
call grantPermissionToRole(createPermission(NEW.uuid, 'DELETE'), hsOfficeRelationADMIN(newPartnerRel));
|
call grantPermissionToRole(createPermission(NEW.uuid, 'DELETE'), hsOfficeRelationOWNER(newPartnerRel));
|
||||||
|
|
||||||
call revokePermissionFromRole(getPermissionId(OLD.uuid, 'UPDATE'), hsOfficeRelationAGENT(oldPartnerRel));
|
call revokePermissionFromRole(getPermissionId(OLD.uuid, 'UPDATE'), hsOfficeRelationADMIN(oldPartnerRel));
|
||||||
call grantPermissionToRole(createPermission(NEW.uuid, 'UPDATE'), hsOfficeRelationAGENT(newPartnerRel));
|
call grantPermissionToRole(createPermission(NEW.uuid, 'UPDATE'), hsOfficeRelationADMIN(newPartnerRel));
|
||||||
|
|
||||||
call revokePermissionFromRole(getPermissionId(OLD.uuid, 'SELECT'), hsOfficeRelationTENANT(oldPartnerRel));
|
call revokePermissionFromRole(getPermissionId(OLD.uuid, 'SELECT'), hsOfficeRelationTENANT(oldPartnerRel));
|
||||||
call grantPermissionToRole(createPermission(NEW.uuid, 'SELECT'), hsOfficeRelationTENANT(newPartnerRel));
|
call grantPermissionToRole(createPermission(NEW.uuid, 'SELECT'), hsOfficeRelationTENANT(newPartnerRel));
|
||||||
|
|
||||||
call revokePermissionFromRole(getPermissionId(oldPartnerDetails.uuid, 'DELETE'), hsOfficeRelationADMIN(oldPartnerRel));
|
call revokePermissionFromRole(getPermissionId(oldPartnerDetails.uuid, 'DELETE'), hsOfficeRelationOWNER(oldPartnerRel));
|
||||||
call grantPermissionToRole(createPermission(newPartnerDetails.uuid, 'DELETE'), hsOfficeRelationADMIN(newPartnerRel));
|
call grantPermissionToRole(createPermission(newPartnerDetails.uuid, 'DELETE'), hsOfficeRelationOWNER(newPartnerRel));
|
||||||
|
|
||||||
call revokePermissionFromRole(getPermissionId(oldPartnerDetails.uuid, 'UPDATE'), hsOfficeRelationAGENT(oldPartnerRel));
|
call revokePermissionFromRole(getPermissionId(oldPartnerDetails.uuid, 'UPDATE'), hsOfficeRelationAGENT(oldPartnerRel));
|
||||||
call grantPermissionToRole(createPermission(newPartnerDetails.uuid, 'UPDATE'), hsOfficeRelationAGENT(newPartnerRel));
|
call grantPermissionToRole(createPermission(newPartnerDetails.uuid, 'UPDATE'), hsOfficeRelationAGENT(newPartnerRel));
|
||||||
|
@ -149,17 +149,6 @@ role:debitorRel.holderPerson:ADMIN -.-> role:debitorRel.holderPerson:REFERRER
|
|||||||
role:global:ADMIN -.-> role:debitorRel.contact:OWNER
|
role:global:ADMIN -.-> role:debitorRel.contact:OWNER
|
||||||
role:debitorRel.contact:OWNER -.-> role:debitorRel.contact:ADMIN
|
role:debitorRel.contact:OWNER -.-> role:debitorRel.contact:ADMIN
|
||||||
role:debitorRel.contact:ADMIN -.-> role:debitorRel.contact:REFERRER
|
role:debitorRel.contact:ADMIN -.-> role:debitorRel.contact:REFERRER
|
||||||
role:global:ADMIN -.-> role:debitorRel:OWNER
|
|
||||||
role:debitorRel:OWNER -.-> role:debitorRel:ADMIN
|
|
||||||
role:debitorRel.anchorPerson:ADMIN -.-> role:debitorRel:ADMIN
|
|
||||||
role:debitorRel:ADMIN -.-> role:debitorRel:AGENT
|
|
||||||
role:debitorRel.holderPerson:ADMIN -.-> role:debitorRel:AGENT
|
|
||||||
role:debitorRel:AGENT -.-> role:debitorRel:TENANT
|
|
||||||
role:debitorRel.holderPerson:ADMIN -.-> role:debitorRel:TENANT
|
|
||||||
role:debitorRel.contact:ADMIN -.-> role:debitorRel:TENANT
|
|
||||||
role:debitorRel:TENANT -.-> role:debitorRel.anchorPerson:REFERRER
|
|
||||||
role:debitorRel:TENANT -.-> role:debitorRel.holderPerson:REFERRER
|
|
||||||
role:debitorRel:TENANT -.-> role:debitorRel.contact:REFERRER
|
|
||||||
role:global:ADMIN -.-> role:refundBankAccount:OWNER
|
role:global:ADMIN -.-> role:refundBankAccount:OWNER
|
||||||
role:refundBankAccount:OWNER -.-> role:refundBankAccount:ADMIN
|
role:refundBankAccount:OWNER -.-> role:refundBankAccount:ADMIN
|
||||||
role:refundBankAccount:ADMIN -.-> role:refundBankAccount:REFERRER
|
role:refundBankAccount:ADMIN -.-> role:refundBankAccount:REFERRER
|
||||||
@ -176,15 +165,14 @@ role:partnerRel.contact:OWNER -.-> role:partnerRel.contact:ADMIN
|
|||||||
role:partnerRel.contact:ADMIN -.-> role:partnerRel.contact:REFERRER
|
role:partnerRel.contact:ADMIN -.-> role:partnerRel.contact:REFERRER
|
||||||
role:global:ADMIN -.-> role:partnerRel:OWNER
|
role:global:ADMIN -.-> role:partnerRel:OWNER
|
||||||
role:partnerRel:OWNER -.-> role:partnerRel:ADMIN
|
role:partnerRel:OWNER -.-> role:partnerRel:ADMIN
|
||||||
role:partnerRel.anchorPerson:ADMIN -.-> role:partnerRel:ADMIN
|
|
||||||
role:partnerRel:ADMIN -.-> role:partnerRel:AGENT
|
role:partnerRel:ADMIN -.-> role:partnerRel:AGENT
|
||||||
role:partnerRel.holderPerson:ADMIN -.-> role:partnerRel:AGENT
|
|
||||||
role:partnerRel:AGENT -.-> role:partnerRel:TENANT
|
role:partnerRel:AGENT -.-> role:partnerRel:TENANT
|
||||||
role:partnerRel.holderPerson:ADMIN -.-> role:partnerRel:TENANT
|
|
||||||
role:partnerRel.contact:ADMIN -.-> role:partnerRel:TENANT
|
role:partnerRel.contact:ADMIN -.-> role:partnerRel:TENANT
|
||||||
role:partnerRel:TENANT -.-> role:partnerRel.anchorPerson:REFERRER
|
role:partnerRel:TENANT -.-> role:partnerRel.anchorPerson:REFERRER
|
||||||
role:partnerRel:TENANT -.-> role:partnerRel.holderPerson:REFERRER
|
role:partnerRel:TENANT -.-> role:partnerRel.holderPerson:REFERRER
|
||||||
role:partnerRel:TENANT -.-> role:partnerRel.contact:REFERRER
|
role:partnerRel:TENANT -.-> role:partnerRel.contact:REFERRER
|
||||||
|
role:partnerRel.anchorPerson:ADMIN -.-> role:partnerRel:OWNER
|
||||||
|
role:partnerRel.holderPerson:ADMIN -.-> role:partnerRel:AGENT
|
||||||
role:partnerRel:ADMIN ==> role:debitorRel:ADMIN
|
role:partnerRel:ADMIN ==> role:debitorRel:ADMIN
|
||||||
role:partnerRel:AGENT ==> role:debitorRel:AGENT
|
role:partnerRel:AGENT ==> role:debitorRel:AGENT
|
||||||
role:debitorRel:AGENT ==> role:partnerRel:TENANT
|
role:debitorRel:AGENT ==> role:partnerRel:TENANT
|
||||||
|
@ -110,15 +110,14 @@ role:debitorRel.contact:OWNER -.-> role:debitorRel.contact:ADMIN
|
|||||||
role:debitorRel.contact:ADMIN -.-> role:debitorRel.contact:REFERRER
|
role:debitorRel.contact:ADMIN -.-> role:debitorRel.contact:REFERRER
|
||||||
role:global:ADMIN -.-> role:debitorRel:OWNER
|
role:global:ADMIN -.-> role:debitorRel:OWNER
|
||||||
role:debitorRel:OWNER -.-> role:debitorRel:ADMIN
|
role:debitorRel:OWNER -.-> role:debitorRel:ADMIN
|
||||||
role:debitorRel.anchorPerson:ADMIN -.-> role:debitorRel:ADMIN
|
|
||||||
role:debitorRel:ADMIN -.-> role:debitorRel:AGENT
|
role:debitorRel:ADMIN -.-> role:debitorRel:AGENT
|
||||||
role:debitorRel.holderPerson:ADMIN -.-> role:debitorRel:AGENT
|
|
||||||
role:debitorRel:AGENT -.-> role:debitorRel:TENANT
|
role:debitorRel:AGENT -.-> role:debitorRel:TENANT
|
||||||
role:debitorRel.holderPerson:ADMIN -.-> role:debitorRel:TENANT
|
|
||||||
role:debitorRel.contact:ADMIN -.-> role:debitorRel:TENANT
|
role:debitorRel.contact:ADMIN -.-> role:debitorRel:TENANT
|
||||||
role:debitorRel:TENANT -.-> role:debitorRel.anchorPerson:REFERRER
|
role:debitorRel:TENANT -.-> role:debitorRel.anchorPerson:REFERRER
|
||||||
role:debitorRel:TENANT -.-> role:debitorRel.holderPerson:REFERRER
|
role:debitorRel:TENANT -.-> role:debitorRel.holderPerson:REFERRER
|
||||||
role:debitorRel:TENANT -.-> role:debitorRel.contact:REFERRER
|
role:debitorRel:TENANT -.-> role:debitorRel.contact:REFERRER
|
||||||
|
role:debitorRel.anchorPerson:ADMIN -.-> role:debitorRel:OWNER
|
||||||
|
role:debitorRel.holderPerson:ADMIN -.-> role:debitorRel:AGENT
|
||||||
role:global:ADMIN -.-> role:bankAccount:OWNER
|
role:global:ADMIN -.-> role:bankAccount:OWNER
|
||||||
role:bankAccount:OWNER -.-> role:bankAccount:ADMIN
|
role:bankAccount:OWNER -.-> role:bankAccount:ADMIN
|
||||||
role:bankAccount:ADMIN -.-> role:bankAccount:REFERRER
|
role:bankAccount:ADMIN -.-> role:bankAccount:REFERRER
|
||||||
|
@ -96,15 +96,14 @@ role:partnerRel.contact:OWNER -.-> role:partnerRel.contact:ADMIN
|
|||||||
role:partnerRel.contact:ADMIN -.-> role:partnerRel.contact:REFERRER
|
role:partnerRel.contact:ADMIN -.-> role:partnerRel.contact:REFERRER
|
||||||
role:global:ADMIN -.-> role:partnerRel:OWNER
|
role:global:ADMIN -.-> role:partnerRel:OWNER
|
||||||
role:partnerRel:OWNER -.-> role:partnerRel:ADMIN
|
role:partnerRel:OWNER -.-> role:partnerRel:ADMIN
|
||||||
role:partnerRel.anchorPerson:ADMIN -.-> role:partnerRel:ADMIN
|
|
||||||
role:partnerRel:ADMIN -.-> role:partnerRel:AGENT
|
role:partnerRel:ADMIN -.-> role:partnerRel:AGENT
|
||||||
role:partnerRel.holderPerson:ADMIN -.-> role:partnerRel:AGENT
|
|
||||||
role:partnerRel:AGENT -.-> role:partnerRel:TENANT
|
role:partnerRel:AGENT -.-> role:partnerRel:TENANT
|
||||||
role:partnerRel.holderPerson:ADMIN -.-> role:partnerRel:TENANT
|
|
||||||
role:partnerRel.contact:ADMIN -.-> role:partnerRel:TENANT
|
role:partnerRel.contact:ADMIN -.-> role:partnerRel:TENANT
|
||||||
role:partnerRel:TENANT -.-> role:partnerRel.anchorPerson:REFERRER
|
role:partnerRel:TENANT -.-> role:partnerRel.anchorPerson:REFERRER
|
||||||
role:partnerRel:TENANT -.-> role:partnerRel.holderPerson:REFERRER
|
role:partnerRel:TENANT -.-> role:partnerRel.holderPerson:REFERRER
|
||||||
role:partnerRel:TENANT -.-> role:partnerRel.contact:REFERRER
|
role:partnerRel:TENANT -.-> role:partnerRel.contact:REFERRER
|
||||||
|
role:partnerRel.anchorPerson:ADMIN -.-> role:partnerRel:OWNER
|
||||||
|
role:partnerRel.holderPerson:ADMIN -.-> role:partnerRel:AGENT
|
||||||
role:membership:OWNER ==> role:membership:ADMIN
|
role:membership:OWNER ==> role:membership:ADMIN
|
||||||
role:partnerRel:ADMIN ==> role:membership:ADMIN
|
role:partnerRel:ADMIN ==> role:membership:ADMIN
|
||||||
role:membership:ADMIN ==> role:membership:AGENT
|
role:membership:ADMIN ==> role:membership:AGENT
|
||||||
|
@ -97,15 +97,14 @@ role:membership.partnerRel.contact:OWNER -.-> role:membership.partnerRel.contact
|
|||||||
role:membership.partnerRel.contact:ADMIN -.-> role:membership.partnerRel.contact:REFERRER
|
role:membership.partnerRel.contact:ADMIN -.-> role:membership.partnerRel.contact:REFERRER
|
||||||
role:global:ADMIN -.-> role:membership.partnerRel:OWNER
|
role:global:ADMIN -.-> role:membership.partnerRel:OWNER
|
||||||
role:membership.partnerRel:OWNER -.-> role:membership.partnerRel:ADMIN
|
role:membership.partnerRel:OWNER -.-> role:membership.partnerRel:ADMIN
|
||||||
role:membership.partnerRel.anchorPerson:ADMIN -.-> role:membership.partnerRel:ADMIN
|
|
||||||
role:membership.partnerRel:ADMIN -.-> role:membership.partnerRel:AGENT
|
role:membership.partnerRel:ADMIN -.-> role:membership.partnerRel:AGENT
|
||||||
role:membership.partnerRel.holderPerson:ADMIN -.-> role:membership.partnerRel:AGENT
|
|
||||||
role:membership.partnerRel:AGENT -.-> role:membership.partnerRel:TENANT
|
role:membership.partnerRel:AGENT -.-> role:membership.partnerRel:TENANT
|
||||||
role:membership.partnerRel.holderPerson:ADMIN -.-> role:membership.partnerRel:TENANT
|
|
||||||
role:membership.partnerRel.contact:ADMIN -.-> role:membership.partnerRel:TENANT
|
role:membership.partnerRel.contact:ADMIN -.-> role:membership.partnerRel:TENANT
|
||||||
role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.anchorPerson:REFERRER
|
role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.anchorPerson:REFERRER
|
||||||
role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.holderPerson:REFERRER
|
role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.holderPerson:REFERRER
|
||||||
role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.contact:REFERRER
|
role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.contact:REFERRER
|
||||||
|
role:membership.partnerRel.anchorPerson:ADMIN -.-> role:membership.partnerRel:OWNER
|
||||||
|
role:membership.partnerRel.holderPerson:ADMIN -.-> role:membership.partnerRel:AGENT
|
||||||
role:membership:OWNER -.-> role:membership:ADMIN
|
role:membership:OWNER -.-> role:membership:ADMIN
|
||||||
role:membership.partnerRel:ADMIN -.-> role:membership:ADMIN
|
role:membership.partnerRel:ADMIN -.-> role:membership:ADMIN
|
||||||
role:membership:ADMIN -.-> role:membership:AGENT
|
role:membership:ADMIN -.-> role:membership:AGENT
|
||||||
|
@ -97,15 +97,14 @@ role:membership.partnerRel.contact:OWNER -.-> role:membership.partnerRel.contact
|
|||||||
role:membership.partnerRel.contact:ADMIN -.-> role:membership.partnerRel.contact:REFERRER
|
role:membership.partnerRel.contact:ADMIN -.-> role:membership.partnerRel.contact:REFERRER
|
||||||
role:global:ADMIN -.-> role:membership.partnerRel:OWNER
|
role:global:ADMIN -.-> role:membership.partnerRel:OWNER
|
||||||
role:membership.partnerRel:OWNER -.-> role:membership.partnerRel:ADMIN
|
role:membership.partnerRel:OWNER -.-> role:membership.partnerRel:ADMIN
|
||||||
role:membership.partnerRel.anchorPerson:ADMIN -.-> role:membership.partnerRel:ADMIN
|
|
||||||
role:membership.partnerRel:ADMIN -.-> role:membership.partnerRel:AGENT
|
role:membership.partnerRel:ADMIN -.-> role:membership.partnerRel:AGENT
|
||||||
role:membership.partnerRel.holderPerson:ADMIN -.-> role:membership.partnerRel:AGENT
|
|
||||||
role:membership.partnerRel:AGENT -.-> role:membership.partnerRel:TENANT
|
role:membership.partnerRel:AGENT -.-> role:membership.partnerRel:TENANT
|
||||||
role:membership.partnerRel.holderPerson:ADMIN -.-> role:membership.partnerRel:TENANT
|
|
||||||
role:membership.partnerRel.contact:ADMIN -.-> role:membership.partnerRel:TENANT
|
role:membership.partnerRel.contact:ADMIN -.-> role:membership.partnerRel:TENANT
|
||||||
role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.anchorPerson:REFERRER
|
role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.anchorPerson:REFERRER
|
||||||
role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.holderPerson:REFERRER
|
role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.holderPerson:REFERRER
|
||||||
role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.contact:REFERRER
|
role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.contact:REFERRER
|
||||||
|
role:membership.partnerRel.anchorPerson:ADMIN -.-> role:membership.partnerRel:OWNER
|
||||||
|
role:membership.partnerRel.holderPerson:ADMIN -.-> role:membership.partnerRel:AGENT
|
||||||
role:membership:OWNER -.-> role:membership:ADMIN
|
role:membership:OWNER -.-> role:membership:ADMIN
|
||||||
role:membership.partnerRel:ADMIN -.-> role:membership:ADMIN
|
role:membership.partnerRel:ADMIN -.-> role:membership:ADMIN
|
||||||
role:membership:ADMIN -.-> role:membership:AGENT
|
role:membership:ADMIN -.-> role:membership:AGENT
|
||||||
|
Loading…
Reference in New Issue
Block a user