From 839703ca48a705649452b61f3c881a0fdf3d62bf Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Tue, 4 Mar 2025 12:20:40 +0100 Subject: [PATCH] relation with updatable holder+anchor and test --- ...-02-27-exchanging-the-partner-person.de.md | 30 ++++++++-------- .../partner/HsOfficePartnerController.java | 7 +--- .../relation/HsOfficeRelationRbacEntity.java | 2 +- .../5033-hs-office-relation-rbac.sql | 14 -------- ...ficeRelationRepositoryIntegrationTest.java | 34 +++++++++++++++++++ 5 files changed, 51 insertions(+), 36 deletions(-) diff --git a/doc/adr/2025-02-27-exchanging-the-partner-person.de.md b/doc/adr/2025-02-27-exchanging-the-partner-person.de.md index e56aa28d..3367cbf2 100644 --- a/doc/adr/2025-02-27-exchanging-the-partner-person.de.md +++ b/doc/adr/2025-02-27-exchanging-the-partner-person.de.md @@ -105,20 +105,20 @@ Nennenswerte Nachteile wurden nicht identifiziert, allenfalls ist es etwas schr - der Aufwand ist relativ gering (vieles ist mit SQL UPDATEs machbar) - die UPDATE Permission dürfte an Relation-AGENT granted werden, ohne damit Schindluder getrieben werden kann (weil das an der API verhindert werden kann) -| Kriterium \ Relations ... | 1. ersetzen | 2. direkt aktualisieren | 3. via Partner aktualisieren | -|----------------------------------------------|------------:|------------------------:|-----------------------------:| -| **Technische und Aufwands-Kriterien** | | | | +| Kriterium \ Relations ... | 1. ersetzen | 2. direkt aktualisieren | 3. via Partner aktualisieren | +|-----------------------------------------------|------------:|------------------------:|-----------------------------:| +| **Technische und Aufwands-Kriterien** | | | | | Beibehaltung der API vs. Umbau (inkl. Risiko) | +2 | -2 | +1 | | Anwendbarkeit auf Partner- und Debitor-Person | | +1 | | -| Anwendbarkeit auf abhängige Relations | -3 | | | -| Performance bei vielen abhängigen Relations | -1 | | | -| Aufwand für explizite Grants | -1 | | | -| **Zwischenergebnis** | **-3** | **-1** | **+1** | -| | | | | -| **Fachliche Kriterien** | | | | -| Kongruenz von Fachlichkeit+API | +1 | -1 | +1 | -| Einheitlichkeit/Generizität der API | | +1 | | -| UPDATE Permission für Relation-AGENT möglich | +1 | | +1 | -| **Zwischenergebnis** | **+2** | **0** | **+2* | -| | | | | -| **Endergebnis** | **-1** | **-1** | **+3** | +| Anwendbarkeit auf abhängige Relations | -3 | | | +| Performance bei vielen abhängigen Relations | -1 | | | +| Aufwand für explizite Grants | -1 | | | +| **Zwischenergebnis** | **-3** | **-1** | **+1** | +| | | | | +| **Fachliche Kriterien** | | | | +| Kongruenz von Fachlichkeit+API | +1 | -1 | +1 | +| Einheitlichkeit/Generizität der API | | +1 | | +| UPDATE Permission für Relation-AGENT möglich | +1 | | +1 | +| **Zwischenergebnis** | **+2** | **0** | **+2** | +| | | | | +| **Endergebnis** | **-1** | **-1** | **+3** | diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerController.java b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerController.java index 8f70e1d1..c535c919 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerController.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerController.java @@ -184,12 +184,7 @@ public class HsOfficePartnerController implements HsOfficePartnersApi { final var newPartnerPerson = saved.getPartnerRel().getHolder(); final var partnerPersonHasChanged = !newPartnerPerson.getUuid().equals(oldPartnerPerson.getUuid()); if (partnerPersonHasChanged) { -// realRelationRepo.findRelationRelatedToPersonUuid(oldPartnerPerson.getUuid()).forEach( rel -> { -// if (rel.getType() == REPRESENTATIVE && rel.getAnchor().getUuid().equals(oldPartnerPerson.getUuid()) ) { -// -// } -// -// } + } } diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationRbacEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationRbacEntity.java index 35063799..d1f43923 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationRbacEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationRbacEntity.java @@ -51,7 +51,7 @@ public class HsOfficeRelationRbacEntity extends HsOfficeRelation { """)) .withRestrictedViewOrderBy(SQL.expression( "(select idName from hs_office.person_iv p where p.uuid = target.holderUuid)")) - .withUpdatableColumns("anchorUuid", "holderUuid", "contactUuid") + .withUpdatableColumns("anchorUuid", "holderUuid", "contactUuid") // BEWARE: additional checks at API-level .importEntityAlias("anchorPerson", HsOfficePersonRbacEntity.class, usingDefaultCase(), dependsOnColumn("anchorUuid"), directlyFetchedByDependsOnColumn(), diff --git a/src/main/resources/db/changelog/5-hs-office/503-relation/5033-hs-office-relation-rbac.sql b/src/main/resources/db/changelog/5-hs-office/503-relation/5033-hs-office-relation-rbac.sql index 97e5bed8..8e1507d4 100644 --- a/src/main/resources/db/changelog/5-hs-office/503-relation/5033-hs-office-relation-rbac.sql +++ b/src/main/resources/db/changelog/5-hs-office/503-relation/5033-hs-office-relation-rbac.sql @@ -309,17 +309,3 @@ END; $$; --// - --- ============================================================================ ---changeset RbacRbacSystemRebuildGenerator:hs-office-relation-rbac-actually-rebuild runOnChange:true validCheckSum:ANY endDelimiter:--// --- ---------------------------------------------------------------------------- - -begin transaction; - call base.defineContext( - 're-creating RBAC for table hs_office.relation', - null, - 'superuser-alex@hostsharing.net' -- FIXME: use env-var - ); - call hs_office.relation_rebuild_rbac_system(); -commit; ---// diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationRepositoryIntegrationTest.java index 5e8c750b..d316274d 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationRepositoryIntegrationTest.java @@ -28,6 +28,7 @@ import static net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType.NATU import static net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType.UNINCORPORATED_FIRM; import static net.hostsharing.hsadminng.rbac.grant.RawRbacGrantEntity.distinctGrantDisplaysOf; import static net.hostsharing.hsadminng.rbac.role.RawRbacRoleEntity.distinctRoleNamesOf; +import static net.hostsharing.hsadminng.rbac.role.RbacRoleType.ADMIN; import static net.hostsharing.hsadminng.rbac.test.JpaAttempt.attempt; import static org.assertj.core.api.Assertions.assertThat; @@ -282,7 +283,40 @@ class HsOfficeRelationRepositoryIntegrationTest extends ContextBasedTestWithClea assertThatRelationIsNotVisibleForUserWithRole( result.returnedValue(), "hs_office.contact#fifthcontact:ADMIN"); + } + @Test + public void hostsharingAdmin_withoutAssumedRole_canUpdateHolderOfArbitraryRelation() { + // given + context("superuser-alex@hostsharing.net"); + final var givenRelation = givenSomeTemporaryRelationBessler( + "Bert", "fifth contact"); + final var oldHolderPerson = givenRelation.getHolder(); + final var newHolderPerson = personRepo.findPersonByOptionalNameLike("Paul").getFirst(); + assertThatRelationActuallyInDatabase(givenRelation); + assertThatRelationIsVisibleForUserWithRole( + givenRelation, + givenRelation.getHolder().roleId(ADMIN)); + + // when + final var result = jpaAttempt.transacted(() -> { + context("superuser-alex@hostsharing.net"); + givenRelation.setHolder(newHolderPerson); + return toCleanup(relationRbacRepo.save(givenRelation).load()); + }); + + // then + result.assertSuccessful(); + assertThat(result.returnedValue().getHolder().getGivenName()).isEqualTo("Paul"); + assertThatRelationIsVisibleForUserWithRole( + result.returnedValue(), + "rbac.global#global:ADMIN"); + assertThatRelationIsVisibleForUserWithRole( + result.returnedValue(), + newHolderPerson.roleId(ADMIN)); + assertThatRelationIsNotVisibleForUserWithRole( + result.returnedValue(), + oldHolderPerson.roleId(ADMIN)); } @Test