diff --git a/src/main/resources/db/changelog/203-hs-office-contact-rbac-generated.md b/src/main/resources/db/changelog/203-hs-office-contact-rbac-generated.md new file mode 100644 index 00000000..f3547312 --- /dev/null +++ b/src/main/resources/db/changelog/203-hs-office-contact-rbac-generated.md @@ -0,0 +1,43 @@ +### rbac contact + +This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually. + +```mermaid +%%{init:{'flowchart':{'htmlLabels':false}}}%% +flowchart TB + +subgraph contact["`**contact**`"] + direction TB + style contact fill:#dd4901,stroke:#274d6e,stroke-width:8px + + subgraph contact:roles[ ] + style contact:roles fill:#dd4901,stroke:white + + role:contact:owner[[contact:owner]] + role:contact:admin[[contact:admin]] + role:contact:referrer[[contact:referrer]] + end + + subgraph contact:permissions[ ] + style contact:permissions fill:#dd4901,stroke:white + + perm:contact:DELETE{{contact:DELETE}} + perm:contact:UPDATE{{contact:UPDATE}} + perm:contact:SELECT{{contact:SELECT}} + end +end + +%% granting roles to users +user:creator ==> role:contact:owner + +%% granting roles to roles +role:global:admin ==> role:contact:owner +role:contact:owner ==> role:contact:admin +role:contact:admin ==> role:contact:referrer + +%% granting permissions to roles +role:contact:owner ==> perm:contact:DELETE +role:contact:admin ==> perm:contact:UPDATE +role:contact:referrer ==> perm:contact:SELECT + +``` diff --git a/src/main/resources/db/changelog/203-hs-office-contact-rbac-generated.sql b/src/main/resources/db/changelog/203-hs-office-contact-rbac-generated.sql new file mode 100644 index 00000000..ac0b5114 --- /dev/null +++ b/src/main/resources/db/changelog/203-hs-office-contact-rbac-generated.sql @@ -0,0 +1,125 @@ +--liquibase formatted sql +-- This code generated was by RbacViewPostgresGenerator, do not amend manually. + + +-- ============================================================================ +--changeset hs-office-contact-rbac-OBJECT:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRelatedRbacObject('hs_office_contact'); +--// + + +-- ============================================================================ +--changeset hs-office-contact-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRbacRoleDescriptors('hsOfficeContact', 'hs_office_contact'); +--// + + +-- ============================================================================ +--changeset hs-office-contact-rbac-insert-trigger:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/* + Creates the roles, grants and permission for the AFTER INSERT TRIGGER. + */ + +create or replace procedure buildRbacSystemForHsOfficeContact( + NEW hs_office_contact +) + language plpgsql as $$ + +declare + +begin + call enterTriggerForObjectUuid(NEW.uuid); + + perform createRoleWithGrants( + hsOfficeContactOwner(NEW), + permissions => array['DELETE'], + incomingSuperRoles => array[globalAdmin()], + userUuids => array[currentUserUuid()] + ); + + perform createRoleWithGrants( + hsOfficeContactAdmin(NEW), + permissions => array['UPDATE'], + incomingSuperRoles => array[hsOfficeContactOwner(NEW)] + ); + + perform createRoleWithGrants( + hsOfficeContactReferrer(NEW), + permissions => array['SELECT'], + incomingSuperRoles => array[hsOfficeContactAdmin(NEW)] + ); + + call leaveTriggerForObjectUuid(NEW.uuid); +end; $$; + +/* + AFTER INSERT TRIGGER to create the role+grant structure for a new hs_office_contact row. + */ + +create or replace function insertTriggerForHsOfficeContact_tf() + returns trigger + language plpgsql + strict as $$ +begin + call buildRbacSystemForHsOfficeContact(NEW); + return NEW; +end; $$; + +create trigger insertTriggerForHsOfficeContact_tg + after insert on hs_office_contact + for each row +execute procedure insertTriggerForHsOfficeContact_tf(); +--// + + +-- ============================================================================ +--changeset hs-office-contact-rbac-INSERT:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/** + Checks if the user or assumed roles are allowed to insert a row to hs_office_contact, + where only global-admin has that permission. +*/ +create or replace function hs_office_contact_insert_permission_missing_tf() + returns trigger + language plpgsql as $$ +begin + raise exception '[403] insert into hs_office_contact not allowed for current subjects % (%)', + currentSubjects(), currentSubjectsUuids(); +end; $$; + +create trigger hs_office_contact_insert_permission_check_tg + before insert on hs_office_contact + for each row + when ( not isGlobalAdmin() ) + execute procedure hs_office_contact_insert_permission_missing_tf(); +--// + +-- ============================================================================ +--changeset hs-office-contact-rbac-IDENTITY-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +call generateRbacIdentityViewFromProjection('hs_office_contact', $idName$ + label + $idName$); +--// + +-- ============================================================================ +--changeset hs-office-contact-rbac-RESTRICTED-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRbacRestrictedView('hs_office_contact', + $orderBy$ + label + $orderBy$, + $updates$ + label = new.label, + postalAddress = new.postalAddress, + emailAddresses = new.emailAddresses, + phoneNumbers = new.phoneNumbers + $updates$); +--// + diff --git a/src/main/resources/db/changelog/213-hs-office-person-rbac-generated.md b/src/main/resources/db/changelog/213-hs-office-person-rbac-generated.md new file mode 100644 index 00000000..aa971642 --- /dev/null +++ b/src/main/resources/db/changelog/213-hs-office-person-rbac-generated.md @@ -0,0 +1,43 @@ +### rbac person + +This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually. + +```mermaid +%%{init:{'flowchart':{'htmlLabels':false}}}%% +flowchart TB + +subgraph person["`**person**`"] + direction TB + style person fill:#dd4901,stroke:#274d6e,stroke-width:8px + + subgraph person:roles[ ] + style person:roles fill:#dd4901,stroke:white + + role:person:owner[[person:owner]] + role:person:admin[[person:admin]] + role:person:referrer[[person:referrer]] + end + + subgraph person:permissions[ ] + style person:permissions fill:#dd4901,stroke:white + + perm:person:DELETE{{person:DELETE}} + perm:person:UPDATE{{person:UPDATE}} + perm:person:SELECT{{person:SELECT}} + end +end + +%% granting roles to users +user:creator ==> role:person:owner + +%% granting roles to roles +role:global:admin ==> role:person:owner +role:person:owner ==> role:person:admin +role:person:admin ==> role:person:referrer + +%% granting permissions to roles +role:person:owner ==> perm:person:DELETE +role:person:admin ==> perm:person:UPDATE +role:person:referrer ==> perm:person:SELECT + +``` diff --git a/src/main/resources/db/changelog/213-hs-office-person-rbac-generated.sql b/src/main/resources/db/changelog/213-hs-office-person-rbac-generated.sql new file mode 100644 index 00000000..afd7ed66 --- /dev/null +++ b/src/main/resources/db/changelog/213-hs-office-person-rbac-generated.sql @@ -0,0 +1,125 @@ +--liquibase formatted sql +-- This code generated was by RbacViewPostgresGenerator, do not amend manually. + + +-- ============================================================================ +--changeset hs-office-person-rbac-OBJECT:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRelatedRbacObject('hs_office_person'); +--// + + +-- ============================================================================ +--changeset hs-office-person-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRbacRoleDescriptors('hsOfficePerson', 'hs_office_person'); +--// + + +-- ============================================================================ +--changeset hs-office-person-rbac-insert-trigger:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/* + Creates the roles, grants and permission for the AFTER INSERT TRIGGER. + */ + +create or replace procedure buildRbacSystemForHsOfficePerson( + NEW hs_office_person +) + language plpgsql as $$ + +declare + +begin + call enterTriggerForObjectUuid(NEW.uuid); + + perform createRoleWithGrants( + hsOfficePersonOwner(NEW), + permissions => array['DELETE'], + incomingSuperRoles => array[globalAdmin()], + userUuids => array[currentUserUuid()] + ); + + perform createRoleWithGrants( + hsOfficePersonAdmin(NEW), + permissions => array['UPDATE'], + incomingSuperRoles => array[hsOfficePersonOwner(NEW)] + ); + + perform createRoleWithGrants( + hsOfficePersonReferrer(NEW), + permissions => array['SELECT'], + incomingSuperRoles => array[hsOfficePersonAdmin(NEW)] + ); + + call leaveTriggerForObjectUuid(NEW.uuid); +end; $$; + +/* + AFTER INSERT TRIGGER to create the role+grant structure for a new hs_office_person row. + */ + +create or replace function insertTriggerForHsOfficePerson_tf() + returns trigger + language plpgsql + strict as $$ +begin + call buildRbacSystemForHsOfficePerson(NEW); + return NEW; +end; $$; + +create trigger insertTriggerForHsOfficePerson_tg + after insert on hs_office_person + for each row +execute procedure insertTriggerForHsOfficePerson_tf(); +--// + + +-- ============================================================================ +--changeset hs-office-person-rbac-INSERT:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/** + Checks if the user or assumed roles are allowed to insert a row to hs_office_person, + where only global-admin has that permission. +*/ +create or replace function hs_office_person_insert_permission_missing_tf() + returns trigger + language plpgsql as $$ +begin + raise exception '[403] insert into hs_office_person not allowed for current subjects % (%)', + currentSubjects(), currentSubjectsUuids(); +end; $$; + +create trigger hs_office_person_insert_permission_check_tg + before insert on hs_office_person + for each row + when ( not isGlobalAdmin() ) + execute procedure hs_office_person_insert_permission_missing_tf(); +--// + +-- ============================================================================ +--changeset hs-office-person-rbac-IDENTITY-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +call generateRbacIdentityViewFromProjection('hs_office_person', $idName$ + concat(tradeName, familyName, givenName) + $idName$); +--// + +-- ============================================================================ +--changeset hs-office-person-rbac-RESTRICTED-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRbacRestrictedView('hs_office_person', + $orderBy$ + concat(tradeName, familyName, givenName) + $orderBy$, + $updates$ + personType = new.personType, + tradeName = new.tradeName, + givenName = new.givenName, + familyName = new.familyName + $updates$); +--// + diff --git a/src/main/resources/db/changelog/223-hs-office-relation-rbac-generated.md b/src/main/resources/db/changelog/223-hs-office-relation-rbac-generated.md new file mode 100644 index 00000000..14f797eb --- /dev/null +++ b/src/main/resources/db/changelog/223-hs-office-relation-rbac-generated.md @@ -0,0 +1,100 @@ +### rbac relation + +This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually. + +```mermaid +%%{init:{'flowchart':{'htmlLabels':false}}}%% +flowchart TB + +subgraph holderPerson["`**holderPerson**`"] + direction TB + style holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph holderPerson:roles[ ] + style holderPerson:roles fill:#99bcdb,stroke:white + + role:holderPerson:owner[[holderPerson:owner]] + role:holderPerson:admin[[holderPerson:admin]] + role:holderPerson:referrer[[holderPerson:referrer]] + end +end + +subgraph anchorPerson["`**anchorPerson**`"] + direction TB + style anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph anchorPerson:roles[ ] + style anchorPerson:roles fill:#99bcdb,stroke:white + + role:anchorPerson:owner[[anchorPerson:owner]] + role:anchorPerson:admin[[anchorPerson:admin]] + role:anchorPerson:referrer[[anchorPerson:referrer]] + end +end + +subgraph contact["`**contact**`"] + direction TB + style contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph contact:roles[ ] + style contact:roles fill:#99bcdb,stroke:white + + role:contact:owner[[contact:owner]] + role:contact:admin[[contact:admin]] + role:contact:referrer[[contact:referrer]] + end +end + +subgraph relation["`**relation**`"] + direction TB + style relation fill:#dd4901,stroke:#274d6e,stroke-width:8px + + subgraph relation:roles[ ] + style relation:roles fill:#dd4901,stroke:white + + role:relation:owner[[relation:owner]] + role:relation:admin[[relation:admin]] + role:relation:agent[[relation:agent]] + role:relation:tenant[[relation:tenant]] + end + + subgraph relation:permissions[ ] + style relation:permissions fill:#dd4901,stroke:white + + perm:relation:DELETE{{relation:DELETE}} + perm:relation:UPDATE{{relation:UPDATE}} + perm:relation:SELECT{{relation:SELECT}} + end +end + +%% granting roles to users +user:creator ==> role:relation:owner + +%% granting roles to roles +role:global:admin -.-> role:anchorPerson:owner +role:anchorPerson:owner -.-> role:anchorPerson:admin +role:anchorPerson:admin -.-> role:anchorPerson:referrer +role:global:admin -.-> role:holderPerson:owner +role:holderPerson:owner -.-> role:holderPerson:admin +role:holderPerson:admin -.-> role:holderPerson:referrer +role:global:admin -.-> role:contact:owner +role:contact:owner -.-> role:contact:admin +role:contact:admin -.-> role:contact:referrer +role:global:admin ==> role:relation:owner +role:relation:owner ==> role:relation:admin +role:anchorPerson:admin ==> role:relation:admin +role:relation:admin ==> role:relation:agent +role:holderPerson:admin ==> role:relation:agent +role:relation:agent ==> role:relation:tenant +role:holderPerson:admin ==> role:relation:tenant +role:contact:admin ==> role:relation:tenant +role:relation:tenant ==> role:anchorPerson:referrer +role:relation:tenant ==> role:holderPerson:referrer +role:relation:tenant ==> role:contact:referrer + +%% granting permissions to roles +role:relation:owner ==> perm:relation:DELETE +role:relation:admin ==> perm:relation:UPDATE +role:relation:tenant ==> perm:relation:SELECT + +``` diff --git a/src/main/resources/db/changelog/223-hs-office-relation-rbac-generated.sql b/src/main/resources/db/changelog/223-hs-office-relation-rbac-generated.sql new file mode 100644 index 00000000..9a1f7d1b --- /dev/null +++ b/src/main/resources/db/changelog/223-hs-office-relation-rbac-generated.sql @@ -0,0 +1,231 @@ +--liquibase formatted sql +-- This code generated was by RbacViewPostgresGenerator, do not amend manually. + + +-- ============================================================================ +--changeset hs-office-relation-rbac-OBJECT:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRelatedRbacObject('hs_office_relation'); +--// + + +-- ============================================================================ +--changeset hs-office-relation-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRbacRoleDescriptors('hsOfficeRelation', 'hs_office_relation'); +--// + + +-- ============================================================================ +--changeset hs-office-relation-rbac-insert-trigger:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/* + Creates the roles, grants and permission for the AFTER INSERT TRIGGER. + */ + +create or replace procedure buildRbacSystemForHsOfficeRelation( + NEW hs_office_relation +) + language plpgsql as $$ + +declare + newHolderPerson hs_office_person; + newAnchorPerson hs_office_person; + newContact hs_office_contact; + +begin + call enterTriggerForObjectUuid(NEW.uuid); + + select * from hs_office_person as p where p.uuid = NEW.holderUuid INTO newHolderPerson; + assert newHolderPerson.uuid is not null, format('newHolderPerson must not be null for NEW.holderUuid = %s', NEW.holderUuid); + + select * from hs_office_person as p where p.uuid = NEW.anchorUuid INTO newAnchorPerson; + assert newAnchorPerson.uuid is not null, format('newAnchorPerson must not be null for NEW.anchorUuid = %s', NEW.anchorUuid); + + select * from hs_office_contact as c where c.uuid = NEW.contactUuid INTO newContact; + assert newContact.uuid is not null, format('newContact must not be null for NEW.contactUuid = %s', NEW.contactUuid); + + + perform createRoleWithGrants( + hsOfficeRelationOwner(NEW), + permissions => array['DELETE'], + incomingSuperRoles => array[globalAdmin()], + userUuids => array[currentUserUuid()] + ); + + perform createRoleWithGrants( + hsOfficeRelationAdmin(NEW), + permissions => array['UPDATE'], + incomingSuperRoles => array[ + hsOfficePersonAdmin(newAnchorPerson), + hsOfficeRelationOwner(NEW)] + ); + + perform createRoleWithGrants( + hsOfficeRelationAgent(NEW), + incomingSuperRoles => array[ + hsOfficePersonAdmin(newHolderPerson), + hsOfficeRelationAdmin(NEW)] + ); + + perform createRoleWithGrants( + hsOfficeRelationTenant(NEW), + permissions => array['SELECT'], + incomingSuperRoles => array[ + hsOfficeRelationAgent(NEW), + hsOfficeContactAdmin(newContact), + hsOfficePersonAdmin(newHolderPerson)], + outgoingSubRoles => array[ + hsOfficePersonReferrer(newHolderPerson), + hsOfficeContactReferrer(newContact), + hsOfficePersonReferrer(newAnchorPerson)] + ); + + call leaveTriggerForObjectUuid(NEW.uuid); +end; $$; + +/* + AFTER INSERT TRIGGER to create the role+grant structure for a new hs_office_relation row. + */ + +create or replace function insertTriggerForHsOfficeRelation_tf() + returns trigger + language plpgsql + strict as $$ +begin + call buildRbacSystemForHsOfficeRelation(NEW); + return NEW; +end; $$; + +create trigger insertTriggerForHsOfficeRelation_tg + after insert on hs_office_relation + for each row +execute procedure insertTriggerForHsOfficeRelation_tf(); +--// + + +-- ============================================================================ +--changeset hs-office-relation-rbac-update-trigger:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/* + Called from the AFTER UPDATE TRIGGER to re-wire the grants. + */ + +create or replace procedure updateRbacRulesForHsOfficeRelation( + OLD hs_office_relation, + NEW hs_office_relation +) + language plpgsql as $$ + +declare + oldHolderPerson hs_office_person; + newHolderPerson hs_office_person; + oldAnchorPerson hs_office_person; + newAnchorPerson hs_office_person; + oldContact hs_office_contact; + newContact hs_office_contact; + +begin + call enterTriggerForObjectUuid(NEW.uuid); + + select * from hs_office_person as p where p.uuid = OLD.holderUuid INTO oldHolderPerson; + assert oldHolderPerson.uuid is not null, format('oldHolderPerson must not be null for OLD.holderUuid = %s', OLD.holderUuid); + + select * from hs_office_person as p where p.uuid = NEW.holderUuid INTO newHolderPerson; + assert newHolderPerson.uuid is not null, format('newHolderPerson must not be null for NEW.holderUuid = %s', NEW.holderUuid); + + select * from hs_office_person as p where p.uuid = OLD.anchorUuid INTO oldAnchorPerson; + assert oldAnchorPerson.uuid is not null, format('oldAnchorPerson must not be null for OLD.anchorUuid = %s', OLD.anchorUuid); + + select * from hs_office_person as p where p.uuid = NEW.anchorUuid INTO newAnchorPerson; + assert newAnchorPerson.uuid is not null, format('newAnchorPerson must not be null for NEW.anchorUuid = %s', NEW.anchorUuid); + + select * from hs_office_contact as c where c.uuid = OLD.contactUuid INTO oldContact; + assert oldContact.uuid is not null, format('oldContact must not be null for OLD.contactUuid = %s', OLD.contactUuid); + + select * from hs_office_contact as c where c.uuid = NEW.contactUuid INTO newContact; + assert newContact.uuid is not null, format('newContact must not be null for NEW.contactUuid = %s', NEW.contactUuid); + + + if NEW.contactUuid <> OLD.contactUuid then + + call revokeRoleFromRole(hsOfficeRelationTenant(OLD), hsOfficeContactAdmin(oldContact)); + call grantRoleToRole(hsOfficeRelationTenant(NEW), hsOfficeContactAdmin(newContact)); + + call revokeRoleFromRole(hsOfficeContactReferrer(oldContact), hsOfficeRelationTenant(OLD)); + call grantRoleToRole(hsOfficeContactReferrer(newContact), hsOfficeRelationTenant(NEW)); + + end if; + + call leaveTriggerForObjectUuid(NEW.uuid); +end; $$; + +/* + AFTER INSERT TRIGGER to re-wire the grant structure for a new hs_office_relation row. + */ + +create or replace function updateTriggerForHsOfficeRelation_tf() + returns trigger + language plpgsql + strict as $$ +begin + call updateRbacRulesForHsOfficeRelation(OLD, NEW); + return NEW; +end; $$; + +create trigger updateTriggerForHsOfficeRelation_tg + after update on hs_office_relation + for each row +execute procedure updateTriggerForHsOfficeRelation_tf(); +--// + + +-- ============================================================================ +--changeset hs-office-relation-rbac-INSERT:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/** + Checks if the user or assumed roles are allowed to insert a row to hs_office_relation, + where only global-admin has that permission. +*/ +create or replace function hs_office_relation_insert_permission_missing_tf() + returns trigger + language plpgsql as $$ +begin + raise exception '[403] insert into hs_office_relation not allowed for current subjects % (%)', + currentSubjects(), currentSubjectsUuids(); +end; $$; + +create trigger hs_office_relation_insert_permission_check_tg + before insert on hs_office_relation + for each row + when ( not isGlobalAdmin() ) + execute procedure hs_office_relation_insert_permission_missing_tf(); +--// + +-- ============================================================================ +--changeset hs-office-relation-rbac-IDENTITY-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +call generateRbacIdentityViewFromProjection('hs_office_relation', $idName$ + (select idName from hs_office_person_iv p where p.uuid = anchorUuid) + || '-with-' || target.type || '-' + || (select idName from hs_office_person_iv p where p.uuid = holderUuid) + + $idName$); +--// + +-- ============================================================================ +--changeset hs-office-relation-rbac-RESTRICTED-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRbacRestrictedView('hs_office_relation', + $orderBy$ + (select idName from hs_office_person_iv p where p.uuid = target.holderUuid) + $orderBy$, + $updates$ + contactUuid = new.contactUuid + $updates$); +--// + diff --git a/src/main/resources/db/changelog/233-hs-office-partner-rbac-generated.md b/src/main/resources/db/changelog/233-hs-office-partner-rbac-generated.md new file mode 100644 index 00000000..98bd276d --- /dev/null +++ b/src/main/resources/db/changelog/233-hs-office-partner-rbac-generated.md @@ -0,0 +1,158 @@ +### rbac partner + +This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually. + +```mermaid +%%{init:{'flowchart':{'htmlLabels':false}}}%% +flowchart TB + +subgraph partnerRel.contact["`**partnerRel.contact**`"] + direction TB + style partnerRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.contact:roles[ ] + style partnerRel.contact:roles fill:#99bcdb,stroke:white + + role:partnerRel.contact:owner[[partnerRel.contact:owner]] + role:partnerRel.contact:admin[[partnerRel.contact:admin]] + role:partnerRel.contact:referrer[[partnerRel.contact:referrer]] + end +end + +subgraph partner["`**partner**`"] + direction TB + style partner fill:#dd4901,stroke:#274d6e,stroke-width:8px + + subgraph partner:permissions[ ] + style partner:permissions fill:#dd4901,stroke:white + + perm:partner:INSERT{{partner:INSERT}} + perm:partner:DELETE{{partner:DELETE}} + perm:partner:UPDATE{{partner:UPDATE}} + perm:partner:SELECT{{partner:SELECT}} + end + + subgraph partnerRel["`**partnerRel**`"] + direction TB + style partnerRel fill:#99bcdb,stroke:#274d6e,stroke-width:8px + subgraph partnerRel.contact["`**partnerRel.contact**`"] + direction TB + style partnerRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.contact:roles[ ] + style partnerRel.contact:roles fill:#99bcdb,stroke:white + + role:partnerRel.contact:owner[[partnerRel.contact:owner]] + role:partnerRel.contact:admin[[partnerRel.contact:admin]] + role:partnerRel.contact:referrer[[partnerRel.contact:referrer]] + end + end + + subgraph partnerRel.anchorPerson["`**partnerRel.anchorPerson**`"] + direction TB + style partnerRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.anchorPerson:roles[ ] + style partnerRel.anchorPerson:roles fill:#99bcdb,stroke:white + + role:partnerRel.anchorPerson:owner[[partnerRel.anchorPerson:owner]] + role:partnerRel.anchorPerson:admin[[partnerRel.anchorPerson:admin]] + role:partnerRel.anchorPerson:referrer[[partnerRel.anchorPerson:referrer]] + end + end + + subgraph partnerRel.holderPerson["`**partnerRel.holderPerson**`"] + direction TB + style partnerRel.holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.holderPerson:roles[ ] + style partnerRel.holderPerson:roles fill:#99bcdb,stroke:white + + role:partnerRel.holderPerson:owner[[partnerRel.holderPerson:owner]] + role:partnerRel.holderPerson:admin[[partnerRel.holderPerson:admin]] + role:partnerRel.holderPerson:referrer[[partnerRel.holderPerson:referrer]] + end + end + + subgraph partnerRel:roles[ ] + style partnerRel:roles fill:#99bcdb,stroke:white + + role:partnerRel:owner[[partnerRel:owner]] + role:partnerRel:admin[[partnerRel:admin]] + role:partnerRel:agent[[partnerRel:agent]] + role:partnerRel:tenant[[partnerRel:tenant]] + end + end +end + +subgraph partnerDetails["`**partnerDetails**`"] + direction TB + style partnerDetails fill:#feb28c,stroke:#274d6e,stroke-width:8px + + subgraph partnerDetails:permissions[ ] + style partnerDetails:permissions fill:#feb28c,stroke:white + + perm:partnerDetails:DELETE{{partnerDetails:DELETE}} + perm:partnerDetails:UPDATE{{partnerDetails:UPDATE}} + perm:partnerDetails:SELECT{{partnerDetails:SELECT}} + end +end + +subgraph partnerRel.anchorPerson["`**partnerRel.anchorPerson**`"] + direction TB + style partnerRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.anchorPerson:roles[ ] + style partnerRel.anchorPerson:roles fill:#99bcdb,stroke:white + + role:partnerRel.anchorPerson:owner[[partnerRel.anchorPerson:owner]] + role:partnerRel.anchorPerson:admin[[partnerRel.anchorPerson:admin]] + role:partnerRel.anchorPerson:referrer[[partnerRel.anchorPerson:referrer]] + end +end + +subgraph partnerRel.holderPerson["`**partnerRel.holderPerson**`"] + direction TB + style partnerRel.holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.holderPerson:roles[ ] + style partnerRel.holderPerson:roles fill:#99bcdb,stroke:white + + role:partnerRel.holderPerson:owner[[partnerRel.holderPerson:owner]] + role:partnerRel.holderPerson:admin[[partnerRel.holderPerson:admin]] + role:partnerRel.holderPerson:referrer[[partnerRel.holderPerson:referrer]] + end +end + +%% granting roles to roles +role:global:admin -.-> role:partnerRel.anchorPerson:owner +role:partnerRel.anchorPerson:owner -.-> role:partnerRel.anchorPerson:admin +role:partnerRel.anchorPerson:admin -.-> role:partnerRel.anchorPerson:referrer +role:global:admin -.-> role:partnerRel.holderPerson:owner +role:partnerRel.holderPerson:owner -.-> role:partnerRel.holderPerson:admin +role:partnerRel.holderPerson:admin -.-> role:partnerRel.holderPerson:referrer +role:global:admin -.-> role:partnerRel.contact:owner +role:partnerRel.contact:owner -.-> role:partnerRel.contact:admin +role:partnerRel.contact:admin -.-> role:partnerRel.contact:referrer +role:global:admin -.-> role:partnerRel:owner +role:partnerRel:owner -.-> role:partnerRel:admin +role:partnerRel.anchorPerson:admin -.-> role:partnerRel:admin +role:partnerRel:admin -.-> role:partnerRel:agent +role:partnerRel.holderPerson:admin -.-> role:partnerRel:agent +role:partnerRel:agent -.-> role:partnerRel:tenant +role:partnerRel.holderPerson:admin -.-> role:partnerRel:tenant +role:partnerRel.contact:admin -.-> role:partnerRel:tenant +role:partnerRel:tenant -.-> role:partnerRel.anchorPerson:referrer +role:partnerRel:tenant -.-> role:partnerRel.holderPerson:referrer +role:partnerRel:tenant -.-> role:partnerRel.contact:referrer + +%% granting permissions to roles +role:global:admin ==> perm:partner:INSERT +role:partnerRel:admin ==> perm:partner:DELETE +role:partnerRel:agent ==> perm:partner:UPDATE +role:partnerRel:tenant ==> perm:partner:SELECT +role:partnerRel:admin ==> perm:partnerDetails:DELETE +role:partnerRel:agent ==> perm:partnerDetails:UPDATE +role:partnerRel:agent ==> perm:partnerDetails:SELECT + +``` diff --git a/src/main/resources/db/changelog/233-hs-office-partner-rbac-generated.sql b/src/main/resources/db/changelog/233-hs-office-partner-rbac-generated.sql new file mode 100644 index 00000000..683a8892 --- /dev/null +++ b/src/main/resources/db/changelog/233-hs-office-partner-rbac-generated.sql @@ -0,0 +1,248 @@ +--liquibase formatted sql +-- This code generated was by RbacViewPostgresGenerator, do not amend manually. + + +-- ============================================================================ +--changeset hs-office-partner-rbac-OBJECT:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRelatedRbacObject('hs_office_partner'); +--// + + +-- ============================================================================ +--changeset hs-office-partner-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRbacRoleDescriptors('hsOfficePartner', 'hs_office_partner'); +--// + + +-- ============================================================================ +--changeset hs-office-partner-rbac-insert-trigger:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/* + Creates the roles, grants and permission for the AFTER INSERT TRIGGER. + */ + +create or replace procedure buildRbacSystemForHsOfficePartner( + NEW hs_office_partner +) + language plpgsql as $$ + +declare + newPartnerRel hs_office_relation; + newPartnerDetails hs_office_partner_details; + +begin + call enterTriggerForObjectUuid(NEW.uuid); + + SELECT * FROM hs_office_relation AS r WHERE r.uuid = NEW.partnerRelUuid INTO newPartnerRel; + assert newPartnerRel.uuid is not null, format('newPartnerRel must not be null for NEW.partnerRelUuid = %s', NEW.partnerRelUuid); + + SELECT * FROM hs_office_partner_details AS d WHERE d.uuid = NEW.detailsUuid INTO newPartnerDetails; + assert newPartnerDetails.uuid is not null, format('newPartnerDetails must not be null for NEW.detailsUuid = %s', NEW.detailsUuid); + + call grantPermissionToRole(createPermission(NEW.uuid, 'DELETE'), hsOfficeRelationAdmin(newPartnerRel)); + call grantPermissionToRole(createPermission(NEW.uuid, 'SELECT'), hsOfficeRelationTenant(newPartnerRel)); + call grantPermissionToRole(createPermission(NEW.uuid, 'UPDATE'), hsOfficeRelationAgent(newPartnerRel)); + call grantPermissionToRole(createPermission(newPartnerDetails.uuid, 'DELETE'), hsOfficeRelationAdmin(newPartnerRel)); + call grantPermissionToRole(createPermission(newPartnerDetails.uuid, 'SELECT'), hsOfficeRelationAgent(newPartnerRel)); + call grantPermissionToRole(createPermission(newPartnerDetails.uuid, 'UPDATE'), hsOfficeRelationAgent(newPartnerRel)); + + call leaveTriggerForObjectUuid(NEW.uuid); +end; $$; + +/* + AFTER INSERT TRIGGER to create the role+grant structure for a new hs_office_partner row. + */ + +create or replace function insertTriggerForHsOfficePartner_tf() + returns trigger + language plpgsql + strict as $$ +begin + call buildRbacSystemForHsOfficePartner(NEW); + return NEW; +end; $$; + +create trigger insertTriggerForHsOfficePartner_tg + after insert on hs_office_partner + for each row +execute procedure insertTriggerForHsOfficePartner_tf(); +--// + + +-- ============================================================================ +--changeset hs-office-partner-rbac-update-trigger:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/* + Called from the AFTER UPDATE TRIGGER to re-wire the grants. + */ + +create or replace procedure updateRbacRulesForHsOfficePartner( + OLD hs_office_partner, + NEW hs_office_partner +) + language plpgsql as $$ + +declare + oldPartnerRel hs_office_relation; + newPartnerRel hs_office_relation; + oldPartnerDetails hs_office_partner_details; + newPartnerDetails hs_office_partner_details; + +begin + call enterTriggerForObjectUuid(NEW.uuid); + + SELECT * FROM hs_office_relation AS r WHERE r.uuid = OLD.partnerRelUuid INTO oldPartnerRel; + assert oldPartnerRel.uuid is not null, format('oldPartnerRel must not be null for OLD.partnerRelUuid = %s', OLD.partnerRelUuid); + + SELECT * FROM hs_office_relation AS r WHERE r.uuid = NEW.partnerRelUuid INTO newPartnerRel; + assert newPartnerRel.uuid is not null, format('newPartnerRel must not be null for NEW.partnerRelUuid = %s', NEW.partnerRelUuid); + + SELECT * FROM hs_office_partner_details AS d WHERE d.uuid = OLD.detailsUuid INTO oldPartnerDetails; + assert oldPartnerDetails.uuid is not null, format('oldPartnerDetails must not be null for OLD.detailsUuid = %s', OLD.detailsUuid); + + SELECT * FROM hs_office_partner_details AS d WHERE d.uuid = NEW.detailsUuid INTO newPartnerDetails; + assert newPartnerDetails.uuid is not null, format('newPartnerDetails must not be null for NEW.detailsUuid = %s', NEW.detailsUuid); + + + if NEW.partnerRelUuid <> OLD.partnerRelUuid then + + call revokePermissionFromRole(getPermissionId(OLD.uuid, 'DELETE'), hsOfficeRelationAdmin(oldPartnerRel)); + call grantPermissionToRole(createPermission(NEW.uuid, 'DELETE'), hsOfficeRelationAdmin(newPartnerRel)); + + call revokePermissionFromRole(getPermissionId(OLD.uuid, 'UPDATE'), hsOfficeRelationAgent(oldPartnerRel)); + call grantPermissionToRole(createPermission(NEW.uuid, 'UPDATE'), hsOfficeRelationAgent(newPartnerRel)); + + call revokePermissionFromRole(getPermissionId(OLD.uuid, 'SELECT'), hsOfficeRelationTenant(oldPartnerRel)); + call grantPermissionToRole(createPermission(NEW.uuid, 'SELECT'), hsOfficeRelationTenant(newPartnerRel)); + + call revokePermissionFromRole(getPermissionId(oldPartnerDetails.uuid, 'DELETE'), hsOfficeRelationAdmin(oldPartnerRel)); + call grantPermissionToRole(createPermission(newPartnerDetails.uuid, 'DELETE'), hsOfficeRelationAdmin(newPartnerRel)); + + call revokePermissionFromRole(getPermissionId(oldPartnerDetails.uuid, 'UPDATE'), hsOfficeRelationAgent(oldPartnerRel)); + call grantPermissionToRole(createPermission(newPartnerDetails.uuid, 'UPDATE'), hsOfficeRelationAgent(newPartnerRel)); + + call revokePermissionFromRole(getPermissionId(oldPartnerDetails.uuid, 'SELECT'), hsOfficeRelationAgent(oldPartnerRel)); + call grantPermissionToRole(createPermission(newPartnerDetails.uuid, 'SELECT'), hsOfficeRelationAgent(newPartnerRel)); + + end if; + + call leaveTriggerForObjectUuid(NEW.uuid); +end; $$; + +/* + AFTER INSERT TRIGGER to re-wire the grant structure for a new hs_office_partner row. + */ + +create or replace function updateTriggerForHsOfficePartner_tf() + returns trigger + language plpgsql + strict as $$ +begin + call updateRbacRulesForHsOfficePartner(OLD, NEW); + return NEW; +end; $$; + +create trigger updateTriggerForHsOfficePartner_tg + after update on hs_office_partner + for each row +execute procedure updateTriggerForHsOfficePartner_tf(); +--// + + +-- ============================================================================ +--changeset hs-office-partner-rbac-INSERT:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/* + Creates INSERT INTO hs_office_partner permissions for the related global rows. + */ +do language plpgsql $$ + declare + row global; + permissionUuid uuid; + roleUuid uuid; + begin + call defineContext('create INSERT INTO hs_office_partner permissions for the related global rows'); + + FOR row IN SELECT * FROM global + LOOP + roleUuid := findRoleId(globalAdmin()); + permissionUuid := createPermission(row.uuid, 'INSERT', 'hs_office_partner'); + call grantPermissionToRole(permissionUuid, roleUuid); + END LOOP; + END; +$$; + +/** + Adds hs_office_partner INSERT permission to specified role of new global rows. +*/ +create or replace function hs_office_partner_global_insert_tf() + returns trigger + language plpgsql + strict as $$ +begin + call grantPermissionToRole( + createPermission(NEW.uuid, 'INSERT', 'hs_office_partner'), + globalAdmin()); + return NEW; +end; $$; + +-- z_... is to put it at the end of after insert triggers, to make sure the roles exist +create trigger z_hs_office_partner_global_insert_tg + after insert on global + for each row +execute procedure hs_office_partner_global_insert_tf(); + +/** + Checks if the user or assumed roles are allowed to insert a row to hs_office_partner, + where only global-admin has that permission. +*/ +create or replace function hs_office_partner_insert_permission_missing_tf() + returns trigger + language plpgsql as $$ +begin + raise exception '[403] insert into hs_office_partner not allowed for current subjects % (%)', + currentSubjects(), currentSubjectsUuids(); +end; $$; + +create trigger hs_office_partner_insert_permission_check_tg + before insert on hs_office_partner + for each row + when ( not isGlobalAdmin() ) + execute procedure hs_office_partner_insert_permission_missing_tf(); +--// + +-- ============================================================================ +--changeset hs-office-partner-rbac-IDENTITY-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + + call generateRbacIdentityViewFromQuery('hs_office_partner', $idName$ + SELECT partner.partnerNumber + || ':' || (SELECT idName FROM hs_office_person_iv p WHERE p.uuid = partner.personUuid) + || '-' || (SELECT idName FROM hs_office_contact_iv c WHERE c.uuid = partner.contactUuid) + FROM hs_office_partner AS partner + + $idName$); +--// + +-- ============================================================================ +--changeset hs-office-partner-rbac-RESTRICTED-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRbacRestrictedView('hs_office_partner', + $orderBy$ + SELECT partner.partnerNumber + || ':' || (SELECT idName FROM hs_office_person_iv p WHERE p.uuid = partner.personUuid) + || '-' || (SELECT idName FROM hs_office_contact_iv c WHERE c.uuid = partner.contactUuid) + FROM hs_office_partner AS partner + $orderBy$, + $updates$ + partnerRelUuid = new.partnerRelUuid, + personUuid = new.personUuid, + contactUuid = new.contactUuid + $updates$); +--// + diff --git a/src/main/resources/db/changelog/234-hs-office-partner-details-rbac-generated.md b/src/main/resources/db/changelog/234-hs-office-partner-details-rbac-generated.md new file mode 100644 index 00000000..ece32f9c --- /dev/null +++ b/src/main/resources/db/changelog/234-hs-office-partner-details-rbac-generated.md @@ -0,0 +1,136 @@ +### rbac partnerDetails + +This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually. + +```mermaid +%%{init:{'flowchart':{'htmlLabels':false}}}%% +flowchart TB + +subgraph partnerRel.contact["`**partnerRel.contact**`"] + direction TB + style partnerRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.contact:roles[ ] + style partnerRel.contact:roles fill:#99bcdb,stroke:white + + role:partnerRel.contact:owner[[partnerRel.contact:owner]] + role:partnerRel.contact:admin[[partnerRel.contact:admin]] + role:partnerRel.contact:referrer[[partnerRel.contact:referrer]] + end +end + +subgraph partnerDetails["`**partnerDetails**`"] + direction TB + style partnerDetails fill:#dd4901,stroke:#274d6e,stroke-width:8px + + subgraph partnerDetails:permissions[ ] + style partnerDetails:permissions fill:#dd4901,stroke:white + + perm:partnerDetails:INSERT{{partnerDetails:INSERT}} + end + + subgraph partnerRel["`**partnerRel**`"] + direction TB + style partnerRel fill:#99bcdb,stroke:#274d6e,stroke-width:8px + subgraph partnerRel.contact["`**partnerRel.contact**`"] + direction TB + style partnerRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.contact:roles[ ] + style partnerRel.contact:roles fill:#99bcdb,stroke:white + + role:partnerRel.contact:owner[[partnerRel.contact:owner]] + role:partnerRel.contact:admin[[partnerRel.contact:admin]] + role:partnerRel.contact:referrer[[partnerRel.contact:referrer]] + end + end + + subgraph partnerRel.anchorPerson["`**partnerRel.anchorPerson**`"] + direction TB + style partnerRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.anchorPerson:roles[ ] + style partnerRel.anchorPerson:roles fill:#99bcdb,stroke:white + + role:partnerRel.anchorPerson:owner[[partnerRel.anchorPerson:owner]] + role:partnerRel.anchorPerson:admin[[partnerRel.anchorPerson:admin]] + role:partnerRel.anchorPerson:referrer[[partnerRel.anchorPerson:referrer]] + end + end + + subgraph partnerRel.holderPerson["`**partnerRel.holderPerson**`"] + direction TB + style partnerRel.holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.holderPerson:roles[ ] + style partnerRel.holderPerson:roles fill:#99bcdb,stroke:white + + role:partnerRel.holderPerson:owner[[partnerRel.holderPerson:owner]] + role:partnerRel.holderPerson:admin[[partnerRel.holderPerson:admin]] + role:partnerRel.holderPerson:referrer[[partnerRel.holderPerson:referrer]] + end + end + + subgraph partnerRel:roles[ ] + style partnerRel:roles fill:#99bcdb,stroke:white + + role:partnerRel:owner[[partnerRel:owner]] + role:partnerRel:admin[[partnerRel:admin]] + role:partnerRel:agent[[partnerRel:agent]] + role:partnerRel:tenant[[partnerRel:tenant]] + end + end +end + +subgraph partnerRel.anchorPerson["`**partnerRel.anchorPerson**`"] + direction TB + style partnerRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.anchorPerson:roles[ ] + style partnerRel.anchorPerson:roles fill:#99bcdb,stroke:white + + role:partnerRel.anchorPerson:owner[[partnerRel.anchorPerson:owner]] + role:partnerRel.anchorPerson:admin[[partnerRel.anchorPerson:admin]] + role:partnerRel.anchorPerson:referrer[[partnerRel.anchorPerson:referrer]] + end +end + +subgraph partnerRel.holderPerson["`**partnerRel.holderPerson**`"] + direction TB + style partnerRel.holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.holderPerson:roles[ ] + style partnerRel.holderPerson:roles fill:#99bcdb,stroke:white + + role:partnerRel.holderPerson:owner[[partnerRel.holderPerson:owner]] + role:partnerRel.holderPerson:admin[[partnerRel.holderPerson:admin]] + role:partnerRel.holderPerson:referrer[[partnerRel.holderPerson:referrer]] + end +end + +%% granting roles to roles +role:global:admin -.-> role:partnerRel.anchorPerson:owner +role:partnerRel.anchorPerson:owner -.-> role:partnerRel.anchorPerson:admin +role:partnerRel.anchorPerson:admin -.-> role:partnerRel.anchorPerson:referrer +role:global:admin -.-> role:partnerRel.holderPerson:owner +role:partnerRel.holderPerson:owner -.-> role:partnerRel.holderPerson:admin +role:partnerRel.holderPerson:admin -.-> role:partnerRel.holderPerson:referrer +role:global:admin -.-> role:partnerRel.contact:owner +role:partnerRel.contact:owner -.-> role:partnerRel.contact:admin +role:partnerRel.contact:admin -.-> role:partnerRel.contact:referrer +role:global:admin -.-> role:partnerRel:owner +role:partnerRel:owner -.-> role:partnerRel:admin +role:partnerRel.anchorPerson:admin -.-> role:partnerRel:admin +role:partnerRel:admin -.-> role:partnerRel:agent +role:partnerRel.holderPerson:admin -.-> role:partnerRel:agent +role:partnerRel:agent -.-> role:partnerRel:tenant +role:partnerRel.holderPerson:admin -.-> role:partnerRel:tenant +role:partnerRel.contact:admin -.-> role:partnerRel:tenant +role:partnerRel:tenant -.-> role:partnerRel.anchorPerson:referrer +role:partnerRel:tenant -.-> role:partnerRel.holderPerson:referrer +role:partnerRel:tenant -.-> role:partnerRel.contact:referrer + +%% granting permissions to roles +role:global:admin ==> perm:partnerDetails:INSERT + +``` diff --git a/src/main/resources/db/changelog/234-hs-office-partner-details-rbac-generated.sql b/src/main/resources/db/changelog/234-hs-office-partner-details-rbac-generated.sql new file mode 100644 index 00000000..04fc7be7 --- /dev/null +++ b/src/main/resources/db/changelog/234-hs-office-partner-details-rbac-generated.sql @@ -0,0 +1,164 @@ +--liquibase formatted sql +-- This code generated was by RbacViewPostgresGenerator, do not amend manually. + + +-- ============================================================================ +--changeset hs-office-partner-details-rbac-OBJECT:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRelatedRbacObject('hs_office_partner_details'); +--// + + +-- ============================================================================ +--changeset hs-office-partner-details-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRbacRoleDescriptors('hsOfficePartnerDetails', 'hs_office_partner_details'); +--// + + +-- ============================================================================ +--changeset hs-office-partner-details-rbac-insert-trigger:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/* + Creates the roles, grants and permission for the AFTER INSERT TRIGGER. + */ + +create or replace procedure buildRbacSystemForHsOfficePartnerDetails( + NEW hs_office_partner_details +) + language plpgsql as $$ + +declare + newPartnerRel hs_office_relation; + +begin + call enterTriggerForObjectUuid(NEW.uuid); + + SELECT partnerRel.* + FROM hs_office_relation AS partnerRel + JOIN hs_office_partner AS partner + ON partner.detailsUuid = NEW.uuid + WHERE partnerRel.uuid = partner.partnerRelUuid + INTO newPartnerRel; + assert newPartnerRel.uuid is not null, format('newPartnerRel must not be null for NEW.partnerRelUuid = %s', NEW.partnerRelUuid); + + call leaveTriggerForObjectUuid(NEW.uuid); +end; $$; + +/* + AFTER INSERT TRIGGER to create the role+grant structure for a new hs_office_partner_details row. + */ + +create or replace function insertTriggerForHsOfficePartnerDetails_tf() + returns trigger + language plpgsql + strict as $$ +begin + call buildRbacSystemForHsOfficePartnerDetails(NEW); + return NEW; +end; $$; + +create trigger insertTriggerForHsOfficePartnerDetails_tg + after insert on hs_office_partner_details + for each row +execute procedure insertTriggerForHsOfficePartnerDetails_tf(); +--// + + +-- ============================================================================ +--changeset hs-office-partner-details-rbac-INSERT:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/* + Creates INSERT INTO hs_office_partner_details permissions for the related global rows. + */ +do language plpgsql $$ + declare + row global; + permissionUuid uuid; + roleUuid uuid; + begin + call defineContext('create INSERT INTO hs_office_partner_details permissions for the related global rows'); + + FOR row IN SELECT * FROM global + LOOP + roleUuid := findRoleId(globalAdmin()); + permissionUuid := createPermission(row.uuid, 'INSERT', 'hs_office_partner_details'); + call grantPermissionToRole(permissionUuid, roleUuid); + END LOOP; + END; +$$; + +/** + Adds hs_office_partner_details INSERT permission to specified role of new global rows. +*/ +create or replace function hs_office_partner_details_global_insert_tf() + returns trigger + language plpgsql + strict as $$ +begin + call grantPermissionToRole( + createPermission(NEW.uuid, 'INSERT', 'hs_office_partner_details'), + globalAdmin()); + return NEW; +end; $$; + +-- z_... is to put it at the end of after insert triggers, to make sure the roles exist +create trigger z_hs_office_partner_details_global_insert_tg + after insert on global + for each row +execute procedure hs_office_partner_details_global_insert_tf(); + +/** + Checks if the user or assumed roles are allowed to insert a row to hs_office_partner_details, + where only global-admin has that permission. +*/ +create or replace function hs_office_partner_details_insert_permission_missing_tf() + returns trigger + language plpgsql as $$ +begin + raise exception '[403] insert into hs_office_partner_details not allowed for current subjects % (%)', + currentSubjects(), currentSubjectsUuids(); +end; $$; + +create trigger hs_office_partner_details_insert_permission_check_tg + before insert on hs_office_partner_details + for each row + when ( not isGlobalAdmin() ) + execute procedure hs_office_partner_details_insert_permission_missing_tf(); +--// + +-- ============================================================================ +--changeset hs-office-partner-details-rbac-IDENTITY-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + + call generateRbacIdentityViewFromQuery('hs_office_partner_details', $idName$ + SELECT partner_iv.idName || '-details' + FROM hs_office_partner_details AS partnerDetails + JOIN hs_office_partner partner ON partner.detailsUuid = partnerDetails.uuid + JOIN hs_office_partner_iv partner_iv ON partner_iv.uuid = partner.uuid + + $idName$); +--// + +-- ============================================================================ +--changeset hs-office-partner-details-rbac-RESTRICTED-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRbacRestrictedView('hs_office_partner_details', + $orderBy$ + SELECT partner_iv.idName || '-details' + FROM hs_office_partner_details AS partnerDetails + JOIN hs_office_partner partner ON partner.detailsUuid = partnerDetails.uuid + JOIN hs_office_partner_iv partner_iv ON partner_iv.uuid = partner.uuid + $orderBy$, + $updates$ + registrationOffice = new.registrationOffice, + registrationNumber = new.registrationNumber, + birthPlace = new.birthPlace, + birthName = new.birthName, + birthday = new.birthday, + dateOfDeath = new.dateOfDeath + $updates$); +--// + diff --git a/src/main/resources/db/changelog/243-hs-office-bankaccount-rbac-generated.md b/src/main/resources/db/changelog/243-hs-office-bankaccount-rbac-generated.md new file mode 100644 index 00000000..4f1604fb --- /dev/null +++ b/src/main/resources/db/changelog/243-hs-office-bankaccount-rbac-generated.md @@ -0,0 +1,43 @@ +### rbac bankAccount + +This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually. + +```mermaid +%%{init:{'flowchart':{'htmlLabels':false}}}%% +flowchart TB + +subgraph bankAccount["`**bankAccount**`"] + direction TB + style bankAccount fill:#dd4901,stroke:#274d6e,stroke-width:8px + + subgraph bankAccount:roles[ ] + style bankAccount:roles fill:#dd4901,stroke:white + + role:bankAccount:owner[[bankAccount:owner]] + role:bankAccount:admin[[bankAccount:admin]] + role:bankAccount:referrer[[bankAccount:referrer]] + end + + subgraph bankAccount:permissions[ ] + style bankAccount:permissions fill:#dd4901,stroke:white + + perm:bankAccount:DELETE{{bankAccount:DELETE}} + perm:bankAccount:UPDATE{{bankAccount:UPDATE}} + perm:bankAccount:SELECT{{bankAccount:SELECT}} + end +end + +%% granting roles to users +user:creator ==> role:bankAccount:owner + +%% granting roles to roles +role:global:admin ==> role:bankAccount:owner +role:bankAccount:owner ==> role:bankAccount:admin +role:bankAccount:admin ==> role:bankAccount:referrer + +%% granting permissions to roles +role:bankAccount:owner ==> perm:bankAccount:DELETE +role:bankAccount:admin ==> perm:bankAccount:UPDATE +role:bankAccount:referrer ==> perm:bankAccount:SELECT + +``` diff --git a/src/main/resources/db/changelog/243-hs-office-bankaccount-rbac-generated.sql b/src/main/resources/db/changelog/243-hs-office-bankaccount-rbac-generated.sql new file mode 100644 index 00000000..9d83aad5 --- /dev/null +++ b/src/main/resources/db/changelog/243-hs-office-bankaccount-rbac-generated.sql @@ -0,0 +1,124 @@ +--liquibase formatted sql +-- This code generated was by RbacViewPostgresGenerator, do not amend manually. + + +-- ============================================================================ +--changeset hs-office-bankaccount-rbac-OBJECT:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRelatedRbacObject('hs_office_bankaccount'); +--// + + +-- ============================================================================ +--changeset hs-office-bankaccount-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRbacRoleDescriptors('hsOfficeBankAccount', 'hs_office_bankaccount'); +--// + + +-- ============================================================================ +--changeset hs-office-bankaccount-rbac-insert-trigger:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/* + Creates the roles, grants and permission for the AFTER INSERT TRIGGER. + */ + +create or replace procedure buildRbacSystemForHsOfficeBankAccount( + NEW hs_office_bankaccount +) + language plpgsql as $$ + +declare + +begin + call enterTriggerForObjectUuid(NEW.uuid); + + perform createRoleWithGrants( + hsOfficeBankAccountOwner(NEW), + permissions => array['DELETE'], + incomingSuperRoles => array[globalAdmin()], + userUuids => array[currentUserUuid()] + ); + + perform createRoleWithGrants( + hsOfficeBankAccountAdmin(NEW), + permissions => array['UPDATE'], + incomingSuperRoles => array[hsOfficeBankAccountOwner(NEW)] + ); + + perform createRoleWithGrants( + hsOfficeBankAccountReferrer(NEW), + permissions => array['SELECT'], + incomingSuperRoles => array[hsOfficeBankAccountAdmin(NEW)] + ); + + call leaveTriggerForObjectUuid(NEW.uuid); +end; $$; + +/* + AFTER INSERT TRIGGER to create the role+grant structure for a new hs_office_bankaccount row. + */ + +create or replace function insertTriggerForHsOfficeBankAccount_tf() + returns trigger + language plpgsql + strict as $$ +begin + call buildRbacSystemForHsOfficeBankAccount(NEW); + return NEW; +end; $$; + +create trigger insertTriggerForHsOfficeBankAccount_tg + after insert on hs_office_bankaccount + for each row +execute procedure insertTriggerForHsOfficeBankAccount_tf(); +--// + + +-- ============================================================================ +--changeset hs-office-bankaccount-rbac-INSERT:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/** + Checks if the user or assumed roles are allowed to insert a row to hs_office_bankaccount, + where only global-admin has that permission. +*/ +create or replace function hs_office_bankaccount_insert_permission_missing_tf() + returns trigger + language plpgsql as $$ +begin + raise exception '[403] insert into hs_office_bankaccount not allowed for current subjects % (%)', + currentSubjects(), currentSubjectsUuids(); +end; $$; + +create trigger hs_office_bankaccount_insert_permission_check_tg + before insert on hs_office_bankaccount + for each row + when ( not isGlobalAdmin() ) + execute procedure hs_office_bankaccount_insert_permission_missing_tf(); +--// + +-- ============================================================================ +--changeset hs-office-bankaccount-rbac-IDENTITY-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +call generateRbacIdentityViewFromProjection('hs_office_bankaccount', $idName$ + iban || ':' || holder + $idName$); +--// + +-- ============================================================================ +--changeset hs-office-bankaccount-rbac-RESTRICTED-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRbacRestrictedView('hs_office_bankaccount', + $orderBy$ + iban || ':' || holder + $orderBy$, + $updates$ + holder = new.holder, + iban = new.iban, + bic = new.bic + $updates$); +--// + diff --git a/src/main/resources/db/changelog/253-hs-office-sepamandate-rbac-generated.md b/src/main/resources/db/changelog/253-hs-office-sepamandate-rbac-generated.md new file mode 100644 index 00000000..f542e78c --- /dev/null +++ b/src/main/resources/db/changelog/253-hs-office-sepamandate-rbac-generated.md @@ -0,0 +1,178 @@ +### rbac sepaMandate + +This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually. + +```mermaid +%%{init:{'flowchart':{'htmlLabels':false}}}%% +flowchart TB + +subgraph bankAccount["`**bankAccount**`"] + direction TB + style bankAccount fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph bankAccount:roles[ ] + style bankAccount:roles fill:#99bcdb,stroke:white + + role:bankAccount:owner[[bankAccount:owner]] + role:bankAccount:admin[[bankAccount:admin]] + role:bankAccount:referrer[[bankAccount:referrer]] + end +end + +subgraph debitorRel.contact["`**debitorRel.contact**`"] + direction TB + style debitorRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph debitorRel.contact:roles[ ] + style debitorRel.contact:roles fill:#99bcdb,stroke:white + + role:debitorRel.contact:owner[[debitorRel.contact:owner]] + role:debitorRel.contact:admin[[debitorRel.contact:admin]] + role:debitorRel.contact:referrer[[debitorRel.contact:referrer]] + end +end + +subgraph debitorRel.anchorPerson["`**debitorRel.anchorPerson**`"] + direction TB + style debitorRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph debitorRel.anchorPerson:roles[ ] + style debitorRel.anchorPerson:roles fill:#99bcdb,stroke:white + + role:debitorRel.anchorPerson:owner[[debitorRel.anchorPerson:owner]] + role:debitorRel.anchorPerson:admin[[debitorRel.anchorPerson:admin]] + role:debitorRel.anchorPerson:referrer[[debitorRel.anchorPerson:referrer]] + end +end + +subgraph debitorRel.holderPerson["`**debitorRel.holderPerson**`"] + direction TB + style debitorRel.holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph debitorRel.holderPerson:roles[ ] + style debitorRel.holderPerson:roles fill:#99bcdb,stroke:white + + role:debitorRel.holderPerson:owner[[debitorRel.holderPerson:owner]] + role:debitorRel.holderPerson:admin[[debitorRel.holderPerson:admin]] + role:debitorRel.holderPerson:referrer[[debitorRel.holderPerson:referrer]] + end +end + +subgraph sepaMandate["`**sepaMandate**`"] + direction TB + style sepaMandate fill:#dd4901,stroke:#274d6e,stroke-width:8px + + subgraph sepaMandate:roles[ ] + style sepaMandate:roles fill:#dd4901,stroke:white + + role:sepaMandate:owner[[sepaMandate:owner]] + role:sepaMandate:admin[[sepaMandate:admin]] + role:sepaMandate:agent[[sepaMandate:agent]] + role:sepaMandate:referrer[[sepaMandate:referrer]] + end + + subgraph sepaMandate:permissions[ ] + style sepaMandate:permissions fill:#dd4901,stroke:white + + perm:sepaMandate:DELETE{{sepaMandate:DELETE}} + perm:sepaMandate:UPDATE{{sepaMandate:UPDATE}} + perm:sepaMandate:SELECT{{sepaMandate:SELECT}} + end +end + +subgraph debitorRel["`**debitorRel**`"] + direction TB + style debitorRel fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph debitorRel.contact["`**debitorRel.contact**`"] + direction TB + style debitorRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph debitorRel.contact:roles[ ] + style debitorRel.contact:roles fill:#99bcdb,stroke:white + + role:debitorRel.contact:owner[[debitorRel.contact:owner]] + role:debitorRel.contact:admin[[debitorRel.contact:admin]] + role:debitorRel.contact:referrer[[debitorRel.contact:referrer]] + end + end + + subgraph debitorRel.anchorPerson["`**debitorRel.anchorPerson**`"] + direction TB + style debitorRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph debitorRel.anchorPerson:roles[ ] + style debitorRel.anchorPerson:roles fill:#99bcdb,stroke:white + + role:debitorRel.anchorPerson:owner[[debitorRel.anchorPerson:owner]] + role:debitorRel.anchorPerson:admin[[debitorRel.anchorPerson:admin]] + role:debitorRel.anchorPerson:referrer[[debitorRel.anchorPerson:referrer]] + end + end + + subgraph debitorRel.holderPerson["`**debitorRel.holderPerson**`"] + direction TB + style debitorRel.holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph debitorRel.holderPerson:roles[ ] + style debitorRel.holderPerson:roles fill:#99bcdb,stroke:white + + role:debitorRel.holderPerson:owner[[debitorRel.holderPerson:owner]] + role:debitorRel.holderPerson:admin[[debitorRel.holderPerson:admin]] + role:debitorRel.holderPerson:referrer[[debitorRel.holderPerson:referrer]] + end + end + + subgraph debitorRel:roles[ ] + style debitorRel:roles fill:#99bcdb,stroke:white + + role:debitorRel:owner[[debitorRel:owner]] + role:debitorRel:admin[[debitorRel:admin]] + role:debitorRel:agent[[debitorRel:agent]] + role:debitorRel:tenant[[debitorRel:tenant]] + end +end + +%% granting roles to users +user:creator ==> role:sepaMandate:owner + +%% granting roles to roles +role:global:admin -.-> role:debitorRel.anchorPerson:owner +role:debitorRel.anchorPerson:owner -.-> role:debitorRel.anchorPerson:admin +role:debitorRel.anchorPerson:admin -.-> role:debitorRel.anchorPerson:referrer +role:global:admin -.-> role:debitorRel.holderPerson:owner +role:debitorRel.holderPerson:owner -.-> role:debitorRel.holderPerson:admin +role:debitorRel.holderPerson:admin -.-> role:debitorRel.holderPerson:referrer +role:global:admin -.-> role:debitorRel.contact:owner +role:debitorRel.contact:owner -.-> role:debitorRel.contact:admin +role:debitorRel.contact:admin -.-> role:debitorRel.contact:referrer +role:global:admin -.-> role:debitorRel:owner +role:debitorRel:owner -.-> role:debitorRel:admin +role:debitorRel.anchorPerson:admin -.-> role:debitorRel:admin +role:debitorRel:admin -.-> role:debitorRel:agent +role:debitorRel.holderPerson:admin -.-> role:debitorRel:agent +role:debitorRel:agent -.-> role:debitorRel:tenant +role:debitorRel.holderPerson:admin -.-> role:debitorRel:tenant +role:debitorRel.contact:admin -.-> role:debitorRel:tenant +role:debitorRel:tenant -.-> role:debitorRel.anchorPerson:referrer +role:debitorRel:tenant -.-> role:debitorRel.holderPerson:referrer +role:debitorRel:tenant -.-> role:debitorRel.contact:referrer +role:global:admin -.-> role:bankAccount:owner +role:bankAccount:owner -.-> role:bankAccount:admin +role:bankAccount:admin -.-> role:bankAccount:referrer +role:global:admin ==> role:sepaMandate:owner +role:sepaMandate:owner ==> role:sepaMandate:admin +role:sepaMandate:admin ==> role:sepaMandate:agent +role:sepaMandate:agent ==> role:bankAccount:referrer +role:sepaMandate:agent ==> role:debitorRel:agent +role:sepaMandate:agent ==> role:sepaMandate:referrer +role:bankAccount:admin ==> role:sepaMandate:referrer +role:debitorRel:agent ==> role:sepaMandate:referrer +role:sepaMandate:referrer ==> role:debitorRel:tenant + +%% granting permissions to roles +role:sepaMandate:owner ==> perm:sepaMandate:DELETE +role:sepaMandate:admin ==> perm:sepaMandate:UPDATE +role:sepaMandate:referrer ==> perm:sepaMandate:SELECT + +``` diff --git a/src/main/resources/db/changelog/253-hs-office-sepamandate-rbac-generated.sql b/src/main/resources/db/changelog/253-hs-office-sepamandate-rbac-generated.sql new file mode 100644 index 00000000..f0718272 --- /dev/null +++ b/src/main/resources/db/changelog/253-hs-office-sepamandate-rbac-generated.sql @@ -0,0 +1,142 @@ +--liquibase formatted sql +-- This code generated was by RbacViewPostgresGenerator, do not amend manually. + + +-- ============================================================================ +--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-insert-trigger:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/* + Creates the roles, grants and permission for the AFTER INSERT TRIGGER. + */ + +create or replace procedure buildRbacSystemForHsOfficeSepaMandate( + NEW hs_office_sepamandate +) + language plpgsql as $$ + +declare + newBankAccount hs_office_bankaccount; + newDebitorRel hs_office_relation; + +begin + call enterTriggerForObjectUuid(NEW.uuid); + + SELECT * FROM hs_office_bankaccount WHERE uuid = NEW.bankAccountUuid INTO newBankAccount; + + SELECT * FROM hs_office_relation WHERE uuid = NEW.debitorRelUuid INTO newDebitorRel; + + perform createRoleWithGrants( + hsOfficeSepaMandateOwner(NEW), + permissions => array['DELETE'], + incomingSuperRoles => array[globalAdmin()], + userUuids => array[currentUserUuid()] + ); + + perform createRoleWithGrants( + hsOfficeSepaMandateAdmin(NEW), + permissions => array['UPDATE'], + incomingSuperRoles => array[hsOfficeSepaMandateOwner(NEW)] + ); + + perform createRoleWithGrants( + hsOfficeSepaMandateAgent(NEW), + incomingSuperRoles => array[hsOfficeSepaMandateAdmin(NEW)], + outgoingSubRoles => array[ + hsOfficeBankAccountReferrer(newBankAccount), + hsOfficeRelationAgent(newDebitorRel)] + ); + + perform createRoleWithGrants( + hsOfficeSepaMandateReferrer(NEW), + permissions => array['SELECT'], + incomingSuperRoles => array[ + hsOfficeSepaMandateAgent(NEW), + hsOfficeRelationAgent(newDebitorRel), + hsOfficeBankAccountAdmin(newBankAccount)], + outgoingSubRoles => array[hsOfficeRelationTenant(newDebitorRel)] + ); + + call leaveTriggerForObjectUuid(NEW.uuid); +end; $$; + +/* + AFTER INSERT TRIGGER to create the role+grant structure for a new hs_office_sepamandate row. + */ + +create or replace function insertTriggerForHsOfficeSepaMandate_tf() + returns trigger + language plpgsql + strict as $$ +begin + call buildRbacSystemForHsOfficeSepaMandate(NEW); + return NEW; +end; $$; + +create trigger insertTriggerForHsOfficeSepaMandate_tg + after insert on hs_office_sepamandate + for each row +execute procedure insertTriggerForHsOfficeSepaMandate_tf(); +--// + + +-- ============================================================================ +--changeset hs-office-sepamandate-rbac-INSERT:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/** + Checks if the user or assumed roles are allowed to insert a row to hs_office_sepamandate, + where only global-admin has that permission. +*/ +create or replace function hs_office_sepamandate_insert_permission_missing_tf() + returns trigger + language plpgsql as $$ +begin + raise exception '[403] insert into hs_office_sepamandate not allowed for current subjects % (%)', + currentSubjects(), currentSubjectsUuids(); +end; $$; + +create trigger hs_office_sepamandate_insert_permission_check_tg + before insert on hs_office_sepamandate + for each row + when ( not isGlobalAdmin() ) + execute procedure hs_office_sepamandate_insert_permission_missing_tf(); +--// + +-- ============================================================================ +--changeset hs-office-sepamandate-rbac-IDENTITY-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +call generateRbacIdentityViewFromProjection('hs_office_sepamandate', $idName$ + concat(tradeName, familyName, givenName) + $idName$); +--// + +-- ============================================================================ +--changeset hs-office-sepamandate-rbac-RESTRICTED-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRbacRestrictedView('hs_office_sepamandate', + $orderBy$ + concat(tradeName, familyName, givenName) + $orderBy$, + $updates$ + reference = new.reference, + agreement = new.agreement, + validity = new.validity + $updates$); +--// + diff --git a/src/main/resources/db/changelog/273-hs-office-debitor-rbac-generated.md b/src/main/resources/db/changelog/273-hs-office-debitor-rbac-generated.md new file mode 100644 index 00000000..a1baa702 --- /dev/null +++ b/src/main/resources/db/changelog/273-hs-office-debitor-rbac-generated.md @@ -0,0 +1,275 @@ +### rbac debitor + +This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually. + +```mermaid +%%{init:{'flowchart':{'htmlLabels':false}}}%% +flowchart TB + +subgraph debitorRel.anchorPerson["`**debitorRel.anchorPerson**`"] + direction TB + style debitorRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph debitorRel.anchorPerson:roles[ ] + style debitorRel.anchorPerson:roles fill:#99bcdb,stroke:white + + role:debitorRel.anchorPerson:owner[[debitorRel.anchorPerson:owner]] + role:debitorRel.anchorPerson:admin[[debitorRel.anchorPerson:admin]] + role:debitorRel.anchorPerson:referrer[[debitorRel.anchorPerson:referrer]] + end +end + +subgraph debitorRel.holderPerson["`**debitorRel.holderPerson**`"] + direction TB + style debitorRel.holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph debitorRel.holderPerson:roles[ ] + style debitorRel.holderPerson:roles fill:#99bcdb,stroke:white + + role:debitorRel.holderPerson:owner[[debitorRel.holderPerson:owner]] + role:debitorRel.holderPerson:admin[[debitorRel.holderPerson:admin]] + role:debitorRel.holderPerson:referrer[[debitorRel.holderPerson:referrer]] + end +end + +subgraph partnerRel.holderPerson["`**partnerRel.holderPerson**`"] + direction TB + style partnerRel.holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.holderPerson:roles[ ] + style partnerRel.holderPerson:roles fill:#99bcdb,stroke:white + + role:partnerRel.holderPerson:owner[[partnerRel.holderPerson:owner]] + role:partnerRel.holderPerson:admin[[partnerRel.holderPerson:admin]] + role:partnerRel.holderPerson:referrer[[partnerRel.holderPerson:referrer]] + end +end + +subgraph debitor["`**debitor**`"] + direction TB + style debitor fill:#dd4901,stroke:#274d6e,stroke-width:8px + + subgraph debitor:permissions[ ] + style debitor:permissions fill:#dd4901,stroke:white + + perm:debitor:INSERT{{debitor:INSERT}} + perm:debitor:DELETE{{debitor:DELETE}} + perm:debitor:UPDATE{{debitor:UPDATE}} + perm:debitor:SELECT{{debitor:SELECT}} + end + + subgraph debitorRel["`**debitorRel**`"] + direction TB + style debitorRel fill:#99bcdb,stroke:#274d6e,stroke-width:8px + subgraph debitorRel.anchorPerson["`**debitorRel.anchorPerson**`"] + direction TB + style debitorRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph debitorRel.anchorPerson:roles[ ] + style debitorRel.anchorPerson:roles fill:#99bcdb,stroke:white + + role:debitorRel.anchorPerson:owner[[debitorRel.anchorPerson:owner]] + role:debitorRel.anchorPerson:admin[[debitorRel.anchorPerson:admin]] + role:debitorRel.anchorPerson:referrer[[debitorRel.anchorPerson:referrer]] + end + end + + subgraph debitorRel.holderPerson["`**debitorRel.holderPerson**`"] + direction TB + style debitorRel.holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph debitorRel.holderPerson:roles[ ] + style debitorRel.holderPerson:roles fill:#99bcdb,stroke:white + + role:debitorRel.holderPerson:owner[[debitorRel.holderPerson:owner]] + role:debitorRel.holderPerson:admin[[debitorRel.holderPerson:admin]] + role:debitorRel.holderPerson:referrer[[debitorRel.holderPerson:referrer]] + end + end + + subgraph debitorRel.contact["`**debitorRel.contact**`"] + direction TB + style debitorRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph debitorRel.contact:roles[ ] + style debitorRel.contact:roles fill:#99bcdb,stroke:white + + role:debitorRel.contact:owner[[debitorRel.contact:owner]] + role:debitorRel.contact:admin[[debitorRel.contact:admin]] + role:debitorRel.contact:referrer[[debitorRel.contact:referrer]] + end + end + + subgraph debitorRel:roles[ ] + style debitorRel:roles fill:#99bcdb,stroke:white + + role:debitorRel:owner[[debitorRel:owner]] + role:debitorRel:admin[[debitorRel:admin]] + role:debitorRel:agent[[debitorRel:agent]] + role:debitorRel:tenant[[debitorRel:tenant]] + end + end +end + +subgraph partnerRel["`**partnerRel**`"] + direction TB + style partnerRel fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.holderPerson["`**partnerRel.holderPerson**`"] + direction TB + style partnerRel.holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.holderPerson:roles[ ] + style partnerRel.holderPerson:roles fill:#99bcdb,stroke:white + + role:partnerRel.holderPerson:owner[[partnerRel.holderPerson:owner]] + role:partnerRel.holderPerson:admin[[partnerRel.holderPerson:admin]] + role:partnerRel.holderPerson:referrer[[partnerRel.holderPerson:referrer]] + end + end + + subgraph partnerRel.contact["`**partnerRel.contact**`"] + direction TB + style partnerRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.contact:roles[ ] + style partnerRel.contact:roles fill:#99bcdb,stroke:white + + role:partnerRel.contact:owner[[partnerRel.contact:owner]] + role:partnerRel.contact:admin[[partnerRel.contact:admin]] + role:partnerRel.contact:referrer[[partnerRel.contact:referrer]] + end + end + + subgraph partnerRel.anchorPerson["`**partnerRel.anchorPerson**`"] + direction TB + style partnerRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.anchorPerson:roles[ ] + style partnerRel.anchorPerson:roles fill:#99bcdb,stroke:white + + role:partnerRel.anchorPerson:owner[[partnerRel.anchorPerson:owner]] + role:partnerRel.anchorPerson:admin[[partnerRel.anchorPerson:admin]] + role:partnerRel.anchorPerson:referrer[[partnerRel.anchorPerson:referrer]] + end + end + + subgraph partnerRel:roles[ ] + style partnerRel:roles fill:#99bcdb,stroke:white + + role:partnerRel:owner[[partnerRel:owner]] + role:partnerRel:admin[[partnerRel:admin]] + role:partnerRel:agent[[partnerRel:agent]] + role:partnerRel:tenant[[partnerRel:tenant]] + end +end + +subgraph partnerRel.contact["`**partnerRel.contact**`"] + direction TB + style partnerRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.contact:roles[ ] + style partnerRel.contact:roles fill:#99bcdb,stroke:white + + role:partnerRel.contact:owner[[partnerRel.contact:owner]] + role:partnerRel.contact:admin[[partnerRel.contact:admin]] + role:partnerRel.contact:referrer[[partnerRel.contact:referrer]] + end +end + +subgraph debitorRel.contact["`**debitorRel.contact**`"] + direction TB + style debitorRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph debitorRel.contact:roles[ ] + style debitorRel.contact:roles fill:#99bcdb,stroke:white + + role:debitorRel.contact:owner[[debitorRel.contact:owner]] + role:debitorRel.contact:admin[[debitorRel.contact:admin]] + role:debitorRel.contact:referrer[[debitorRel.contact:referrer]] + end +end + +subgraph partnerRel.anchorPerson["`**partnerRel.anchorPerson**`"] + direction TB + style partnerRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.anchorPerson:roles[ ] + style partnerRel.anchorPerson:roles fill:#99bcdb,stroke:white + + role:partnerRel.anchorPerson:owner[[partnerRel.anchorPerson:owner]] + role:partnerRel.anchorPerson:admin[[partnerRel.anchorPerson:admin]] + role:partnerRel.anchorPerson:referrer[[partnerRel.anchorPerson:referrer]] + end +end + +subgraph refundBankAccount["`**refundBankAccount**`"] + direction TB + style refundBankAccount fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph refundBankAccount:roles[ ] + style refundBankAccount:roles fill:#99bcdb,stroke:white + + role:refundBankAccount:owner[[refundBankAccount:owner]] + role:refundBankAccount:admin[[refundBankAccount:admin]] + role:refundBankAccount:referrer[[refundBankAccount:referrer]] + end +end + +%% granting roles to roles +role:global:admin -.-> role:debitorRel.anchorPerson:owner +role:debitorRel.anchorPerson:owner -.-> role:debitorRel.anchorPerson:admin +role:debitorRel.anchorPerson:admin -.-> role:debitorRel.anchorPerson:referrer +role:global:admin -.-> role:debitorRel.holderPerson:owner +role:debitorRel.holderPerson:owner -.-> role:debitorRel.holderPerson:admin +role:debitorRel.holderPerson:admin -.-> role:debitorRel.holderPerson:referrer +role:global:admin -.-> role:debitorRel.contact:owner +role:debitorRel.contact:owner -.-> role:debitorRel.contact:admin +role:debitorRel.contact:admin -.-> role:debitorRel.contact:referrer +role:global:admin -.-> role:debitorRel:owner +role:debitorRel:owner -.-> role:debitorRel:admin +role:debitorRel.anchorPerson:admin -.-> role:debitorRel:admin +role:debitorRel:admin -.-> role:debitorRel:agent +role:debitorRel.holderPerson:admin -.-> role:debitorRel:agent +role:debitorRel:agent -.-> role:debitorRel:tenant +role:debitorRel.holderPerson:admin -.-> role:debitorRel:tenant +role:debitorRel.contact:admin -.-> role:debitorRel:tenant +role:debitorRel:tenant -.-> role:debitorRel.anchorPerson:referrer +role:debitorRel:tenant -.-> role:debitorRel.holderPerson:referrer +role:debitorRel:tenant -.-> role:debitorRel.contact:referrer +role:global:admin -.-> role:refundBankAccount:owner +role:refundBankAccount:owner -.-> role:refundBankAccount:admin +role:refundBankAccount:admin -.-> role:refundBankAccount:referrer +role:refundBankAccount:admin ==> role:debitorRel:agent +role:debitorRel:agent ==> role:refundBankAccount:referrer +role:global:admin -.-> role:partnerRel.anchorPerson:owner +role:partnerRel.anchorPerson:owner -.-> role:partnerRel.anchorPerson:admin +role:partnerRel.anchorPerson:admin -.-> role:partnerRel.anchorPerson:referrer +role:global:admin -.-> role:partnerRel.holderPerson:owner +role:partnerRel.holderPerson:owner -.-> role:partnerRel.holderPerson:admin +role:partnerRel.holderPerson:admin -.-> role:partnerRel.holderPerson:referrer +role:global:admin -.-> role:partnerRel.contact:owner +role:partnerRel.contact:owner -.-> role:partnerRel.contact:admin +role:partnerRel.contact:admin -.-> role:partnerRel.contact:referrer +role:global:admin -.-> role:partnerRel:owner +role:partnerRel:owner -.-> role:partnerRel:admin +role:partnerRel.anchorPerson:admin -.-> role:partnerRel:admin +role:partnerRel:admin -.-> role:partnerRel:agent +role:partnerRel.holderPerson:admin -.-> role:partnerRel:agent +role:partnerRel:agent -.-> role:partnerRel:tenant +role:partnerRel.holderPerson:admin -.-> role:partnerRel:tenant +role:partnerRel.contact:admin -.-> role:partnerRel:tenant +role:partnerRel:tenant -.-> role:partnerRel.anchorPerson:referrer +role:partnerRel:tenant -.-> role:partnerRel.holderPerson:referrer +role:partnerRel:tenant -.-> role:partnerRel.contact:referrer +role:partnerRel:admin ==> role:debitorRel:admin +role:partnerRel:agent ==> role:debitorRel:agent +role:debitorRel:agent ==> role:partnerRel:tenant + +%% granting permissions to roles +role:global:admin ==> perm:debitor:INSERT +role:debitorRel:owner ==> perm:debitor:DELETE +role:debitorRel:admin ==> perm:debitor:UPDATE +role:debitorRel:tenant ==> perm:debitor:SELECT + +``` diff --git a/src/main/resources/db/changelog/273-hs-office-debitor-rbac-generated.sql b/src/main/resources/db/changelog/273-hs-office-debitor-rbac-generated.sql new file mode 100644 index 00000000..760f1fe9 --- /dev/null +++ b/src/main/resources/db/changelog/273-hs-office-debitor-rbac-generated.sql @@ -0,0 +1,296 @@ +--liquibase formatted sql +-- This code generated was by RbacViewPostgresGenerator, do not amend manually. + + +-- ============================================================================ +--changeset hs-office-debitor-rbac-OBJECT:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRelatedRbacObject('hs_office_debitor'); +--// + + +-- ============================================================================ +--changeset hs-office-debitor-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRbacRoleDescriptors('hsOfficeDebitor', 'hs_office_debitor'); +--// + + +-- ============================================================================ +--changeset hs-office-debitor-rbac-insert-trigger:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/* + Creates the roles, grants and permission for the AFTER INSERT TRIGGER. + */ + +create or replace procedure buildRbacSystemForHsOfficeDebitor( + NEW hs_office_debitor +) + language plpgsql as $$ + +declare + newPartnerRel hs_office_relation; + newDebitorRel hs_office_relation; + newRefundBankAccount hs_office_bankaccount; + +begin + call enterTriggerForObjectUuid(NEW.uuid); + + SELECT * + FROM hs_office_relation AS partnerRel + WHERE ${debitorRel}.anchorUuid = partnerRel.holderUuid + INTO newPartnerRel; + assert newPartnerRel.uuid is not null, format('newPartnerRel must not be null for NEW.partnerRelUuid = %s', NEW.partnerRelUuid); + + SELECT * + FROM hs_office_relation AS r + WHERE r.type = 'DEBITOR' AND r.holderUuid = NEW.debitorRelUuid + INTO newDebitorRel; + assert newDebitorRel.uuid is not null, format('newDebitorRel must not be null for NEW.debitorRelUuid = %s', NEW.debitorRelUuid); + + SELECT * + FROM hs_office_relation AS r + WHERE r.type = 'DEBITOR' AND r.holderUuid = NEW.debitorRelUuid + INTO newRefundBankAccount; + assert newRefundBankAccount.uuid is not null, format('newRefundBankAccount must not be null for NEW.refundBankAccountUuid = %s', NEW.refundBankAccountUuid); + + call grantRoleToRole(hsOfficeBankAccountReferrer(newRefundBankAccount), hsOfficeRelationAgent(newDebitorRel)); + call grantRoleToRole(hsOfficeRelationAdmin(newDebitorRel), hsOfficeRelationAdmin(newPartnerRel)); + call grantRoleToRole(hsOfficeRelationAgent(newDebitorRel), hsOfficeBankAccountAdmin(newRefundBankAccount)); + call grantRoleToRole(hsOfficeRelationAgent(newDebitorRel), hsOfficeRelationAgent(newPartnerRel)); + call grantRoleToRole(hsOfficeRelationTenant(newPartnerRel), hsOfficeRelationAgent(newDebitorRel)); + + call grantPermissionToRole(createPermission(NEW.uuid, 'DELETE'), hsOfficeRelationOwner(newDebitorRel)); + call grantPermissionToRole(createPermission(NEW.uuid, 'SELECT'), hsOfficeRelationTenant(newDebitorRel)); + call grantPermissionToRole(createPermission(NEW.uuid, 'UPDATE'), hsOfficeRelationAdmin(newDebitorRel)); + + call leaveTriggerForObjectUuid(NEW.uuid); +end; $$; + +/* + AFTER INSERT TRIGGER to create the role+grant structure for a new hs_office_debitor row. + */ + +create or replace function insertTriggerForHsOfficeDebitor_tf() + returns trigger + language plpgsql + strict as $$ +begin + call buildRbacSystemForHsOfficeDebitor(NEW); + return NEW; +end; $$; + +create trigger insertTriggerForHsOfficeDebitor_tg + after insert on hs_office_debitor + for each row +execute procedure insertTriggerForHsOfficeDebitor_tf(); +--// + + +-- ============================================================================ +--changeset hs-office-debitor-rbac-update-trigger:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/* + Called from the AFTER UPDATE TRIGGER to re-wire the grants. + */ + +create or replace procedure updateRbacRulesForHsOfficeDebitor( + OLD hs_office_debitor, + NEW hs_office_debitor +) + language plpgsql as $$ + +declare + oldPartnerRel hs_office_relation; + newPartnerRel hs_office_relation; + oldDebitorRel hs_office_relation; + newDebitorRel hs_office_relation; + oldRefundBankAccount hs_office_bankaccount; + newRefundBankAccount hs_office_bankaccount; + +begin + call enterTriggerForObjectUuid(NEW.uuid); + + SELECT * + FROM hs_office_relation AS partnerRel + WHERE ${debitorRel}.anchorUuid = partnerRel.holderUuid + INTO oldPartnerRel; + assert oldPartnerRel.uuid is not null, format('oldPartnerRel must not be null for OLD.partnerRelUuid = %s', OLD.partnerRelUuid); + + SELECT * + FROM hs_office_relation AS partnerRel + WHERE ${debitorRel}.anchorUuid = partnerRel.holderUuid + INTO newPartnerRel; + assert newPartnerRel.uuid is not null, format('newPartnerRel must not be null for NEW.partnerRelUuid = %s', NEW.partnerRelUuid); + + SELECT * + FROM hs_office_relation AS r + WHERE r.type = 'DEBITOR' AND r.holderUuid = OLD.debitorRelUuid + INTO oldDebitorRel; + assert oldDebitorRel.uuid is not null, format('oldDebitorRel must not be null for OLD.debitorRelUuid = %s', OLD.debitorRelUuid); + + SELECT * + FROM hs_office_relation AS r + WHERE r.type = 'DEBITOR' AND r.holderUuid = NEW.debitorRelUuid + INTO newDebitorRel; + assert newDebitorRel.uuid is not null, format('newDebitorRel must not be null for NEW.debitorRelUuid = %s', NEW.debitorRelUuid); + + SELECT * + FROM hs_office_relation AS r + WHERE r.type = 'DEBITOR' AND r.holderUuid = OLD.debitorRelUuid + INTO oldRefundBankAccount; + assert oldRefundBankAccount.uuid is not null, format('oldRefundBankAccount must not be null for OLD.refundBankAccountUuid = %s', OLD.refundBankAccountUuid); + + SELECT * + FROM hs_office_relation AS r + WHERE r.type = 'DEBITOR' AND r.holderUuid = NEW.debitorRelUuid + INTO newRefundBankAccount; + assert newRefundBankAccount.uuid is not null, format('newRefundBankAccount must not be null for NEW.refundBankAccountUuid = %s', NEW.refundBankAccountUuid); + + + if NEW.refundBankAccountUuid <> OLD.refundBankAccountUuid then + + call revokeRoleFromRole(hsOfficeRelationAgent(oldDebitorRel), hsOfficeBankAccountAdmin(oldRefundBankAccount)); + call grantRoleToRole(hsOfficeRelationAgent(newDebitorRel), hsOfficeBankAccountAdmin(newRefundBankAccount)); + + call revokeRoleFromRole(hsOfficeBankAccountReferrer(oldRefundBankAccount), hsOfficeRelationAgent(oldDebitorRel)); + call grantRoleToRole(hsOfficeBankAccountReferrer(newRefundBankAccount), hsOfficeRelationAgent(newDebitorRel)); + + end if; + + call leaveTriggerForObjectUuid(NEW.uuid); +end; $$; + +/* + AFTER INSERT TRIGGER to re-wire the grant structure for a new hs_office_debitor row. + */ + +create or replace function updateTriggerForHsOfficeDebitor_tf() + returns trigger + language plpgsql + strict as $$ +begin + call updateRbacRulesForHsOfficeDebitor(OLD, NEW); + return NEW; +end; $$; + +create trigger updateTriggerForHsOfficeDebitor_tg + after update on hs_office_debitor + for each row +execute procedure updateTriggerForHsOfficeDebitor_tf(); +--// + + +-- ============================================================================ +--changeset hs-office-debitor-rbac-INSERT:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/* + Creates INSERT INTO hs_office_debitor permissions for the related global rows. + */ +do language plpgsql $$ + declare + row global; + permissionUuid uuid; + roleUuid uuid; + begin + call defineContext('create INSERT INTO hs_office_debitor permissions for the related global rows'); + + FOR row IN SELECT * FROM global + LOOP + roleUuid := findRoleId(globalAdmin()); + permissionUuid := createPermission(row.uuid, 'INSERT', 'hs_office_debitor'); + call grantPermissionToRole(permissionUuid, roleUuid); + END LOOP; + END; +$$; + +/** + Adds hs_office_debitor INSERT permission to specified role of new global rows. +*/ +create or replace function hs_office_debitor_global_insert_tf() + returns trigger + language plpgsql + strict as $$ +begin + call grantPermissionToRole( + createPermission(NEW.uuid, 'INSERT', 'hs_office_debitor'), + globalAdmin()); + return NEW; +end; $$; + +-- z_... is to put it at the end of after insert triggers, to make sure the roles exist +create trigger z_hs_office_debitor_global_insert_tg + after insert on global + for each row +execute procedure hs_office_debitor_global_insert_tf(); + +/** + Checks if the user or assumed roles are allowed to insert a row to hs_office_debitor, + where only global-admin has that permission. +*/ +create or replace function hs_office_debitor_insert_permission_missing_tf() + returns trigger + language plpgsql as $$ +begin + raise exception '[403] insert into hs_office_debitor not allowed for current subjects % (%)', + currentSubjects(), currentSubjectsUuids(); +end; $$; + +create trigger hs_office_debitor_insert_permission_check_tg + before insert on hs_office_debitor + for each row + when ( not isGlobalAdmin() ) + execute procedure hs_office_debitor_insert_permission_missing_tf(); +--// + +-- ============================================================================ +--changeset hs-office-debitor-rbac-IDENTITY-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + + call generateRbacIdentityViewFromQuery('hs_office_debitor', $idName$ + SELECT debitor.uuid, + 'D-' || (SELECT partner.partnerNumber + FROM hs_office_partner partner + JOIN hs_office_relation partnerRel + ON partnerRel.uuid = partner.partnerRelUUid AND partnerRel.type = 'PARTNER' + JOIN hs_office_relation debitorRel + ON debitorRel.anchorUuid = partnerRel.holderUuid AND partnerRel.type = 'DEBITOR' + WHERE debitorRel.uuid = debitor.debitorRelUuid) + || to_char(debitorNumberSuffix, 'fm00') + from hs_office_debitor as debitor + + $idName$); +--// + +-- ============================================================================ +--changeset hs-office-debitor-rbac-RESTRICTED-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- +call generateRbacRestrictedView('hs_office_debitor', + $orderBy$ + SELECT debitor.uuid, + 'D-' || (SELECT partner.partnerNumber + FROM hs_office_partner partner + JOIN hs_office_relation partnerRel + ON partnerRel.uuid = partner.partnerRelUUid AND partnerRel.type = 'PARTNER' + JOIN hs_office_relation debitorRel + ON debitorRel.anchorUuid = partnerRel.holderUuid AND partnerRel.type = 'DEBITOR' + WHERE debitorRel.uuid = debitor.debitorRelUuid) + || to_char(debitorNumberSuffix, 'fm00') + from hs_office_debitor as debitor + $orderBy$, + $updates$ + debitorRel = new.debitorRel, + billable = new.billable, + debitorUuid = new.debitorUuid, + refundBankAccountUuid = new.refundBankAccountUuid, + vatId = new.vatId, + vatCountryCode = new.vatCountryCode, + vatBusiness = new.vatBusiness, + vatReverseCharge = new.vatReverseCharge, + defaultPrefix = new.defaultPrefix + $updates$); +--// +