From 36654a69d8613cdce50bd7dcb01c35444315de31 Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Fri, 16 Feb 2024 16:48:37 +0100 Subject: [PATCH 1/2] fix misleading findPermissionId naming --- .../2022-07-18.row-level-security-mechanism.md | 4 ++-- sql/rbac-tests.sql | 8 ++++---- sql/rbac-view-option-experiments.sql | 4 ++-- .../resources/db/changelog/050-rbac-base.sql | 17 ++++++++++++++++- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/doc/adr/2022-07-18.row-level-security-mechanism.md b/doc/adr/2022-07-18.row-level-security-mechanism.md index 21225288..6276bd4d 100644 --- a/doc/adr/2022-07-18.row-level-security-mechanism.md +++ b/doc/adr/2022-07-18.row-level-security-mechanism.md @@ -74,7 +74,7 @@ For restricted DB-users, which are used by the backend, access to rows is filter FOR SELECT TO restricted USING ( - isPermissionGrantedToSubject(findPermissionId('customer', id, 'view'), currentUserUuid()) + isPermissionGrantedToSubject(findEffectivePermissionId('customer', id, 'view'), currentUserUuid()) ); SET SESSION AUTHORIZATION restricted; @@ -101,7 +101,7 @@ We are bound to PostgreSQL, including integration tests and testing the RBAC sys CREATE OR REPLACE RULE "_RETURN" AS ON SELECT TO cust_view DO INSTEAD - SELECT * FROM customer WHERE isPermissionGrantedToSubject(findPermissionId('customer', id, 'view'), currentUserUuid()); + SELECT * FROM customer WHERE isPermissionGrantedToSubject(findEffectivePermissionId('customer', id, 'view'), currentUserUuid()); SET SESSION AUTHORIZATION restricted; SET hsadminng.currentUser TO 'alex@example.com'; diff --git a/sql/rbac-tests.sql b/sql/rbac-tests.sql index 0183a6a2..4e179dee 100644 --- a/sql/rbac-tests.sql +++ b/sql/rbac-tests.sql @@ -19,11 +19,11 @@ select * FROM queryAllPermissionsOfSubjectId(findRbacUser('rosa@example.com')); select * -FROM queryAllRbacUsersWithPermissionsFor(findPermissionId('customer', +FROM queryAllRbacUsersWithPermissionsFor(findEffectivePermissionId('customer', (SELECT uuid FROM RbacObject WHERE objectTable = 'customer' LIMIT 1), 'add-package')); select * -FROM queryAllRbacUsersWithPermissionsFor(findPermissionId('package', +FROM queryAllRbacUsersWithPermissionsFor(findEffectivePermissionId('package', (SELECT uuid FROM RbacObject WHERE objectTable = 'package' LIMIT 1), 'delete')); @@ -34,12 +34,12 @@ $$ result bool; BEGIN userId = findRbacUser('superuser-alex@hostsharing.net'); - result = (SELECT * FROM isPermissionGrantedToSubject(findPermissionId('package', 94928, 'add-package'), userId)); + result = (SELECT * FROM isPermissionGrantedToSubject(findEffectivePermissionId('package', 94928, 'add-package'), userId)); IF (result) THEN RAISE EXCEPTION 'expected permission NOT to be granted, but it is'; end if; - result = (SELECT * FROM isPermissionGrantedToSubject(findPermissionId('package', 94928, 'view'), userId)); + result = (SELECT * FROM isPermissionGrantedToSubject(findEffectivePermissionId('package', 94928, 'view'), userId)); IF (NOT result) THEN RAISE EXCEPTION 'expected permission to be granted, but it is NOT'; end if; diff --git a/sql/rbac-view-option-experiments.sql b/sql/rbac-view-option-experiments.sql index 3a6cab1a..d3ef736a 100644 --- a/sql/rbac-view-option-experiments.sql +++ b/sql/rbac-view-option-experiments.sql @@ -20,7 +20,7 @@ CREATE POLICY customer_policy ON customer TO restricted USING ( -- id=1000 - isPermissionGrantedToSubject(findPermissionId('test_customer', id, 'view'), currentUserUuid()) + isPermissionGrantedToSubject(findEffectivePermissionId('test_customer', id, 'view'), currentUserUuid()) ); SET SESSION AUTHORIZATION restricted; @@ -35,7 +35,7 @@ SELECT * FROM customer; CREATE OR REPLACE RULE "_RETURN" AS ON SELECT TO cust_view DO INSTEAD - SELECT * FROM customer WHERE isPermissionGrantedToSubject(findPermissionId('test_customer', id, 'view'), currentUserUuid()); + SELECT * FROM customer WHERE isPermissionGrantedToSubject(findEffectivePermissionId('test_customer', id, 'view'), currentUserUuid()); SELECT * from cust_view LIMIT 10; select queryAllPermissionsOfSubjectId(findRbacUser('superuser-alex@hostsharing.net')); diff --git a/src/main/resources/db/changelog/050-rbac-base.sql b/src/main/resources/db/changelog/050-rbac-base.sql index aab14b95..40c15646 100644 --- a/src/main/resources/db/changelog/050-rbac-base.sql +++ b/src/main/resources/db/changelog/050-rbac-base.sql @@ -438,9 +438,24 @@ create or replace function findPermissionId(forObjectUuid uuid, forOp RbacOp) select uuid from RbacPermission p where p.objectUuid = forObjectUuid - and p.op in ('*', forOp) + and p.op = forOp $$; +create or replace function findEffectivePermissionId(forObjectUuid uuid, forOp RbacOp) + returns uuid + returns null on null input + stable -- leakproof + language plpgsql as $$ +declare + permissionId uuid; +begin + permissionId := findPermissionId(forObjectUuid, forOp); + if permissionId is null and forOp <> '*' then + permissionId := findPermissionId(forObjectUuid, '*'); + end if; + return permissionId; +end $$; + --// -- ============================================================================ From d9558f2cfe71b90faffb803b22ce475dc645e550 Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Sat, 24 Feb 2024 09:04:07 +0100 Subject: [PATCH 2/2] add-trigger-object-to-rbacgrant (#18) Co-authored-by: Michael Hoennig Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/18 Reviewed-by: Timotheus Pokorra --- .../resources/db/changelog/050-rbac-base.sql | 21 ++++--- .../resources/db/changelog/055-rbac-views.sql | 2 + .../db/changelog/056-rbac-trigger-context.sql | 61 +++++++++++++++++++ .../db/changelog/113-test-customer-rbac.sql | 3 + .../db/changelog/123-test-package-rbac.sql | 5 +- .../db/changelog/133-test-domain-rbac.sql | 3 + .../223-hs-office-relationship-rbac.sql | 2 + .../changelog/233-hs-office-partner-rbac.sql | 2 + .../253-hs-office-sepamandate-rbac.sql | 2 + .../changelog/273-hs-office-debitor-rbac.sql | 2 + .../303-hs-office-membership-rbac.sql | 2 + .../313-hs-office-coopshares-rbac.sql | 2 + .../323-hs-office-coopassets-rbac.sql | 2 + .../db/changelog/db.changelog-master.yaml | 2 + .../hs/office/migration/ImportOfficeData.java | 35 +++++------ ...RelationshipRepositoryIntegrationTest.java | 4 -- src/test/resources/migration/contacts.csv | 2 +- 17 files changed, 116 insertions(+), 36 deletions(-) create mode 100644 src/main/resources/db/changelog/056-rbac-trigger-context.sql diff --git a/src/main/resources/db/changelog/050-rbac-base.sql b/src/main/resources/db/changelog/050-rbac-base.sql index 40c15646..fe2f30ae 100644 --- a/src/main/resources/db/changelog/050-rbac-base.sql +++ b/src/main/resources/db/changelog/050-rbac-base.sql @@ -467,12 +467,13 @@ end $$; create table RbacGrants ( uuid uuid primary key default uuid_generate_v4(), + grantedByTriggerOf uuid references RbacObject (uuid) on delete cascade initially deferred , grantedByRoleUuid uuid references RbacRole (uuid), ascendantUuid uuid references RbacReference (uuid), descendantUuid uuid references RbacReference (uuid), assumed boolean not null default true, -- auto assumed (true) vs. needs assumeRoles (false) - unique (ascendantUuid, descendantUuid) -); + unique (ascendantUuid, descendantUuid), + constraint rbacGrant_createdBy check ( grantedByRoleUuid is null or grantedByTriggerOf is null) ); create index on RbacGrants (ascendantUuid); create index on RbacGrants (descendantUuid); @@ -576,8 +577,8 @@ begin perform assertReferenceType('permissionId (descendant)', permissionIds[i], 'RbacPermission'); insert - into RbacGrants (ascendantUuid, descendantUuid, assumed) - values (roleUuid, permissionIds[i], true) + into RbacGrants (grantedByTriggerOf, ascendantUuid, descendantUuid, assumed) + values (currentTriggerObjectUuid(), roleUuid, permissionIds[i], true) on conflict do nothing; -- allow granting multiple times end loop; end; @@ -594,8 +595,8 @@ begin end if; insert - into RbacGrants (ascendantuuid, descendantUuid, assumed) - values (superRoleId, subRoleId, doAssume) + into RbacGrants (grantedByTriggerOf, ascendantuuid, descendantUuid, assumed) + values (currentTriggerObjectUuid(), superRoleId, subRoleId, doAssume) on conflict do nothing; -- allow granting multiple times end; $$; @@ -617,8 +618,8 @@ begin end if; insert - into RbacGrants (ascendantuuid, descendantUuid, assumed) - values (superRoleId, subRoleId, doAssume) + into RbacGrants (grantedByTriggerOf, ascendantuuid, descendantUuid, assumed) + values (currentTriggerObjectUuid(), superRoleId, subRoleId, doAssume) on conflict do nothing; -- allow granting multiple times end; $$; @@ -640,8 +641,8 @@ begin end if; insert - into RbacGrants (ascendantuuid, descendantUuid, assumed) - values (superRoleId, subRoleId, doAssume) + into RbacGrants (grantedByTriggerOf, ascendantuuid, descendantUuid, assumed) + values (currentTriggerObjectUuid(), superRoleId, subRoleId, doAssume) on conflict do nothing; -- allow granting multiple times end; $$; diff --git a/src/main/resources/db/changelog/055-rbac-views.sql b/src/main/resources/db/changelog/055-rbac-views.sql index d1d1d926..b1757c56 100644 --- a/src/main/resources/db/changelog/055-rbac-views.sql +++ b/src/main/resources/db/changelog/055-rbac-views.sql @@ -56,6 +56,7 @@ drop view if exists rbacgrants_ev; create or replace view rbacgrants_ev as -- @formatter:off select x.grantUuid as uuid, + x.grantedByTriggerOf as grantedByTriggerOf, go.objectTable || '#' || findIdNameByObjectUuid(go.objectTable, go.uuid) || '.' || r.roletype as grantedByRoleIdName, x.ascendingIdName as ascendantIdName, x.descendingIdName as descendantIdName, @@ -65,6 +66,7 @@ create or replace view rbacgrants_ev as x.assumed from ( select g.uuid as grantUuid, + g.grantedbytriggerof as grantedbytriggerof, g.grantedbyroleuuid, g.ascendantuuid, g.descendantuuid, g.assumed, coalesce( diff --git a/src/main/resources/db/changelog/056-rbac-trigger-context.sql b/src/main/resources/db/changelog/056-rbac-trigger-context.sql new file mode 100644 index 00000000..80a92987 --- /dev/null +++ b/src/main/resources/db/changelog/056-rbac-trigger-context.sql @@ -0,0 +1,61 @@ +--liquibase formatted sql + + +-- ============================================================================ +--changeset rbac-trigger-context-ENTER:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +create or replace procedure enterTriggerForObjectUuid(currentObjectUuid uuid) + language plpgsql as $$ +declare + existingObjectUuid text; +begin + existingObjectUuid = current_setting('hsadminng.currentObjectUuid', true); + if (existingObjectUuid > '' ) then + raise exception '[500] currentObjectUuid already defined, already in trigger of "%"', existingObjectUuid; + end if; + execute format('set local hsadminng.currentObjectUuid to %L', currentObjectUuid); +end; $$; + + +-- ============================================================================ +--changeset rbac-trigger-context-CURRENT-ID:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +/* + Returns the uuid of the object uuid whose trigger is currently executed as set via `enterTriggerForObjectUuid(...)`. + */ + +create or replace function currentTriggerObjectUuid() + returns uuid + stable -- leakproof + language plpgsql as $$ +declare + currentObjectUuid uuid; +begin + begin + currentObjectUuid = current_setting('hsadminng.currentObjectUuid')::uuid; + return currentObjectUuid; + exception + when others then + return null::uuid; + end; +end; $$; +--// + + +-- ============================================================================ +--changeset rbac-trigger-context-LEAVE:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +create or replace procedure leaveTriggerForObjectUuid(currentObjectUuid uuid) + language plpgsql as $$ +declare + existingObjectUuid uuid; +begin + existingObjectUuid = current_setting('hsadminng.currentObjectUuid', true); + if ( existingObjectUuid <> currentObjectUuid ) then + raise exception '[500] currentObjectUuid does not match: "%"', existingObjectUuid; + end if; + execute format('reset hsadminng.currentObjectUuid'); +end; $$; + diff --git a/src/main/resources/db/changelog/113-test-customer-rbac.sql b/src/main/resources/db/changelog/113-test-customer-rbac.sql index 1f563aa2..d7682cc1 100644 --- a/src/main/resources/db/changelog/113-test-customer-rbac.sql +++ b/src/main/resources/db/changelog/113-test-customer-rbac.sql @@ -34,6 +34,8 @@ begin raise exception 'invalid usage of TRIGGER AFTER INSERT'; end if; + call enterTriggerForObjectUuid(NEW.uuid); + -- the owner role with full access for Hostsharing administrators testCustomerOwnerUuid = createRoleWithGrants( testCustomerOwner(NEW), @@ -59,6 +61,7 @@ begin permissions => array['view'] ); + call leaveTriggerForObjectUuid(NEW.uuid); return NEW; end; $$; diff --git a/src/main/resources/db/changelog/123-test-package-rbac.sql b/src/main/resources/db/changelog/123-test-package-rbac.sql index 8a2fd857..9e68468c 100644 --- a/src/main/resources/db/changelog/123-test-package-rbac.sql +++ b/src/main/resources/db/changelog/123-test-package-rbac.sql @@ -26,13 +26,13 @@ create or replace function createRbacRolesForTestPackage() strict as $$ declare parentCustomer test_customer; - packageOwnerRoleUuid uuid; - packageAdminRoleUuid uuid; begin if TG_OP <> 'INSERT' then raise exception 'invalid usage of TRIGGER AFTER INSERT'; end if; + call enterTriggerForObjectUuid(NEW.uuid); + select * from test_customer as c where c.uuid = NEW.customerUuid into parentCustomer; -- an owner role is created and assigned to the customer's admin role @@ -57,6 +57,7 @@ begin outgoingSubRoles => array[testCustomerTenant(parentCustomer)] ); + call leaveTriggerForObjectUuid(NEW.uuid); return NEW; end; $$; diff --git a/src/main/resources/db/changelog/133-test-domain-rbac.sql b/src/main/resources/db/changelog/133-test-domain-rbac.sql index 89b63018..a78bfb5f 100644 --- a/src/main/resources/db/changelog/133-test-domain-rbac.sql +++ b/src/main/resources/db/changelog/133-test-domain-rbac.sql @@ -53,6 +53,8 @@ begin raise exception 'invalid usage of TRIGGER AFTER INSERT'; end if; + call enterTriggerForObjectUuid(NEW.uuid); + select * from test_package where uuid = NEW.packageUuid into parentPackage; -- an owner role is created and assigned to the package's admin group @@ -72,6 +74,7 @@ begin -- a tenent role is only created on demand + call leaveTriggerForObjectUuid(NEW.uuid); return NEW; end; $$; diff --git a/src/main/resources/db/changelog/223-hs-office-relationship-rbac.sql b/src/main/resources/db/changelog/223-hs-office-relationship-rbac.sql index 03b0b748..928af48c 100644 --- a/src/main/resources/db/changelog/223-hs-office-relationship-rbac.sql +++ b/src/main/resources/db/changelog/223-hs-office-relationship-rbac.sql @@ -33,6 +33,7 @@ declare oldContact hs_office_contact; newContact hs_office_contact; begin + call enterTriggerForObjectUuid(NEW.uuid); hsOfficeRelationshipTenant := hsOfficeRelationshipTenant(NEW); @@ -96,6 +97,7 @@ begin raise exception 'invalid usage of TRIGGER'; end if; + call leaveTriggerForObjectUuid(NEW.uuid); return NEW; end; $$; diff --git a/src/main/resources/db/changelog/233-hs-office-partner-rbac.sql b/src/main/resources/db/changelog/233-hs-office-partner-rbac.sql index d4b0105c..4b4da009 100644 --- a/src/main/resources/db/changelog/233-hs-office-partner-rbac.sql +++ b/src/main/resources/db/changelog/233-hs-office-partner-rbac.sql @@ -36,6 +36,7 @@ declare oldContact hs_office_contact; newContact hs_office_contact; begin + call enterTriggerForObjectUuid(NEW.uuid); select * from hs_office_relationship as r where r.uuid = NEW.partnerroleuuid into newPartnerRole; select * from hs_office_person as p where p.uuid = NEW.personUuid into newPerson; @@ -159,6 +160,7 @@ begin raise exception 'invalid usage of TRIGGER'; end if; + call leaveTriggerForObjectUuid(NEW.uuid); return NEW; end; $$; diff --git a/src/main/resources/db/changelog/253-hs-office-sepamandate-rbac.sql b/src/main/resources/db/changelog/253-hs-office-sepamandate-rbac.sql index f09f2a4b..02895c48 100644 --- a/src/main/resources/db/changelog/253-hs-office-sepamandate-rbac.sql +++ b/src/main/resources/db/changelog/253-hs-office-sepamandate-rbac.sql @@ -30,6 +30,7 @@ declare newHsOfficeDebitor hs_office_debitor; newHsOfficeBankAccount hs_office_bankAccount; begin + call enterTriggerForObjectUuid(NEW.uuid); select * from hs_office_debitor as p where p.uuid = NEW.debitorUuid into newHsOfficeDebitor; select * from hs_office_bankAccount as c where c.uuid = NEW.bankAccountUuid into newHsOfficeBankAccount; @@ -75,6 +76,7 @@ begin raise exception 'invalid usage of TRIGGER'; end if; + call leaveTriggerForObjectUuid(NEW.uuid); return NEW; end; $$; diff --git a/src/main/resources/db/changelog/273-hs-office-debitor-rbac.sql b/src/main/resources/db/changelog/273-hs-office-debitor-rbac.sql index e6572e55..30573125 100644 --- a/src/main/resources/db/changelog/273-hs-office-debitor-rbac.sql +++ b/src/main/resources/db/changelog/273-hs-office-debitor-rbac.sql @@ -36,6 +36,7 @@ declare newBankAccount hs_office_bankaccount; oldBankAccount hs_office_bankaccount; begin + call enterTriggerForObjectUuid(NEW.uuid); hsOfficeDebitorTenant := hsOfficeDebitorTenant(NEW); @@ -145,6 +146,7 @@ begin raise exception 'invalid usage of TRIGGER'; end if; + call leaveTriggerForObjectUuid(NEW.uuid); return NEW; end; $$; diff --git a/src/main/resources/db/changelog/303-hs-office-membership-rbac.sql b/src/main/resources/db/changelog/303-hs-office-membership-rbac.sql index 8197cf09..949f939c 100644 --- a/src/main/resources/db/changelog/303-hs-office-membership-rbac.sql +++ b/src/main/resources/db/changelog/303-hs-office-membership-rbac.sql @@ -30,6 +30,7 @@ declare newHsOfficePartner hs_office_partner; newHsOfficeDebitor hs_office_debitor; begin + call enterTriggerForObjectUuid(NEW.uuid); select * from hs_office_partner as p where p.uuid = NEW.partnerUuid into newHsOfficePartner; select * from hs_office_debitor as c where c.uuid = NEW.mainDebitorUuid into newHsOfficeDebitor; @@ -74,6 +75,7 @@ begin raise exception 'invalid usage of TRIGGER'; end if; + call leaveTriggerForObjectUuid(NEW.uuid); return NEW; end; $$; diff --git a/src/main/resources/db/changelog/313-hs-office-coopshares-rbac.sql b/src/main/resources/db/changelog/313-hs-office-coopshares-rbac.sql index d6afcfc8..dd465d9f 100644 --- a/src/main/resources/db/changelog/313-hs-office-coopshares-rbac.sql +++ b/src/main/resources/db/changelog/313-hs-office-coopshares-rbac.sql @@ -29,6 +29,7 @@ create or replace function hsOfficeCoopSharesTransactionRbacRolesTrigger() declare newHsOfficeMembership hs_office_membership; begin + call enterTriggerForObjectUuid(NEW.uuid); select * from hs_office_membership as p where p.uuid = NEW.membershipUuid into newHsOfficeMembership; @@ -49,6 +50,7 @@ begin raise exception 'invalid usage of TRIGGER'; end if; + call leaveTriggerForObjectUuid(NEW.uuid); return NEW; end; $$; diff --git a/src/main/resources/db/changelog/323-hs-office-coopassets-rbac.sql b/src/main/resources/db/changelog/323-hs-office-coopassets-rbac.sql index 6589eaa2..ac65c141 100644 --- a/src/main/resources/db/changelog/323-hs-office-coopassets-rbac.sql +++ b/src/main/resources/db/changelog/323-hs-office-coopassets-rbac.sql @@ -29,6 +29,7 @@ create or replace function hsOfficeCoopAssetsTransactionRbacRolesTrigger() declare newHsOfficeMembership hs_office_membership; begin + call enterTriggerForObjectUuid(NEW.uuid); select * from hs_office_membership as p where p.uuid = NEW.membershipUuid into newHsOfficeMembership; @@ -49,6 +50,7 @@ begin raise exception 'invalid usage of TRIGGER'; end if; + call leaveTriggerForObjectUuid(NEW.uuid); return NEW; end; $$; diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index fdd04507..2b8417c3 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -25,6 +25,8 @@ databaseChangeLog: file: db/changelog/054-rbac-context.sql - include: file: db/changelog/055-rbac-views.sql + - include: + file: db/changelog/056-rbac-trigger-context.sql - include: file: db/changelog/057-rbac-role-builder.sql - include: diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/migration/ImportOfficeData.java b/src/test/java/net/hostsharing/hsadminng/hs/office/migration/ImportOfficeData.java index 562eaf06..325317b2 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/migration/ImportOfficeData.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/migration/ImportOfficeData.java @@ -278,20 +278,19 @@ public class ImportOfficeData extends ContextBasedTest { 2000002=rel(relAnchor='LP Hostsharing eG', relType='PARTNER', relHolder='?? Test PS', contact='Petra Schmidt , Test PS'), 2000003=rel(relAnchor='LP Hostsharing eG', relType='PARTNER', relHolder='null null, null'), 2000004=rel(relAnchor='NP Mellies, Michael', relType='OPERATIONS', relHolder='NP Mellies, Michael', contact='Herr Michael Mellies '), - 2000005=rel(relAnchor='LP JM GmbH', relType='EX_PARTNER', relHolder='LP JM e.K.', contact='JM e.K.'), - 2000006=rel(relAnchor='LP JM GmbH', relType='OPERATIONS', relHolder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'), - 2000007=rel(relAnchor='LP JM GmbH', relType='VIP_CONTACT', relHolder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'), - 2000008=rel(relAnchor='LP JM GmbH', relType='SUBSCRIBER', relMark='operations-announce', relHolder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'), - 2000009=rel(relAnchor='LP JM GmbH', relType='REPRESENTATIVE', relHolder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'), - 2000010=rel(relAnchor='LP JM GmbH', relType='SUBSCRIBER', relMark='members-announce', relHolder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'), - 2000011=rel(relAnchor='LP JM GmbH', relType='SUBSCRIBER', relMark='customers-announce', relHolder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'), - 2000012=rel(relAnchor='LP JM GmbH', relType='VIP_CONTACT', relHolder='LP JM GmbH', contact='Frau Tammy Meyer-VIP , JM GmbH'), - 2000013=rel(relAnchor='?? Test PS', relType='OPERATIONS', relHolder='?? Test PS', contact='Petra Schmidt , Test PS'), - 2000014=rel(relAnchor='?? Test PS', relType='REPRESENTATIVE', relHolder='?? Test PS', contact='Petra Schmidt , Test PS'), - 2000015=rel(relAnchor='NP Mellies, Michael', relType='SUBSCRIBER', relMark='operations-announce', relHolder='NP Fanninga, Frauke', contact='Frau Frauke Fanninga '), - 2000016=rel(relAnchor='NP Mellies, Michael', relType='REPRESENTATIVE', relHolder='NP Mellies, Michael', contact='Herr Michael Mellies '), - 2000017=rel(relAnchor='null null, null', relType='REPRESENTATIVE', relHolder='null null, null') - } + 2000005=rel(relAnchor='NP Mellies, Michael', relType='REPRESENTATIVE', relHolder='NP Mellies, Michael', contact='Herr Michael Mellies '), + 2000006=rel(relAnchor='LP JM GmbH', relType='EX_PARTNER', relHolder='LP JM e.K.', contact='JM e.K.'), + 2000007=rel(relAnchor='LP JM GmbH', relType='OPERATIONS', relHolder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'), + 2000008=rel(relAnchor='LP JM GmbH', relType='VIP_CONTACT', relHolder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'), + 2000009=rel(relAnchor='LP JM GmbH', relType='SUBSCRIBER', relMark='operations-announce', relHolder='LP JM GmbH', contact='Herr Andrew Meyer-Operation , JM GmbH'), + 2000010=rel(relAnchor='LP JM GmbH', relType='REPRESENTATIVE', relHolder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'), + 2000011=rel(relAnchor='LP JM GmbH', relType='SUBSCRIBER', relMark='members-announce', relHolder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'), + 2000012=rel(relAnchor='LP JM GmbH', relType='SUBSCRIBER', relMark='customers-announce', relHolder='LP JM GmbH', contact='Herr Philip Meyer-Contract , JM GmbH'), + 2000013=rel(relAnchor='LP JM GmbH', relType='VIP_CONTACT', relHolder='LP JM GmbH', contact='Frau Tammy Meyer-VIP , JM GmbH'), + 2000014=rel(relAnchor='?? Test PS', relType='OPERATIONS', relHolder='?? Test PS', contact='Petra Schmidt , Test PS'), + 2000015=rel(relAnchor='?? Test PS', relType='REPRESENTATIVE', relHolder='?? Test PS', contact='Petra Schmidt , Test PS'), + 2000016=rel(relAnchor='NP Mellies, Michael', relType='SUBSCRIBER', relMark='operations-announce', relHolder='NP Fanninga, Frauke', contact='Frau Frauke Fanninga ') + } """); } @@ -412,7 +411,7 @@ public class ImportOfficeData extends ContextBasedTest { idsToRemove.add(id); } }); - assertThat(idsToRemove.size()).isEqualTo(2); // only from partner #99 (partner+contractual roles) + assertThat(idsToRemove.size()).isEqualTo(1); // only from partner #99 (partner+contractual roles) idsToRemove.forEach(id -> relationships.remove(id)); } @@ -421,7 +420,7 @@ public class ImportOfficeData extends ContextBasedTest { void removeEmptyPartners() { assumeThatWeAreImportingControlledTestData(); - // avoid a error when persisting the deliberetely invalid partner entry #99 + // avoid a error when persisting the deliberately invalid partner entry #99 final var idsToRemove = new HashSet(); partners.forEach( (id, r) -> { // such a record @@ -439,7 +438,7 @@ public class ImportOfficeData extends ContextBasedTest { void removeEmptyDebitors() { assumeThatWeAreImportingControlledTestData(); - // avoid a error when persisting the deliberetely invalid partner entry #99 + // avoid a error when persisting the deliberately invalid partner entry #99 final var idsToRemove = new HashSet(); debitors.forEach( (id, r) -> { // such a record @@ -881,11 +880,9 @@ public class ImportOfficeData extends ContextBasedTest { if (relationships.values().stream() .filter(rel -> rel.getRelAnchor() == partnerPerson && rel.getRelType() == HsOfficeRelationshipType.REPRESENTATIVE) .findFirst().isEmpty()) { - //addRelationship(partnerPerson, partnerPerson, partner.getContact(), HsOfficeRelationshipType.REPRESENTATIVE); contractualMissing.add(partner.getPartnerNumber()); } }); - assertThat(contractualMissing).isEmpty(); // comment out if we do want to allow missing contractual contact } private static boolean containsRole(final Record rec, final String role) { final var roles = rec.getString("roles"); diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipRepositoryIntegrationTest.java index 8b732d66..8d89479c 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipRepositoryIntegrationTest.java @@ -342,10 +342,6 @@ class HsOfficeRelationshipRepositoryIntegrationTest extends ContextBasedTestWith final var initialGrantNames = Array.from(distinctGrantDisplaysOf(rawGrantRepo.findAll())); final var givenRelationship = givenSomeTemporaryRelationshipBessler( "Anita", "twelfth"); - assertThat(distinctRoleNamesOf(rawRoleRepo.findAll()).size()).as("unexpected number of roles created") - .isEqualTo(initialRoleNames.length + 3); - assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll()).size()).as("unexpected number of grants created") - .isEqualTo(initialGrantNames.length + 13); // when final var result = jpaAttempt.transacted(() -> { diff --git a/src/test/resources/migration/contacts.csv b/src/test/resources/migration/contacts.csv index 0984c0d5..3aa1aa04 100644 --- a/src/test/resources/migration/contacts.csv +++ b/src/test/resources/migration/contacts.csv @@ -1,7 +1,7 @@ contact_id; bp_id; salut; first_name; last_name; title; firma; co; street; zipcode;city; country; phone_private; phone_office; phone_mobile; fax; email; roles # eine natürliche Person, implizites contractual -1101; 17; Herr; Michael; Mellies; ; ; ; Kleine Freiheit 50; 26524; Hage; DE; ; +49 4931 123456; +49 1522 123456;; mih@example.org; partner,billing,operation +1101; 17; Herr; Michael; Mellies; ; ; ; Kleine Freiheit 50; 26524; Hage; DE; ; +49 4931 123456; +49 1522 123456;; mih@example.org; partner,contractual,billing,operation # eine juristische Person mit drei separaten Ansprechpartnern, vip-contact und ex-partner 1200; 20;; ; ; ; JM e.K.;; Wiesenweg 15; 12335; Berlin; DE; +49 30 6666666; +49 30 5555555; ; +49 30 6666666; jm-ex-partner@example.org; ex-partner