test-data-generation working up to membership, fails in coop-shares
This commit is contained in:
parent
76b98eab2e
commit
fe23a496e6
@ -12,8 +12,6 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
|
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
|
||||||
|
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import jakarta.persistence.PersistenceContext;
|
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -32,9 +30,6 @@ public class HsOfficeMembershipController implements HsOfficeMembershipsApi {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private HsOfficeMembershipRepository membershipRepo;
|
private HsOfficeMembershipRepository membershipRepo;
|
||||||
|
|
||||||
@PersistenceContext
|
|
||||||
private EntityManager em;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public ResponseEntity<List<HsOfficeMembershipResource>> listMemberships(
|
public ResponseEntity<List<HsOfficeMembershipResource>> listMemberships(
|
||||||
@ -121,7 +116,7 @@ public class HsOfficeMembershipController implements HsOfficeMembershipsApi {
|
|||||||
|
|
||||||
final var current = membershipRepo.findByUuid(membershipUuid).orElseThrow();
|
final var current = membershipRepo.findByUuid(membershipUuid).orElseThrow();
|
||||||
|
|
||||||
new HsOfficeMembershipEntityPatcher(em, mapper, current).apply(body);
|
new HsOfficeMembershipEntityPatcher(mapper, current).apply(body);
|
||||||
|
|
||||||
final var saved = membershipRepo.save(current);
|
final var saved = membershipRepo.save(current);
|
||||||
final var mapped = mapper.map(saved, HsOfficeMembershipResource.class, SEPA_MANDATE_ENTITY_TO_RESOURCE_POSTMAPPER);
|
final var mapped = mapper.map(saved, HsOfficeMembershipResource.class, SEPA_MANDATE_ENTITY_TO_RESOURCE_POSTMAPPER);
|
||||||
|
@ -4,20 +4,29 @@ import com.vladmihalcea.hibernate.type.range.PostgreSQLRangeType;
|
|||||||
import com.vladmihalcea.hibernate.type.range.Range;
|
import com.vladmihalcea.hibernate.type.range.Range;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import net.hostsharing.hsadminng.errors.DisplayName;
|
import net.hostsharing.hsadminng.errors.DisplayName;
|
||||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
|
import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEntity;
|
||||||
import net.hostsharing.hsadminng.persistence.HasUuid;
|
import net.hostsharing.hsadminng.persistence.HasUuid;
|
||||||
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
|
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
|
||||||
|
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
|
||||||
|
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL;
|
||||||
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.Fetch;
|
|
||||||
import org.hibernate.annotations.FetchMode;
|
|
||||||
import org.hibernate.annotations.Type;
|
import org.hibernate.annotations.Type;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
|
import java.io.IOException;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.*;
|
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.*;
|
||||||
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn;
|
||||||
|
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.RbacUserReference.UserRole.CREATOR;
|
||||||
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
||||||
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.REFERRER;
|
||||||
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.fetchedBySql;
|
||||||
|
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
|
||||||
@ -35,7 +44,6 @@ public class HsOfficeMembershipEntity implements HasUuid, Stringifyable {
|
|||||||
private static Stringify<HsOfficeMembershipEntity> stringify = stringify(HsOfficeMembershipEntity.class)
|
private static Stringify<HsOfficeMembershipEntity> stringify = stringify(HsOfficeMembershipEntity.class)
|
||||||
.withProp(e -> MEMBER_NUMBER_TAG + e.getMemberNumber())
|
.withProp(e -> MEMBER_NUMBER_TAG + e.getMemberNumber())
|
||||||
.withProp(e -> e.getPartner().toShortString())
|
.withProp(e -> e.getPartner().toShortString())
|
||||||
.withProp(e -> e.getMainDebitor().toShortString())
|
|
||||||
.withProp(e -> e.getValidity().asString())
|
.withProp(e -> e.getValidity().asString())
|
||||||
.withProp(HsOfficeMembershipEntity::getReasonForTermination)
|
.withProp(HsOfficeMembershipEntity::getReasonForTermination)
|
||||||
.quotedValues(false);
|
.quotedValues(false);
|
||||||
@ -48,11 +56,6 @@ public class HsOfficeMembershipEntity implements HasUuid, Stringifyable {
|
|||||||
@JoinColumn(name = "partneruuid")
|
@JoinColumn(name = "partneruuid")
|
||||||
private HsOfficePartnerEntity partner;
|
private HsOfficePartnerEntity partner;
|
||||||
|
|
||||||
@ManyToOne
|
|
||||||
@Fetch(FetchMode.JOIN)
|
|
||||||
@JoinColumn(name = "maindebitoruuid")
|
|
||||||
private HsOfficeDebitorEntity mainDebitor;
|
|
||||||
|
|
||||||
@Column(name = "membernumbersuffix", length = 2)
|
@Column(name = "membernumbersuffix", length = 2)
|
||||||
private String memberNumberSuffix;
|
private String memberNumberSuffix;
|
||||||
|
|
||||||
@ -113,4 +116,43 @@ public class HsOfficeMembershipEntity implements HasUuid, Stringifyable {
|
|||||||
setReasonForTermination(HsOfficeReasonForTermination.NONE);
|
setReasonForTermination(HsOfficeReasonForTermination.NONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static RbacView rbac() {
|
||||||
|
return rbacViewFor("membership", HsOfficeMembershipEntity.class)
|
||||||
|
.withIdentityView(SQL.query("""
|
||||||
|
SELECT m.uuid AS uuid,
|
||||||
|
'M-' || p.partnerNumber || m.memberNumberSuffix as idName
|
||||||
|
FROM hs_office_membership AS m
|
||||||
|
JOIN hs_office_partner AS p ON p.uuid = m.partnerUuid
|
||||||
|
"""))
|
||||||
|
.withRestrictedViewOrderBy(SQL.projection("validity"))
|
||||||
|
.withUpdatableColumns("validity", "membershipFeeBillable", "reasonForTermination")
|
||||||
|
|
||||||
|
.importEntityAlias("partnerRel", HsOfficeRelationshipEntity.class,
|
||||||
|
dependsOnColumn("partnerUuid"),
|
||||||
|
fetchedBySql("""
|
||||||
|
SELECT r.*
|
||||||
|
FROM hs_office_partner AS p
|
||||||
|
JOIN hs_office_relationship AS r ON r.uuid = p.partnerRoleUuid
|
||||||
|
WHERE p.uuid = ${REF}.partnerUuid
|
||||||
|
"""))
|
||||||
|
.toRole("partnerRel", ADMIN).grantPermission("membership", INSERT)
|
||||||
|
|
||||||
|
.createRole(OWNER, (with) -> {
|
||||||
|
with.owningUser(CREATOR);
|
||||||
|
with.incomingSuperRole("partnerRel", ADMIN);
|
||||||
|
with.permission(DELETE);
|
||||||
|
})
|
||||||
|
.createSubRole(ADMIN, (with) -> {
|
||||||
|
with.permission(UPDATE);
|
||||||
|
})
|
||||||
|
.createSubRole(REFERRER, (with) -> {
|
||||||
|
with.outgoingSubRole("partnerRel", TENANT);
|
||||||
|
with.permission(SELECT);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException {
|
||||||
|
rbac().generateWithBaseFileName("303-hs-office-membership-rbac");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,37 +1,26 @@
|
|||||||
package net.hostsharing.hsadminng.hs.office.membership;
|
package net.hostsharing.hsadminng.hs.office.membership;
|
||||||
|
|
||||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
|
|
||||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeMembershipPatchResource;
|
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeMembershipPatchResource;
|
||||||
import net.hostsharing.hsadminng.mapper.EntityPatcher;
|
import net.hostsharing.hsadminng.mapper.EntityPatcher;
|
||||||
import net.hostsharing.hsadminng.mapper.Mapper;
|
import net.hostsharing.hsadminng.mapper.Mapper;
|
||||||
import net.hostsharing.hsadminng.mapper.OptionalFromJson;
|
import net.hostsharing.hsadminng.mapper.OptionalFromJson;
|
||||||
|
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class HsOfficeMembershipEntityPatcher implements EntityPatcher<HsOfficeMembershipPatchResource> {
|
public class HsOfficeMembershipEntityPatcher implements EntityPatcher<HsOfficeMembershipPatchResource> {
|
||||||
|
|
||||||
private final EntityManager em;
|
|
||||||
private final Mapper mapper;
|
private final Mapper mapper;
|
||||||
private final HsOfficeMembershipEntity entity;
|
private final HsOfficeMembershipEntity entity;
|
||||||
|
|
||||||
public HsOfficeMembershipEntityPatcher(
|
public HsOfficeMembershipEntityPatcher(
|
||||||
final EntityManager em,
|
|
||||||
final Mapper mapper,
|
final Mapper mapper,
|
||||||
final HsOfficeMembershipEntity entity) {
|
final HsOfficeMembershipEntity entity) {
|
||||||
this.em = em;
|
|
||||||
this.mapper = mapper;
|
this.mapper = mapper;
|
||||||
this.entity = entity;
|
this.entity = entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void apply(final HsOfficeMembershipPatchResource resource) {
|
public void apply(final HsOfficeMembershipPatchResource resource) {
|
||||||
OptionalFromJson.of(resource.getMainDebitorUuid())
|
|
||||||
.ifPresent(newValue -> {
|
|
||||||
verifyNotNull(newValue, "debitor");
|
|
||||||
entity.setMainDebitor(em.getReference(HsOfficeDebitorEntity.class, newValue));
|
|
||||||
});
|
|
||||||
OptionalFromJson.of(resource.getValidTo()).ifPresent(
|
OptionalFromJson.of(resource.getValidTo()).ifPresent(
|
||||||
entity::setValidTo);
|
entity::setValidTo);
|
||||||
Optional.ofNullable(resource.getReasonForTermination())
|
Optional.ofNullable(resource.getReasonForTermination())
|
||||||
@ -40,10 +29,4 @@ public class HsOfficeMembershipEntityPatcher implements EntityPatcher<HsOfficeMe
|
|||||||
OptionalFromJson.of(resource.getMembershipFeeBillable()).ifPresent(
|
OptionalFromJson.of(resource.getMembershipFeeBillable()).ifPresent(
|
||||||
entity::setMembershipFeeBillable);
|
entity::setMembershipFeeBillable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyNotNull(final UUID newValue, final String propertyName) {
|
|
||||||
if (newValue == null) {
|
|
||||||
throw new IllegalArgumentException("property '" + propertyName + "' must not be null");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ create table if not exists hs_office_membership
|
|||||||
(
|
(
|
||||||
uuid uuid unique references RbacObject (uuid) initially deferred,
|
uuid uuid unique references RbacObject (uuid) initially deferred,
|
||||||
partnerUuid uuid not null references hs_office_partner(uuid),
|
partnerUuid uuid not null references hs_office_partner(uuid),
|
||||||
mainDebitorUuid uuid not null references hs_office_debitor(uuid),
|
|
||||||
memberNumberSuffix char(2) not null check (
|
memberNumberSuffix char(2) not null check (
|
||||||
memberNumberSuffix::text ~ '^[0-9][0-9]$'),
|
memberNumberSuffix::text ~ '^[0-9][0-9]$'),
|
||||||
validity daterange not null,
|
validity daterange not null,
|
||||||
|
@ -1,75 +1,158 @@
|
|||||||
### hs_office_membership RBAC
|
### rbac membership
|
||||||
|
|
||||||
|
This code generated was by RbacViewMermaidFlowchartGenerator at 2024-03-12T17:26:50.174602110.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
|
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||||
flowchart TB
|
flowchart TB
|
||||||
|
|
||||||
subgraph global
|
subgraph partnerRel["`**partnerRel**`"]
|
||||||
style global fill:#eee
|
|
||||||
|
|
||||||
role:global.admin[global.admin]
|
|
||||||
end
|
|
||||||
|
|
||||||
subgraph hsOfficeDebitor
|
|
||||||
direction TB
|
direction TB
|
||||||
style hsOfficeDebitor fill:#eee
|
style partnerRel fill:#99bcdb,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
role:hsOfficeDebitor.owner[debitor.owner]
|
subgraph partnerRel.contact["`**partnerRel.contact**`"]
|
||||||
--> role:hsOfficeDebitor.admin[debitor.admin]
|
direction TB
|
||||||
--> role:hsOfficeDebitor.tenant[debitor.tenant]
|
style partnerRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px
|
||||||
--> role:hsOfficeDebitor.guest[debitor.guest]
|
|
||||||
|
subgraph partnerRel.contact:roles[ ]
|
||||||
|
style partnerRel.contact:roles fill:#99bcdb,stroke:white
|
||||||
|
|
||||||
|
role:partnerRel.contact:owner[[partnerRel.contact:owner]]
|
||||||
|
role:partnerRel.contact:admin[[partnerRel.contact:admin]]
|
||||||
|
role:partnerRel.contact:referrer[[partnerRel.contact:referrer]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph partnerRel.anchorPerson["`**partnerRel.anchorPerson**`"]
|
||||||
|
direction TB
|
||||||
|
style partnerRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
|
subgraph partnerRel.anchorPerson:roles[ ]
|
||||||
|
style partnerRel.anchorPerson:roles fill:#99bcdb,stroke:white
|
||||||
|
|
||||||
|
role:partnerRel.anchorPerson:owner[[partnerRel.anchorPerson:owner]]
|
||||||
|
role:partnerRel.anchorPerson:admin[[partnerRel.anchorPerson:admin]]
|
||||||
|
role:partnerRel.anchorPerson:referrer[[partnerRel.anchorPerson:referrer]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph partnerRel.holderPerson["`**partnerRel.holderPerson**`"]
|
||||||
|
direction TB
|
||||||
|
style partnerRel.holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
|
subgraph partnerRel.holderPerson:roles[ ]
|
||||||
|
style partnerRel.holderPerson:roles fill:#99bcdb,stroke:white
|
||||||
|
|
||||||
|
role:partnerRel.holderPerson:owner[[partnerRel.holderPerson:owner]]
|
||||||
|
role:partnerRel.holderPerson:admin[[partnerRel.holderPerson:admin]]
|
||||||
|
role:partnerRel.holderPerson:referrer[[partnerRel.holderPerson:referrer]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph partnerRel:roles[ ]
|
||||||
|
style partnerRel:roles fill:#99bcdb,stroke:white
|
||||||
|
|
||||||
|
role:partnerRel:owner[[partnerRel:owner]]
|
||||||
|
role:partnerRel:admin[[partnerRel:admin]]
|
||||||
|
role:partnerRel:agent[[partnerRel:agent]]
|
||||||
|
role:partnerRel:tenant[[partnerRel:tenant]]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
subgraph hsOfficePartner
|
subgraph partnerRel.contact["`**partnerRel.contact**`"]
|
||||||
direction TB
|
direction TB
|
||||||
style hsOfficePartner fill:#eee
|
style partnerRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
role:hsOfficePartner.owner[partner.admin]
|
subgraph partnerRel.contact:roles[ ]
|
||||||
--> role:hsOfficePartner.admin[partner.admin]
|
style partnerRel.contact:roles fill:#99bcdb,stroke:white
|
||||||
--> role:hsOfficePartner.agent[partner.agent]
|
|
||||||
--> role:hsOfficePartner.tenant[partner.tenant]
|
role:partnerRel.contact:owner[[partnerRel.contact:owner]]
|
||||||
--> role:hsOfficePartner.guest[partner.guest]
|
role:partnerRel.contact:admin[[partnerRel.contact:admin]]
|
||||||
|
role:partnerRel.contact:referrer[[partnerRel.contact:referrer]]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
subgraph hsOfficeMembership
|
subgraph membership["`**membership**`"]
|
||||||
|
direction TB
|
||||||
role:hsOfficeMembership.owner[membership.owner]
|
style membership fill:#dd4901,stroke:#274d6e,stroke-width:8px
|
||||||
%% permissions
|
|
||||||
role:hsOfficeMembership.owner --> perm:hsOfficeMembership.*{{membership.*}}
|
|
||||||
%% incoming
|
|
||||||
role:global.admin ---> role:hsOfficeMembership.owner
|
|
||||||
|
|
||||||
role:hsOfficeMembership.admin[membership.admin]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficeMembership.admin --> perm:hsOfficeMembership.edit{{membership.edit}}
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeMembership.owner ---> role:hsOfficeMembership.admin
|
|
||||||
|
|
||||||
role:hsOfficeMembership.agent[membership.agent]
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeMembership.admin ---> role:hsOfficeMembership.agent
|
|
||||||
role:hsOfficePartner.admin --> role:hsOfficeMembership.agent
|
|
||||||
role:hsOfficeDebitor.admin --> role:hsOfficeMembership.agent
|
|
||||||
%% outgoing
|
|
||||||
role:hsOfficeMembership.agent --> role:hsOfficePartner.tenant
|
|
||||||
role:hsOfficeMembership.agent --> role:hsOfficeDebitor.tenant
|
|
||||||
|
|
||||||
role:hsOfficeMembership.tenant[membership.tenant]
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeMembership.agent --> role:hsOfficeMembership.tenant
|
|
||||||
role:hsOfficePartner.agent --> role:hsOfficeMembership.tenant
|
|
||||||
role:hsOfficeDebitor.agent --> role:hsOfficeMembership.tenant
|
|
||||||
%% outgoing
|
|
||||||
role:hsOfficeMembership.tenant --> role:hsOfficePartner.guest
|
|
||||||
role:hsOfficeMembership.tenant --> role:hsOfficeDebitor.guest
|
|
||||||
|
|
||||||
role:hsOfficeMembership.guest[membership.guest]
|
subgraph membership:roles[ ]
|
||||||
%% permissions
|
style membership:roles fill:#dd4901,stroke:white
|
||||||
role:hsOfficeMembership.guest --> perm:hsOfficeMembership.view{{membership.view}}
|
|
||||||
%% incoming
|
role:membership:owner[[membership:owner]]
|
||||||
role:hsOfficeMembership.tenant --> role:hsOfficeMembership.guest
|
role:membership:admin[[membership:admin]]
|
||||||
role:hsOfficePartner.tenant --> role:hsOfficeMembership.guest
|
role:membership:referrer[[membership:referrer]]
|
||||||
role:hsOfficeDebitor.tenant --> role:hsOfficeMembership.guest
|
end
|
||||||
|
|
||||||
|
subgraph membership:permissions[ ]
|
||||||
|
style membership:permissions fill:#dd4901,stroke:white
|
||||||
|
|
||||||
|
perm:membership:INSERT{{membership:INSERT}}
|
||||||
|
perm:membership:DELETE{{membership:DELETE}}
|
||||||
|
perm:membership:UPDATE{{membership:UPDATE}}
|
||||||
|
perm:membership:SELECT{{membership:SELECT}}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
subgraph partnerRel.anchorPerson["`**partnerRel.anchorPerson**`"]
|
||||||
|
direction TB
|
||||||
|
style partnerRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
|
subgraph partnerRel.anchorPerson:roles[ ]
|
||||||
|
style partnerRel.anchorPerson:roles fill:#99bcdb,stroke:white
|
||||||
|
|
||||||
|
role:partnerRel.anchorPerson:owner[[partnerRel.anchorPerson:owner]]
|
||||||
|
role:partnerRel.anchorPerson:admin[[partnerRel.anchorPerson:admin]]
|
||||||
|
role:partnerRel.anchorPerson:referrer[[partnerRel.anchorPerson:referrer]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph partnerRel.holderPerson["`**partnerRel.holderPerson**`"]
|
||||||
|
direction TB
|
||||||
|
style partnerRel.holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
|
subgraph partnerRel.holderPerson:roles[ ]
|
||||||
|
style partnerRel.holderPerson:roles fill:#99bcdb,stroke:white
|
||||||
|
|
||||||
|
role:partnerRel.holderPerson:owner[[partnerRel.holderPerson:owner]]
|
||||||
|
role:partnerRel.holderPerson:admin[[partnerRel.holderPerson:admin]]
|
||||||
|
role:partnerRel.holderPerson:referrer[[partnerRel.holderPerson:referrer]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
%% granting roles to users
|
||||||
|
user:creator ==> role:membership:owner
|
||||||
|
|
||||||
|
%% granting roles to roles
|
||||||
|
role:global:admin -.-> role:partnerRel.anchorPerson:owner
|
||||||
|
role:partnerRel.anchorPerson:owner -.-> role:partnerRel.anchorPerson:admin
|
||||||
|
role:partnerRel.anchorPerson:admin -.-> role:partnerRel.anchorPerson:referrer
|
||||||
|
role:global:admin -.-> role:partnerRel.holderPerson:owner
|
||||||
|
role:partnerRel.holderPerson:owner -.-> role:partnerRel.holderPerson:admin
|
||||||
|
role:partnerRel.holderPerson:admin -.-> role:partnerRel.holderPerson:referrer
|
||||||
|
role:global:admin -.-> role:partnerRel.contact:owner
|
||||||
|
role:partnerRel.contact:owner -.-> role:partnerRel.contact:admin
|
||||||
|
role:partnerRel.contact:admin -.-> role:partnerRel.contact:referrer
|
||||||
|
role:global:admin -.-> role:partnerRel:owner
|
||||||
|
role:partnerRel:owner -.-> role:partnerRel:admin
|
||||||
|
role:partnerRel.anchorPerson:admin -.-> role:partnerRel:admin
|
||||||
|
role:partnerRel:admin -.-> role:partnerRel:agent
|
||||||
|
role:partnerRel.holderPerson:admin -.-> role:partnerRel:agent
|
||||||
|
role:partnerRel:agent -.-> role:partnerRel:tenant
|
||||||
|
role:partnerRel.holderPerson:admin -.-> role:partnerRel:tenant
|
||||||
|
role:partnerRel.contact:admin -.-> role:partnerRel:tenant
|
||||||
|
role:partnerRel:tenant -.-> role:partnerRel.anchorPerson:referrer
|
||||||
|
role:partnerRel:tenant -.-> role:partnerRel.holderPerson:referrer
|
||||||
|
role:partnerRel:tenant -.-> role:partnerRel.contact:referrer
|
||||||
|
role:partnerRel:admin ==> role:membership:owner
|
||||||
|
role:membership:owner ==> role:membership:admin
|
||||||
|
role:membership:admin ==> role:membership:referrer
|
||||||
|
role:membership:referrer ==> role:partnerRel:tenant
|
||||||
|
|
||||||
|
%% granting permissions to roles
|
||||||
|
role:global:admin ==> perm:membership:INSERT
|
||||||
|
role:membership:owner ==> perm:membership:DELETE
|
||||||
|
role:membership:admin ==> perm:membership:UPDATE
|
||||||
|
role:membership:referrer ==> perm:membership:SELECT
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
|
-- This code generated was by RbacViewPostgresGenerator at 2024-03-12T17:26:50.179864268.
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-membership-rbac-OBJECT:1 endDelimiter:--//
|
--changeset hs-office-membership-rbac-OBJECT:1 endDelimiter:--//
|
||||||
@ -15,150 +17,160 @@ call generateRbacRoleDescriptors('hsOfficeMembership', 'hs_office_membership');
|
|||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-membership-rbac-ROLES-CREATION:1 endDelimiter:--//
|
--changeset hs-office-membership-rbac-insert-trigger:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Creates and updates the roles and their assignments for membership entities.
|
Creates the roles, grants and permission for the AFTER INSERT TRIGGER.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
create or replace function hsOfficeMembershipRbacRolesTrigger()
|
create or replace procedure buildRbacSystemForHsOfficeMembership(
|
||||||
returns trigger
|
NEW hs_office_membership
|
||||||
language plpgsql
|
)
|
||||||
strict as $$
|
language plpgsql as $$
|
||||||
|
|
||||||
declare
|
declare
|
||||||
newHsOfficePartner hs_office_partner;
|
newPartnerRel hs_office_relationship;
|
||||||
newHsOfficePartnerRel hs_office_relationship;
|
|
||||||
newHsOfficeDebitor hs_office_debitor;
|
|
||||||
begin
|
begin
|
||||||
call enterTriggerForObjectUuid(NEW.uuid);
|
call enterTriggerForObjectUuid(NEW.uuid);
|
||||||
|
|
||||||
select * from hs_office_partner as p where p.uuid = NEW.partnerUuid into newHsOfficePartner;
|
SELECT r.*
|
||||||
select * from hs_office_relationship as r where r.relType = 'PARTNER' and r.relHolderUuid = NEW.partnerUuid into newHsOfficePartnerRel;
|
FROM hs_office_partner AS p
|
||||||
select * from hs_office_debitor as c where c.uuid = NEW.mainDebitorUuid into newHsOfficeDebitor;
|
JOIN hs_office_relationship AS r ON r.uuid = p.partnerRoleUuid
|
||||||
|
WHERE p.uuid = NEW.partnerUuid
|
||||||
|
INTO newPartnerRel;
|
||||||
|
assert newPartnerRel.uuid is not null, format('newPartnerRel must not be null for NEW.partnerUuid = %s', NEW.partnerUuid);
|
||||||
|
|
||||||
if TG_OP = 'INSERT' then
|
|
||||||
|
|
||||||
-- === ATTENTION: code generated from related Mermaid flowchart: ===
|
perform createRoleWithGrants(
|
||||||
|
hsOfficeMembershipOwner(NEW),
|
||||||
|
permissions => array['DELETE'],
|
||||||
|
userUuids => array[currentUserUuid()],
|
||||||
|
incomingSuperRoles => array[hsOfficeRelationshipAdmin(newPartnerRel)]
|
||||||
|
);
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficeMembershipOwner(NEW),
|
hsOfficeMembershipAdmin(NEW),
|
||||||
permissions => array['DELETE'],
|
permissions => array['UPDATE'],
|
||||||
incomingSuperRoles => array[globalAdmin()]
|
incomingSuperRoles => array[hsOfficeMembershipOwner(NEW)]
|
||||||
);
|
);
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficeMembershipAdmin(NEW),
|
hsOfficeMembershipReferrer(NEW),
|
||||||
permissions => array['UPDATE'],
|
permissions => array['SELECT'],
|
||||||
incomingSuperRoles => array[hsOfficeMembershipOwner(NEW)]
|
incomingSuperRoles => array[hsOfficeMembershipAdmin(NEW)],
|
||||||
);
|
outgoingSubRoles => array[hsOfficeRelationshipTenant(newPartnerRel)]
|
||||||
|
);
|
||||||
perform createRoleWithGrants(
|
|
||||||
hsOfficeMembershipAgent(NEW),
|
|
||||||
incomingSuperRoles => array[hsOfficeMembershipAdmin(NEW), hsOfficeRelationshipAdmin(newHsOfficePartnerRel), hsOfficeDebitorAdmin(newHsOfficeDebitor)],
|
|
||||||
outgoingSubRoles => array[hsOfficeRelationshipTenant(newHsOfficePartnerRel), hsOfficeDebitorTenant(newHsOfficeDebitor)]
|
|
||||||
);
|
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
|
||||||
hsOfficeMembershipTenant(NEW),
|
|
||||||
incomingSuperRoles => array[hsOfficeMembershipAgent(NEW), hsOfficeRelationshipAgent(newHsOfficePartnerRel), hsOfficeDebitorAgent(newHsOfficeDebitor)],
|
|
||||||
outgoingSubRoles => array[hsOfficeRelationshipGuest(newHsOfficePartnerRel), hsOfficeDebitorGuest(newHsOfficeDebitor)]
|
|
||||||
);
|
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
|
||||||
hsOfficeMembershipGuest(NEW),
|
|
||||||
permissions => array['SELECT'],
|
|
||||||
incomingSuperRoles => array[hsOfficeMembershipTenant(NEW), hsOfficeRelationshipTenant(newHsOfficePartnerRel), hsOfficeDebitorTenant(newHsOfficeDebitor)]
|
|
||||||
);
|
|
||||||
|
|
||||||
-- === END of code generated from Mermaid flowchart. ===
|
|
||||||
|
|
||||||
else
|
|
||||||
raise exception 'invalid usage of TRIGGER';
|
|
||||||
end if;
|
|
||||||
|
|
||||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||||
return NEW;
|
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
An AFTER INSERT TRIGGER which creates the role structure for a new customer.
|
AFTER INSERT TRIGGER to create the role+grant structure for a new hs_office_membership row.
|
||||||
*/
|
*/
|
||||||
create trigger createRbacRolesForHsOfficeMembership_Trigger
|
|
||||||
after insert
|
create or replace function insertTriggerForHsOfficeMembership_tf()
|
||||||
on hs_office_membership
|
returns trigger
|
||||||
|
language plpgsql
|
||||||
|
strict as $$
|
||||||
|
begin
|
||||||
|
call buildRbacSystemForHsOfficeMembership(NEW);
|
||||||
|
return NEW;
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
create trigger insertTriggerForHsOfficeMembership_tg
|
||||||
|
after insert on hs_office_membership
|
||||||
for each row
|
for each row
|
||||||
execute procedure hsOfficeMembershipRbacRolesTrigger();
|
execute procedure insertTriggerForHsOfficeMembership_tf();
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-membership-rbac-IDENTITY-VIEW:1 endDelimiter:--//
|
--changeset hs-office-membership-rbac-INSERT:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
call generateRbacIdentityViewFromProjection('hs_office_membership', $idName$
|
|
||||||
'#' ||
|
/*
|
||||||
(select partnerNumber from hs_office_partner p where p.uuid = target.partnerUuid) ||
|
Creates INSERT INTO hs_office_membership permissions for the related global rows.
|
||||||
memberNumberSuffix ||
|
*/
|
||||||
':' || (select split_part(idName, ':', 2) from hs_office_partner_iv p where p.uuid = target.partnerUuid)
|
do language plpgsql $$
|
||||||
$idName$);
|
declare
|
||||||
|
row global;
|
||||||
|
permissionUuid uuid;
|
||||||
|
roleUuid uuid;
|
||||||
|
begin
|
||||||
|
call defineContext('create INSERT INTO hs_office_membership permissions for the related global rows');
|
||||||
|
|
||||||
|
FOR row IN SELECT * FROM global
|
||||||
|
LOOP
|
||||||
|
roleUuid := findRoleId(globalAdmin());
|
||||||
|
permissionUuid := createPermission(row.uuid, 'INSERT', 'hs_office_membership');
|
||||||
|
call grantPermissionToRole(permissionUuid, roleUuid);
|
||||||
|
END LOOP;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Adds hs_office_membership INSERT permission to specified role of new global rows.
|
||||||
|
*/
|
||||||
|
create or replace function hs_office_membership_global_insert_tf()
|
||||||
|
returns trigger
|
||||||
|
language plpgsql
|
||||||
|
strict as $$
|
||||||
|
begin
|
||||||
|
call grantPermissionToRole(
|
||||||
|
globalAdmin(),
|
||||||
|
createPermission(NEW.uuid, 'INSERT', 'hs_office_membership'));
|
||||||
|
return NEW;
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
create trigger hs_office_membership_global_insert_tg
|
||||||
|
after insert on global
|
||||||
|
for each row
|
||||||
|
execute procedure hs_office_membership_global_insert_tf();
|
||||||
|
|
||||||
|
/**
|
||||||
|
Checks if the user or assumed roles are allowed to insert a row to hs_office_membership.
|
||||||
|
*/
|
||||||
|
create or replace function hs_office_membership_insert_permission_missing_tf()
|
||||||
|
returns trigger
|
||||||
|
language plpgsql as $$
|
||||||
|
begin
|
||||||
|
raise exception '[403] insert into hs_office_membership not allowed for current subjects % (%)',
|
||||||
|
currentSubjects(), currentSubjectsUuids();
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
create trigger hs_office_membership_insert_permission_check_tg
|
||||||
|
before insert on hs_office_membership
|
||||||
|
for each row
|
||||||
|
when ( not isGlobalAdmin() )
|
||||||
|
execute procedure hs_office_membership_insert_permission_missing_tf();
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
--changeset hs-office-membership-rbac-IDENTITY-VIEW:1 endDelimiter:--//
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
call generateRbacIdentityViewFromQuery('hs_office_membership', $idName$
|
||||||
|
SELECT m.uuid AS uuid,
|
||||||
|
'M-' || p.partnerNumber || m.memberNumberSuffix as idName
|
||||||
|
FROM hs_office_membership AS m
|
||||||
|
JOIN hs_office_partner AS p ON p.uuid = m.partnerUuid
|
||||||
|
|
||||||
|
$idName$);
|
||||||
|
--//
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-membership-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
|
--changeset hs-office-membership-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
call generateRbacRestrictedView('hs_office_membership',
|
call generateRbacRestrictedView('hs_office_membership',
|
||||||
orderby => 'target.memberNumberSuffix',
|
$orderBy$
|
||||||
columnUpdates => $updates$
|
validity
|
||||||
validity = new.validity,
|
$orderBy$,
|
||||||
reasonForTermination = new.reasonForTermination,
|
$updates$
|
||||||
membershipFeeBillable = new.membershipFeeBillable
|
validity = new.validity,
|
||||||
|
membershipFeeBillable = new.membershipFeeBillable,
|
||||||
|
reasonForTermination = new.reasonForTermination
|
||||||
$updates$);
|
$updates$);
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
|
||||||
--changeset hs-office-membership-rbac-NEW-Membership:1 endDelimiter:--//
|
|
||||||
-- ----------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
Creates a global permission for new-membership and assigns it to the hostsharing admins role.
|
|
||||||
*/
|
|
||||||
do language plpgsql $$
|
|
||||||
declare
|
|
||||||
addCustomerPermissions uuid[];
|
|
||||||
globalObjectUuid uuid;
|
|
||||||
globalAdminRoleUuid uuid ;
|
|
||||||
begin
|
|
||||||
call defineContext('granting global new-membership permission to global admin role', null, null, null);
|
|
||||||
|
|
||||||
globalAdminRoleUuid := findRoleId(globalAdmin());
|
|
||||||
globalObjectUuid := (select uuid from global);
|
|
||||||
addCustomerPermissions := createPermissions(globalObjectUuid, array ['new-membership']);
|
|
||||||
call grantPermissionsToRole(globalAdminRoleUuid, addCustomerPermissions);
|
|
||||||
end;
|
|
||||||
$$;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Used by the trigger to prevent the add-customer to current user respectively assumed roles.
|
|
||||||
*/
|
|
||||||
create or replace function addHsOfficeMembershipNotAllowedForCurrentSubjects()
|
|
||||||
returns trigger
|
|
||||||
language PLPGSQL
|
|
||||||
as $$
|
|
||||||
begin
|
|
||||||
raise exception '[403] new-membership not permitted for %',
|
|
||||||
array_to_string(currentSubjects(), ';', 'null');
|
|
||||||
end; $$;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Checks if the user or assumed roles are allowed to create a new customer.
|
|
||||||
*/
|
|
||||||
create trigger hs_office_membership_insert_trigger
|
|
||||||
before insert
|
|
||||||
on hs_office_membership
|
|
||||||
for each row
|
|
||||||
-- TODO.spec: who is allowed to create new memberships
|
|
||||||
when ( not hasAssumedRole() )
|
|
||||||
execute procedure addHsOfficeMembershipNotAllowedForCurrentSubjects();
|
|
||||||
--//
|
|
||||||
|
|
||||||
|
@ -10,42 +10,26 @@
|
|||||||
*/
|
*/
|
||||||
create or replace procedure createHsOfficeMembershipTestData(
|
create or replace procedure createHsOfficeMembershipTestData(
|
||||||
forPartnerNumber numeric(5),
|
forPartnerNumber numeric(5),
|
||||||
forMainDebitorNumberSuffix numeric,
|
|
||||||
newMemberNumberSuffix char(2) )
|
newMemberNumberSuffix char(2) )
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
declare
|
declare
|
||||||
currentTask varchar;
|
currentTask varchar;
|
||||||
relatedPartner hs_office_partner;
|
relatedPartner hs_office_partner;
|
||||||
relatedDebitorRel hs_office_relationship;
|
|
||||||
relatedDebitor hs_office_debitor;
|
|
||||||
begin
|
begin
|
||||||
currentTask := 'creating Membership test-data ' ||
|
currentTask := 'creating Membership test-data ' ||
|
||||||
'P-' || forPartnerNumber::text ||
|
'P-' || forPartnerNumber::text ||
|
||||||
'D-...' || forMainDebitorNumberSuffix ||
|
|
||||||
'M-...' || newMemberNumberSuffix;
|
'M-...' || newMemberNumberSuffix;
|
||||||
call defineContext(currentTask, null, 'superuser-alex@hostsharing.net', 'global#global.admin');
|
call defineContext(currentTask, null, 'superuser-alex@hostsharing.net', 'global#global.admin');
|
||||||
execute format('set local hsadminng.currentTask to %L', currentTask);
|
execute format('set local hsadminng.currentTask to %L', currentTask);
|
||||||
|
|
||||||
select partner.* from hs_office_partner partner
|
select partner.* from hs_office_partner partner
|
||||||
where partner.partnerNumber = forPartnerNumber into relatedPartner;
|
where partner.partnerNumber = forPartnerNumber into relatedPartner;
|
||||||
select debitorRel.* from hs_office_relationship debitorRel
|
|
||||||
join hs_office_relationship partnerRel
|
|
||||||
on debitorRel.relAnchorUuid=partnerRel.relHolderUuid and partnerRel.relType='PARTNER'
|
|
||||||
join hs_office_partner partner
|
|
||||||
on partner.partnerRoleUuid = partnerRel.uuid
|
|
||||||
where debitorRel.relType='ACCOUNTING' -- FIXME: 'DEBITOR'
|
|
||||||
into relatedDebitorRel;
|
|
||||||
select debitor.* from hs_office_debitor debitor
|
|
||||||
where debitor.debitorRelUuid = relatedDebitorRel.uuid
|
|
||||||
and debitor.debitorNumberSuffix = forMainDebitorNumberSuffix
|
|
||||||
into relatedDebitor;
|
|
||||||
|
|
||||||
raise notice 'creating test Membership: M-% %', forPartnerNumber, newMemberNumberSuffix;
|
raise notice 'creating test Membership: M-% %', forPartnerNumber, newMemberNumberSuffix;
|
||||||
raise notice '- using partner (%): %', relatedPartner.uuid, relatedPartner;
|
raise notice '- using partner (%): %', relatedPartner.uuid, relatedPartner;
|
||||||
raise notice '- using debitor (%): %', relatedDebitor.uuid, relatedDebitor;
|
|
||||||
insert
|
insert
|
||||||
into hs_office_membership (uuid, partneruuid, maindebitoruuid, memberNumberSuffix, validity, reasonfortermination)
|
into hs_office_membership (uuid, partneruuid, memberNumberSuffix, validity, reasonfortermination)
|
||||||
values (uuid_generate_v4(), relatedPartner.uuid, relatedDebitor.uuid, newMemberNumberSuffix, daterange('20221001' , null, '[]'), 'NONE');
|
values (uuid_generate_v4(), relatedPartner.uuid, newMemberNumberSuffix, daterange('20221001' , null, '[]'), 'NONE');
|
||||||
end; $$;
|
end; $$;
|
||||||
--//
|
--//
|
||||||
|
|
||||||
@ -56,9 +40,9 @@ end; $$;
|
|||||||
|
|
||||||
do language plpgsql $$
|
do language plpgsql $$
|
||||||
begin
|
begin
|
||||||
call createHsOfficeMembershipTestData(10001, 11, '01');
|
call createHsOfficeMembershipTestData(10001, '01');
|
||||||
call createHsOfficeMembershipTestData(10002, 12, '02');
|
call createHsOfficeMembershipTestData(10002, '02');
|
||||||
call createHsOfficeMembershipTestData(10003, 13, '03');
|
call createHsOfficeMembershipTestData(10003, '03');
|
||||||
end;
|
end;
|
||||||
$$;
|
$$;
|
||||||
--//
|
--//
|
||||||
|
@ -334,9 +334,6 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.body("uuid", isUuidValid())
|
.body("uuid", isUuidValid())
|
||||||
.body("partner.person.tradeName", is(givenMembership.getPartner().getPartnerRole().getRelHolder().getTradeName()))
|
.body("partner.person.tradeName", is(givenMembership.getPartner().getPartnerRole().getRelHolder().getTradeName()))
|
||||||
.body("mainDebitor.debitorNumber", is(givenMembership.getMainDebitor().getDebitorNumber()))
|
|
||||||
.body("mainDebitor.debitorNumberSuffix", is((int) givenMembership.getMainDebitor().getDebitorNumberSuffix()))
|
|
||||||
.body("mainDebitor.debitorNumberSuffix", is((int) givenMembership.getMainDebitor().getDebitorNumberSuffix()))
|
|
||||||
.body("memberNumberSuffix", is(givenMembership.getMemberNumberSuffix()))
|
.body("memberNumberSuffix", is(givenMembership.getMemberNumberSuffix()))
|
||||||
.body("validFrom", is("2022-11-01"))
|
.body("validFrom", is("2022-11-01"))
|
||||||
.body("validTo", is("2023-12-31"))
|
.body("validTo", is("2023-12-31"))
|
||||||
@ -347,7 +344,6 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
assertThat(membershipRepo.findByUuid(givenMembership.getUuid())).isPresent().get()
|
assertThat(membershipRepo.findByUuid(givenMembership.getUuid())).isPresent().get()
|
||||||
.matches(mandate -> {
|
.matches(mandate -> {
|
||||||
assertThat(mandate.getPartner().toShortString()).isEqualTo("LP First GmbH");
|
assertThat(mandate.getPartner().toShortString()).isEqualTo("LP First GmbH");
|
||||||
assertThat(mandate.getMainDebitor().toString()).isEqualTo(givenMembership.getMainDebitor().toString());
|
|
||||||
assertThat(mandate.getMemberNumberSuffix()).isEqualTo(givenMembership.getMemberNumberSuffix());
|
assertThat(mandate.getMemberNumberSuffix()).isEqualTo(givenMembership.getMemberNumberSuffix());
|
||||||
assertThat(mandate.getValidity().asString()).isEqualTo("[2022-11-01,2024-01-01)");
|
assertThat(mandate.getValidity().asString()).isEqualTo("[2022-11-01,2024-01-01)");
|
||||||
assertThat(mandate.getReasonForTermination()).isEqualTo(HsOfficeReasonForTermination.CANCELLATION);
|
assertThat(mandate.getReasonForTermination()).isEqualTo(HsOfficeReasonForTermination.CANCELLATION);
|
||||||
@ -390,7 +386,6 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
assertThat(membershipRepo.findByUuid(givenMembership.getUuid())).isPresent().get()
|
assertThat(membershipRepo.findByUuid(givenMembership.getUuid())).isPresent().get()
|
||||||
.matches(mandate -> {
|
.matches(mandate -> {
|
||||||
assertThat(mandate.getPartner().toShortString()).isEqualTo("LP First GmbH");
|
assertThat(mandate.getPartner().toShortString()).isEqualTo("LP First GmbH");
|
||||||
assertThat(mandate.getMainDebitor().toString()).isEqualTo(givenMembership.getMainDebitor().toString());
|
|
||||||
assertThat(mandate.getMemberNumberSuffix()).isEqualTo(givenMembership.getMemberNumberSuffix());
|
assertThat(mandate.getMemberNumberSuffix()).isEqualTo(givenMembership.getMemberNumberSuffix());
|
||||||
assertThat(mandate.getValidity().asString()).isEqualTo("[2022-11-01,)");
|
assertThat(mandate.getValidity().asString()).isEqualTo("[2022-11-01,)");
|
||||||
assertThat(mandate.getReasonForTermination()).isEqualTo(NONE);
|
assertThat(mandate.getReasonForTermination()).isEqualTo(NONE);
|
||||||
@ -501,7 +496,6 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
final var newMembership = HsOfficeMembershipEntity.builder()
|
final var newMembership = HsOfficeMembershipEntity.builder()
|
||||||
.uuid(UUID.randomUUID())
|
.uuid(UUID.randomUUID())
|
||||||
.partner(givenPartner)
|
.partner(givenPartner)
|
||||||
.mainDebitor(givenDebitor)
|
|
||||||
.memberNumberSuffix(TEMP_MEMBER_NUMBER_SUFFIX)
|
.memberNumberSuffix(TEMP_MEMBER_NUMBER_SUFFIX)
|
||||||
.validity(Range.closedInfinite(LocalDate.parse("2022-11-01")))
|
.validity(Range.closedInfinite(LocalDate.parse("2022-11-01")))
|
||||||
.reasonForTermination(NONE)
|
.reasonForTermination(NONE)
|
||||||
|
@ -17,7 +17,6 @@ import java.time.LocalDate;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static net.hostsharing.hsadminng.hs.office.debitor.TestHsOfficeDebitor.TEST_DEBITOR;
|
|
||||||
import static net.hostsharing.hsadminng.hs.office.partner.TestHsOfficePartner.TEST_PARTNER;
|
import static net.hostsharing.hsadminng.hs.office.partner.TestHsOfficePartner.TEST_PARTNER;
|
||||||
import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
|
import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
@ -32,7 +31,6 @@ class HsOfficeMembershipEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
> {
|
> {
|
||||||
|
|
||||||
private static final UUID INITIAL_MEMBERSHIP_UUID = UUID.randomUUID();
|
private static final UUID INITIAL_MEMBERSHIP_UUID = UUID.randomUUID();
|
||||||
private static final UUID PATCHED_MAIN_DEBITOR_UUID = UUID.randomUUID();
|
|
||||||
private static final LocalDate GIVEN_VALID_FROM = LocalDate.parse("2020-04-15");
|
private static final LocalDate GIVEN_VALID_FROM = LocalDate.parse("2020-04-15");
|
||||||
private static final LocalDate PATCHED_VALID_TO = LocalDate.parse("2022-12-31");
|
private static final LocalDate PATCHED_VALID_TO = LocalDate.parse("2022-12-31");
|
||||||
|
|
||||||
@ -56,7 +54,6 @@ class HsOfficeMembershipEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
protected HsOfficeMembershipEntity newInitialEntity() {
|
protected HsOfficeMembershipEntity newInitialEntity() {
|
||||||
final var entity = new HsOfficeMembershipEntity();
|
final var entity = new HsOfficeMembershipEntity();
|
||||||
entity.setUuid(INITIAL_MEMBERSHIP_UUID);
|
entity.setUuid(INITIAL_MEMBERSHIP_UUID);
|
||||||
entity.setMainDebitor(TEST_DEBITOR);
|
|
||||||
entity.setPartner(TEST_PARTNER);
|
entity.setPartner(TEST_PARTNER);
|
||||||
entity.setValidity(Range.closedInfinite(GIVEN_VALID_FROM));
|
entity.setValidity(Range.closedInfinite(GIVEN_VALID_FROM));
|
||||||
entity.setMembershipFeeBillable(GIVEN_MEMBERSHIP_FEE_BILLABLE);
|
entity.setMembershipFeeBillable(GIVEN_MEMBERSHIP_FEE_BILLABLE);
|
||||||
@ -70,19 +67,12 @@ class HsOfficeMembershipEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected HsOfficeMembershipEntityPatcher createPatcher(final HsOfficeMembershipEntity membership) {
|
protected HsOfficeMembershipEntityPatcher createPatcher(final HsOfficeMembershipEntity membership) {
|
||||||
return new HsOfficeMembershipEntityPatcher(em, mapper, membership);
|
return new HsOfficeMembershipEntityPatcher(mapper, membership);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<Property> propertyTestDescriptors() {
|
protected Stream<Property> propertyTestDescriptors() {
|
||||||
return Stream.of(
|
return Stream.of(
|
||||||
new JsonNullableProperty<>(
|
|
||||||
"debitor",
|
|
||||||
HsOfficeMembershipPatchResource::setMainDebitorUuid,
|
|
||||||
PATCHED_MAIN_DEBITOR_UUID,
|
|
||||||
HsOfficeMembershipEntity::setMainDebitor,
|
|
||||||
newDebitor(PATCHED_MAIN_DEBITOR_UUID))
|
|
||||||
.notNullable(),
|
|
||||||
new JsonNullableProperty<>(
|
new JsonNullableProperty<>(
|
||||||
"valid",
|
"valid",
|
||||||
HsOfficeMembershipPatchResource::setValidTo,
|
HsOfficeMembershipPatchResource::setValidTo,
|
||||||
@ -102,10 +92,4 @@ class HsOfficeMembershipEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
HsOfficeMembershipEntity::setMembershipFeeBillable)
|
HsOfficeMembershipEntity::setMembershipFeeBillable)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HsOfficeDebitorEntity newDebitor(final UUID uuid) {
|
|
||||||
final var newDebitor = new HsOfficeDebitorEntity();
|
|
||||||
newDebitor.setUuid(uuid);
|
|
||||||
return newDebitor;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ import java.lang.reflect.InvocationTargetException;
|
|||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import static net.hostsharing.hsadminng.hs.office.debitor.TestHsOfficeDebitor.TEST_DEBITOR;
|
|
||||||
import static net.hostsharing.hsadminng.hs.office.partner.TestHsOfficePartner.TEST_PARTNER;
|
import static net.hostsharing.hsadminng.hs.office.partner.TestHsOfficePartner.TEST_PARTNER;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
@ -20,7 +19,6 @@ class HsOfficeMembershipEntityUnitTest {
|
|||||||
final HsOfficeMembershipEntity givenMembership = HsOfficeMembershipEntity.builder()
|
final HsOfficeMembershipEntity givenMembership = HsOfficeMembershipEntity.builder()
|
||||||
.memberNumberSuffix("01")
|
.memberNumberSuffix("01")
|
||||||
.partner(TEST_PARTNER)
|
.partner(TEST_PARTNER)
|
||||||
.mainDebitor(TEST_DEBITOR)
|
|
||||||
.validity(Range.closedInfinite(GIVEN_VALID_FROM))
|
.validity(Range.closedInfinite(GIVEN_VALID_FROM))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.distin
|
|||||||
import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.distinctRoleNamesOf;
|
import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.distinctRoleNamesOf;
|
||||||
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;
|
||||||
|
|
||||||
@DataJpaTest
|
@DataJpaTest
|
||||||
@Import( { Context.class, JpaAttempt.class })
|
@Import( { Context.class, JpaAttempt.class })
|
||||||
class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCleanup {
|
class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCleanup {
|
||||||
@ -72,7 +73,6 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
|
|||||||
final var newMembership = HsOfficeMembershipEntity.builder()
|
final var newMembership = HsOfficeMembershipEntity.builder()
|
||||||
.memberNumberSuffix("11")
|
.memberNumberSuffix("11")
|
||||||
.partner(givenPartner)
|
.partner(givenPartner)
|
||||||
.mainDebitor(givenDebitor)
|
|
||||||
.validity(Range.closedInfinite(LocalDate.parse("2020-01-01")))
|
.validity(Range.closedInfinite(LocalDate.parse("2020-01-01")))
|
||||||
.membershipFeeBillable(true)
|
.membershipFeeBillable(true)
|
||||||
.build();
|
.build();
|
||||||
@ -99,11 +99,9 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
|
|||||||
// when
|
// when
|
||||||
attempt(em, () -> {
|
attempt(em, () -> {
|
||||||
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("First").get(0);
|
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("First").get(0);
|
||||||
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike("First").get(0);
|
|
||||||
final var newMembership = HsOfficeMembershipEntity.builder()
|
final var newMembership = HsOfficeMembershipEntity.builder()
|
||||||
.memberNumberSuffix("17")
|
.memberNumberSuffix("17")
|
||||||
.partner(givenPartner)
|
.partner(givenPartner)
|
||||||
.mainDebitor(givenDebitor)
|
|
||||||
.validity(Range.closedInfinite(LocalDate.parse("2020-01-01")))
|
.validity(Range.closedInfinite(LocalDate.parse("2020-01-01")))
|
||||||
.membershipFeeBillable(true)
|
.membershipFeeBillable(true)
|
||||||
.build();
|
.build();
|
||||||
@ -219,7 +217,7 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
|
|||||||
public void globalAdmin_canUpdateValidityOfArbitraryMembership() {
|
public void globalAdmin_canUpdateValidityOfArbitraryMembership() {
|
||||||
// given
|
// given
|
||||||
context("superuser-alex@hostsharing.net");
|
context("superuser-alex@hostsharing.net");
|
||||||
final var givenMembership = givenSomeTemporaryMembership("First", "First", "11");
|
final var givenMembership = givenSomeTemporaryMembership("First", "11");
|
||||||
assertThatMembershipIsVisibleForUserWithRole(
|
assertThatMembershipIsVisibleForUserWithRole(
|
||||||
givenMembership,
|
givenMembership,
|
||||||
"hs_office_debitor#1000111:FirstGmbH-firstcontact.admin");
|
"hs_office_debitor#1000111:FirstGmbH-firstcontact.admin");
|
||||||
@ -246,7 +244,7 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
|
|||||||
public void debitorAdmin_canViewButNotUpdateRelatedMembership() {
|
public void debitorAdmin_canViewButNotUpdateRelatedMembership() {
|
||||||
// given
|
// given
|
||||||
context("superuser-alex@hostsharing.net");
|
context("superuser-alex@hostsharing.net");
|
||||||
final var givenMembership = givenSomeTemporaryMembership("First", "First", "13");
|
final var givenMembership = givenSomeTemporaryMembership("First", "13");
|
||||||
assertThatMembershipIsVisibleForUserWithRole(
|
assertThatMembershipIsVisibleForUserWithRole(
|
||||||
givenMembership,
|
givenMembership,
|
||||||
"hs_office_debitor#1000111:FirstGmbH-firstcontact.admin");
|
"hs_office_debitor#1000111:FirstGmbH-firstcontact.admin");
|
||||||
@ -299,7 +297,7 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
|
|||||||
public void globalAdmin_withoutAssumedRole_canDeleteAnyMembership() {
|
public void globalAdmin_withoutAssumedRole_canDeleteAnyMembership() {
|
||||||
// given
|
// given
|
||||||
context("superuser-alex@hostsharing.net", null);
|
context("superuser-alex@hostsharing.net", null);
|
||||||
final var givenMembership = givenSomeTemporaryMembership("First", "Second", "12");
|
final var givenMembership = givenSomeTemporaryMembership("First", "12");
|
||||||
|
|
||||||
// when
|
// when
|
||||||
final var result = jpaAttempt.transacted(() -> {
|
final var result = jpaAttempt.transacted(() -> {
|
||||||
@ -319,7 +317,7 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
|
|||||||
public void nonGlobalAdmin_canNotDeleteTheirRelatedMembership() {
|
public void nonGlobalAdmin_canNotDeleteTheirRelatedMembership() {
|
||||||
// given
|
// given
|
||||||
context("superuser-alex@hostsharing.net");
|
context("superuser-alex@hostsharing.net");
|
||||||
final var givenMembership = givenSomeTemporaryMembership("First", "Third", "14");
|
final var givenMembership = givenSomeTemporaryMembership("First", "14");
|
||||||
|
|
||||||
// when
|
// when
|
||||||
final var result = jpaAttempt.transacted(() -> {
|
final var result = jpaAttempt.transacted(() -> {
|
||||||
@ -345,7 +343,7 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
|
|||||||
context("superuser-alex@hostsharing.net");
|
context("superuser-alex@hostsharing.net");
|
||||||
final var initialRoleNames = Array.from(distinctRoleNamesOf(rawRoleRepo.findAll()));
|
final var initialRoleNames = Array.from(distinctRoleNamesOf(rawRoleRepo.findAll()));
|
||||||
final var initialGrantNames = Array.from(distinctGrantDisplaysOf(rawGrantRepo.findAll()));
|
final var initialGrantNames = Array.from(distinctGrantDisplaysOf(rawGrantRepo.findAll()));
|
||||||
final var givenMembership = givenSomeTemporaryMembership("First", "First", "15");
|
final var givenMembership = givenSomeTemporaryMembership("First", "15");
|
||||||
assertThat(distinctRoleNamesOf(rawRoleRepo.findAll()).size()).as("precondition failed: unexpected number of roles created")
|
assertThat(distinctRoleNamesOf(rawRoleRepo.findAll()).size()).as("precondition failed: unexpected number of roles created")
|
||||||
.isEqualTo(initialRoleNames.length + 5);
|
.isEqualTo(initialRoleNames.length + 5);
|
||||||
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll()).size()).as("precondition failed: unexpected number of grants created")
|
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll()).size()).as("precondition failed: unexpected number of grants created")
|
||||||
@ -383,15 +381,13 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
|
|||||||
"[creating Membership test-data Seconde.K.12, hs_office_membership, INSERT]");
|
"[creating Membership test-data Seconde.K.12, hs_office_membership, INSERT]");
|
||||||
}
|
}
|
||||||
|
|
||||||
private HsOfficeMembershipEntity givenSomeTemporaryMembership(final String partnerTradeName, final String debitorName, final String memberNumberSuffix) {
|
private HsOfficeMembershipEntity givenSomeTemporaryMembership(final String partnerTradeName, final String memberNumberSuffix) {
|
||||||
return jpaAttempt.transacted(() -> {
|
return jpaAttempt.transacted(() -> {
|
||||||
context("superuser-alex@hostsharing.net");
|
context("superuser-alex@hostsharing.net");
|
||||||
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike(partnerTradeName).get(0);
|
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike(partnerTradeName).get(0);
|
||||||
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike(debitorName).get(0);
|
|
||||||
final var newMembership = HsOfficeMembershipEntity.builder()
|
final var newMembership = HsOfficeMembershipEntity.builder()
|
||||||
.memberNumberSuffix(memberNumberSuffix)
|
.memberNumberSuffix(memberNumberSuffix)
|
||||||
.partner(givenPartner)
|
.partner(givenPartner)
|
||||||
.mainDebitor(givenDebitor)
|
|
||||||
.validity(Range.closedInfinite(LocalDate.parse("2020-01-01")))
|
.validity(Range.closedInfinite(LocalDate.parse("2020-01-01")))
|
||||||
.membershipFeeBillable(true)
|
.membershipFeeBillable(true)
|
||||||
.build();
|
.build();
|
||||||
|
@ -704,7 +704,6 @@ public class ImportOfficeData extends ContextBasedTest {
|
|||||||
isBlank(rec.getString("member_until"))
|
isBlank(rec.getString("member_until"))
|
||||||
? HsOfficeReasonForTermination.NONE
|
? HsOfficeReasonForTermination.NONE
|
||||||
: HsOfficeReasonForTermination.UNKNOWN)
|
: HsOfficeReasonForTermination.UNKNOWN)
|
||||||
.mainDebitor(debitor)
|
|
||||||
.build();
|
.build();
|
||||||
memberships.put(rec.getInteger("bp_id"), membership);
|
memberships.put(rec.getInteger("bp_id"), membership);
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,8 @@ spring:
|
|||||||
platform: postgres
|
platform: postgres
|
||||||
|
|
||||||
datasource:
|
datasource:
|
||||||
url-tc: jdbc:tc:postgresql:15.5-bookworm:///spring_boot_testcontainers
|
url: jdbc:tc:postgresql:15.5-bookworm:///spring_boot_testcontainers
|
||||||
url: jdbc:postgresql://localhost:5432/postgres
|
url-local: jdbc:postgresql://localhost:5432/postgres
|
||||||
username: postgres
|
username: postgres
|
||||||
password: password
|
password: password
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user