preparation for changing updatable columns #161

Merged
hsh-michaelhoennig merged 7 commits from feature/updatable-relation-holder into master 2025-03-03 12:01:45 +01:00
5 changed files with 76 additions and 16 deletions
Showing only changes of commit 512035b5b4 - Show all commits

View File

@ -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("contactUuid")
.withUpdatableColumns("anchorUuid", "holderUuid", "contactUuid")
.importEntityAlias("anchorPerson", HsOfficePersonRbacEntity.class, usingDefaultCase(),
dependsOnColumn("anchorUuid"),
directlyFetchedByDependsOnColumn(),

View File

@ -235,7 +235,7 @@ begin
*/
newColumns := 'new.' || replace(columnNames, ', ', ', new.');
sql := format($sql$
create function %1$s_instead_of_insert_tf()
create or replace function %1$s_instead_of_insert_tf()
returns trigger
language plpgsql as $f$
declare
@ -254,7 +254,7 @@ begin
Creates an instead of insert trigger for the restricted view.
*/
sql := format($sql$
create trigger instead_of_insert_tg
create or replace trigger instead_of_insert_tg
instead of insert
on %1$s_rv
for each row
@ -266,7 +266,7 @@ begin
Instead of delete trigger function for the restricted view.
*/
sql := format($sql$
create function %1$s_instead_of_delete_tf()
create or replace function %1$s_instead_of_delete_tf()
returns trigger
language plpgsql as $f$
begin
@ -283,7 +283,7 @@ begin
Creates an instead of delete trigger for the restricted view.
*/
sql := format($sql$
create trigger instead_of_delete_tg
create or replace trigger instead_of_delete_tg
instead of delete
on %1$s_rv
for each row
@ -297,7 +297,7 @@ begin
*/
if columnUpdates is not null then
sql := format($sql$
create function %1$s_instead_of_update_tf()
create or replace function %1$s_instead_of_update_tf()
returns trigger
language plpgsql as $f$
begin
@ -316,7 +316,7 @@ begin
Creates an instead of delete trigger for the restricted view.
*/
sql = format($sql$
create trigger instead_of_update_tg
create or replace trigger instead_of_update_tg
instead of update
on %1$s_rv
for each row

View File

@ -110,7 +110,7 @@ execute procedure hs_office.relation_build_rbac_system_after_insert_tf();
-- ============================================================================
--changeset RolesGrantsAndPermissionsGenerator:hs-office-relation-rbac-update-trigger endDelimiter:--//
--changeset RolesGrantsAndPermissionsGenerator:hs-office-relation-rbac-update-trigger runOnChange:true validCheckSum:ANY endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
@ -124,7 +124,9 @@ create or replace procedure hs_office.relation_update_rbac_system(
language plpgsql as $$
begin
if NEW.contactUuid is distinct from OLD.contactUuid then
if NEW.holderUuid is distinct from OLD.holderUuid
or NEW.anchorUuid is distinct from OLD.anchorUuid
or NEW.contactUuid is distinct from OLD.contactUuid then
delete from rbac.grant g where g.grantedbytriggerof = OLD.uuid;
call hs_office.relation_build_rbac_system(NEW);
end if;
@ -143,7 +145,7 @@ begin
return NEW;
end; $$;
create trigger update_rbac_system_after_update_tg
create or replace trigger update_rbac_system_after_update_tg
after update on hs_office.relation
for each row
execute procedure hs_office.relation_update_rbac_system_after_update_tf();
@ -241,20 +243,22 @@ call rbac.generateRbacIdentityViewFromProjection('hs_office.relation',
-- ============================================================================
--changeset RbacRestrictedViewGenerator:hs-office-relation-rbac-RESTRICTED-VIEW endDelimiter:--//
--changeset RbacRestrictedViewGenerator:hs-office-relation-rbac-RESTRICTED-VIEW runOnChange:true validCheckSum:ANY endDelimiter:--//
-- ----------------------------------------------------------------------------
call rbac.generateRbacRestrictedView('hs_office.relation',
$orderBy$
(select idName from hs_office.person_iv p where p.uuid = target.holderUuid)
$orderBy$,
$updates$
anchorUuid = new.anchorUuid,
holderUuid = new.holderUuid,
contactUuid = new.contactUuid
$updates$);
--//
-- ============================================================================
--changeset RbacRbacSystemRebuildGenerator:hs-office-relation-rbac-rebuild endDelimiter:--//
--changeset RbacRbacSystemRebuildGenerator:hs-office-relation-rbac-rebuild runOnChange:true validCheckSum:ANY endDelimiter:--//
-- ----------------------------------------------------------------------------
-- HOWTO: Rebuild RBAC-system for table hs_office.relation after changing its RBAC specification.
@ -305,3 +309,17 @@ 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;
--//

View File

@ -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;
@ -283,7 +284,44 @@ class HsOfficeRelationRepositoryIntegrationTest extends ContextBasedTestWithClea
result.returnedValue(),
"hs_office.contact#fifthcontact:ADMIN");
relationRbacRepo.deleteByUuid(givenRelation.getUuid());
// FIXME relationRbacRepo.deleteByUuid(givenRelation.getUuid());
}
@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));
// FIXME: relationRbacRepo.deleteByUuid(givenRelation.getUuid());
}
@Test
@ -296,13 +334,17 @@ class HsOfficeRelationRepositoryIntegrationTest extends ContextBasedTestWithClea
givenRelation,
"hs_office.relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerAnita:AGENT");
assertThatRelationActuallyInDatabase(givenRelation);
final var givenContact = contactRealRepo.findContactByOptionalCaptionLike("sixth contact")
.stream()
.findFirst()
.orElseThrow();
// when
final var result = jpaAttempt.transacted(() -> {
context(
"superuser-alex@hostsharing.net",
"hs_office.relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerAnita:AGENT");
givenRelation.setContact(null);
givenRelation.setContact(givenContact);
return relationRbacRepo.save(givenRelation);
});

View File

@ -12129,8 +12129,8 @@ INSERT INTO hs_office.debitor (uuid, version, debitornumbersuffix, debitorreluui
-- Data for Name: membership; Type: TABLE DATA; Schema: hs_office; Owner: postgres
--
INSERT INTO hs_office.membership (uuid, version, partneruuid, membernumbersuffix, validity, status, membershipfeebillable) VALUES ('4330e211-e36c-45ec-9332-f7593ff42811', 0, 'c27d1b0c-7e43-4b64-ae69-4317f51023ba', '01', '[2022-10-01,)', 'ACTIVE', true);
INSERT INTO hs_office.membership (uuid, version, partneruuid, membernumbersuffix, validity, status, membershipfeebillable) VALUES ('bed3c145-aa55-425f-9211-be9f5e9f4ebe', 0, '11583dae-da71-4786-a61d-d70f51ce988e', '02', '[2022-10-01,)', 'ACTIVE', true);
INSERT INTO hs_office.membership (uuid, version, partneruuid, membernumbersuffix, validity, status, membershipfeebillable) VALUES ('4330e211-e36c-45ec-9332-f7593ff42811', 0, 'c27d1b0c-7e43-4b64-ae69-4317f51023ba', '01', '[2022-10-01,2025-01-01)', 'ACTIVE', true);
INSERT INTO hs_office.membership (uuid, version, partneruuid, membernumbersuffix, validity, status, membershipfeebillable) VALUES ('bed3c145-aa55-425f-9211-be9f5e9f4ebe', 0, '11583dae-da71-4786-a61d-d70f51ce988e', '02', '[2022-10-01,2026-01-01)', 'ACTIVE', true);
INSERT INTO hs_office.membership (uuid, version, partneruuid, membernumbersuffix, validity, status, membershipfeebillable) VALUES ('a42d61c5-7dad-4379-9dd9-39a8d21ddc32', 0, '7fe704c0-2e54-463e-891e-533f0274da76', '03', '[2022-10-01,)', 'ACTIVE', true);