add @Version property to all RBAC-Entities #34
@ -10,15 +10,12 @@ import net.hostsharing.hsadminng.errors.DisplayName;
|
|||||||
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity;
|
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity;
|
||||||
import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
|
import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
|
||||||
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
|
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
|
||||||
import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
|
|
||||||
import net.hostsharing.hsadminng.stringify.Stringify;
|
import net.hostsharing.hsadminng.stringify.Stringify;
|
||||||
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
||||||
import org.hibernate.annotations.GenericGenerator;
|
import org.hibernate.annotations.GenericGenerator;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
package net.hostsharing.hsadminng.hs.office.debitor;
|
package net.hostsharing.hsadminng.hs.office.debitor;
|
||||||
|
|
||||||
import lombok.*;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
import net.hostsharing.hsadminng.errors.DisplayName;
|
import net.hostsharing.hsadminng.errors.DisplayName;
|
||||||
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity;
|
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity;
|
||||||
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
|
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
|
||||||
@ -15,7 +19,13 @@ import org.hibernate.annotations.JoinFormula;
|
|||||||
import org.hibernate.annotations.NotFound;
|
import org.hibernate.annotations.NotFound;
|
||||||
import org.hibernate.annotations.NotFoundAction;
|
import org.hibernate.annotations.NotFoundAction;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
import jakarta.validation.constraints.Pattern;
|
import jakarta.validation.constraints.Pattern;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -26,6 +36,7 @@ import static jakarta.persistence.CascadeType.PERSIST;
|
|||||||
import static jakarta.persistence.CascadeType.REFRESH;
|
import static jakarta.persistence.CascadeType.REFRESH;
|
||||||
import static java.util.Optional.ofNullable;
|
import static java.util.Optional.ofNullable;
|
||||||
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.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.Nullable.NULLABLE;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Nullable.NULLABLE;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
|
||||||
@ -160,6 +171,8 @@ public class HsOfficeDebitorEntity implements RbacObject, Stringifyable {
|
|||||||
.toRole("global", ADMIN).grantPermission(INSERT)
|
.toRole("global", ADMIN).grantPermission(INSERT)
|
||||||
|
|
||||||
.importRootEntityAliasProxy("debitorRel", HsOfficeRelationEntity.class,
|
.importRootEntityAliasProxy("debitorRel", HsOfficeRelationEntity.class,
|
||||||
|
// TODO.spec: do we need a distinct case for DEBITOR-Relation?
|
||||||
|
usingDefaultCase(),
|
||||||
directlyFetchedByDependsOnColumn(),
|
directlyFetchedByDependsOnColumn(),
|
||||||
dependsOnColumn("debitorRelUuid"))
|
dependsOnColumn("debitorRelUuid"))
|
||||||
.createPermission(DELETE).grantedTo("debitorRel", OWNER)
|
.createPermission(DELETE).grantedTo("debitorRel", OWNER)
|
||||||
|
@ -29,8 +29,6 @@ import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.ADMIN;
|
|||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.AGENT;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.AGENT;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.OWNER;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.OWNER;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.TENANT;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.TENANT;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.TENANT;
|
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.TENANT;
|
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.fetchedBySql;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.fetchedBySql;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
|
||||||
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
||||||
|
@ -23,6 +23,7 @@ import java.util.UUID;
|
|||||||
|
|
||||||
import static jakarta.persistence.CascadeType.*;
|
import static jakarta.persistence.CascadeType.*;
|
||||||
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.ColumnValue.usingDefaultCase;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.SELECT;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.SELECT;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
||||||
@ -95,18 +96,19 @@ public class HsOfficePartnerEntity implements Stringifyable, RbacObject {
|
|||||||
.toRole("global", ADMIN).grantPermission(INSERT)
|
.toRole("global", ADMIN).grantPermission(INSERT)
|
||||||
|
|
||||||
.importRootEntityAliasProxy("partnerRel", HsOfficeRelationEntity.class,
|
.importRootEntityAliasProxy("partnerRel", HsOfficeRelationEntity.class,
|
||||||
|
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 {
|
||||||
|
@ -35,6 +35,8 @@ public class HsOfficePersonEntity implements RbacObject, Stringifyable {
|
|||||||
private static Stringify<HsOfficePersonEntity> toString = stringify(HsOfficePersonEntity.class, "person")
|
private static Stringify<HsOfficePersonEntity> toString = stringify(HsOfficePersonEntity.class, "person")
|
||||||
.withProp(Fields.personType, HsOfficePersonEntity::getPersonType)
|
.withProp(Fields.personType, HsOfficePersonEntity::getPersonType)
|
||||||
.withProp(Fields.tradeName, HsOfficePersonEntity::getTradeName)
|
.withProp(Fields.tradeName, HsOfficePersonEntity::getTradeName)
|
||||||
|
.withProp(Fields.salutation, HsOfficePersonEntity::getSalutation)
|
||||||
|
.withProp(Fields.title, HsOfficePersonEntity::getTitle)
|
||||||
.withProp(Fields.familyName, HsOfficePersonEntity::getFamilyName)
|
.withProp(Fields.familyName, HsOfficePersonEntity::getFamilyName)
|
||||||
.withProp(Fields.givenName, HsOfficePersonEntity::getGivenName);
|
.withProp(Fields.givenName, HsOfficePersonEntity::getGivenName);
|
||||||
|
|
||||||
@ -51,6 +53,12 @@ public class HsOfficePersonEntity implements RbacObject, Stringifyable {
|
|||||||
@Column(name = "tradename")
|
@Column(name = "tradename")
|
||||||
private String tradeName;
|
private String tradeName;
|
||||||
|
|
||||||
|
@Column(name = "salutation")
|
||||||
|
private String salutation;
|
||||||
|
|
||||||
|
@Column(name = "title")
|
||||||
|
private String title;
|
||||||
|
|
||||||
@Column(name = "familyname")
|
@Column(name = "familyname")
|
||||||
private String familyName;
|
private String familyName;
|
||||||
|
|
||||||
@ -71,7 +79,7 @@ public class HsOfficePersonEntity implements RbacObject, Stringifyable {
|
|||||||
public static RbacView rbac() {
|
public static RbacView rbac() {
|
||||||
return rbacViewFor("person", HsOfficePersonEntity.class)
|
return rbacViewFor("person", HsOfficePersonEntity.class)
|
||||||
.withIdentityView(SQL.projection("concat(tradeName, familyName, givenName)"))
|
.withIdentityView(SQL.projection("concat(tradeName, familyName, givenName)"))
|
||||||
.withUpdatableColumns("personType", "tradeName", "givenName", "familyName")
|
.withUpdatableColumns("personType", "title", "salutation", "tradeName", "givenName", "familyName")
|
||||||
.toRole("global", GUEST).grantPermission(INSERT)
|
.toRole("global", GUEST).grantPermission(INSERT)
|
||||||
|
|
||||||
.createRole(OWNER, (with) -> {
|
.createRole(OWNER, (with) -> {
|
||||||
|
@ -22,6 +22,8 @@ class HsOfficePersonEntityPatcher implements EntityPatcher<HsOfficePersonPatchRe
|
|||||||
.map(HsOfficePersonType::valueOf)
|
.map(HsOfficePersonType::valueOf)
|
||||||
.ifPresent(entity::setPersonType);
|
.ifPresent(entity::setPersonType);
|
||||||
OptionalFromJson.of(resource.getTradeName()).ifPresent(entity::setTradeName);
|
OptionalFromJson.of(resource.getTradeName()).ifPresent(entity::setTradeName);
|
||||||
|
OptionalFromJson.of(resource.getSalutation()).ifPresent(entity::setSalutation);
|
||||||
|
OptionalFromJson.of(resource.getTitle()).ifPresent(entity::setTitle);
|
||||||
OptionalFromJson.of(resource.getFamilyName()).ifPresent(entity::setFamilyName);
|
OptionalFromJson.of(resource.getFamilyName()).ifPresent(entity::setFamilyName);
|
||||||
OptionalFromJson.of(resource.getGivenName()).ifPresent(entity::setGivenName);
|
OptionalFromJson.of(resource.getGivenName()).ifPresent(entity::setGivenName);
|
||||||
}
|
}
|
||||||
|
@ -11,17 +11,19 @@ import net.hostsharing.hsadminng.stringify.Stringify;
|
|||||||
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
import java.io.IOException;
|
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.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.GLOBAL;
|
|
||||||
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.*;
|
||||||
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.Role.*;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.directlyFetchedByDependsOnColumn;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.directlyFetchedByDependsOnColumn;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
|
|
||||||
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@ -104,31 +106,55 @@ public class HsOfficeRelationEntity implements RbacObject, Stringifyable {
|
|||||||
dependsOnColumn("contactUuid"),
|
dependsOnColumn("contactUuid"),
|
||||||
directlyFetchedByDependsOnColumn(),
|
directlyFetchedByDependsOnColumn(),
|
||||||
NOT_NULL)
|
NOT_NULL)
|
||||||
.createRole(OWNER, (with) -> {
|
.switchOnColumn("type",
|
||||||
with.owningUser(CREATOR);
|
inCaseOf("REPRESENTATIVE", then -> {
|
||||||
with.incomingSuperRole(GLOBAL, ADMIN);
|
then.createRole(OWNER, (with) -> {
|
||||||
// TODO: if type=REPRESENTATIIVE
|
with.owningUser(CREATOR);
|
||||||
// with.incomingSuperRole("holderPerson", ADMIN);
|
with.incomingSuperRole(GLOBAL, ADMIN);
|
||||||
with.permission(DELETE);
|
with.incomingSuperRole("holderPerson", ADMIN);
|
||||||
})
|
with.permission(DELETE);
|
||||||
.createSubRole(ADMIN, (with) -> {
|
})
|
||||||
with.incomingSuperRole("anchorPerson", ADMIN);
|
.createSubRole(ADMIN, (with) -> {
|
||||||
// TODO: if type=REPRESENTATIIVE
|
with.outgoingSubRole("anchorPerson", OWNER);
|
||||||
// with.outgoingSuperRole("anchorPerson", OWNER);
|
with.permission(UPDATE);
|
||||||
with.permission(UPDATE);
|
})
|
||||||
})
|
.createSubRole(AGENT, (with) -> {
|
||||||
.createSubRole(AGENT, (with) -> {
|
with.incomingSuperRole("anchorPerson", ADMIN);
|
||||||
with.incomingSuperRole("holderPerson", ADMIN);
|
})
|
||||||
})
|
.createSubRole(TENANT, (with) -> {
|
||||||
.createSubRole(TENANT, (with) -> {
|
with.incomingSuperRole("contact", ADMIN);
|
||||||
with.incomingSuperRole("holderPerson", ADMIN);
|
with.outgoingSubRole("anchorPerson", REFERRER);
|
||||||
with.incomingSuperRole("contact", ADMIN);
|
with.outgoingSubRole("holderPerson", REFERRER);
|
||||||
with.outgoingSubRole("anchorPerson", REFERRER);
|
with.outgoingSubRole("contact", REFERRER);
|
||||||
with.outgoingSubRole("holderPerson", REFERRER);
|
with.permission(SELECT);
|
||||||
with.outgoingSubRole("contact", REFERRER);
|
});
|
||||||
with.permission(SELECT);
|
}),
|
||||||
})
|
// inCaseOf("DEBITOR", then -> {}), TODO.spec: needs to be defined
|
||||||
|
inOtherCases(then -> {
|
||||||
|
then.createRole(OWNER, (with) -> {
|
||||||
|
with.owningUser(CREATOR);
|
||||||
|
with.incomingSuperRole(GLOBAL, ADMIN);
|
||||||
|
with.incomingSuperRole("anchorPerson", ADMIN);
|
||||||
|
with.permission(DELETE);
|
||||||
|
})
|
||||||
|
.createSubRole(ADMIN, (with) -> {
|
||||||
|
with.permission(UPDATE);
|
||||||
|
})
|
||||||
|
.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);
|
||||||
|
})
|
||||||
|
.createSubRole(TENANT, (with) -> {
|
||||||
|
with.incomingSuperRole("contact", ADMIN);
|
||||||
|
with.outgoingSubRole("anchorPerson", REFERRER);
|
||||||
|
with.outgoingSubRole("holderPerson", REFERRER);
|
||||||
|
with.outgoingSubRole("contact", REFERRER);
|
||||||
|
with.permission(SELECT);
|
||||||
|
});
|
||||||
|
}))
|
||||||
.toRole("anchorPerson", ADMIN).grantPermission(INSERT);
|
.toRole("anchorPerson", ADMIN).grantPermission(INSERT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity;
|
|||||||
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationEntity;
|
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationEntity;
|
||||||
import net.hostsharing.hsadminng.hs.office.sepamandate.HsOfficeSepaMandateEntity;
|
import net.hostsharing.hsadminng.hs.office.sepamandate.HsOfficeSepaMandateEntity;
|
||||||
import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
|
import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
|
||||||
import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
|
|
||||||
import net.hostsharing.hsadminng.test.cust.TestCustomerEntity;
|
import net.hostsharing.hsadminng.test.cust.TestCustomerEntity;
|
||||||
import net.hostsharing.hsadminng.test.dom.TestDomainEntity;
|
import net.hostsharing.hsadminng.test.dom.TestDomainEntity;
|
||||||
import net.hostsharing.hsadminng.test.pac.TestPackageEntity;
|
import net.hostsharing.hsadminng.test.pac.TestPackageEntity;
|
||||||
@ -27,18 +26,22 @@ 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 net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.directlyFetchedByDependsOnColumn;
|
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
|
||||||
|
// TODO.refa: rename to RbacDSL
|
||||||
public class RbacView {
|
public class RbacView {
|
||||||
|
|
||||||
public static final String GLOBAL = "global";
|
public static final String GLOBAL = "global";
|
||||||
@ -61,11 +64,23 @@ 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, CaseDef> cases = new LinkedHashMap<>() {
|
||||||
|
@Override
|
||||||
|
public CaseDef put(final String key, final CaseDef value) {
|
||||||
|
if (containsKey(key)) {
|
||||||
|
throw new IllegalArgumentException("duplicate case: " + key);
|
||||||
|
}
|
||||||
|
return super.put(key, value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/** Crates an RBAC definition template for the given entity class and defining the given alias.
|
/** Crates an RBAC definition template for the given entity class and defining the given alias.
|
||||||
*
|
*
|
||||||
@ -239,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.impl: 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) {
|
||||||
@ -278,12 +297,13 @@ public class RbacView {
|
|||||||
public <EC extends RbacObject> RbacView importRootEntityAliasProxy(
|
public <EC extends RbacObject> RbacView importRootEntityAliasProxy(
|
||||||
final String aliasName,
|
final String aliasName,
|
||||||
final Class<? extends RbacObject> entityClass,
|
final Class<? extends RbacObject> entityClass,
|
||||||
|
final ColumnValue forCase,
|
||||||
final SQL fetchSql,
|
final SQL fetchSql,
|
||||||
final Column dependsOnColum) {
|
final Column dependsOnColum) {
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,25 +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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: remove once it's not used in HsOffice...Entity anymore
|
|
||||||
public RbacView importEntityAlias(
|
|
||||||
final String aliasName, final Class<? extends RbacObject> entityClass,
|
|
||||||
final Column dependsOnColum) {
|
|
||||||
importEntityAliasImpl(aliasName, entityClass, directlyFetchedByDependsOnColumn(), dependsOnColum, false, null);
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
@ -366,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()
|
||||||
@ -381,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.forCases == null || 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),
|
||||||
@ -398,6 +411,18 @@ public class RbacView {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RbacView switchOnColumn(final String discriminatorColumName, final CaseDef... caseDefs) {
|
||||||
|
this.discriminatorColumName = discriminatorColumName;
|
||||||
|
allCases.addAll(stream(caseDefs).toList());
|
||||||
|
|
||||||
|
stream(caseDefs).forEach(caseDef -> {
|
||||||
|
this.processingCase = caseDef;
|
||||||
|
caseDef.def.accept(this);
|
||||||
|
this.processingCase = null;
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
private void verifyVersionColumnExists() {
|
private void verifyVersionColumnExists() {
|
||||||
if (stream(rootEntityAlias.entityClass.getDeclaredFields())
|
if (stream(rootEntityAlias.entityClass.getDeclaredFields())
|
||||||
.noneMatch(f -> f.getAnnotation(Version.class) != null)) {
|
.noneMatch(f -> f.getAnnotation(Version.class) != null)) {
|
||||||
@ -455,7 +480,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.value) + ".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"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -495,22 +528,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 Set<CaseDef> forCases = new HashSet<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
final var arrow = isAssumed() ? " --> " : " -- // --> ";
|
final var arrow = isAssumed() ? " --> " : " -- // --> ";
|
||||||
return switch (grantType()) {
|
final var grant = 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -536,7 +575,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;
|
||||||
}
|
}
|
||||||
@ -545,6 +584,23 @@ public class RbacView {
|
|||||||
return assumed;
|
return assumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RbacGrantDefinition forCase(final CaseDef processingCase) {
|
||||||
|
forCases.add(processingCase);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isConditional() {
|
||||||
|
return forCases != null && !forCases.isEmpty() && forCases.size()<allCases.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean matchesCase(final ColumnValue requestedCase) {
|
||||||
|
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 isToCreate() {
|
boolean isToCreate() {
|
||||||
return toCreate;
|
return toCreate;
|
||||||
}
|
}
|
||||||
@ -566,8 +622,9 @@ public class RbacView {
|
|||||||
.orElse(false);
|
.orElse(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unassumed() {
|
public RbacGrantDefinition unassumed() {
|
||||||
this.assumed = false;
|
this.assumed = false;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum GrantType {
|
public enum GrantType {
|
||||||
@ -793,7 +850,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));
|
||||||
}
|
}
|
||||||
@ -801,10 +858,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) {
|
||||||
@ -1021,6 +1080,23 @@ public class RbacView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ColumnValue {
|
||||||
|
|
||||||
|
public static ColumnValue usingDefaultCase() {
|
||||||
|
return new ColumnValue(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ColumnValue usingCase(final String value) {
|
||||||
|
return new ColumnValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final String value;
|
||||||
|
|
||||||
|
private ColumnValue(final String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static class AliasNameMapper {
|
private static class AliasNameMapper {
|
||||||
|
|
||||||
private final RbacView importedRbacView;
|
private final RbacView importedRbacView;
|
||||||
@ -1045,6 +1121,55 @@ public class RbacView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class CaseDef extends ColumnValue {
|
||||||
|
|
||||||
|
final Consumer<RbacView> def;
|
||||||
|
|
||||||
|
private CaseDef(final String discriminatorColumnValue, final Consumer<RbacView> def) {
|
||||||
|
super(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(value).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(value, caseDef.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isDefaultCase() {
|
||||||
|
return value == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return isDefaultCase()
|
||||||
|
? "inOtherCases"
|
||||||
|
: "inCaseOf:" + value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCase(final ColumnValue requestedCase) {
|
||||||
|
return Objects.equals(requestedCase.value, this.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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,10 +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.isAssumed() ? " " : "|XX| ");
|
+ (grant.isAssumed() ? " " : "|XX| ");
|
||||||
return switch (grant.grantType()) {
|
final var grantDef = 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());
|
||||||
@ -118,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) {
|
||||||
@ -146,16 +165,17 @@ public class RbacViewMermaidFlowchartGenerator {
|
|||||||
Files.writeString(
|
Files.writeString(
|
||||||
path,
|
path,
|
||||||
"""
|
"""
|
||||||
### rbac %{entityAlias}
|
### rbac %{entityAlias}%{case}
|
||||||
|
|
||||||
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())
|
||||||
|
.replace("%{case}", forCase == null ? "" : " " + forCase),
|
||||||
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,10 +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.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;
|
||||||
@ -22,7 +25,7 @@ import static org.apache.commons.lang3.StringUtils.uncapitalize;
|
|||||||
class RolesGrantsAndPermissionsGenerator {
|
class RolesGrantsAndPermissionsGenerator {
|
||||||
|
|
||||||
private final RbacView rbacDef;
|
private final RbacView rbacDef;
|
||||||
private final Set<RbacView.RbacGrantDefinition> rbacGrants = new HashSet<>();
|
private final Set<RbacGrantDefinition> rbacGrants = new HashSet<>();
|
||||||
private final String liquibaseTagPrefix;
|
private final String liquibaseTagPrefix;
|
||||||
private final String simpleEntityName;
|
private final String simpleEntityName;
|
||||||
private final String simpleEntityVarName;
|
private final String simpleEntityVarName;
|
||||||
@ -31,7 +34,7 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
RolesGrantsAndPermissionsGenerator(final RbacView rbacDef, final String liquibaseTagPrefix) {
|
RolesGrantsAndPermissionsGenerator(final RbacView rbacDef, final String liquibaseTagPrefix) {
|
||||||
this.rbacDef = rbacDef;
|
this.rbacDef = rbacDef;
|
||||||
this.rbacGrants.addAll(rbacDef.getGrantDefs().stream()
|
this.rbacGrants.addAll(rbacDef.getGrantDefs().stream()
|
||||||
.filter(RbacView.RbacGrantDefinition::isToCreate)
|
.filter(RbacGrantDefinition::isToCreate)
|
||||||
.collect(toSet()));
|
.collect(toSet()));
|
||||||
this.liquibaseTagPrefix = liquibaseTagPrefix;
|
this.liquibaseTagPrefix = liquibaseTagPrefix;
|
||||||
|
|
||||||
@ -67,13 +70,11 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
NEW ${rawTableName}
|
NEW ${rawTableName}
|
||||||
)
|
)
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
|
|
||||||
declare
|
|
||||||
"""
|
"""
|
||||||
.replace("${simpleEntityName}", simpleEntityName)
|
.replace("${simpleEntityName}", simpleEntityName)
|
||||||
.replace("${rawTableName}", rawTableName));
|
.replace("${rawTableName}", rawTableName));
|
||||||
|
|
||||||
plPgSql.chopEmptyLines();
|
plPgSql.writeLn("declare");
|
||||||
plPgSql.indented(() -> {
|
plPgSql.indented(() -> {
|
||||||
referencedEntityAliases()
|
referencedEntityAliases()
|
||||||
.forEach((ea) -> plPgSql.writeLn(entityRefVar(NEW, ea) + " " + ea.getRawTableName() + ";"));
|
.forEach((ea) -> plPgSql.writeLn(entityRefVar(NEW, ea) + " " + ea.getRawTableName() + ";"));
|
||||||
@ -172,6 +173,10 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
.anyMatch(e -> true);
|
.anyMatch(e -> true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean hasAnyConditionalGrants() {
|
||||||
|
return rbacDef.getGrantDefs().stream().anyMatch(RbacGrantDefinition::isConditional);
|
||||||
|
}
|
||||||
|
|
||||||
private void generateCreateRolesAndGrantsAfterInsert(final StringWriter plPgSql) {
|
private void generateCreateRolesAndGrantsAfterInsert(final StringWriter plPgSql) {
|
||||||
referencedEntityAliases()
|
referencedEntityAliases()
|
||||||
.forEach((ea) -> {
|
.forEach((ea) -> {
|
||||||
@ -186,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.value != null) {
|
||||||
|
plPgSql.writeLn(ifOrElsIf + "NEW." + rbacDef.getDiscriminatorColumName() + " = '" + caseDef.value + "' 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,7 +271,7 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
|
|
||||||
private void updateGrantsDependingOn(final StringWriter plPgSql, final String columnName) {
|
private void updateGrantsDependingOn(final StringWriter plPgSql, final String columnName) {
|
||||||
rbacDef.getGrantDefs().stream()
|
rbacDef.getGrantDefs().stream()
|
||||||
.filter(RbacView.RbacGrantDefinition::isToCreate)
|
.filter(RbacGrantDefinition::isToCreate)
|
||||||
.filter(g -> g.dependsOnColumn(columnName))
|
.filter(g -> g.dependsOnColumn(columnName))
|
||||||
.filter(g -> !isInsertPermissionGrant(g))
|
.filter(g -> !isInsertPermissionGrant(g))
|
||||||
.forEach(g -> {
|
.forEach(g -> {
|
||||||
@ -259,21 +282,31 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Boolean isInsertPermissionGrant(final RbacView.RbacGrantDefinition g) {
|
private static Boolean isInsertPermissionGrant(final RbacGrantDefinition g) {
|
||||||
final var isInsertPermissionGrant = ofNullable(g.getPermDef()).map(RbacPermissionDefinition::getPermission).map(p -> p == INSERT).orElse(false);
|
final var isInsertPermissionGrant = ofNullable(g.getPermDef()).map(RbacPermissionDefinition::getPermission).map(p -> p == INSERT).orElse(false);
|
||||||
return isInsertPermissionGrant;
|
return isInsertPermissionGrant;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateGrants(final StringWriter plPgSql, final RbacView.RbacGrantDefinition.GrantType grantType) {
|
private void generateGrants(final StringWriter plPgSql, final RbacGrantDefinition.GrantType grantType, final CaseDef caseDef) {
|
||||||
plPgSql.ensureSingleEmptyLine();
|
|
||||||
rbacGrants.stream()
|
rbacGrants.stream()
|
||||||
|
.filter(g -> g.matchesCase(caseDef))
|
||||||
.filter(g -> g.grantType() == grantType)
|
.filter(g -> g.grantType() == grantType)
|
||||||
.map(this::generateGrant)
|
.map(this::generateGrant)
|
||||||
.sorted()
|
.sorted()
|
||||||
.forEach(text -> plPgSql.writeLn(text));
|
.forEach(text -> plPgSql.writeLn(text, with("ref", NEW.name())));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String generateRevoke(RbacView.RbacGrantDefinition grantDef) {
|
private void generateGrants(final StringWriter plPgSql, final RbacGrantDefinition.GrantType grantType) {
|
||||||
|
plPgSql.ensureSingleEmptyLine();
|
||||||
|
rbacGrants.stream()
|
||||||
|
.filter(g -> !g.isConditional())
|
||||||
|
.filter(g -> g.grantType() == grantType)
|
||||||
|
.map(this::generateGrant)
|
||||||
|
.sorted()
|
||||||
|
.forEach(text -> plPgSql.writeLn(text, with("ref", NEW.name())));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generateRevoke(RbacGrantDefinition grantDef) {
|
||||||
return switch (grantDef.grantType()) {
|
return switch (grantDef.grantType()) {
|
||||||
case ROLE_TO_USER -> throw new IllegalArgumentException("unexpected grant");
|
case ROLE_TO_USER -> throw new IllegalArgumentException("unexpected grant");
|
||||||
case ROLE_TO_ROLE -> "call revokeRoleFromRole(${subRoleRef}, ${superRoleRef});"
|
case ROLE_TO_ROLE -> "call revokeRoleFromRole(${subRoleRef}, ${superRoleRef});"
|
||||||
@ -285,8 +318,8 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private String generateGrant(RbacView.RbacGrantDefinition grantDef) {
|
private String generateGrant(RbacGrantDefinition grantDef) {
|
||||||
return switch (grantDef.grantType()) {
|
final var grantSql = switch (grantDef.grantType()) {
|
||||||
case ROLE_TO_USER -> throw new IllegalArgumentException("unexpected grant");
|
case ROLE_TO_USER -> throw new IllegalArgumentException("unexpected grant");
|
||||||
case ROLE_TO_ROLE -> "call grantRoleToRole(${subRoleRef}, ${superRoleRef}${assumed});"
|
case ROLE_TO_ROLE -> "call grantRoleToRole(${subRoleRef}, ${superRoleRef}${assumed});"
|
||||||
.replace("${assumed}", grantDef.isAssumed() ? "" : ", unassumed()")
|
.replace("${assumed}", grantDef.isAssumed() ? "" : ", unassumed()")
|
||||||
@ -298,6 +331,7 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
.replace("${permRef}", createPerm(NEW, grantDef.getPermDef()))
|
.replace("${permRef}", createPerm(NEW, grantDef.getPermDef()))
|
||||||
.replace("${superRoleRef}", roleRef(NEW, grantDef.getSuperRoleDef()));
|
.replace("${superRoleRef}", roleRef(NEW, grantDef.getSuperRoleDef()));
|
||||||
};
|
};
|
||||||
|
return grantSql;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String findPerm(final PostgresTriggerReference ref, final RbacPermissionDefinition permDef) {
|
private String findPerm(final PostgresTriggerReference ref, final RbacPermissionDefinition permDef) {
|
||||||
@ -362,11 +396,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");
|
||||||
@ -380,7 +411,7 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
final var grantsToUsers = findGrantsToUserForRole(rbacDef.getRootEntityAlias(), role);
|
final var grantsToUsers = findGrantsToUserForRole(rbacDef.getRootEntityAlias(), role);
|
||||||
if (!grantsToUsers.isEmpty()) {
|
if (!grantsToUsers.isEmpty()) {
|
||||||
final var arrayElements = grantsToUsers.stream()
|
final var arrayElements = grantsToUsers.stream()
|
||||||
.map(RbacView.RbacGrantDefinition::getUserDef)
|
.map(RbacGrantDefinition::getUserDef)
|
||||||
.map(this::toPlPgSqlReference)
|
.map(this::toPlPgSqlReference)
|
||||||
.toList();
|
.toList();
|
||||||
plPgSql.indented(() ->
|
plPgSql.indented(() ->
|
||||||
@ -393,7 +424,7 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
final var permissionGrantsForRole = findPermissionsGrantsForRole(rbacDef.getRootEntityAlias(), role);
|
final var permissionGrantsForRole = findPermissionsGrantsForRole(rbacDef.getRootEntityAlias(), role);
|
||||||
if (!permissionGrantsForRole.isEmpty()) {
|
if (!permissionGrantsForRole.isEmpty()) {
|
||||||
final var arrayElements = permissionGrantsForRole.stream()
|
final var arrayElements = permissionGrantsForRole.stream()
|
||||||
.map(RbacView.RbacGrantDefinition::getPermDef)
|
.map(RbacGrantDefinition::getPermDef)
|
||||||
.map(RbacPermissionDefinition::getPermission)
|
.map(RbacPermissionDefinition::getPermission)
|
||||||
.map(RbacView.Permission::name)
|
.map(RbacView.Permission::name)
|
||||||
.map(p -> "'" + p + "'")
|
.map(p -> "'" + p + "'")
|
||||||
@ -406,26 +437,30 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void generateIncomingSuperRolesForRole(final StringWriter plPgSql, final RbacView.Role role) {
|
private void generateIncomingSuperRolesForRole(final StringWriter plPgSql, final RbacView.Role role) {
|
||||||
final var incomingGrants = findIncomingSuperRolesForRole(rbacDef.getRootEntityAlias(), role);
|
final var unconditionalIncomingGrants = findIncomingSuperRolesForRole(rbacDef.getRootEntityAlias(), role).stream()
|
||||||
if (!incomingGrants.isEmpty()) {
|
.filter(g -> !g.isConditional())
|
||||||
final var arrayElements = incomingGrants.stream()
|
.toList();
|
||||||
|
if (!unconditionalIncomingGrants.isEmpty()) {
|
||||||
|
final var arrayElements = unconditionalIncomingGrants.stream()
|
||||||
.map(g -> toPlPgSqlReference(NEW, g.getSuperRoleDef(), g.isAssumed()))
|
.map(g -> toPlPgSqlReference(NEW, g.getSuperRoleDef(), g.isAssumed()))
|
||||||
.sorted().toList();
|
.sorted().toList();
|
||||||
plPgSql.indented(() ->
|
plPgSql.indented(() ->
|
||||||
plPgSql.writeLn("incomingSuperRoles => array[" + joinArrayElements(arrayElements, 1) + "],\n"));
|
plPgSql.writeLn("incomingSuperRoles => array[" + joinArrayElements(arrayElements, 1) + "],\n"));
|
||||||
rbacGrants.removeAll(incomingGrants);
|
rbacGrants.removeAll(unconditionalIncomingGrants);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateOutgoingSubRolesForRole(final StringWriter plPgSql, final RbacView.Role role) {
|
private void generateOutgoingSubRolesForRole(final StringWriter plPgSql, final RbacView.Role role) {
|
||||||
final var outgoingGrants = findOutgoingSuperRolesForRole(rbacDef.getRootEntityAlias(), role);
|
final var unconditionalOutgoingGrants = findOutgoingSuperRolesForRole(rbacDef.getRootEntityAlias(), role).stream()
|
||||||
if (!outgoingGrants.isEmpty()) {
|
.filter(g -> !g.isConditional())
|
||||||
final var arrayElements = outgoingGrants.stream()
|
.toList();
|
||||||
|
if (!unconditionalOutgoingGrants.isEmpty()) {
|
||||||
|
final var arrayElements = unconditionalOutgoingGrants.stream()
|
||||||
.map(g -> toPlPgSqlReference(NEW, g.getSubRoleDef(), g.isAssumed()))
|
.map(g -> toPlPgSqlReference(NEW, g.getSubRoleDef(), g.isAssumed()))
|
||||||
.sorted().toList();
|
.sorted().toList();
|
||||||
plPgSql.indented(() ->
|
plPgSql.indented(() ->
|
||||||
plPgSql.writeLn("outgoingSubRoles => array[" + joinArrayElements(arrayElements, 1) + "],\n"));
|
plPgSql.writeLn("outgoingSubRoles => array[" + joinArrayElements(arrayElements, 1) + "],\n"));
|
||||||
rbacGrants.removeAll(outgoingGrants);
|
rbacGrants.removeAll(unconditionalOutgoingGrants);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,7 +470,7 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
: arrayElements.stream().collect(joining(",\n\t", "\n\t", ""));
|
: arrayElements.stream().collect(joining(",\n\t", "\n\t", ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<RbacView.RbacGrantDefinition> findPermissionsGrantsForRole(
|
private Set<RbacGrantDefinition> findPermissionsGrantsForRole(
|
||||||
final RbacView.EntityAlias entityAlias,
|
final RbacView.EntityAlias entityAlias,
|
||||||
final RbacView.Role role) {
|
final RbacView.Role role) {
|
||||||
final var roleDef = rbacDef.findRbacRole(entityAlias, role);
|
final var roleDef = rbacDef.findRbacRole(entityAlias, role);
|
||||||
@ -444,7 +479,7 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
.collect(toSet());
|
.collect(toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<RbacView.RbacGrantDefinition> findGrantsToUserForRole(
|
private Set<RbacGrantDefinition> findGrantsToUserForRole(
|
||||||
final RbacView.EntityAlias entityAlias,
|
final RbacView.EntityAlias entityAlias,
|
||||||
final RbacView.Role role) {
|
final RbacView.Role role) {
|
||||||
final var roleDef = rbacDef.findRbacRole(entityAlias, role);
|
final var roleDef = rbacDef.findRbacRole(entityAlias, role);
|
||||||
@ -453,7 +488,7 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
.collect(toSet());
|
.collect(toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<RbacView.RbacGrantDefinition> findIncomingSuperRolesForRole(
|
private Set<RbacGrantDefinition> findIncomingSuperRolesForRole(
|
||||||
final RbacView.EntityAlias entityAlias,
|
final RbacView.EntityAlias entityAlias,
|
||||||
final RbacView.Role role) {
|
final RbacView.Role role) {
|
||||||
final var roleDef = rbacDef.findRbacRole(entityAlias, role);
|
final var roleDef = rbacDef.findRbacRole(entityAlias, role);
|
||||||
@ -462,7 +497,7 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
.collect(toSet());
|
.collect(toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<RbacView.RbacGrantDefinition> findOutgoingSuperRolesForRole(
|
private Set<RbacGrantDefinition> findOutgoingSuperRolesForRole(
|
||||||
final RbacView.EntityAlias entityAlias,
|
final RbacView.EntityAlias entityAlias,
|
||||||
final RbacView.Role role) {
|
final RbacView.Role role) {
|
||||||
final var roleDef = rbacDef.findRbacRole(entityAlias, role);
|
final var roleDef = rbacDef.findRbacRole(entityAlias, role);
|
||||||
@ -506,7 +541,7 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
private void generateUpdateTrigger(final StringWriter plPgSql) {
|
private void generateUpdateTrigger(final StringWriter plPgSql) {
|
||||||
|
|
||||||
generateHeader(plPgSql, "update");
|
generateHeader(plPgSql, "update");
|
||||||
if ( hasAnyUpdatableAndNullableEntityAliases() ) {
|
if ( hasAnyUpdatableAndNullableEntityAliases() || hasAnyConditionalGrants() ) {
|
||||||
generateSimplifiedUpdateTriggerFunction(plPgSql);
|
generateSimplifiedUpdateTriggerFunction(plPgSql);
|
||||||
} else {
|
} else {
|
||||||
generateUpdateTriggerFunction(plPgSql);
|
generateUpdateTriggerFunction(plPgSql);
|
||||||
|
@ -167,7 +167,7 @@ public class RbacGrantsDiagramService {
|
|||||||
return "users";
|
return "users";
|
||||||
}
|
}
|
||||||
if (refType.equals("perm")) {
|
if (refType.equals("perm")) {
|
||||||
return node.idName().split(" ", 4)[3];
|
return node.idName().split(":", 3)[1];
|
||||||
}
|
}
|
||||||
if (refType.equals("role")) {
|
if (refType.equals("role")) {
|
||||||
final var withoutRolePrefix = node.idName().substring("role:".length());
|
final var withoutRolePrefix = node.idName().substring("role:".length());
|
||||||
@ -209,7 +209,7 @@ public class RbacGrantsDiagramService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class LimitedHashSet<T> extends HashSet<T> {
|
static class LimitedHashSet<T> extends HashSet<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean add(final T t) {
|
public boolean add(final T t) {
|
||||||
|
@ -23,6 +23,10 @@ components:
|
|||||||
$ref: '#/components/schemas/HsOfficePersonType'
|
$ref: '#/components/schemas/HsOfficePersonType'
|
||||||
tradeName:
|
tradeName:
|
||||||
type: string
|
type: string
|
||||||
|
salutation:
|
||||||
|
type: string
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
givenName:
|
givenName:
|
||||||
type: string
|
type: string
|
||||||
familyName:
|
familyName:
|
||||||
@ -35,6 +39,10 @@ components:
|
|||||||
$ref: '#/components/schemas/HsOfficePersonType'
|
$ref: '#/components/schemas/HsOfficePersonType'
|
||||||
tradeName:
|
tradeName:
|
||||||
type: string
|
type: string
|
||||||
|
salutation:
|
||||||
|
type: string
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
givenName:
|
givenName:
|
||||||
type: string
|
type: string
|
||||||
familyName:
|
familyName:
|
||||||
@ -51,6 +59,12 @@ components:
|
|||||||
tradeName:
|
tradeName:
|
||||||
type: string
|
type: string
|
||||||
nullable: true
|
nullable: true
|
||||||
|
salutation:
|
||||||
|
type: string
|
||||||
|
nullable: true
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
nullable: true
|
||||||
givenName:
|
givenName:
|
||||||
type: string
|
type: string
|
||||||
nullable: true
|
nullable: true
|
||||||
|
@ -248,7 +248,7 @@ declare
|
|||||||
objectUuidOfRole uuid;
|
objectUuidOfRole uuid;
|
||||||
roleUuid uuid;
|
roleUuid uuid;
|
||||||
begin
|
begin
|
||||||
-- TODO.refact: extract function toRbacRoleDescriptor(roleIdName varchar) + find other occurrences
|
-- TODO.refa: extract function toRbacRoleDescriptor(roleIdName varchar) + find other occurrences
|
||||||
roleParts = overlay(roleIdName placing '#' from length(roleIdName) + 1 - strpos(reverse(roleIdName), ':'));
|
roleParts = overlay(roleIdName placing '#' from length(roleIdName) + 1 - strpos(reverse(roleIdName), ':'));
|
||||||
objectTableFromRoleIdName = split_part(roleParts, '#', 1);
|
objectTableFromRoleIdName = split_part(roleParts, '#', 1);
|
||||||
objectNameFromRoleIdName = split_part(roleParts, '#', 2);
|
objectNameFromRoleIdName = split_part(roleParts, '#', 2);
|
||||||
@ -356,16 +356,13 @@ create trigger deleteRbacRolesOfRbacObject_Trigger
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
*/
|
*/
|
||||||
create domain RbacOp as varchar(67) -- TODO: shorten to 8, once the deprecated values are gone
|
create domain RbacOp as varchar(6)
|
||||||
check (
|
check (
|
||||||
VALUE = 'DELETE'
|
VALUE = 'DELETE'
|
||||||
or VALUE = 'UPDATE'
|
or VALUE = 'UPDATE'
|
||||||
or VALUE = 'SELECT'
|
or VALUE = 'SELECT'
|
||||||
or VALUE = 'INSERT'
|
or VALUE = 'INSERT'
|
||||||
or VALUE = 'ASSUME'
|
or VALUE = 'ASSUME'
|
||||||
-- TODO: all values below are deprecated, use insert with table
|
|
||||||
or VALUE ~ '^add-[a-z]+$'
|
|
||||||
or VALUE ~ '^new-[a-z-]+$'
|
|
||||||
);
|
);
|
||||||
|
|
||||||
create table RbacPermission
|
create table RbacPermission
|
||||||
@ -417,37 +414,6 @@ begin
|
|||||||
return permissionUuid;
|
return permissionUuid;
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
-- TODO: deprecated, remove and amend all usages to createPermission
|
|
||||||
create or replace function createPermissions(forObjectUuid uuid, permitOps RbacOp[])
|
|
||||||
returns uuid[]
|
|
||||||
language plpgsql as $$
|
|
||||||
declare
|
|
||||||
refId uuid;
|
|
||||||
permissionIds uuid[] = array []::uuid[];
|
|
||||||
begin
|
|
||||||
if (forObjectUuid is null) then
|
|
||||||
raise exception 'forObjectUuid must not be null';
|
|
||||||
end if;
|
|
||||||
|
|
||||||
for i in array_lower(permitOps, 1)..array_upper(permitOps, 1)
|
|
||||||
loop
|
|
||||||
refId = (select uuid from RbacPermission where objectUuid = forObjectUuid and op = permitOps[i]);
|
|
||||||
if (refId is null) then
|
|
||||||
insert
|
|
||||||
into RbacReference ("type")
|
|
||||||
values ('RbacPermission')
|
|
||||||
returning uuid into refId;
|
|
||||||
insert
|
|
||||||
into RbacPermission (uuid, objectUuid, op)
|
|
||||||
values (refId, forObjectUuid, permitOps[i]);
|
|
||||||
end if;
|
|
||||||
permissionIds = permissionIds || refId;
|
|
||||||
end loop;
|
|
||||||
|
|
||||||
return permissionIds;
|
|
||||||
end;
|
|
||||||
$$;
|
|
||||||
|
|
||||||
create or replace function findEffectivePermissionId(forObjectUuid uuid, forOp RbacOp, forOpTableName text = null)
|
create or replace function findEffectivePermissionId(forObjectUuid uuid, forOp RbacOp, forOpTableName text = null)
|
||||||
returns uuid
|
returns uuid
|
||||||
returns null on null input
|
returns null on null input
|
||||||
@ -649,25 +615,6 @@ begin
|
|||||||
end;
|
end;
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
-- TODO: deprecated, remove and use grantPermissionToRole(...)
|
|
||||||
create or replace procedure grantPermissionsToRole(roleUuid uuid, permissionIds uuid[])
|
|
||||||
language plpgsql as $$
|
|
||||||
begin
|
|
||||||
if cardinality(permissionIds) = 0 then return; end if;
|
|
||||||
|
|
||||||
for i in array_lower(permissionIds, 1)..array_upper(permissionIds, 1)
|
|
||||||
loop
|
|
||||||
perform assertReferenceType('roleId (ascendant)', roleUuid, 'RbacRole');
|
|
||||||
perform assertReferenceType('permissionId (descendant)', permissionIds[i], 'RbacPermission');
|
|
||||||
|
|
||||||
insert
|
|
||||||
into RbacGrants (grantedByTriggerOf, ascendantUuid, descendantUuid, assumed)
|
|
||||||
values (currentTriggerObjectUuid(), roleUuid, permissionIds[i], true)
|
|
||||||
on conflict do nothing; -- allow granting multiple times
|
|
||||||
end loop;
|
|
||||||
end;
|
|
||||||
$$;
|
|
||||||
|
|
||||||
create or replace procedure grantRoleToRole(subRoleId uuid, superRoleId uuid, doAssume bool = true)
|
create or replace procedure grantRoleToRole(subRoleId uuid, superRoleId uuid, doAssume bool = true)
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
begin
|
begin
|
||||||
@ -691,7 +638,7 @@ declare
|
|||||||
superRoleId uuid;
|
superRoleId uuid;
|
||||||
subRoleId uuid;
|
subRoleId uuid;
|
||||||
begin
|
begin
|
||||||
-- TODO: maybe separate method grantRoleToRoleIfNotNull(...) for NULLABLE references
|
-- TODO.refa: maybe separate method grantRoleToRoleIfNotNull(...) for NULLABLE references
|
||||||
if superRole.objectUuid is null or subRole.objectuuid is null then
|
if superRole.objectUuid is null or subRole.objectuuid is null then
|
||||||
return;
|
return;
|
||||||
end if;
|
end if;
|
||||||
@ -712,30 +659,6 @@ begin
|
|||||||
on conflict do nothing; -- allow granting multiple times
|
on conflict do nothing; -- allow granting multiple times
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
create or replace procedure grantRoleToRoleIfNotNull(subRole RbacRoleDescriptor, superRole RbacRoleDescriptor, doAssume bool = true)
|
|
||||||
language plpgsql as $$
|
|
||||||
declare
|
|
||||||
superRoleId uuid;
|
|
||||||
subRoleId uuid;
|
|
||||||
begin
|
|
||||||
if ( superRoleId is null ) then return; end if;
|
|
||||||
superRoleId := findRoleId(superRole);
|
|
||||||
if ( subRoleId is null ) then return; end if;
|
|
||||||
subRoleId := findRoleId(subRole);
|
|
||||||
|
|
||||||
perform assertReferenceType('superRoleId (ascendant)', superRoleId, 'RbacRole');
|
|
||||||
perform assertReferenceType('subRoleId (descendant)', subRoleId, 'RbacRole');
|
|
||||||
|
|
||||||
if isGranted(subRoleId, superRoleId) then
|
|
||||||
call raiseDuplicateRoleGrantException(subRoleId, superRoleId);
|
|
||||||
end if;
|
|
||||||
|
|
||||||
insert
|
|
||||||
into RbacGrants (grantedByTriggerOf, ascendantuuid, descendantUuid, assumed)
|
|
||||||
values (currentTriggerObjectUuid(), superRoleId, subRoleId, doAssume)
|
|
||||||
on conflict do nothing; -- allow granting multiple times
|
|
||||||
end; $$;
|
|
||||||
|
|
||||||
create or replace procedure revokeRoleFromRole(subRole RbacRoleDescriptor, superRole RbacRoleDescriptor)
|
create or replace procedure revokeRoleFromRole(subRole RbacRoleDescriptor, superRole RbacRoleDescriptor)
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
declare
|
declare
|
||||||
|
@ -20,19 +20,18 @@ begin
|
|||||||
return currentSubjectsUuids[1];
|
return currentSubjectsUuids[1];
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
create or replace procedure grantRoleToUserUnchecked(grantedByRoleUuid uuid, roleUuid uuid, userUuid uuid, doAssume boolean = true)
|
create or replace procedure grantRoleToUserUnchecked(grantedByRoleUuid uuid, grantedRoleUuid uuid, userUuid uuid, doAssume boolean = true)
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
begin
|
begin
|
||||||
perform assertReferenceType('grantingRoleUuid', grantedByRoleUuid, 'RbacRole');
|
perform assertReferenceType('grantingRoleUuid', grantedByRoleUuid, 'RbacRole');
|
||||||
perform assertReferenceType('roleId (descendant)', roleUuid, 'RbacRole');
|
perform assertReferenceType('roleId (descendant)', grantedRoleUuid, 'RbacRole');
|
||||||
perform assertReferenceType('userId (ascendant)', userUuid, 'RbacUser');
|
perform assertReferenceType('userId (ascendant)', userUuid, 'RbacUser');
|
||||||
|
|
||||||
insert
|
insert
|
||||||
into RbacGrants (grantedByRoleUuid, ascendantUuid, descendantUuid, assumed)
|
into RbacGrants (grantedByRoleUuid, ascendantUuid, descendantUuid, assumed)
|
||||||
values (grantedByRoleUuid, userUuid, roleUuid, doAssume);
|
values (grantedByRoleUuid, userUuid, grantedRoleUuid, doAssume)
|
||||||
-- TODO.spec: What should happen on multiple grants? What if options (doAssume) are not the same?
|
-- TODO: check if grantedByRoleUuid+doAssume are the same, otherwise raise exception?
|
||||||
-- Most powerful or latest grant wins? What about managed?
|
on conflict do nothing; -- allow granting multiple times
|
||||||
-- on conflict do nothing; -- allow granting multiple times
|
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
create or replace procedure grantRoleToUser(grantedByRoleUuid uuid, grantedRoleUuid uuid, userUuid uuid, doAssume boolean = true)
|
create or replace procedure grantRoleToUser(grantedByRoleUuid uuid, grantedRoleUuid uuid, userUuid uuid, doAssume boolean = true)
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
--changeset rbac-role-builder-create-role:1 endDelimiter:--//
|
--changeset rbac-role-builder-create-role:1 endDelimiter:--//
|
||||||
-- -----------------------------------------------------------------
|
-- -----------------------------------------------------------------
|
||||||
|
|
||||||
|
-- TODO: rename to defineRoleWithGrants because it does not complain if the role already exists
|
||||||
create or replace function createRoleWithGrants(
|
create or replace function createRoleWithGrants(
|
||||||
roleDescriptor RbacRoleDescriptor,
|
roleDescriptor RbacRoleDescriptor,
|
||||||
permissions RbacOp[] = array[]::RbacOp[],
|
permissions RbacOp[] = array[]::RbacOp[],
|
||||||
@ -28,7 +29,7 @@ declare
|
|||||||
userUuid uuid;
|
userUuid uuid;
|
||||||
userGrantsByRoleUuid uuid;
|
userGrantsByRoleUuid uuid;
|
||||||
begin
|
begin
|
||||||
roleUuid := createRole(roleDescriptor);
|
roleUuid := coalesce(findRoleId(roleDescriptor), createRole(roleDescriptor));
|
||||||
|
|
||||||
foreach permission in array permissions
|
foreach permission in array permissions
|
||||||
loop
|
loop
|
||||||
|
@ -20,6 +20,8 @@ create table if not exists hs_office_person
|
|||||||
version int not null default 0,
|
version int not null default 0,
|
||||||
personType HsOfficePersonType not null,
|
personType HsOfficePersonType not null,
|
||||||
tradeName varchar(96),
|
tradeName varchar(96),
|
||||||
|
salutation varchar(30),
|
||||||
|
title varchar(20),
|
||||||
givenName varchar(48),
|
givenName varchar(48),
|
||||||
familyName varchar(48)
|
familyName varchar(48)
|
||||||
);
|
);
|
||||||
|
@ -138,6 +138,8 @@ call generateRbacRestrictedView('hs_office_person',
|
|||||||
$orderBy$,
|
$orderBy$,
|
||||||
$updates$
|
$updates$
|
||||||
personType = new.personType,
|
personType = new.personType,
|
||||||
|
title = new.title,
|
||||||
|
salutation = new.salutation,
|
||||||
tradeName = new.tradeName,
|
tradeName = new.tradeName,
|
||||||
givenName = new.givenName,
|
givenName = new.givenName,
|
||||||
familyName = new.familyName
|
familyName = new.familyName
|
||||||
|
@ -0,0 +1,102 @@
|
|||||||
|
### rbac relation inCaseOf:REPRESENTATIVE
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
```
|
@ -1,4 +1,4 @@
|
|||||||
### rbac relation
|
### rbac relation inOtherCases
|
||||||
|
|
||||||
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
||||||
|
|
||||||
@ -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));
|
||||||
|
@ -151,15 +151,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: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 +175,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
|
||||||
|
@ -186,13 +186,13 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
"{ grant perm:debitor#D-1000122:DELETE to role:relation#FirstGmbH-with-DEBITOR-FourtheG:OWNER by system and assume }",
|
"{ grant perm:debitor#D-1000122:DELETE to role:relation#FirstGmbH-with-DEBITOR-FourtheG:OWNER by system and assume }",
|
||||||
"{ grant perm:relation#FirstGmbH-with-DEBITOR-FourtheG:DELETE to role:relation#FirstGmbH-with-DEBITOR-FourtheG:OWNER by system and assume }",
|
"{ grant perm:relation#FirstGmbH-with-DEBITOR-FourtheG:DELETE to role:relation#FirstGmbH-with-DEBITOR-FourtheG:OWNER by system and assume }",
|
||||||
"{ grant role:relation#FirstGmbH-with-DEBITOR-FourtheG:OWNER to role:global#global:ADMIN by system and assume }",
|
"{ grant role:relation#FirstGmbH-with-DEBITOR-FourtheG:OWNER to role:global#global:ADMIN by system and assume }",
|
||||||
|
"{ grant role:relation#FirstGmbH-with-DEBITOR-FourtheG:OWNER to role:person#FirstGmbH:ADMIN by system and assume }",
|
||||||
"{ grant role:relation#FirstGmbH-with-DEBITOR-FourtheG:OWNER to user:superuser-alex@hostsharing.net by relation#FirstGmbH-with-DEBITOR-FourtheG:OWNER and assume }",
|
"{ grant role:relation#FirstGmbH-with-DEBITOR-FourtheG:OWNER to user:superuser-alex@hostsharing.net by relation#FirstGmbH-with-DEBITOR-FourtheG:OWNER and assume }",
|
||||||
|
|
||||||
// admin
|
// admin
|
||||||
"{ grant perm:debitor#D-1000122:UPDATE to role:relation#FirstGmbH-with-DEBITOR-FourtheG:ADMIN by system and assume }",
|
"{ grant perm:debitor#D-1000122:UPDATE to role:relation#FirstGmbH-with-DEBITOR-FourtheG:ADMIN by system and assume }",
|
||||||
"{ grant perm:relation#FirstGmbH-with-DEBITOR-FourtheG:UPDATE to role:relation#FirstGmbH-with-DEBITOR-FourtheG:ADMIN by system and assume }",
|
"{ grant perm:relation#FirstGmbH-with-DEBITOR-FourtheG:UPDATE to role:relation#FirstGmbH-with-DEBITOR-FourtheG:ADMIN by system and assume }",
|
||||||
"{ grant role:relation#FirstGmbH-with-DEBITOR-FourtheG:ADMIN to role:relation#FirstGmbH-with-DEBITOR-FourtheG:OWNER by system and assume }",
|
"{ grant role:relation#FirstGmbH-with-DEBITOR-FourtheG:ADMIN to role:relation#FirstGmbH-with-DEBITOR-FourtheG:OWNER by system and assume }",
|
||||||
"{ grant role:relation#FirstGmbH-with-DEBITOR-FourtheG:ADMIN to role:person#FirstGmbH:ADMIN by system and assume }",
|
|
||||||
"{ grant role:relation#FirstGmbH-with-DEBITOR-FourtheG:ADMIN to role:relation#HostsharingeG-with-PARTNER-FirstGmbH:ADMIN by system and assume }",
|
"{ grant role:relation#FirstGmbH-with-DEBITOR-FourtheG:ADMIN to role:relation#HostsharingeG-with-PARTNER-FirstGmbH:ADMIN by system and assume }",
|
||||||
|
|
||||||
// agent
|
// agent
|
||||||
@ -208,7 +208,6 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
"{ grant role:person#FirstGmbH:REFERRER to role:relation#FirstGmbH-with-DEBITOR-FourtheG:TENANT by system and assume }",
|
"{ grant role:person#FirstGmbH:REFERRER to role:relation#FirstGmbH-with-DEBITOR-FourtheG:TENANT by system and assume }",
|
||||||
"{ grant role:person#FourtheG:REFERRER to role:relation#FirstGmbH-with-DEBITOR-FourtheG:TENANT by system and assume }",
|
"{ grant role:person#FourtheG:REFERRER to role:relation#FirstGmbH-with-DEBITOR-FourtheG:TENANT by system and assume }",
|
||||||
"{ grant role:relation#FirstGmbH-with-DEBITOR-FourtheG:TENANT to role:contact#fourthcontact:ADMIN by system and assume }",
|
"{ grant role:relation#FirstGmbH-with-DEBITOR-FourtheG:TENANT to role:contact#fourthcontact:ADMIN by system and assume }",
|
||||||
"{ grant role:relation#FirstGmbH-with-DEBITOR-FourtheG:TENANT to role:person#FourtheG:ADMIN by system and assume }",
|
|
||||||
"{ grant role:relation#FirstGmbH-with-DEBITOR-FourtheG:TENANT to role:relation#FirstGmbH-with-DEBITOR-FourtheG:AGENT by system and assume }",
|
"{ grant role:relation#FirstGmbH-with-DEBITOR-FourtheG:TENANT to role:relation#FirstGmbH-with-DEBITOR-FourtheG:AGENT by system and assume }",
|
||||||
|
|
||||||
null));
|
null));
|
||||||
|
@ -134,6 +134,7 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
|
|||||||
"{ grant perm:membership#M-1000117:SELECT to role:membership#M-1000117:AGENT by system and assume }",
|
"{ grant perm:membership#M-1000117:SELECT to role:membership#M-1000117:AGENT by system and assume }",
|
||||||
"{ grant role:membership#M-1000117:AGENT to role:membership#M-1000117:ADMIN by system and assume }",
|
"{ grant role:membership#M-1000117:AGENT to role:membership#M-1000117:ADMIN by system and assume }",
|
||||||
|
|
||||||
|
// referrer
|
||||||
"{ grant role:membership#M-1000117:AGENT to role:relation#HostsharingeG-with-PARTNER-FirstGmbH:AGENT by system and assume }",
|
"{ grant role:membership#M-1000117:AGENT to role:relation#HostsharingeG-with-PARTNER-FirstGmbH:AGENT by system and assume }",
|
||||||
"{ grant role:relation#HostsharingeG-with-PARTNER-FirstGmbH:TENANT to role:membership#M-1000117:AGENT by system and assume }",
|
"{ grant role:relation#HostsharingeG-with-PARTNER-FirstGmbH:TENANT to role:membership#M-1000117:AGENT by system and assume }",
|
||||||
|
|
||||||
|
@ -218,23 +218,6 @@ public class ImportOfficeData extends ContextBasedTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
@Order(1021)
|
|
||||||
void buildDebitorRelations() {
|
|
||||||
debitors.forEach( (id, debitor) -> {
|
|
||||||
final var debitorRel = HsOfficeRelationEntity.builder()
|
|
||||||
.type(HsOfficeRelationType.DEBITOR)
|
|
||||||
.anchor(debitor.getPartner().getPartnerRel().getHolder())
|
|
||||||
.holder(debitor.getPartner().getPartnerRel().getHolder()) // just 1 debitor/partner in legacy hsadmin
|
|
||||||
// FIXME .contact()
|
|
||||||
.build();
|
|
||||||
if (debitorRel.getAnchor() != null && debitorRel.getHolder() != null &&
|
|
||||||
debitorRel.getContact() != null ) {
|
|
||||||
relations.put(relationId++, debitorRel);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Order(1029)
|
@Order(1029)
|
||||||
void verifyContacts() {
|
void verifyContacts() {
|
||||||
@ -292,29 +275,25 @@ public class ImportOfficeData extends ContextBasedTest {
|
|||||||
{
|
{
|
||||||
2000000=rel(anchor='LP Hostsharing eG', type='PARTNER', holder='NP Mellies, Michael', contact='Herr Michael Mellies '),
|
2000000=rel(anchor='LP Hostsharing eG', type='PARTNER', holder='NP Mellies, Michael', contact='Herr Michael Mellies '),
|
||||||
2000001=rel(anchor='NP Mellies, Michael', type='DEBITOR', holder='NP Mellies, Michael', contact='Herr Michael Mellies '),
|
2000001=rel(anchor='NP Mellies, Michael', type='DEBITOR', holder='NP Mellies, Michael', contact='Herr Michael Mellies '),
|
||||||
2000002=rel(anchor='NP Mellies, Michael', type='DEBITOR', holder='NP Mellies, Michael', contact='Herr Michael Mellies '),
|
2000002=rel(anchor='LP Hostsharing eG', type='PARTNER', holder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
||||||
2000003=rel(anchor='LP Hostsharing eG', type='PARTNER', holder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
2000003=rel(anchor='LP JM GmbH', type='DEBITOR', holder='LP JM GmbH', contact='Frau Dr. Jenny Meyer-Billing , JM GmbH'),
|
||||||
2000004=rel(anchor='LP JM GmbH', type='DEBITOR', holder='LP JM GmbH', contact='Frau Dr. Jenny Meyer-Billing , JM GmbH'),
|
2000004=rel(anchor='LP Hostsharing eG', type='PARTNER', holder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
||||||
2000005=rel(anchor='LP JM GmbH', type='DEBITOR', holder='LP JM GmbH', contact='Frau Dr. Jenny Meyer-Billing , JM GmbH'),
|
2000005=rel(anchor='?? Test PS', type='DEBITOR', holder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
||||||
2000006=rel(anchor='LP Hostsharing eG', type='PARTNER', holder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
2000006=rel(anchor='LP Hostsharing eG', type='PARTNER', holder='null null, null'),
|
||||||
2000007=rel(anchor='?? Test PS', type='DEBITOR', holder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
2000007=rel(anchor='null null, null', type='DEBITOR'),
|
||||||
2000008=rel(anchor='?? Test PS', type='DEBITOR', holder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
2000008=rel(anchor='NP Mellies, Michael', type='OPERATIONS', holder='NP Mellies, Michael', contact='Herr Michael Mellies '),
|
||||||
2000009=rel(anchor='LP Hostsharing eG', type='PARTNER', holder='null null, null'),
|
2000009=rel(anchor='NP Mellies, Michael', type='REPRESENTATIVE', holder='NP Mellies, Michael', contact='Herr Michael Mellies '),
|
||||||
2000010=rel(anchor='null null, null', type='DEBITOR'),
|
2000010=rel(anchor='LP JM GmbH', type='EX_PARTNER', holder='LP JM e.K.', contact='JM e.K.'),
|
||||||
2000011=rel(anchor='null null, null', type='DEBITOR'),
|
2000011=rel(anchor='LP JM GmbH', type='OPERATIONS', holder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'),
|
||||||
2000012=rel(anchor='NP Mellies, Michael', type='OPERATIONS', holder='NP Mellies, Michael', contact='Herr Michael Mellies '),
|
2000012=rel(anchor='LP JM GmbH', type='VIP_CONTACT', holder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'),
|
||||||
2000013=rel(anchor='NP Mellies, Michael', type='REPRESENTATIVE', holder='NP Mellies, Michael', contact='Herr Michael Mellies '),
|
2000013=rel(anchor='LP JM GmbH', type='SUBSCRIBER', mark='operations-announce', holder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'),
|
||||||
2000014=rel(anchor='LP JM GmbH', type='EX_PARTNER', holder='LP JM e.K.', contact='JM e.K.'),
|
2000014=rel(anchor='LP JM GmbH', type='REPRESENTATIVE', holder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
||||||
2000015=rel(anchor='LP JM GmbH', type='OPERATIONS', holder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'),
|
2000015=rel(anchor='LP JM GmbH', type='SUBSCRIBER', mark='members-announce', holder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
||||||
2000016=rel(anchor='LP JM GmbH', type='VIP_CONTACT', holder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'),
|
2000016=rel(anchor='LP JM GmbH', type='SUBSCRIBER', mark='customers-announce', holder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
||||||
2000017=rel(anchor='LP JM GmbH', type='SUBSCRIBER', mark='operations-announce', holder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'),
|
2000017=rel(anchor='LP JM GmbH', type='VIP_CONTACT', holder='LP JM GmbH', contact='Frau Tammy Meyer-VIP , JM GmbH'),
|
||||||
2000018=rel(anchor='LP JM GmbH', type='REPRESENTATIVE', holder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
2000018=rel(anchor='?? Test PS', type='OPERATIONS', holder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
||||||
2000019=rel(anchor='LP JM GmbH', type='SUBSCRIBER', mark='members-announce', holder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
2000019=rel(anchor='?? Test PS', type='REPRESENTATIVE', holder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
||||||
2000020=rel(anchor='LP JM GmbH', type='SUBSCRIBER', mark='customers-announce', holder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'),
|
2000020=rel(anchor='NP Mellies, Michael', type='SUBSCRIBER', mark='operations-announce', holder='NP Fanninga, Frauke', contact='Frau Frauke Fanninga ')
|
||||||
2000021=rel(anchor='LP JM GmbH', type='VIP_CONTACT', holder='LP JM GmbH', contact='Frau Tammy Meyer-VIP , JM GmbH'),
|
|
||||||
2000022=rel(anchor='?? Test PS', type='OPERATIONS', holder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
|
||||||
2000023=rel(anchor='?? Test PS', type='REPRESENTATIVE', holder='?? Test PS', contact='Petra Schmidt , Test PS'),
|
|
||||||
2000024=rel(anchor='NP Mellies, Michael', type='SUBSCRIBER', mark='operations-announce', holder='NP Fanninga, Frauke', contact='Frau Frauke Fanninga ')
|
|
||||||
}
|
}
|
||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
@ -425,14 +404,33 @@ public class ImportOfficeData extends ContextBasedTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Order(2009)
|
@Order(3001)
|
||||||
|
void removeSelfRepresentativeRelations() {
|
||||||
|
assumeThatWeAreImportingControlledTestData();
|
||||||
|
|
||||||
|
// this happens if a natural person is marked as 'contractual' for itself
|
||||||
|
final var idsToRemove = new HashSet<Integer>();
|
||||||
|
relations.forEach( (id, r) -> {
|
||||||
|
if (r.getHolder() == r.getAnchor() ) {
|
||||||
|
idsToRemove.add(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// remove self-representatives
|
||||||
|
idsToRemove.forEach(id -> {
|
||||||
|
System.out.println("removing self representative relation: " + relations.get(id).toString());
|
||||||
|
relations.remove(id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(3002)
|
||||||
void removeEmptyRelations() {
|
void removeEmptyRelations() {
|
||||||
assumeThatWeAreImportingControlledTestData();
|
assumeThatWeAreImportingControlledTestData();
|
||||||
|
|
||||||
// avoid a error when persisting the deliberately invalid partner entry #99
|
// avoid a error when persisting the deliberately invalid partner entry #99
|
||||||
final var idsToRemove = new HashSet<Integer>();
|
final var idsToRemove = new HashSet<Integer>();
|
||||||
relations.forEach( (id, r) -> {
|
relations.forEach( (id, r) -> {
|
||||||
// such a record
|
|
||||||
if (r.getContact() == null || r.getContact().getLabel() == null ||
|
if (r.getContact() == null || r.getContact().getLabel() == null ||
|
||||||
r.getHolder() == null || r.getHolder().getPersonType() == null ) {
|
r.getHolder() == null || r.getHolder().getPersonType() == null ) {
|
||||||
idsToRemove.add(id);
|
idsToRemove.add(id);
|
||||||
@ -447,7 +445,7 @@ public class ImportOfficeData extends ContextBasedTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Order(2002)
|
@Order(3003)
|
||||||
void removeEmptyPartners() {
|
void removeEmptyPartners() {
|
||||||
assumeThatWeAreImportingControlledTestData();
|
assumeThatWeAreImportingControlledTestData();
|
||||||
|
|
||||||
@ -471,7 +469,7 @@ public class ImportOfficeData extends ContextBasedTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Order(2003)
|
@Order(3004)
|
||||||
void removeEmptyDebitors() {
|
void removeEmptyDebitors() {
|
||||||
assumeThatWeAreImportingControlledTestData();
|
assumeThatWeAreImportingControlledTestData();
|
||||||
|
|
||||||
@ -490,7 +488,7 @@ public class ImportOfficeData extends ContextBasedTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Order(3000)
|
@Order(9000)
|
||||||
@Commit
|
@Commit
|
||||||
void persistEntities() {
|
void persistEntities() {
|
||||||
|
|
||||||
@ -516,6 +514,7 @@ public class ImportOfficeData extends ContextBasedTest {
|
|||||||
relations.forEach(this::persist);
|
relations.forEach(this::persist);
|
||||||
}).assertSuccessful();
|
}).assertSuccessful();
|
||||||
|
|
||||||
|
System.out.println("persisting " + partners.size() + " partners");
|
||||||
jpaAttempt.transacted(() -> {
|
jpaAttempt.transacted(() -> {
|
||||||
context(rbacSuperuser);
|
context(rbacSuperuser);
|
||||||
partners.forEach((id, partner) -> {
|
partners.forEach((id, partner) -> {
|
||||||
@ -533,7 +532,7 @@ public class ImportOfficeData extends ContextBasedTest {
|
|||||||
context(rbacSuperuser);
|
context(rbacSuperuser);
|
||||||
debitors.forEach((id, debitor) -> {
|
debitors.forEach((id, debitor) -> {
|
||||||
debitor.setDebitorRel(em.merge(debitor.getDebitorRel()));
|
debitor.setDebitorRel(em.merge(debitor.getDebitorRel()));
|
||||||
em.persist(debitor);
|
persist(id, debitor);
|
||||||
});
|
});
|
||||||
}).assertSuccessful();
|
}).assertSuccessful();
|
||||||
|
|
||||||
@ -721,7 +720,6 @@ public class ImportOfficeData extends ContextBasedTest {
|
|||||||
null, // will be set in contacts import
|
null, // will be set in contacts import
|
||||||
null // will beset in contacts import
|
null // will beset in contacts import
|
||||||
);
|
);
|
||||||
relations.put(relationId++, debitorRel);
|
|
||||||
|
|
||||||
final var debitor = HsOfficeDebitorEntity.builder()
|
final var debitor = HsOfficeDebitorEntity.builder()
|
||||||
.debitorNumberSuffix("00")
|
.debitorNumberSuffix("00")
|
||||||
|
@ -10,7 +10,6 @@ import net.hostsharing.hsadminng.hs.office.test.ContextBasedTestWithCleanup;
|
|||||||
import net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantRepository;
|
import net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantRepository;
|
||||||
import net.hostsharing.hsadminng.rbac.rbacrole.RawRbacObjectRepository;
|
import net.hostsharing.hsadminng.rbac.rbacrole.RawRbacObjectRepository;
|
||||||
import net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleRepository;
|
import net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleRepository;
|
||||||
import net.hostsharing.test.Array;
|
|
||||||
import net.hostsharing.test.JpaAttempt;
|
import net.hostsharing.test.JpaAttempt;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.Nested;
|
import org.junit.jupiter.api.Nested;
|
||||||
@ -25,13 +24,13 @@ import jakarta.persistence.EntityManager;
|
|||||||
import jakarta.persistence.PersistenceContext;
|
import jakarta.persistence.PersistenceContext;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.distinctGrantDisplaysOf;
|
import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.distinctGrantDisplaysOf;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacObjectEntity.objectDisplaysOf;
|
import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacObjectEntity.objectDisplaysOf;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.distinctRoleNamesOf;
|
import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.distinctRoleNamesOf;
|
||||||
import static net.hostsharing.test.Array.fromFormatted;
|
import static net.hostsharing.test.Array.from;
|
||||||
import static net.hostsharing.test.JpaAttempt.attempt;
|
import static net.hostsharing.test.JpaAttempt.attempt;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
@ -130,7 +129,7 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
}).assertSuccessful();
|
}).assertSuccessful();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(distinctRoleNamesOf(rawRoleRepo.findAll())).containsExactlyInAnyOrder(Array.from(
|
assertThat(distinctRoleNamesOf(rawRoleRepo.findAll())).containsExactlyInAnyOrder(from(
|
||||||
initialRoleNames,
|
initialRoleNames,
|
||||||
"hs_office_relation#HostsharingeG-with-PARTNER-ErbenBesslerMelBessler:OWNER",
|
"hs_office_relation#HostsharingeG-with-PARTNER-ErbenBesslerMelBessler:OWNER",
|
||||||
"hs_office_relation#HostsharingeG-with-PARTNER-ErbenBesslerMelBessler:ADMIN",
|
"hs_office_relation#HostsharingeG-with-PARTNER-ErbenBesslerMelBessler:ADMIN",
|
||||||
@ -140,44 +139,43 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
.map(s -> s.replace("ErbenBesslerMelBessler", "EBess"))
|
.map(s -> s.replace("ErbenBesslerMelBessler", "EBess"))
|
||||||
.map(s -> s.replace("fourthcontact", "4th"))
|
.map(s -> s.replace("fourthcontact", "4th"))
|
||||||
.map(s -> s.replace("hs_office_", ""))
|
.map(s -> s.replace("hs_office_", ""))
|
||||||
.containsExactlyInAnyOrder(distinct(fromFormatted(
|
.containsExactlyInAnyOrder(distinct(from(
|
||||||
initialGrantNames,
|
initialGrantNames,
|
||||||
"{ grant perm:relation#HostsharingeG-with-PARTNER-EBess:INSERT>sepamandate to role:relation#HostsharingeG-with-PARTNER-EBess:ADMIN by system and assume }",
|
"{ grant perm:relation#HostsharingeG-with-PARTNER-EBess:INSERT>sepamandate to role:relation#HostsharingeG-with-PARTNER-EBess:ADMIN by system and assume }",
|
||||||
|
|
||||||
// permissions on partner
|
// permissions on partner
|
||||||
"{ grant perm:partner#P-20032:DELETE to role:relation#HostsharingeG-with-PARTNER-EBess:ADMIN by system and assume }",
|
"{ grant perm:partner#P-20032:DELETE to role:relation#HostsharingeG-with-PARTNER-EBess:OWNER by system and assume }",
|
||||||
"{ grant perm:partner#P-20032:UPDATE to role:relation#HostsharingeG-with-PARTNER-EBess:AGENT by system and assume }",
|
"{ grant perm:partner#P-20032:UPDATE to role:relation#HostsharingeG-with-PARTNER-EBess:ADMIN by system and assume }",
|
||||||
"{ grant perm:partner#P-20032:SELECT to role:relation#HostsharingeG-with-PARTNER-EBess:TENANT by system and assume }",
|
"{ grant perm:partner#P-20032:SELECT to role:relation#HostsharingeG-with-PARTNER-EBess:TENANT by system and assume }",
|
||||||
|
|
||||||
// permissions on partner-details
|
// permissions on partner-details
|
||||||
"{ grant perm:partner_details#P-20032:DELETE to role:relation#HostsharingeG-with-PARTNER-EBess:ADMIN by system and assume }",
|
"{ grant perm:partner_details#P-20032:DELETE to role:relation#HostsharingeG-with-PARTNER-EBess:OWNER by system and assume }",
|
||||||
"{ grant perm:partner_details#P-20032:UPDATE to role:relation#HostsharingeG-with-PARTNER-EBess:AGENT by system and assume }",
|
"{ grant perm:partner_details#P-20032:UPDATE to role:relation#HostsharingeG-with-PARTNER-EBess:AGENT by system and assume }",
|
||||||
"{ grant perm:partner_details#P-20032:SELECT to role:relation#HostsharingeG-with-PARTNER-EBess:AGENT by system and assume }",
|
"{ grant perm:partner_details#P-20032:SELECT to role:relation#HostsharingeG-with-PARTNER-EBess:AGENT by system and assume }",
|
||||||
|
|
||||||
// permissions on partner-relation
|
// permissions on partner-relation
|
||||||
"{ grant perm:relation#HostsharingeG-with-PARTNER-EBess:DELETE to role:relation#HostsharingeG-with-PARTNER-EBess:OWNER by system and assume }",
|
"{ grant perm:relation#HostsharingeG-with-PARTNER-EBess:DELETE to role:relation#HostsharingeG-with-PARTNER-EBess:OWNER by system and assume }",
|
||||||
"{ grant perm:relation#HostsharingeG-with-PARTNER-EBess:UPDATE to role:relation#HostsharingeG-with-PARTNER-EBess:ADMIN by system and assume }",
|
"{ grant perm:relation#HostsharingeG-with-PARTNER-EBess:UPDATE to role:relation#HostsharingeG-with-PARTNER-EBess:ADMIN by system and assume }",
|
||||||
"{ grant perm:relation#HostsharingeG-with-PARTNER-EBess:SELECT to role:relation#HostsharingeG-with-PARTNER-EBess:TENANT by system and assume }",
|
"{ grant perm:relation#HostsharingeG-with-PARTNER-EBess:SELECT to role:relation#HostsharingeG-with-PARTNER-EBess:TENANT by system and assume }",
|
||||||
|
|
||||||
// relation owner
|
// relation owner
|
||||||
"{ grant role:relation#HostsharingeG-with-PARTNER-EBess:OWNER to role:global#global:ADMIN by system and assume }",
|
"{ grant role:relation#HostsharingeG-with-PARTNER-EBess:OWNER to role:global#global:ADMIN by system and assume }",
|
||||||
"{ grant role:relation#HostsharingeG-with-PARTNER-EBess:OWNER to user:superuser-alex@hostsharing.net by relation#HostsharingeG-with-PARTNER-EBess:OWNER and assume }",
|
"{ grant role:relation#HostsharingeG-with-PARTNER-EBess:OWNER to user:superuser-alex@hostsharing.net by relation#HostsharingeG-with-PARTNER-EBess:OWNER and assume }",
|
||||||
|
|
||||||
// relation admin
|
// relation admin
|
||||||
"{ grant role:relation#HostsharingeG-with-PARTNER-EBess:ADMIN to role:relation#HostsharingeG-with-PARTNER-EBess:OWNER by system and assume }",
|
"{ grant role:relation#HostsharingeG-with-PARTNER-EBess:ADMIN to role:relation#HostsharingeG-with-PARTNER-EBess:OWNER by system and assume }",
|
||||||
"{ grant role:relation#HostsharingeG-with-PARTNER-EBess:ADMIN to role:person#HostsharingeG:ADMIN by system and assume }",
|
"{ grant role:relation#HostsharingeG-with-PARTNER-EBess:OWNER to role:person#HostsharingeG:ADMIN by system and assume }",
|
||||||
|
|
||||||
// relation agent
|
// relation agent
|
||||||
"{ grant role:relation#HostsharingeG-with-PARTNER-EBess:AGENT to role:person#EBess:ADMIN by system and assume }",
|
"{ grant role:relation#HostsharingeG-with-PARTNER-EBess:AGENT to role:person#EBess:ADMIN by system and assume }",
|
||||||
"{ grant role:relation#HostsharingeG-with-PARTNER-EBess:AGENT to role:relation#HostsharingeG-with-PARTNER-EBess:ADMIN by system and assume }",
|
"{ grant role:relation#HostsharingeG-with-PARTNER-EBess:AGENT to role:relation#HostsharingeG-with-PARTNER-EBess:ADMIN by system and assume }",
|
||||||
|
|
||||||
// relation tenant
|
// relation tenant
|
||||||
"{ grant role:contact#4th:REFERRER to role:relation#HostsharingeG-with-PARTNER-EBess:TENANT by system and assume }",
|
"{ grant role:contact#4th:REFERRER to role:relation#HostsharingeG-with-PARTNER-EBess:TENANT by system and assume }",
|
||||||
"{ grant role:person#EBess:REFERRER to role:relation#HostsharingeG-with-PARTNER-EBess:TENANT by system and assume }",
|
"{ grant role:person#EBess:REFERRER to role:relation#HostsharingeG-with-PARTNER-EBess:TENANT by system and assume }",
|
||||||
"{ grant role:person#HostsharingeG:REFERRER to role:relation#HostsharingeG-with-PARTNER-EBess:TENANT by system and assume }",
|
"{ grant role:person#HostsharingeG:REFERRER to role:relation#HostsharingeG-with-PARTNER-EBess:TENANT by system and assume }",
|
||||||
"{ grant role:relation#HostsharingeG-with-PARTNER-EBess:TENANT to role:contact#4th:ADMIN by system and assume }",
|
"{ grant role:relation#HostsharingeG-with-PARTNER-EBess:TENANT to role:contact#4th:ADMIN by system and assume }",
|
||||||
"{ grant role:relation#HostsharingeG-with-PARTNER-EBess:TENANT to role:person#EBess:ADMIN by system and assume }",
|
"{ grant role:relation#HostsharingeG-with-PARTNER-EBess:TENANT to role:relation#HostsharingeG-with-PARTNER-EBess:AGENT by system and assume }",
|
||||||
"{ grant role:relation#HostsharingeG-with-PARTNER-EBess:TENANT to role:relation#HostsharingeG-with-PARTNER-EBess:AGENT by system and assume }",
|
|
||||||
null)));
|
null)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,9 +409,9 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
public void deletingAPartnerAlsoDeletesRelatedRolesAndGrants() {
|
public void deletingAPartnerAlsoDeletesRelatedRolesAndGrants() {
|
||||||
// given
|
// given
|
||||||
context("superuser-alex@hostsharing.net");
|
context("superuser-alex@hostsharing.net");
|
||||||
final var initialObjects = Array.from(objectDisplaysOf(rawObjectRepo.findAll()));
|
final var initialObjects = from(objectDisplaysOf(rawObjectRepo.findAll()));
|
||||||
final var initialRoleNames = Array.from(distinctRoleNamesOf(rawRoleRepo.findAll()));
|
final var initialRoleNames = from(distinctRoleNamesOf(rawRoleRepo.findAll()));
|
||||||
final var initialGrantNames = Array.from(distinctGrantDisplaysOf(rawGrantRepo.findAll()));
|
final var initialGrantNames = from(distinctGrantDisplaysOf(rawGrantRepo.findAll()));
|
||||||
final var givenPartner = givenSomeTemporaryHostsharingPartner(20034, "Erben Bessler", "twelfth");
|
final var givenPartner = givenSomeTemporaryHostsharingPartner(20034, "Erben Bessler", "twelfth");
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@ -499,8 +497,6 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
|
|
||||||
private String[] distinct(final String[] strings) {
|
private String[] distinct(final String[] strings) {
|
||||||
// TODO: alternatively cleanup all rbac objects in @AfterEach?
|
// TODO: alternatively cleanup all rbac objects in @AfterEach?
|
||||||
final var set = new HashSet<String>();
|
return Arrays.stream(strings).filter(Objects::nonNull).distinct().toList().toArray(new String[0]);
|
||||||
set.addAll(List.of(strings));
|
|
||||||
return set.toArray(new String[0]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,9 @@ class HsOfficePersonEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
final var entity = new HsOfficePersonEntity();
|
final var entity = new HsOfficePersonEntity();
|
||||||
entity.setUuid(INITIAL_PERSON_UUID);
|
entity.setUuid(INITIAL_PERSON_UUID);
|
||||||
entity.setPersonType(HsOfficePersonType.LEGAL_PERSON);
|
entity.setPersonType(HsOfficePersonType.LEGAL_PERSON);
|
||||||
entity.setTradeName("initial@example.org");
|
entity.setTradeName("initial trade name");
|
||||||
|
entity.setTitle("Dr. Init.");
|
||||||
|
entity.setSalutation("Herr Initial");
|
||||||
entity.setFamilyName("initial postal address");
|
entity.setFamilyName("initial postal address");
|
||||||
entity.setGivenName("+01 100 123456789");
|
entity.setGivenName("+01 100 123456789");
|
||||||
return entity;
|
return entity;
|
||||||
@ -54,6 +56,16 @@ class HsOfficePersonEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
HsOfficePersonPatchResource::setTradeName,
|
HsOfficePersonPatchResource::setTradeName,
|
||||||
"patched trade name",
|
"patched trade name",
|
||||||
HsOfficePersonEntity::setTradeName),
|
HsOfficePersonEntity::setTradeName),
|
||||||
|
new JsonNullableProperty<>(
|
||||||
|
"title",
|
||||||
|
HsOfficePersonPatchResource::setTitle,
|
||||||
|
"Dr. Patch.",
|
||||||
|
HsOfficePersonEntity::setTitle),
|
||||||
|
new JsonNullableProperty<>(
|
||||||
|
"salutation",
|
||||||
|
HsOfficePersonPatchResource::setSalutation,
|
||||||
|
"Hallo Ini",
|
||||||
|
HsOfficePersonEntity::setSalutation),
|
||||||
new JsonNullableProperty<>(
|
new JsonNullableProperty<>(
|
||||||
"familyName",
|
"familyName",
|
||||||
HsOfficePersonPatchResource::setFamilyName,
|
HsOfficePersonPatchResource::setFamilyName,
|
||||||
|
@ -60,19 +60,63 @@ class HsOfficePersonEntityUnitTest {
|
|||||||
assertThat(actualDisplay).isEqualTo("NP some family name, some given name");
|
assertThat(actualDisplay).isEqualTo("NP some family name, some given name");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void toShortStringWithSalutationAndTitleReturnsSalutationAndTitle() {
|
||||||
|
final var givenPersonEntity = HsOfficePersonEntity.builder()
|
||||||
|
.personType(HsOfficePersonType.NATURAL_PERSON)
|
||||||
|
.salutation("Frau")
|
||||||
|
.title("Dr.")
|
||||||
|
.familyName("some family name")
|
||||||
|
.givenName("some given name")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final var actualDisplay = givenPersonEntity.toShortString();
|
||||||
|
|
||||||
|
assertThat(actualDisplay).isEqualTo("NP some family name, some given name");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void toShortStringWithSalutationAndWithoutTitleReturnsSalutation() {
|
||||||
|
final var givenPersonEntity = HsOfficePersonEntity.builder()
|
||||||
|
.personType(HsOfficePersonType.NATURAL_PERSON)
|
||||||
|
.salutation("Frau")
|
||||||
|
.familyName("some family name")
|
||||||
|
.givenName("some given name")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final var actualDisplay = givenPersonEntity.toShortString();
|
||||||
|
|
||||||
|
assertThat(actualDisplay).isEqualTo("NP Frau some family name, some given name");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void toShortStringWithoutSalutationAndWithTitleReturnsTitle() {
|
||||||
|
final var givenPersonEntity = HsOfficePersonEntity.builder()
|
||||||
|
.personType(HsOfficePersonType.NATURAL_PERSON)
|
||||||
|
.title("Dr. Dr.")
|
||||||
|
.familyName("some family name")
|
||||||
|
.givenName("some given name")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final var actualDisplay = givenPersonEntity.toShortString();
|
||||||
|
|
||||||
|
assertThat(actualDisplay).isEqualTo("NP some family name, some given name");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void toStringWithAllFieldsReturnsAllButUuid() {
|
void toStringWithAllFieldsReturnsAllButUuid() {
|
||||||
final var givenPersonEntity = HsOfficePersonEntity.builder()
|
final var givenPersonEntity = HsOfficePersonEntity.builder()
|
||||||
.uuid(UUID.randomUUID())
|
.uuid(UUID.randomUUID())
|
||||||
.personType(HsOfficePersonType.NATURAL_PERSON)
|
.personType(HsOfficePersonType.NATURAL_PERSON)
|
||||||
.tradeName("some trade name")
|
.tradeName("some trade name")
|
||||||
|
.title("Dr.")
|
||||||
.familyName("some family name")
|
.familyName("some family name")
|
||||||
.givenName("some given name")
|
.givenName("some given name")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final var actualDisplay = givenPersonEntity.toString();
|
final var actualDisplay = givenPersonEntity.toString();
|
||||||
|
|
||||||
assertThat(actualDisplay).isEqualTo("person(personType='NP', tradeName='some trade name', familyName='some family name', givenName='some given name')");
|
assertThat(actualDisplay).isEqualTo("person(personType='NP', tradeName='some trade name', title='Dr.', familyName='some family name', givenName='some given name')");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -86,4 +130,42 @@ class HsOfficePersonEntityUnitTest {
|
|||||||
|
|
||||||
assertThat(actualDisplay).isEqualTo("person(familyName='some family name', givenName='some given name')");
|
assertThat(actualDisplay).isEqualTo("person(familyName='some family name', givenName='some given name')");
|
||||||
}
|
}
|
||||||
|
@Test
|
||||||
|
void toStringWithSalutationAndTitleRetursSalutationAndTitle() {
|
||||||
|
final var givenPersonEntity = HsOfficePersonEntity.builder()
|
||||||
|
.salutation("Herr")
|
||||||
|
.title("Prof. Dr.")
|
||||||
|
.familyName("some family name")
|
||||||
|
.givenName("some given name")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final var actualDisplay = givenPersonEntity.toString();
|
||||||
|
|
||||||
|
assertThat(actualDisplay).isEqualTo("person(salutation='Herr', title='Prof. Dr.', familyName='some family name', givenName='some given name')");
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
void toStringWithSalutationAndWithoutTitleSkipsTitle() {
|
||||||
|
final var givenPersonEntity = HsOfficePersonEntity.builder()
|
||||||
|
.salutation("Herr")
|
||||||
|
.familyName("some family name")
|
||||||
|
.givenName("some given name")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final var actualDisplay = givenPersonEntity.toString();
|
||||||
|
|
||||||
|
assertThat(actualDisplay).isEqualTo("person(salutation='Herr', familyName='some family name', givenName='some given name')");
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
void toStringWithoutSalutationAndWithTitleSkipsSalutation() {
|
||||||
|
final var givenPersonEntity = HsOfficePersonEntity.builder()
|
||||||
|
.title("some title")
|
||||||
|
.familyName("some family name")
|
||||||
|
.givenName("some given name")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final var actualDisplay = givenPersonEntity.toString();
|
||||||
|
|
||||||
|
assertThat(actualDisplay).isEqualTo("person(title='some title', familyName='some family name', givenName='some given name')");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -362,7 +362,7 @@ class HsOfficeRelationControllerAcceptanceTest extends ContextBasedTestWithClean
|
|||||||
assertThat(givenRelation.getContact().getLabel()).isEqualTo("seventh contact");
|
assertThat(givenRelation.getContact().getLabel()).isEqualTo("seventh contact");
|
||||||
final var givenContact = contactRepo.findContactByOptionalLabelLike("fourth").get(0);
|
final var givenContact = contactRepo.findContactByOptionalLabelLike("fourth").get(0);
|
||||||
|
|
||||||
final var location = RestAssured // @formatter:off
|
RestAssured // @formatter:off
|
||||||
.given()
|
.given()
|
||||||
.header("current-user", "superuser-alex@hostsharing.net")
|
.header("current-user", "superuser-alex@hostsharing.net")
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
|
@ -140,9 +140,10 @@ class HsOfficeRelationRepositoryIntegrationTest extends ContextBasedTestWithClea
|
|||||||
|
|
||||||
"{ grant perm:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:UPDATE to role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:ADMIN by system and assume }",
|
"{ grant perm:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:UPDATE to role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:ADMIN by system and assume }",
|
||||||
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:ADMIN to role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:OWNER by system and assume }",
|
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:ADMIN to role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:OWNER by system and assume }",
|
||||||
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:ADMIN to role:hs_office_person#ErbenBesslerMelBessler:ADMIN by system and assume }",
|
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:OWNER to role:hs_office_person#BesslerBert:ADMIN by system and assume }",
|
||||||
|
"{ grant role:hs_office_person#ErbenBesslerMelBessler:OWNER to role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:ADMIN by system and assume }",
|
||||||
|
|
||||||
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:AGENT to role:hs_office_person#BesslerBert:ADMIN by system and assume }",
|
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:AGENT to role:hs_office_person#ErbenBesslerMelBessler:ADMIN by system and assume }",
|
||||||
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:AGENT to role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:ADMIN by system and assume }",
|
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:AGENT to role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:ADMIN by system and assume }",
|
||||||
|
|
||||||
"{ grant perm:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:SELECT to role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:TENANT by system and assume }",
|
"{ grant perm:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:SELECT to role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:TENANT by system and assume }",
|
||||||
@ -153,8 +154,6 @@ class HsOfficeRelationRepositoryIntegrationTest extends ContextBasedTestWithClea
|
|||||||
|
|
||||||
// REPRESENTATIVE holder person -> (represented) anchor person
|
// REPRESENTATIVE holder person -> (represented) anchor person
|
||||||
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:TENANT to role:hs_office_contact#fourthcontact:ADMIN by system and assume }",
|
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:TENANT to role:hs_office_contact#fourthcontact:ADMIN by system and assume }",
|
||||||
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:TENANT to role:hs_office_person#BesslerBert:ADMIN by system and assume }",
|
|
||||||
|
|
||||||
null)
|
null)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -217,10 +216,10 @@ class HsOfficeRelationRepositoryIntegrationTest extends ContextBasedTestWithClea
|
|||||||
context("superuser-alex@hostsharing.net");
|
context("superuser-alex@hostsharing.net");
|
||||||
final var givenRelation = givenSomeTemporaryRelationBessler(
|
final var givenRelation = givenSomeTemporaryRelationBessler(
|
||||||
"Bert", "fifth contact");
|
"Bert", "fifth contact");
|
||||||
|
assertThatRelationActuallyInDatabase(givenRelation);
|
||||||
assertThatRelationIsVisibleForUserWithRole(
|
assertThatRelationIsVisibleForUserWithRole(
|
||||||
givenRelation,
|
givenRelation,
|
||||||
"hs_office_person#ErbenBesslerMelBessler:ADMIN");
|
"hs_office_person#ErbenBesslerMelBessler:ADMIN");
|
||||||
assertThatRelationActuallyInDatabase(givenRelation);
|
|
||||||
context("superuser-alex@hostsharing.net");
|
context("superuser-alex@hostsharing.net");
|
||||||
final var givenContact = contactRepo.findContactByOptionalLabelLike("sixth contact").stream().findFirst().orElseThrow();
|
final var givenContact = contactRepo.findContactByOptionalLabelLike("sixth contact").stream().findFirst().orElseThrow();
|
||||||
|
|
||||||
@ -249,19 +248,19 @@ class HsOfficeRelationRepositoryIntegrationTest extends ContextBasedTestWithClea
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void holderAdmin_canNotUpdateRelatedRelation() {
|
public void relationAgent_canSelectButNotUpdateRelatedRelation() {
|
||||||
// given
|
// given
|
||||||
context("superuser-alex@hostsharing.net");
|
context("superuser-alex@hostsharing.net");
|
||||||
final var givenRelation = givenSomeTemporaryRelationBessler(
|
final var givenRelation = givenSomeTemporaryRelationBessler(
|
||||||
"Anita", "eighth");
|
"Anita", "eighth");
|
||||||
assertThatRelationIsVisibleForUserWithRole(
|
assertThatRelationIsVisibleForUserWithRole(
|
||||||
givenRelation,
|
givenRelation,
|
||||||
"hs_office_person#BesslerAnita:ADMIN");
|
"hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerAnita:AGENT");
|
||||||
assertThatRelationActuallyInDatabase(givenRelation);
|
assertThatRelationActuallyInDatabase(givenRelation);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
final var result = jpaAttempt.transacted(() -> {
|
final var result = jpaAttempt.transacted(() -> {
|
||||||
context("superuser-alex@hostsharing.net", "hs_office_person#BesslerAnita:ADMIN");
|
context("superuser-alex@hostsharing.net", "hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerAnita:AGENT");
|
||||||
givenRelation.setContact(null);
|
givenRelation.setContact(null);
|
||||||
return relationRepo.save(givenRelation);
|
return relationRepo.save(givenRelation);
|
||||||
});
|
});
|
||||||
|
@ -17,7 +17,6 @@ import org.springframework.data.jpa.repository.Query;
|
|||||||
import org.springframework.data.repository.Repository;
|
import org.springframework.data.repository.Repository;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static java.lang.System.out;
|
import static java.lang.System.out;
|
||||||
@ -272,12 +271,11 @@ public abstract class ContextBasedTestWithCleanup extends ContextBasedTest {
|
|||||||
/**
|
/**
|
||||||
* Generates a diagram of the RBAC-Grants to the current subjects (user or assumed roles).
|
* Generates a diagram of the RBAC-Grants to the current subjects (user or assumed roles).
|
||||||
*/
|
*/
|
||||||
protected void generateRbacDiagramForCurrentSubjects(final EnumSet<RbacGrantsDiagramService.Include> include) {
|
protected void generateRbacDiagramForCurrentSubjects(final EnumSet<RbacGrantsDiagramService.Include> include, final String name) {
|
||||||
final var title = testInfo.getTestMethod().map(Method::getName).orElseThrow();
|
|
||||||
RbacGrantsDiagramService.writeToFile(
|
RbacGrantsDiagramService.writeToFile(
|
||||||
title,
|
name,
|
||||||
diagramService.allGrantsToCurrentUser(include),
|
diagramService.allGrantsToCurrentUser(include),
|
||||||
"doc/" + title + ".md"
|
"doc/temp/" + name + ".md"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user