diff --git a/src/main/resources/db/changelog/250-hs-office-sepamandate.sql b/src/main/resources/db/changelog/250-hs-office-sepamandate.sql new file mode 100644 index 00000000..144d0357 --- /dev/null +++ b/src/main/resources/db/changelog/250-hs-office-sepamandate.sql @@ -0,0 +1,23 @@ +--liquibase formatted sql + +-- ============================================================================ +--changeset hs-office-sepamandate-MAIN-TABLE:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +create table if not exists hs_office_sepamandate +( + uuid uuid unique references RbacObject (uuid) initially deferred, + debitorUuid uuid not null references hs_office_debitor(uuid), + bankAccountUuid uuid not null references hs_office_bankaccount(uuid), + reference varchar(96), + validity daterange not null +); +--// + + +-- ============================================================================ +--changeset hs-office-sepamandate-MAIN-TABLE-JOURNAL:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +call create_journal('hs_office_sepamandate'); +--// diff --git a/src/main/resources/db/changelog/253-hs-office-sepamandate-rbac.md b/src/main/resources/db/changelog/253-hs-office-sepamandate-rbac.md new file mode 100644 index 00000000..78bb7751 --- /dev/null +++ b/src/main/resources/db/changelog/253-hs-office-sepamandate-rbac.md @@ -0,0 +1,71 @@ +### hs_office_sepaMandate RBAC + +```mermaid +flowchart TB + +subgraph global + style global fill:#eee + + role:global.admin[global.admin] +end + +subgraph hsOfficeBankAccount + direction TB + style hsOfficeBankAccount fill:#eee + + role:hsOfficeBankAccount.owner[bankAccount.owner] + --> role:hsOfficeBankAccount.admin[bankAccount.admin] + --> role:hsOfficeBankAccount.tenant[bankAccount.tenant] + --> role:hsOfficeBankAccount.guest[bankAccount.guest] +end + +subgraph hsOfficeDebitor + direction TB + style hsOfficeDebitor fill:#eee + + role:hsOfficeDebitor.owner[debitor.admin] + --> role:hsOfficeDebitor.admin[debitor.admin] + --> role:hsOfficeDebitor.agent[debitor.agent] + --> role:hsOfficeDebitor.tenant[debitor.tenant] + --> role:hsOfficeDebitor.guest[debitor.guest] +end + +subgraph hsOfficeSepaMandate + + role:hsOfficeSepaMandate.owner[sepaMandate.owner] + %% permissions + role:hsOfficeSepaMandate.owner --> perm:hsOfficeSepaMandate.*{{sepaMandate.*}} + %% incoming + role:global.admin ---> role:hsOfficeSepaMandate.owner + + role:hsOfficeSepaMandate.admin[sepaMandate.admin] + %% permissions + role:hsOfficeSepaMandate.admin --> perm:hsOfficeSepaMandate.edit{{sepaMandate.edit}} + %% incoming + role:hsOfficeSepaMandate.owner ---> role:hsOfficeSepaMandate.admin + + role:hsOfficeSepaMandate.agent[sepaMandate.agent] + %% incoming + role:hsOfficeSepaMandate.admin ---> role:hsOfficeSepaMandate.agent + role:hsOfficeDebitor.admin --> role:hsOfficeSepaMandate.agent + role:hsOfficeBankAccount.admin --> role:hsOfficeSepaMandate.agent + %% outgoing + role:hsOfficeSepaMandate.agent --> role:hsOfficeDebitor.tenant + role:hsOfficeSepaMandate.admin --> role:hsOfficeBankAccount.tenant + + role:hsOfficeSepaMandate.tenant[sepaMandate.tenant] + %% incoming + role:hsOfficeSepaMandate.agent --> role:hsOfficeSepaMandate.tenant + %% outgoing + role:hsOfficeSepaMandate.tenant --> role:hsOfficeDebitor.guest + role:hsOfficeSepaMandate.tenant --> role:hsOfficeBankAccount.guest + + role:hsOfficeSepaMandate.guest[sepaMandate.guest] + %% permissions + role:hsOfficeSepaMandate.guest --> perm:hsOfficeSepaMandate.view{{sepaMandate.view}} + %% incoming + role:hsOfficeSepaMandate.tenant --> role:hsOfficeSepaMandate.guest +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 new file mode 100644 index 00000000..56bbff58 --- /dev/null +++ b/src/main/resources/db/changelog/253-hs-office-sepamandate-rbac.sql @@ -0,0 +1,157 @@ +--liquibase formatted sql + +-- ============================================================================ +--changeset hs-office-sepaMandate-rbac-OBJECT:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRelatedRbacObject('hs_office_sepaMandate'); +--// + + +-- ============================================================================ +--changeset hs-office-sepaMandate-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRbacRoleDescriptors('hsOfficeSepaMandate', 'hs_office_sepaMandate'); +--// + + +-- ============================================================================ +--changeset hs-office-sepaMandate-rbac-ROLES-CREATION:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/* + Creates and updates the roles and their assignments for sepaMandate entities. + */ + +create or replace function hsOfficeSepaMandateRbacRolesTrigger() + returns trigger + language plpgsql + strict as $$ +declare + newHsOfficeDebitor hs_office_debitor; + newHsOfficeBankAccount hs_office_bankAccount; +begin + + 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; + + if TG_OP = 'INSERT' then + + + -- === ATTENTION: code generated from related Mermaid flowchart: === + + + perform createRoleWithGrants( + hsOfficeSepaMandateOwner(NEW), + permissions => array['*'], + incomingSuperRoles => array[globalAdmin()] + ); + + perform createRoleWithGrants( + hsOfficeSepaMandateAdmin(NEW), + permissions => array['edit'], + incomingSuperRoles => array[hsOfficeSepaMandateOwner(NEW)], + outgoingSubRoles => array[hsOfficeBankAccountTenant(newHsOfficeBankAccount)] + ); + + perform createRoleWithGrants( + hsOfficeSepaMandateAgent(NEW), + incomingSuperRoles => array[hsOfficeSepaMandateAdmin(NEW), hsOfficeDebitorAdmin(newHsOfficeDebitor), hsOfficeBankAccountAdmin(newHsOfficeBankAccount)], + outgoingSubRoles => array[hsOfficeDebitorTenant(newHsOfficeDebitor)] + ); + + perform createRoleWithGrants( + hsOfficeSepaMandateTenant(NEW), + incomingSuperRoles => array[hsOfficeSepaMandateAgent(NEW)], + outgoingSubRoles => array[hsOfficeDebitorGuest(newHsOfficeDebitor), hsOfficeBankAccountGuest(newHsOfficeBankAccount)] + ); + + perform createRoleWithGrants( + hsOfficeSepaMandateGuest(NEW), + permissions => array['view'], + incomingSuperRoles => array[hsOfficeSepaMandateTenant(NEW)] + ); + + -- === END of code generated from Mermaid flowchart. === + + + else + raise exception 'invalid usage of TRIGGER'; + end if; + + return NEW; +end; $$; + +/* + An AFTER INSERT TRIGGER which creates the role structure for a new customer. + */ +create trigger createRbacRolesForHsOfficeSepaMandate_Trigger + after insert + on hs_office_sepaMandate + for each row +execute procedure hsOfficeSepaMandateRbacRolesTrigger(); +--// + + +-- ============================================================================ +--changeset hs-office-sepaMandate-rbac-IDENTITY-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRbacIdentityView('hs_office_sepaMandate', idNameExpression => 'target.reference'); +--// + + +-- ============================================================================ +--changeset hs-office-sepaMandate-rbac-RESTRICTED-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRbacRestrictedView('hs_office_sepaMandate', + orderby => 'target.reference', + columnUpdates => $updates$ + validity = new.validity + $updates$); +--// + + +-- ============================================================================ +--changeset hs-office-sepaMandate-rbac-NEW-SepaMandate:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +/* + Creates a global permission for new-sepaMandate and assigns it to the hostsharing admins role. + */ +do language plpgsql $$ + declare + addCustomerPermissions uuid[]; + globalObjectUuid uuid; + globalAdminRoleUuid uuid ; + begin + call defineContext('granting global new-sepaMandate permission to global admin role', null, null, null); + + globalAdminRoleUuid := findRoleId(globalAdmin()); + globalObjectUuid := (select uuid from global); + addCustomerPermissions := createPermissions(globalObjectUuid, array ['new-sepamandate']); + call grantPermissionsToRole(globalAdminRoleUuid, addCustomerPermissions); + end; +$$; + +/** + Used by the trigger to prevent the add-customer to current user respectively assumed roles. + */ +create or replace function addHsOfficeSepaMandateNotAllowedForCurrentSubjects() + returns trigger + language PLPGSQL +as $$ +begin + raise exception '[403] new-sepaMandate not permitted for %', + array_to_string(currentSubjects(), ';', 'null'); +end; $$; + +/** + Checks if the user or assumed roles are allowed to create a new customer. + */ +create trigger hs_office_sepaMandate_insert_trigger + before insert + on hs_office_sepaMandate + for each row + -- TODO.spec: who is allowed to create new sepaMandates + when ( not hasAssumedRole() ) +execute procedure addHsOfficeSepaMandateNotAllowedForCurrentSubjects(); +--// + diff --git a/src/main/resources/db/changelog/258-hs-office-sepamandate-test-data.sql b/src/main/resources/db/changelog/258-hs-office-sepamandate-test-data.sql new file mode 100644 index 00000000..7af102a4 --- /dev/null +++ b/src/main/resources/db/changelog/258-hs-office-sepamandate-test-data.sql @@ -0,0 +1,51 @@ +--liquibase formatted sql + + +-- ============================================================================ +--changeset hs-office-sepaMandate-TEST-DATA-GENERATOR:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/* + Creates a single sepaMandate test record. + */ +create or replace procedure createHsOfficeSepaMandateTestData( tradeNameAndHolderName varchar ) + language plpgsql as $$ +declare + currentTask varchar; + idName varchar; + relatedDebitor hs_office_debitor; + relatedBankAccount hs_office_bankAccount; +begin + idName := cleanIdentifier( tradeNameAndHolderName); + currentTask := 'creating SEPA-mandate test-data ' || idName; + call defineContext(currentTask, null, 'superuser-alex@hostsharing.net', 'global#global.admin'); + execute format('set local hsadminng.currentTask to %L', currentTask); + + select debitor.* from hs_office_debitor debitor + join hs_office_partner parter on parter.uuid = debitor.partnerUuid + join hs_office_person person on person.uuid = parter.personUuid + where person.tradeName = tradeNameAndHolderName into relatedDebitor; + select c.* from hs_office_bankAccount c where c.holder = tradeNameAndHolderName into relatedBankAccount; + + raise notice 'creating test SEPA-mandate: %', idName; + raise notice '- using debitor (%): %', relatedDebitor.uuid, relatedDebitor; + raise notice '- using bankAccount (%): %', relatedBankAccount.uuid, relatedBankAccount; + insert + into hs_office_sepaMandate (uuid, debitoruuid, bankAccountuuid, reference, validity) + values (uuid_generate_v4(), relatedDebitor.uuid, relatedBankAccount.uuid, 'ref'||idName, daterange('20221001' , '20261231', '[]')); +end; $$; +--// + + +-- ============================================================================ +--changeset hs-office-sepaMandate-TEST-DATA-GENERATION:1 –context=dev,tc endDelimiter:--// +-- ---------------------------------------------------------------------------- + +do language plpgsql $$ + begin + call createHsOfficeSepaMandateTestData('First GmbH'); + call createHsOfficeSepaMandateTestData('Second e.K.'); + call createHsOfficeSepaMandateTestData('Third OHG'); + end; +$$; +--// diff --git a/src/main/resources/db/changelog/273-hs-office-debitor-rbac.md b/src/main/resources/db/changelog/273-hs-office-debitor-rbac.md index ab738860..55e2459a 100644 --- a/src/main/resources/db/changelog/273-hs-office-debitor-rbac.md +++ b/src/main/resources/db/changelog/273-hs-office-debitor-rbac.md @@ -12,6 +12,8 @@ end subgraph office style office fill:#eee + subgraph sepa + subgraph bankaccount style bankaccount fill: #e9f7ef @@ -40,6 +42,11 @@ subgraph office %% incoming role:hsOfficeBankAccount.tenant ---> role:hsOfficeBankAccount.guest end + + subgraph hsOfficeSepaMandate + end + + end subgraph contact style contact fill: #e9f7ef @@ -186,6 +193,42 @@ subgraph office end +subgraph hsOfficeSepaMandate + + role:hsOfficeSepaMandate.owner[sepaMandate.owner] + %% permissions + role:hsOfficeSepaMandate.owner --> perm:hsOfficeSepaMandate.*{{sepaMandate.*}} + %% incoming + role:global.admin ---> role:hsOfficeSepaMandate.owner + + role:hsOfficeSepaMandate.admin[sepaMandate.admin] + %% permissions + role:hsOfficeSepaMandate.admin --> perm:hsOfficeSepaMandate.edit{{sepaMandate.edit}} + %% incoming + role:hsOfficeSepaMandate.owner ---> role:hsOfficeSepaMandate.admin + + role:hsOfficeSepaMandate.agent[sepaMandate.agent] + %% incoming + role:hsOfficeSepaMandate.admin ---> role:hsOfficeSepaMandate.agent + role:hsOfficeDebitor.admin --> role:hsOfficeSepaMandate.agent + role:hsOfficeBankAccount.admin --> role:hsOfficeSepaMandate.agent + %% outgoing + role:hsOfficeSepaMandate.agent --> role:hsOfficeDebitor.tenant + role:hsOfficeSepaMandate.admin --> role:hsOfficeBankAccount.tenant + + role:hsOfficeSepaMandate.tenant[sepaMandate.tenant] + %% incoming + role:hsOfficeSepaMandate.agent --> role:hsOfficeSepaMandate.tenant + %% outgoing + role:hsOfficeSepaMandate.tenant --> role:hsOfficeDebitor.guest + role:hsOfficeSepaMandate.tenant --> role:hsOfficeBankAccount.guest + + role:hsOfficeSepaMandate.guest[sepaMandate.guest] + %% permissions + role:hsOfficeSepaMandate.guest --> perm:hsOfficeSepaMandate.view{{sepaMandate.view}} + %% incoming + role:hsOfficeSepaMandate.tenant --> role:hsOfficeSepaMandate.guest +end subgraph hosting style hosting fill:#eee diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index 376c4609..4d041f5c 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -85,3 +85,9 @@ databaseChangeLog: file: db/changelog/273-hs-office-debitor-rbac.sql - include: file: db/changelog/278-hs-office-debitor-test-data.sql + - include: + file: db/changelog/250-hs-office-sepamandate.sql + - include: + file: db/changelog/253-hs-office-sepamandate-rbac.sql + - include: + file: db/changelog/258-hs-office-sepamandate-test-data.sql