relation with updatable holder+anchor and test

This commit is contained in:
Michael Hoennig 2025-03-04 12:20:40 +01:00
parent 573ac44b62
commit 839703ca48
5 changed files with 51 additions and 36 deletions
doc/adr
src
main
java/net/hostsharing/hsadminng/hs/office
resources/db/changelog/5-hs-office/503-relation
test/java/net/hostsharing/hsadminng/hs/office/relation

@ -106,7 +106,7 @@ Nennenswerte Nachteile wurden nicht identifiziert, allenfalls ist es etwas schr
- 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** | | | |
| Beibehaltung der API vs. Umbau (inkl. Risiko) | +2 | -2 | +1 |
| Anwendbarkeit auf Partner- und Debitor-Person | | +1 | |
@ -119,6 +119,6 @@ Nennenswerte Nachteile wurden nicht identifiziert, allenfalls ist es etwas schr
| 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* |
| **Zwischenergebnis** | **+2** | **0** | **+2** |
| | | | |
| **Endergebnis** | **-1** | **-1** | **+3** |

@ -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()) ) {
//
// }
//
// }
}
}

@ -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(),

@ -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;
--//

@ -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