From e1895e373529ba79c01dfe3dedbada8c57f547a4 Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Thu, 20 Oct 2022 20:11:31 +0200 Subject: [PATCH] hs-office-partner-details --- .../debitor/HsOfficeDebitorRepository.java | 2 +- .../partner/HsOfficePartnerController.java | 15 +-- .../partner/HsOfficePartnerDetailsEntity.java | 58 ++++++++++++ .../HsOfficePartnerDetailsEntityPatcher.java | 32 +++++++ .../office/partner/HsOfficePartnerEntity.java | 15 +-- .../partner/HsOfficePartnerEntityPatcher.java | 16 +--- .../partner/HsOfficePartnerRepository.java | 2 +- .../hs-office/api-mappings.yaml | 2 + .../hs-office/hs-office-partner-schemas.yaml | 52 ++++++++--- .../resources/db/changelog/050-rbac-base.sql | 2 +- .../db/changelog/054-rbac-context.sql | 2 +- .../db/changelog/220-hs-office-partner.sql | 28 +++++- .../changelog/223-hs-office-partner-rbac.md | 12 +++ .../changelog/223-hs-office-partner-rbac.sql | 45 ++++++--- .../224-hs-office-partner-details-rbac.sql | 85 +++++++++++++++++ .../228-hs-office-partner-test-data.sql | 50 +++++----- .../db/changelog/db.changelog-master.yaml | 2 + .../debitor/HsOfficeDebitorEntityTest.java | 4 +- ...fficeDebitorRepositoryIntegrationTest.java | 15 +-- ...ceMembershipRepositoryIntegrationTest.java | 3 +- ...OfficePartnerControllerAcceptanceTest.java | 70 ++++++++------ ...cePartnerDetailsEntityPatcherUnitTest.java | 93 +++++++++++++++++++ .../HsOfficePartnerDetailsEntityTest.java | 51 ++++++++++ .../HsOfficePartnerEntityPatcherUnitTest.java | 52 +++-------- ...fficePartnerRepositoryIntegrationTest.java | 74 +++++++-------- ...eSepaMandateRepositoryIntegrationTest.java | 3 +- 26 files changed, 573 insertions(+), 212 deletions(-) create mode 100644 src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerDetailsEntity.java create mode 100644 src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerDetailsEntityPatcher.java create mode 100644 src/main/resources/db/changelog/224-hs-office-partner-details-rbac.sql create mode 100644 src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerDetailsEntityPatcherUnitTest.java create mode 100644 src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerDetailsEntityTest.java diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepository.java b/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepository.java index 686f42ca..27cb6f92 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepository.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepository.java @@ -23,7 +23,7 @@ public interface HsOfficeDebitorRepository extends Repository new NoSuchElementException("cannot find person uuid " + body.getPersonUuid()) )); + entityToSave.setDetails(map(body.getDetails(), HsOfficePartnerDetailsEntity.class)); + entityToSave.getDetails().setUuid(UUID.randomUUID()); final var saved = partnerRepo.save(entityToSave); @@ -129,14 +131,13 @@ public class HsOfficePartnerController implements HsOfficePartnersApi { final var current = partnerRepo.findByUuid(partnerUuid).orElseThrow(); - new HsOfficePartnerEntityPatcher(em, current, contactRepo::findByUuid, personRepo::findByUuid).apply(body); + new HsOfficePartnerEntityPatcher(em, current).apply(body); final var saved = partnerRepo.save(current); final var mapped = map(saved, HsOfficePartnerResource.class); return ResponseEntity.ok(mapped); } - final BiConsumer PARTNER_ENTITY_TO_RESOURCE_POSTMAPPER = (entity, resource) -> { resource.setPerson(map(entity.getPerson(), HsOfficePersonResource.class)); resource.setContact(map(entity.getContact(), HsOfficeContactResource.class)); @@ -145,11 +146,11 @@ public class HsOfficePartnerController implements HsOfficePartnersApi { // TODO.impl: user postmapper + getReference private HsOfficePartnerEntity mapToHsOfficePartnerEntity(final HsOfficePartnerInsertResource resource) { final var entity = new HsOfficePartnerEntity(); - entity.setBirthday(resource.getBirthday()); - entity.setBirthName(resource.getBirthName()); - entity.setDateOfDeath(resource.getDateOfDeath()); - entity.setRegistrationNumber(resource.getRegistrationNumber()); - entity.setRegistrationOffice(resource.getRegistrationOffice()); + // entity.setBirthday(resource.getBirthday()); + // entity.setBirthName(resource.getBirthName()); + // entity.setDateOfDeath(resource.getDateOfDeath()); + // entity.setRegistrationNumber(resource.getRegistrationNumber()); + // entity.setRegistrationOffice(resource.getRegistrationOffice()); return entity; } } diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerDetailsEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerDetailsEntity.java new file mode 100644 index 00000000..e802655b --- /dev/null +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerDetailsEntity.java @@ -0,0 +1,58 @@ +package net.hostsharing.hsadminng.hs.office.partner; + +import lombok.*; +import net.hostsharing.hsadminng.Stringify; +import net.hostsharing.hsadminng.Stringifyable; +import net.hostsharing.hsadminng.errors.DisplayName; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.time.LocalDate; +import java.util.UUID; + +import static net.hostsharing.hsadminng.Stringify.stringify; + +@Entity +@Table(name = "hs_office_partner_details_rv") +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@DisplayName("PartnerDetails") +public class HsOfficePartnerDetailsEntity implements Stringifyable { + + private static Stringify stringify = stringify( + HsOfficePartnerDetailsEntity.class, + "partnerDetails") + .withProp(HsOfficePartnerDetailsEntity::getRegistrationOffice) + .withProp(HsOfficePartnerDetailsEntity::getRegistrationNumber) + .withProp(HsOfficePartnerDetailsEntity::getBirthday) + .withProp(HsOfficePartnerDetailsEntity::getBirthday) + .withProp(HsOfficePartnerDetailsEntity::getDateOfDeath) + .withSeparator(", ") + .quotedValues(false); + + private @Id UUID uuid; + + private @Column(name = "registrationoffice") String registrationOffice; + private @Column(name = "registrationnumber") String registrationNumber; + private @Column(name = "birthname") String birthName; + private @Column(name = "birthday") LocalDate birthday; + private @Column(name = "dateofdeath") LocalDate dateOfDeath; + + @Override + public String toString() { + return stringify.apply(this); + } + + @Override + public String toShortString() { + return registrationNumber != null ? registrationNumber + : birthName != null ? birthName + : birthday != null ? birthday.toString() + : dateOfDeath != null ? dateOfDeath.toString() : ""; + } +} diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerDetailsEntityPatcher.java b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerDetailsEntityPatcher.java new file mode 100644 index 00000000..05fffa85 --- /dev/null +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerDetailsEntityPatcher.java @@ -0,0 +1,32 @@ +package net.hostsharing.hsadminng.hs.office.partner; + +import net.hostsharing.hsadminng.EntityPatcher; +import net.hostsharing.hsadminng.OptionalFromJson; +import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePartnerDetailsPatchResource; + +import javax.persistence.EntityManager; +import java.util.UUID; + +class HsOfficePartnerDetailsEntityPatcher implements EntityPatcher { + + private final EntityManager em; + private final HsOfficePartnerDetailsEntity entity; + + HsOfficePartnerDetailsEntityPatcher( + final EntityManager em, + final HsOfficePartnerDetailsEntity entity) { + this.em = em; + this.entity = entity; + } + + @Override + public void apply(final HsOfficePartnerDetailsPatchResource resource) { + if (resource != null) { + OptionalFromJson.of(resource.getRegistrationOffice()).ifPresent(entity::setRegistrationOffice); + OptionalFromJson.of(resource.getRegistrationNumber()).ifPresent(entity::setRegistrationNumber); + OptionalFromJson.of(resource.getBirthday()).ifPresent(entity::setBirthday); + OptionalFromJson.of(resource.getBirthName()).ifPresent(entity::setBirthName); + OptionalFromJson.of(resource.getDateOfDeath()).ifPresent(entity::setDateOfDeath); + } + } +} diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntity.java index f29ab270..11e8bab1 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntity.java @@ -6,6 +6,8 @@ import net.hostsharing.hsadminng.Stringify; import net.hostsharing.hsadminng.Stringifyable; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity; +import org.hibernate.annotations.NotFound; +import org.hibernate.annotations.NotFoundAction; import javax.persistence.*; import java.time.LocalDate; @@ -32,18 +34,17 @@ public class HsOfficePartnerEntity implements Stringifyable { private @Id UUID uuid; @ManyToOne - @JoinColumn(name = "personuuid") + @JoinColumn(name = "personuuid", nullable = false) private HsOfficePersonEntity person; @ManyToOne - @JoinColumn(name = "contactuuid") + @JoinColumn(name = "contactuuid", nullable = false) private HsOfficeContactEntity contact; - private @Column(name = "registrationoffice") String registrationOffice; - private @Column(name = "registrationnumber") String registrationNumber; - private @Column(name = "birthname") String birthName; - private @Column(name = "birthday") LocalDate birthday; - private @Column(name = "dateofdeath") LocalDate dateOfDeath; + @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DETACH}, optional = true) + @JoinColumn(name = "detailsuuid", nullable = true) + @NotFound(action= NotFoundAction.IGNORE) + private HsOfficePartnerDetailsEntity details; @Override public String toString() { diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatcher.java b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatcher.java index 2695d884..08550246 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatcher.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatcher.java @@ -17,18 +17,11 @@ import java.util.function.Supplier; class HsOfficePartnerEntityPatcher implements EntityPatcher { private final EntityManager em; private final HsOfficePartnerEntity entity; - private final Function> fetchContact; - private final Function> fetchPerson; - HsOfficePartnerEntityPatcher( final EntityManager em, - final HsOfficePartnerEntity entity, - final Function> fetchContact, - final Function> fetchPerson) { + final HsOfficePartnerEntity entity) { this.em = em; this.entity = entity; - this.fetchContact = fetchContact; - this.fetchPerson = fetchPerson; } @Override @@ -41,11 +34,8 @@ class HsOfficePartnerEntityPatcher implements EntityPatcher role:hsOfficePerson.guest[person.guest] end +subgraph hsOfficePartnerDetails + direction TB + + perm:hsOfficePartnerDetails.*{{partner.*}} + perm:hsOfficePartnerDetails.edit{{partner.edit}} + perm:hsOfficePartnerDetails.view{{partner.view}} +end + subgraph hsOfficePartner role:hsOfficePartner.owner[partner.owner] %% permissions role:hsOfficePartner.owner --> perm:hsOfficePartner.*{{partner.*}} + role:hsOfficePartner.owner --> perm:hsOfficePartnerDetails.*{{partner.*}} %% incoming role:global.admin ---> role:hsOfficePartner.owner role:hsOfficePartner.admin[partner.admin] %% permissions role:hsOfficePartner.admin --> perm:hsOfficePartner.edit{{partner.edit}} + role:hsOfficePartner.admin --> perm:hsOfficePartnerDetails.edit{{partner.edit}} %% incoming role:hsOfficePartner.owner ---> role:hsOfficePartner.admin %% outgoing @@ -45,6 +55,8 @@ subgraph hsOfficePartner role:hsOfficePartner.admin --> role:hsOfficeContact.tenant role:hsOfficePartner.agent[partner.agent] + %% permissions + role:hsOfficePartner.agent --> perm:hsOfficePartnerDetails.view{{partner.view}} %% incoming role:hsOfficePartner.admin ---> role:hsOfficePartner.agent role:hsOfficePerson.admin --> role:hsOfficePartner.agent diff --git a/src/main/resources/db/changelog/223-hs-office-partner-rbac.sql b/src/main/resources/db/changelog/223-hs-office-partner-rbac.sql index 3369624e..83a99573 100644 --- a/src/main/resources/db/changelog/223-hs-office-partner-rbac.sql +++ b/src/main/resources/db/changelog/223-hs-office-partner-rbac.sql @@ -39,6 +39,8 @@ begin if TG_OP = 'INSERT' then + -- === ATTENTION: code generated from related Mermaid flowchart: === + perform createRoleWithGrants( hsOfficePartnerOwner(NEW), permissions => array['*'], @@ -72,14 +74,40 @@ begin hsOfficeContactGuest(newContact)] ); - perform createRoleWithGrants( hsOfficePartnerGuest(NEW), permissions => array['view'], - incomingSuperRoles => array[ - hsOfficePartnerTenant(NEW)] + incomingSuperRoles => array[hsOfficePartnerTenant(NEW)] ); + -- === END of code generated from Mermaid flowchart. === + + -- Each partner-details entity belong exactly to one partner entity + -- and it makes little sense just to delegate partner-details roles. + -- Therefore, we did not model partner-details roles, + -- but instead just assign extra permissions to existing partner-roles. + + --Attention: Cannot be in partner-details because of insert order (partner is not in database yet) + + call grantPermissionsToRole( + getRoleId(hsOfficePartnerOwner(NEW), 'fail'), + createPermissions(NEW.detailsUuid, array ['*']) + ); + + call grantPermissionsToRole( + getRoleId(hsOfficePartnerAdmin(NEW), 'fail'), + createPermissions(NEW.detailsUuid, array ['edit']) + ); + + call grantPermissionsToRole( + -- Yes, here hsOfficePartnerAGENT is used, not hsOfficePartnerTENANT. + -- Do NOT grant view permission on partner-details to hsOfficePartnerTENANT! + -- Otherwise package-admins etc. would be able to read the data. + getRoleId(hsOfficePartnerAgent(NEW), 'fail'), + createPermissions(NEW.detailsUuid, array ['view']) + ); + + elsif TG_OP = 'UPDATE' then if OLD.personUuid <> NEW.personUuid then @@ -87,10 +115,10 @@ begin call revokeRoleFromRole(hsOfficePersonTenant(oldPerson), hsOfficePartnerAdmin(OLD)); call grantRoleToRole(hsOfficePersonTenant(newPerson), hsOfficePartnerAdmin(NEW)); - + call revokeRoleFromRole(hsOfficePartnerAgent(OLD), hsOfficePersonAdmin(oldPerson)); call grantRoleToRole(hsOfficePartnerAgent(NEW), hsOfficePersonAdmin(newPerson)); - + call revokeRoleFromRole(hsOfficePersonGuest(oldPerson), hsOfficePartnerTenant(OLD)); call grantRoleToRole(hsOfficePersonGuest(newPerson), hsOfficePartnerTenant(NEW)); end if; @@ -152,12 +180,7 @@ call generateRbacRestrictedView('hs_office_partner', '(select idName from hs_office_person_iv p where p.uuid = target.personUuid)', $updates$ personUuid = new.personUuid, - contactUuid = new.contactUuid, - registrationOffice = new.registrationOffice, - registrationNumber = new.registrationNumber, - birthday = new.birthday, - birthName = new.birthName, - dateOfDeath = new.dateOfDeath + contactUuid = new.contactUuid $updates$); --// diff --git a/src/main/resources/db/changelog/224-hs-office-partner-details-rbac.sql b/src/main/resources/db/changelog/224-hs-office-partner-details-rbac.sql new file mode 100644 index 00000000..97bab5e5 --- /dev/null +++ b/src/main/resources/db/changelog/224-hs-office-partner-details-rbac.sql @@ -0,0 +1,85 @@ +--liquibase formatted sql + +-- ============================================================================ +--changeset hs-office-partner-details-rbac-OBJECT:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRelatedRbacObject('hs_office_partner_details'); +--// + + + + + +-- ============================================================================ +--changeset hs-office-partner-details-rbac-IDENTITY-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRbacIdentityView('hs_office_partner_details', $idName$ + (select idName || '-details' from hs_office_partner_iv partner_iv + join hs_office_partner partner on (partner_iv.uuid = partner.uuid) + where partner.detailsUuid = target.uuid) + $idName$); +--// + + +-- ============================================================================ +--changeset hs-office-partner-details-rbac-RESTRICTED-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRbacRestrictedView('hs_office_partner_details', + 'target.uuid', -- no specific order required + $updates$ + registrationOffice = new.registrationOffice, + registrationNumber = new.registrationNumber, + birthName = new.birthName, + birthday = new.birthday, + dateOfDeath = new.dateOfDeath + $updates$); +--// + + +-- ============================================================================ +--changeset hs-office-partner-details-rbac-NEW-CONTACT:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +/* + Creates a global permission for new-partner-details and assigns it to the hostsharing admins role. + */ +do language plpgsql $$ + declare + addCustomerPermissions uuid[]; + globalObjectUuid uuid; + globalAdminRoleUuid uuid ; + begin + call defineContext('granting global new-partner-details permission to global admin role', null, null, null); + + globalAdminRoleUuid := findRoleId(globalAdmin()); + globalObjectUuid := (select uuid from global); + addCustomerPermissions := createPermissions(globalObjectUuid, array ['new-partner-details']); + call grantPermissionsToRole(globalAdminRoleUuid, addCustomerPermissions); + end; +$$; + +-- TODO.refa: the code below could be moved to a generator, maybe even the code above. +-- Additionally, the code below is not neccesary for all entities, specifiy when it is! + +/** + Used by the trigger to prevent the add-partner-details to current user respectively assumed roles. + */ +create or replace function addHsOfficePartnerDetailsNotAllowedForCurrentSubjects() + returns trigger + language PLPGSQL +as $$ +begin + raise exception '[403] new-partner-details not permitted for %', + array_to_string(currentSubjects(), ';', 'null'); +end; $$; + +/** + Checks if the user or assumed roles are allowed to create new partner-details. + */ +create trigger hs_office_partner_details_insert_trigger + before insert + on hs_office_partner_details + for each row + when ( not hasAssumedRole() ) +execute procedure addHsOfficePartnerDetailsNotAllowedForCurrentSubjects(); +--// + diff --git a/src/main/resources/db/changelog/228-hs-office-partner-test-data.sql b/src/main/resources/db/changelog/228-hs-office-partner-test-data.sql index 45928bfd..648a850d 100644 --- a/src/main/resources/db/changelog/228-hs-office-partner-test-data.sql +++ b/src/main/resources/db/changelog/228-hs-office-partner-test-data.sql @@ -11,11 +11,12 @@ create or replace procedure createHsOfficePartnerTestData( personTradeOrFamilyName varchar, contactLabel varchar ) language plpgsql as $$ declare - currentTask varchar; - idName varchar; - relatedPerson hs_office_person; - relatedContact hs_office_contact; - birthday date; + currentTask varchar; + idName varchar; + relatedPerson hs_office_person; + relatedContact hs_office_contact; + relatedDetailsUuid uuid; + birthday date; begin idName := cleanIdentifier( personTradeOrFamilyName|| '-' || contactLabel); currentTask := 'creating partner test-data ' || idName; @@ -36,34 +37,25 @@ begin raise notice 'creating test partner: %', idName; raise notice '- using person (%): %', relatedPerson.uuid, relatedPerson; raise notice '- using contact (%): %', relatedContact.uuid, relatedContact; + + if relatedPerson.persontype = 'NATURAL' then + insert + into hs_office_partner_details (uuid, birthName, birthday) + values (uuid_generate_v4(), 'Meyer', '1987-10-31') + returning uuid into relatedDetailsUuid; + else + insert + into hs_office_partner_details (uuid, registrationOffice, registrationNumber) + values (uuid_generate_v4(), 'Hamburg', '12345') + returning uuid into relatedDetailsUuid; + end if; + insert - into hs_office_partner (uuid, personuuid, contactuuid, birthday) - values (uuid_generate_v4(), relatedPerson.uuid, relatedContact.uuid, birthDay); + into hs_office_partner (uuid, personuuid, contactuuid, detailsUuid) + values (uuid_generate_v4(), relatedPerson.uuid, relatedContact.uuid, relatedDetailsUuid); end; $$; --// -/* - Creates a range of test partner for mass data generation. - */ -create or replace procedure createHsOfficePartnerTestData( - startCount integer, -- count of auto generated rows before the run - endCount integer -- count of auto generated rows after the run -) - language plpgsql as $$ -declare - person hs_office_person; - contact hs_office_contact; -begin - for t in startCount..endCount - loop - select p.* from hs_office_person p where tradeName = intToVarChar(t, 4) into person; - select c.* from hs_office_contact c where c.label = intToVarChar(t, 4) || '#' || t into contact; - - call createHsOfficePartnerTestData(person.uuid, contact.uuid); - commit; - end loop; -end; $$; ---// -- ============================================================================ diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index c082e609..7905881e 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -65,6 +65,8 @@ databaseChangeLog: file: db/changelog/220-hs-office-partner.sql - include: file: db/changelog/223-hs-office-partner-rbac.sql + - include: + file: db/changelog/224-hs-office-partner-details-rbac.sql - include: file: db/changelog/228-hs-office-partner-test-data.sql - include: diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorEntityTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorEntityTest.java index a65793a2..5be98ecc 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorEntityTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorEntityTest.java @@ -1,6 +1,7 @@ package net.hostsharing.hsadminng.hs.office.debitor; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity; +import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerDetailsEntity; import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity; import org.junit.jupiter.api.Test; @@ -17,7 +18,8 @@ class HsOfficeDebitorEntityTest { .person(HsOfficePersonEntity.builder() .tradeName("some trade name") .build()) - .birthName("some birth name") + .details(HsOfficePartnerDetailsEntity.builder().birthName("some birth name").build()) + .build()) .billingContact(HsOfficeContactEntity.builder().label("some label").build()) .build(); diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepositoryIntegrationTest.java index 598ffc4d..74a99673 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepositoryIntegrationTest.java @@ -66,7 +66,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest { class CreateDebitor { @Test - public void testHostsharingAdmin_withoutAssumedRole_canCreateNewDebitor() { + public void globalAdmin_canCreateNewDebitor() { // given context("superuser-alex@hostsharing.net"); final var count = debitorRepo.count(); @@ -170,7 +170,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest { class FindByOptionalName { @Test - public void globalAdmin_withoutAssumedRole_canViewAllDebitors() { + public void globalAdmin_canViewAllDebitors() { // given context("superuser-alex@hostsharing.net"); @@ -219,7 +219,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest { class FindByDebitorNumberLike { @Test - public void globalAdmin_withoutAssumedRole_canViewAllDebitors() { + public void globalAdmin_canViewAllDebitors() { // given context("superuser-alex@hostsharing.net"); @@ -235,7 +235,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest { class FindByNameLike { @Test - public void globalAdmin_withoutAssumedRole_canViewAllDebitors() { + public void globalAdmin_canViewAllDebitors() { // given context("superuser-alex@hostsharing.net"); @@ -251,7 +251,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest { class UpdateDebitor { @Test - public void hostsharingAdmin_withoutAssumedRole_canUpdateArbitraryDebitor() { + public void globalAdmin_canUpdateArbitraryDebitor() { // given context("superuser-alex@hostsharing.net"); final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "fifth contact"); @@ -336,7 +336,8 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest { private void assertThatDebitorActuallyInDatabase(final HsOfficeDebitorEntity saved) { final var found = debitorRepo.findByUuid(saved.getUuid()); - assertThat(found).isNotEmpty().get().isNotSameAs(saved).usingRecursiveComparison().isEqualTo(saved); + assertThat(found).isNotEmpty().get().isNotSameAs(saved) + .extracting(Object::toString).isEqualTo(saved.toString()); } private void assertThatDebitorIsVisibleForUserWithRole( @@ -363,7 +364,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest { class DeleteByUuid { @Test - public void globalAdmin_withoutAssumedRole_canDeleteAnyDebitor() { + public void globalAdmin_canDeleteAnyDebitor() { // given context("superuser-alex@hostsharing.net", null); final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "tenth"); diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepositoryIntegrationTest.java index 72f5569f..3dea88f7 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepositoryIntegrationTest.java @@ -271,7 +271,8 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTest { private void assertThatMembershipExistsAndIsAccessibleToCurrentContext(final HsOfficeMembershipEntity saved) { final var found = membershipRepo.findByUuid(saved.getUuid()); - assertThat(found).isNotEmpty().get().isNotSameAs(saved).usingRecursiveComparison().isEqualTo(saved); + assertThat(found).isNotEmpty().get().isNotSameAs(saved) + .extracting(Object::toString).isEqualTo(saved.toString()); } private void assertThatMembershipIsVisibleForUserWithRole( diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerControllerAcceptanceTest.java index e0fe31a1..5c408603 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerControllerAcceptanceTest.java @@ -79,23 +79,27 @@ class HsOfficePartnerControllerAcceptanceTest { { "person": { "familyName": "Smith" }, "contact": { "label": "fifth contact" }, - "birthday": "1987-10-31" + "details": { "birthday": "1987-10-31" } }, { "person": { "tradeName": "First GmbH" }, - "contact": { "label": "first contact" } + "contact": { "label": "first contact" }, + "details": { "registrationOffice": "Hamburg" } }, { "person": { "tradeName": "Third OHG" }, - "contact": { "label": "third contact" } + "contact": { "label": "third contact" }, + "details": { "registrationOffice": "Hamburg" } }, { "person": { "tradeName": "Second e.K." }, - "contact": { "label": "second contact" } + "contact": { "label": "second contact" }, + "details": { "registrationOffice": "Hamburg" } }, { "person": { "personType": "SOLE_REPRESENTATION" }, - "contact": { "label": "forth contact" } + "contact": { "label": "forth contact" }, + "details": { "registrationOffice": "Hamburg" } } ] """)); @@ -122,8 +126,10 @@ class HsOfficePartnerControllerAcceptanceTest { { "contactUuid": "%s", "personUuid": "%s", - "registrationOffice": "Registergericht Hamburg", - "registrationNumber": "123456" + "details": { + "registrationOffice": "Registergericht Aurich", + "registrationNumber": "123456" + } } """.formatted(givenContact.getUuid(), givenPerson.getUuid())) .port(port) @@ -133,7 +139,8 @@ class HsOfficePartnerControllerAcceptanceTest { .statusCode(201) .contentType(ContentType.JSON) .body("uuid", isUuidValid()) - .body("registrationNumber", is("123456")) + .body("details.registrationOffice", is("Registergericht Aurich")) + .body("details.registrationNumber", is("123456")) .body("contact.label", is(givenContact.getLabel())) .body("person.tradeName", is(givenPerson.getTradeName())) .header("Location", startsWith("http://localhost")) @@ -289,11 +296,13 @@ class HsOfficePartnerControllerAcceptanceTest { { "contactUuid": "%s", "personUuid": "%s", - "registrationOffice": "Registergericht Hamburg", - "registrationNumber": "222222", - "birthName": "Maja Schmidt", - "birthday": "1938-04-08", - "dateOfDeath": "2022-01-12" + "details": { + "registrationOffice": "Registergericht Hamburg", + "registrationNumber": "222222", + "birthName": "Maja Schmidt", + "birthday": "1938-04-08", + "dateOfDeath": "2022-01-12" + } } """.formatted(givenContact.getUuid(), givenPerson.getUuid())) .port(port) @@ -303,7 +312,7 @@ class HsOfficePartnerControllerAcceptanceTest { .statusCode(200) .contentType(ContentType.JSON) .body("uuid", isUuidValid()) - .body("registrationNumber", is("222222")) + .body("details.registrationNumber", is("222222")) .body("contact.label", is(givenContact.getLabel())) .body("person.tradeName", is(givenPerson.getTradeName())); // @formatter:on @@ -314,11 +323,11 @@ class HsOfficePartnerControllerAcceptanceTest { .matches(person -> { assertThat(person.getPerson().getTradeName()).isEqualTo("Third OHG"); assertThat(person.getContact().getLabel()).isEqualTo("forth contact"); - assertThat(person.getRegistrationOffice()).isEqualTo("Registergericht Hamburg"); - assertThat(person.getRegistrationNumber()).isEqualTo("222222"); - assertThat(person.getBirthName()).isEqualTo("Maja Schmidt"); - assertThat(person.getBirthday()).isEqualTo("1938-04-08"); - assertThat(person.getDateOfDeath()).isEqualTo("2022-01-12"); + assertThat(person.getDetails().getRegistrationOffice()).isEqualTo("Registergericht Hamburg"); + assertThat(person.getDetails().getRegistrationNumber()).isEqualTo("222222"); + assertThat(person.getDetails().getBirthName()).isEqualTo("Maja Schmidt"); + assertThat(person.getDetails().getBirthday()).isEqualTo("1938-04-08"); + assertThat(person.getDetails().getDateOfDeath()).isEqualTo("2022-01-12"); return true; }); } @@ -335,9 +344,11 @@ class HsOfficePartnerControllerAcceptanceTest { .contentType(ContentType.JSON) .body(""" { - "birthName": "Maja Schmidt", - "birthday": "1938-04-08", - "dateOfDeath": "2022-01-12" + "details": { + "birthName": "Maja Schmidt", + "birthday": "1938-04-08", + "dateOfDeath": "2022-01-12" + } } """) .port(port) @@ -347,7 +358,7 @@ class HsOfficePartnerControllerAcceptanceTest { .statusCode(200) .contentType(ContentType.JSON) .body("uuid", isUuidValid()) - .body("birthName", is("Maja Schmidt")) + .body("details.birthName", is("Maja Schmidt")) .body("contact.label", is(givenPartner.getContact().getLabel())) .body("person.tradeName", is(givenPartner.getPerson().getTradeName())); // @formatter:on @@ -357,11 +368,11 @@ class HsOfficePartnerControllerAcceptanceTest { .matches(person -> { assertThat(person.getPerson().getTradeName()).isEqualTo(givenPartner.getPerson().getTradeName()); assertThat(person.getContact().getLabel()).isEqualTo(givenPartner.getContact().getLabel()); - assertThat(person.getRegistrationOffice()).isEqualTo(null); - assertThat(person.getRegistrationNumber()).isEqualTo(null); - assertThat(person.getBirthName()).isEqualTo("Maja Schmidt"); - assertThat(person.getBirthday()).isEqualTo("1938-04-08"); - assertThat(person.getDateOfDeath()).isEqualTo("2022-01-12"); + assertThat(person.getDetails().getRegistrationOffice()).isEqualTo(null); + assertThat(person.getDetails().getRegistrationNumber()).isEqualTo(null); + assertThat(person.getDetails().getBirthName()).isEqualTo("Maja Schmidt"); + assertThat(person.getDetails().getBirthday()).isEqualTo("1938-04-08"); + assertThat(person.getDetails().getDateOfDeath()).isEqualTo("2022-01-12"); return true; }); } @@ -440,6 +451,9 @@ class HsOfficePartnerControllerAcceptanceTest { .uuid(UUID.randomUUID()) .person(givenPerson) .contact(givenContact) + .details(HsOfficePartnerDetailsEntity.builder() + .uuid((UUID.randomUUID())) + .build()) .build(); toCleanup(newPartner.getUuid()); diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerDetailsEntityPatcherUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerDetailsEntityPatcherUnitTest.java new file mode 100644 index 00000000..3b3811e5 --- /dev/null +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerDetailsEntityPatcherUnitTest.java @@ -0,0 +1,93 @@ +package net.hostsharing.hsadminng.hs.office.partner; + +import net.hostsharing.hsadminng.PatchUnitTestBase; +import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity; +import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePartnerDetailsPatchResource; +import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import javax.persistence.EntityManager; +import java.time.LocalDate; +import java.util.UUID; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.lenient; + +@TestInstance(PER_CLASS) +@ExtendWith(MockitoExtension.class) +class HsOfficePartnerDetailsEntityPatcherUnitTest extends PatchUnitTestBase< + HsOfficePartnerDetailsPatchResource, + HsOfficePartnerDetailsEntity + > { + + private static final UUID INITIAL_PARTNER_UUID = UUID.randomUUID(); + private static final UUID INITIAL_CONTACT_UUID = UUID.randomUUID(); + private static final UUID INITIAL_PERSON_UUID = UUID.randomUUID(); + + private static final LocalDate INITIAL_BIRTHDAY = LocalDate.parse("1900-01-01"); + private static final LocalDate PATCHED_BIRTHDAY = LocalDate.parse("1990-12-31"); + + private static final LocalDate INITIAL_DAY_OF_DEATH = LocalDate.parse("2000-01-01"); + private static final LocalDate PATCHED_DATE_OF_DEATH = LocalDate.parse("2022-08-31"); + + @Mock + private EntityManager em; + + @BeforeEach + void initMocks() { + lenient().when(em.getReference(eq(HsOfficeContactEntity.class), any())).thenAnswer(invocation -> + HsOfficeContactEntity.builder().uuid(invocation.getArgument(1)).build()); + lenient().when(em.getReference(eq(HsOfficePersonEntity.class), any())).thenAnswer(invocation -> + HsOfficePersonEntity.builder().uuid(invocation.getArgument(1)).build()); + } + + @Override + protected HsOfficePartnerDetailsEntity newInitialEntity() { + final var entity = new HsOfficePartnerDetailsEntity(); + entity.setUuid(INITIAL_PARTNER_UUID); + entity.setRegistrationOffice("initial Reg-Office"); + entity.setRegistrationNumber("initial Reg-Number"); + entity.setBirthday(INITIAL_BIRTHDAY); + entity.setBirthName("initial birth name"); + entity.setDateOfDeath(INITIAL_DAY_OF_DEATH); + return entity; + } + + @Override + protected HsOfficePartnerDetailsPatchResource newPatchResource() { + return new HsOfficePartnerDetailsPatchResource(); + } + + @Override + protected HsOfficePartnerDetailsEntityPatcher createPatcher(final HsOfficePartnerDetailsEntity details) { + return new HsOfficePartnerDetailsEntityPatcher(em, details); + } + + @Override + protected Stream propertyTestDescriptors() { + return Stream.of( + new JsonNullableProperty<>( + "registrationOffice", + HsOfficePartnerDetailsPatchResource::setRegistrationOffice, + "patched Reg-Office", + HsOfficePartnerDetailsEntity::setRegistrationOffice), + new JsonNullableProperty<>( + "birthday", + HsOfficePartnerDetailsPatchResource::setBirthday, + PATCHED_BIRTHDAY, + HsOfficePartnerDetailsEntity::setBirthday), + new JsonNullableProperty<>( + "dayOfDeath", + HsOfficePartnerDetailsPatchResource::setDateOfDeath, + PATCHED_DATE_OF_DEATH, + HsOfficePartnerDetailsEntity::setDateOfDeath) + ); + } +} diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerDetailsEntityTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerDetailsEntityTest.java new file mode 100644 index 00000000..cccc39d3 --- /dev/null +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerDetailsEntityTest.java @@ -0,0 +1,51 @@ +package net.hostsharing.hsadminng.hs.office.partner; + +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; + +import static org.assertj.core.api.Assertions.assertThat; + +class HsOfficePartnerDetailsEntityTest { + + final HsOfficePartnerDetailsEntity given = HsOfficePartnerDetailsEntity.builder() + .registrationOffice("Hamburg") + .registrationNumber("12345") + .birthday(LocalDate.parse("2002-01-15")) + .birthName("Melly Miller") + .dateOfDeath(LocalDate.parse("2081-12-21")) + .build(); + + @Test + void toStringContainsAllProperties() { + + final var result = given.toString(); + + assertThat(result).isEqualTo("partnerDetails(Hamburg, 12345, 2002-01-15, 2002-01-15, 2081-12-21)"); + } + + @Test + void toShortStringContainsFirstNonNullValue() { + + assertThat(given.toShortString()).isEqualTo("12345"); + + assertThat(HsOfficePartnerDetailsEntity.builder() + .birthName("Melly Miller") + .birthday(LocalDate.parse("2002-01-15")) + .dateOfDeath(LocalDate.parse("2081-12-21")) + .build().toShortString()).isEqualTo("Melly Miller"); + + assertThat(HsOfficePartnerDetailsEntity.builder() + .birthday(LocalDate.parse("2002-01-15")) + .dateOfDeath(LocalDate.parse("2081-12-21")) + .build().toShortString()).isEqualTo("2002-01-15"); + + assertThat(HsOfficePartnerDetailsEntity.builder() + .dateOfDeath(LocalDate.parse("2081-12-21")) + .build().toShortString()).isEqualTo("2081-12-21"); + + + assertThat(HsOfficePartnerDetailsEntity.builder() + .build().toShortString()).isEqualTo(""); + } +} diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatcherUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatcherUnitTest.java index 46f51001..a7b11bd1 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatcherUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatcherUnitTest.java @@ -1,9 +1,9 @@ package net.hostsharing.hsadminng.hs.office.partner; +import net.hostsharing.hsadminng.PatchUnitTestBase; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePartnerPatchResource; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity; -import net.hostsharing.hsadminng.PatchUnitTestBase; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.extension.ExtendWith; @@ -11,14 +11,12 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import javax.persistence.EntityManager; -import java.time.LocalDate; -import java.util.Optional; import java.util.UUID; import java.util.stream.Stream; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; -import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; import static org.mockito.Mockito.lenient; @TestInstance(PER_CLASS) @@ -31,28 +29,27 @@ class HsOfficePartnerEntityPatcherUnitTest extends PatchUnitTestBase< private static final UUID INITIAL_PARTNER_UUID = UUID.randomUUID(); private static final UUID INITIAL_CONTACT_UUID = UUID.randomUUID(); private static final UUID INITIAL_PERSON_UUID = UUID.randomUUID(); + private static final UUID INITIAL_DETAILS_UUID = UUID.randomUUID(); private static final UUID PATCHED_CONTACT_UUID = UUID.randomUUID(); private static final UUID PATCHED_PERSON_UUID = UUID.randomUUID(); - private static final LocalDate INITIAL_BIRTHDAY = LocalDate.parse("1900-01-01"); - private static final LocalDate PATCHED_BIRTHDAY = LocalDate.parse("1990-12-31"); - - private static final LocalDate INITIAL_DAY_OF_DEATH = LocalDate.parse("2000-01-01"); - private static final LocalDate PATCHED_DATE_OF_DEATH = LocalDate.parse("2022-08-31"); - private final HsOfficePersonEntity givenInitialPerson = HsOfficePersonEntity.builder() .uuid(INITIAL_PERSON_UUID) .build(); private final HsOfficeContactEntity givenInitialContact = HsOfficeContactEntity.builder() .uuid(INITIAL_CONTACT_UUID) .build(); + + private final HsOfficePartnerDetailsEntity givenInitialDetails = HsOfficePartnerDetailsEntity.builder() + .uuid(INITIAL_DETAILS_UUID) + .build(); @Mock private EntityManager em; @BeforeEach void initMocks() { lenient().when(em.getReference(eq(HsOfficeContactEntity.class), any())).thenAnswer(invocation -> - HsOfficeContactEntity.builder().uuid(invocation.getArgument(1)).build()); + HsOfficeContactEntity.builder().uuid(invocation.getArgument(1)).build()); lenient().when(em.getReference(eq(HsOfficePersonEntity.class), any())).thenAnswer(invocation -> HsOfficePersonEntity.builder().uuid(invocation.getArgument(1)).build()); } @@ -63,11 +60,7 @@ class HsOfficePartnerEntityPatcherUnitTest extends PatchUnitTestBase< entity.setUuid(INITIAL_PARTNER_UUID); entity.setPerson(givenInitialPerson); entity.setContact(givenInitialContact); - entity.setRegistrationOffice("initial Reg-Office"); - entity.setRegistrationNumber("initial Reg-Number"); - entity.setBirthday(INITIAL_BIRTHDAY); - entity.setBirthName("initial birth name"); - entity.setDateOfDeath(INITIAL_DAY_OF_DEATH); + entity.setDetails(givenInitialDetails); return entity; } @@ -78,15 +71,7 @@ class HsOfficePartnerEntityPatcherUnitTest extends PatchUnitTestBase< @Override protected HsOfficePartnerEntityPatcher createPatcher(final HsOfficePartnerEntity partner) { - return new HsOfficePartnerEntityPatcher( - em, - partner, - uuid -> uuid == PATCHED_CONTACT_UUID - ? Optional.of(newContact(uuid)) - : Optional.empty(), - uuid -> uuid == PATCHED_PERSON_UUID - ? Optional.of(newPerson(uuid)) - : Optional.empty()); + return new HsOfficePartnerEntityPatcher(em, partner); } @Override @@ -105,22 +90,7 @@ class HsOfficePartnerEntityPatcherUnitTest extends PatchUnitTestBase< PATCHED_PERSON_UUID, HsOfficePartnerEntity::setPerson, newPerson(PATCHED_PERSON_UUID)) - .notNullable(), - new JsonNullableProperty<>( - "registrationOffice", - HsOfficePartnerPatchResource::setRegistrationOffice, - "patched Reg-Office", - HsOfficePartnerEntity::setRegistrationOffice), - new JsonNullableProperty<>( - "birthday", - HsOfficePartnerPatchResource::setBirthday, - PATCHED_BIRTHDAY, - HsOfficePartnerEntity::setBirthday), - new JsonNullableProperty<>( - "dayOfDeath", - HsOfficePartnerPatchResource::setDateOfDeath, - PATCHED_DATE_OF_DEATH, - HsOfficePartnerEntity::setDateOfDeath) + .notNullable() ); } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java index 3dce4b26..603540a4 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java @@ -20,7 +20,6 @@ import org.springframework.test.annotation.DirtiesContext; import javax.persistence.EntityManager; import javax.servlet.http.HttpServletRequest; -import java.time.LocalDate; import java.util.*; import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.grantDisplaysOf; @@ -77,6 +76,9 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest { .uuid(UUID.randomUUID()) .person(givenPerson) .contact(givenContact) + .details(HsOfficePartnerDetailsEntity.builder() + .uuid(UUID.randomUUID()) + .build()) .build()); return partnerRepo.save(newPartner); }); @@ -107,6 +109,7 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest { .uuid(UUID.randomUUID()) .person(givenPerson) .contact(givenContact) + .details(HsOfficePartnerDetailsEntity.builder().uuid(UUID.randomUUID()).build()) .build()); return partnerRepo.save(newPartner); }); @@ -126,28 +129,32 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest { .containsExactlyInAnyOrder(Array.fromFormatted( initialGrantNames, // owner - "{ grant perm * on partner#EBess-4th to role partner#EBess-4th.owner by system and assume }", - "{ grant role partner#EBess-4th.owner to role global#global.admin by system and assume }", + "{ grant perm * on partner#EBess-4th to role partner#EBess-4th.owner by system and assume }", + "{ grant perm * on partner_details#EBess-4th-details to role partner#EBess-4th.owner by system and assume }", + "{ grant role partner#EBess-4th.owner to role global#global.admin by system and assume }", // admin - "{ grant perm edit on partner#EBess-4th to role partner#EBess-4th.admin by system and assume }", - "{ grant role partner#EBess-4th.admin to role partner#EBess-4th.owner by system and assume }", - "{ grant role person#EBess.tenant to role partner#EBess-4th.admin by system and assume }", - "{ grant role contact#4th.tenant to role partner#EBess-4th.admin by system and assume }", + "{ grant perm edit on partner#EBess-4th to role partner#EBess-4th.admin by system and assume }", + "{ grant perm edit on partner_details#EBess-4th-details to role partner#EBess-4th.admin by system and assume }", + "{ grant role partner#EBess-4th.admin to role partner#EBess-4th.owner by system and assume }", + "{ grant role person#EBess.tenant to role partner#EBess-4th.admin by system and assume }", + "{ grant role contact#4th.tenant to role partner#EBess-4th.admin by system and assume }", // agent - "{ grant role partner#EBess-4th.agent to role partner#EBess-4th.admin by system and assume }", - "{ grant role partner#EBess-4th.agent to role person#EBess.admin by system and assume }", - "{ grant role partner#EBess-4th.agent to role contact#4th.admin by system and assume }", + "{ grant perm view on partner_details#EBess-4th-details to role partner#EBess-4th.agent by system and assume }", + "{ grant role partner#EBess-4th.agent to role partner#EBess-4th.admin by system and assume }", + "{ grant role partner#EBess-4th.agent to role person#EBess.admin by system and assume }", + "{ grant role partner#EBess-4th.agent to role contact#4th.admin by system and assume }", // tenant - "{ grant role partner#EBess-4th.tenant to role partner#EBess-4th.agent by system and assume }", - "{ grant role person#EBess.guest to role partner#EBess-4th.tenant by system and assume }", - "{ grant role contact#4th.guest to role partner#EBess-4th.tenant by system and assume }", + "{ grant role partner#EBess-4th.tenant to role partner#EBess-4th.agent by system and assume }", + "{ grant role person#EBess.guest to role partner#EBess-4th.tenant by system and assume }", + "{ grant role contact#4th.guest to role partner#EBess-4th.tenant by system and assume }", // guest - "{ grant perm view on partner#EBess-4th to role partner#EBess-4th.guest by system and assume }", - "{ grant role partner#EBess-4th.guest to role partner#EBess-4th.tenant by system and assume }", + "{ grant perm view on partner#EBess-4th to role partner#EBess-4th.guest by system and assume }", + "{ grant role partner#EBess-4th.guest to role partner#EBess-4th.tenant by system and assume }", + null)); } @@ -226,7 +233,6 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest { context("superuser-alex@hostsharing.net"); givenPartner.setContact(givenNewContact); givenPartner.setPerson(givenNewPerson); - givenPartner.setDateOfDeath(LocalDate.parse("2022-09-15")); return toCleanup(partnerRepo.save(givenPartner)); }); @@ -246,47 +252,26 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest { } @Test - public void personAdmin_canNotUpdateRelatedPartner() { - // given - context("superuser-alex@hostsharing.net"); - final var givenPartner = givenSomeTemporaryPartnerBessler("eighth"); - assertThatPartnerIsVisibleForUserWithRole( - givenPartner, - "hs_office_person#ErbenBesslerMelBessler.admin"); - assertThatPartnerActuallyInDatabase(givenPartner); - - // when - final var result = jpaAttempt.transacted(() -> { - context("superuser-alex@hostsharing.net", "hs_office_person#ErbenBesslerMelBessler.admin"); - givenPartner.setDateOfDeath(LocalDate.parse("2022-09-15")); - return partnerRepo.save(givenPartner); - }); - - // then - result.assertExceptionWithRootCauseMessage(JpaSystemException.class, - "[403] Subject ", " is not allowed to update hs_office_partner uuid"); - } - - @Test - public void contactAdmin_canNotUpdateRelatedPartner() { + public void partnerAgent_canNotUpdateRelatedPartner() { // given context("superuser-alex@hostsharing.net"); final var givenPartner = givenSomeTemporaryPartnerBessler("ninth"); assertThatPartnerIsVisibleForUserWithRole( givenPartner, - "hs_office_contact#ninthcontact.admin"); + "hs_office_partner#ErbenBesslerMelBessler-ninthcontact.agent"); assertThatPartnerActuallyInDatabase(givenPartner); + final var givenNewContact = contactRepo.findContactByOptionalLabelLike("tenth").get(0); // when final var result = jpaAttempt.transacted(() -> { - context("superuser-alex@hostsharing.net", "hs_office_contact#ninthcontact.admin"); - givenPartner.setDateOfDeath(LocalDate.parse("2022-09-15")); + context("superuser-alex@hostsharing.net", "hs_office_partner#ErbenBesslerMelBessler-ninthcontact.agent"); + givenPartner.getDetails().setBirthName("new birthname"); return partnerRepo.save(givenPartner); }); // then result.assertExceptionWithRootCauseMessage(JpaSystemException.class, - "[403] Subject ", " is not allowed to update hs_office_partner uuid"); + "[403] Subject ", " is not allowed to update hs_office_partner_details uuid"); } private void assertThatPartnerActuallyInDatabase(final HsOfficePartnerEntity saved) { @@ -424,6 +409,9 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest { .uuid(UUID.randomUUID()) .person(givenPerson) .contact(givenContact) + .details(HsOfficePartnerDetailsEntity.builder() + .uuid(UUID.randomUUID()) + .build()) .build(); toCleanup(newPartner); diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepositoryIntegrationTest.java index 39f06512..e4f83d8b 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepositoryIntegrationTest.java @@ -290,7 +290,8 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTest { private void assertThatSepaMandateActuallyInDatabase(final HsOfficeSepaMandateEntity saved) { final var found = sepaMandateRepo.findByUuid(saved.getUuid()); - assertThat(found).isNotEmpty().get().isNotSameAs(saved).usingRecursiveComparison().isEqualTo(saved); + assertThat(found).isNotEmpty().get().isNotSameAs(saved) + .extracting(Object::toString).isEqualTo(saved.toString()); } private void assertThatSepaMandateIsVisibleForUserWithRole(