RBAC generator with conditional grants used for REPRESENTATIVE-Relation #33

Merged
hsh-michaelhoennig merged 31 commits from rbac-generator-with-conditional-grants into master 2024-04-08 11:16:07 +02:00
4 changed files with 369 additions and 93 deletions
Showing only changes of commit 59c41a176e - Show all commits

View File

@ -4,14 +4,24 @@ import lombok.*;
import net.hostsharing.hsadminng.errors.DisplayName;
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity;
import net.hostsharing.hsadminng.persistence.HasUuid;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL;
import net.hostsharing.hsadminng.stringify.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable;
import jakarta.persistence.*;
import java.io.IOException;
import java.time.LocalDate;
import java.util.UUID;
import static java.util.Optional.ofNullable;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Nullable.NOT_NULL;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.INSERT;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.directlyFetchedByDependsOnColumn;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
@Entity
@ -83,4 +93,22 @@ public class HsOfficeCoopSharesTransactionEntity implements Stringifyable, HasUu
public String toShortString() {
return "%s%+d".formatted(getMemberNumberTagged(), shareCount);
}
public static RbacView rbac() {
return rbacViewFor("coopSharesTransaction", HsOfficeCoopSharesTransactionEntity.class)
.withIdentityView(SQL.projection("reference"))
.withUpdatableColumns("comment")
.importEntityAlias("membership", HsOfficeMembershipEntity.class,
dependsOnColumn("membershipUuid"),
directlyFetchedByDependsOnColumn(),
NOT_NULL)
.toRole("membership", ADMIN).grantPermission(INSERT)
.toRole("membership", ADMIN).grantPermission(UPDATE)
.toRole("membership", ADMIN).grantPermission(SELECT);
}
public static void main(String[] args) throws IOException {
rbac().generateWithBaseFileName("313-hs-office-coopshares-rbac");
}
}

View File

@ -1,29 +1,250 @@
### hs_office_coopSharesTransaction RBAC
### rbac coopSharesTransaction
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
```mermaid
%%{init:{'flowchart':{'htmlLabels':false}}}%%
flowchart TB
subgraph hsOfficeMembership
subgraph membership.partnerRel.holderPerson["`**membership.partnerRel.holderPerson**`"]
direction TB
style hsOfficeMembership fill:#eee
role:hsOfficeMembership.owner[membership.admin]
--> role:hsOfficeMembership.admin[membership.admin]
--> role:hsOfficeMembership.agent[membership.agent]
--> role:hsOfficeMembership.tenant[membership.tenant]
--> role:hsOfficeMembership.guest[membership.guest]
role:hsOfficePartner.agent --> role:hsOfficeMembership.agent
style membership.partnerRel.holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px
subgraph membership.partnerRel.holderPerson:roles[ ]
style membership.partnerRel.holderPerson:roles fill:#99bcdb,stroke:white
role:membership.partnerRel.holderPerson:owner[[membership.partnerRel.holderPerson:owner]]
role:membership.partnerRel.holderPerson:admin[[membership.partnerRel.holderPerson:admin]]
role:membership.partnerRel.holderPerson:referrer[[membership.partnerRel.holderPerson:referrer]]
end
end
subgraph hsOfficeCoopSharesTransaction
role:hsOfficeMembership.admin
--> perm:hsOfficeCoopSharesTransaction.create{{coopSharesTx.create}}
role:hsOfficeMembership.agent
--> perm:hsOfficeCoopSharesTransaction.view{{coopSharesTx.view}}
subgraph membership.partnerRel.anchorPerson["`**membership.partnerRel.anchorPerson**`"]
direction TB
style membership.partnerRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px
subgraph membership.partnerRel.anchorPerson:roles[ ]
style membership.partnerRel.anchorPerson:roles fill:#99bcdb,stroke:white
role:membership.partnerRel.anchorPerson:owner[[membership.partnerRel.anchorPerson:owner]]
role:membership.partnerRel.anchorPerson:admin[[membership.partnerRel.anchorPerson:admin]]
role:membership.partnerRel.anchorPerson:referrer[[membership.partnerRel.anchorPerson:referrer]]
end
end
subgraph coopSharesTransaction["`**coopSharesTransaction**`"]
direction TB
style coopSharesTransaction fill:#dd4901,stroke:#274d6e,stroke-width:8px
subgraph coopSharesTransaction:permissions[ ]
style coopSharesTransaction:permissions fill:#dd4901,stroke:white
perm:coopSharesTransaction:INSERT{{coopSharesTransaction:INSERT}}
perm:coopSharesTransaction:UPDATE{{coopSharesTransaction:UPDATE}}
perm:coopSharesTransaction:SELECT{{coopSharesTransaction:SELECT}}
end
end
subgraph membership["`**membership**`"]
direction TB
style membership fill:#99bcdb,stroke:#274d6e,stroke-width:8px
subgraph membership.partnerRel.holderPerson["`**membership.partnerRel.holderPerson**`"]
direction TB
style membership.partnerRel.holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px
subgraph membership.partnerRel.holderPerson:roles[ ]
style membership.partnerRel.holderPerson:roles fill:#99bcdb,stroke:white
role:membership.partnerRel.holderPerson:owner[[membership.partnerRel.holderPerson:owner]]
role:membership.partnerRel.holderPerson:admin[[membership.partnerRel.holderPerson:admin]]
role:membership.partnerRel.holderPerson:referrer[[membership.partnerRel.holderPerson:referrer]]
end
end
subgraph membership.partnerRel.anchorPerson["`**membership.partnerRel.anchorPerson**`"]
direction TB
style membership.partnerRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px
subgraph membership.partnerRel.anchorPerson:roles[ ]
style membership.partnerRel.anchorPerson:roles fill:#99bcdb,stroke:white
role:membership.partnerRel.anchorPerson:owner[[membership.partnerRel.anchorPerson:owner]]
role:membership.partnerRel.anchorPerson:admin[[membership.partnerRel.anchorPerson:admin]]
role:membership.partnerRel.anchorPerson:referrer[[membership.partnerRel.anchorPerson:referrer]]
end
end
subgraph membership.partnerRel["`**membership.partnerRel**`"]
direction TB
style membership.partnerRel fill:#99bcdb,stroke:#274d6e,stroke-width:8px
subgraph membership.partnerRel.holderPerson["`**membership.partnerRel.holderPerson**`"]
direction TB
style membership.partnerRel.holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px
subgraph membership.partnerRel.holderPerson:roles[ ]
style membership.partnerRel.holderPerson:roles fill:#99bcdb,stroke:white
role:membership.partnerRel.holderPerson:owner[[membership.partnerRel.holderPerson:owner]]
role:membership.partnerRel.holderPerson:admin[[membership.partnerRel.holderPerson:admin]]
role:membership.partnerRel.holderPerson:referrer[[membership.partnerRel.holderPerson:referrer]]
end
end
subgraph membership.partnerRel.anchorPerson["`**membership.partnerRel.anchorPerson**`"]
direction TB
style membership.partnerRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px
subgraph membership.partnerRel.anchorPerson:roles[ ]
style membership.partnerRel.anchorPerson:roles fill:#99bcdb,stroke:white
role:membership.partnerRel.anchorPerson:owner[[membership.partnerRel.anchorPerson:owner]]
role:membership.partnerRel.anchorPerson:admin[[membership.partnerRel.anchorPerson:admin]]
role:membership.partnerRel.anchorPerson:referrer[[membership.partnerRel.anchorPerson:referrer]]
end
end
subgraph membership.partnerRel.contact["`**membership.partnerRel.contact**`"]
direction TB
style membership.partnerRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px
subgraph membership.partnerRel.contact:roles[ ]
style membership.partnerRel.contact:roles fill:#99bcdb,stroke:white
role:membership.partnerRel.contact:owner[[membership.partnerRel.contact:owner]]
role:membership.partnerRel.contact:admin[[membership.partnerRel.contact:admin]]
role:membership.partnerRel.contact:referrer[[membership.partnerRel.contact:referrer]]
end
end
subgraph membership.partnerRel:roles[ ]
style membership.partnerRel:roles fill:#99bcdb,stroke:white
role:membership.partnerRel:owner[[membership.partnerRel:owner]]
role:membership.partnerRel:admin[[membership.partnerRel:admin]]
role:membership.partnerRel:agent[[membership.partnerRel:agent]]
role:membership.partnerRel:tenant[[membership.partnerRel:tenant]]
end
end
subgraph membership.partnerRel.contact["`**membership.partnerRel.contact**`"]
direction TB
style membership.partnerRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px
subgraph membership.partnerRel.contact:roles[ ]
style membership.partnerRel.contact:roles fill:#99bcdb,stroke:white
role:membership.partnerRel.contact:owner[[membership.partnerRel.contact:owner]]
role:membership.partnerRel.contact:admin[[membership.partnerRel.contact:admin]]
role:membership.partnerRel.contact:referrer[[membership.partnerRel.contact:referrer]]
end
end
subgraph membership:roles[ ]
style membership:roles fill:#99bcdb,stroke:white
role:membership:owner[[membership:owner]]
role:membership:admin[[membership:admin]]
role:membership:referrer[[membership:referrer]]
end
end
subgraph membership.partnerRel["`**membership.partnerRel**`"]
direction TB
style membership.partnerRel fill:#99bcdb,stroke:#274d6e,stroke-width:8px
subgraph membership.partnerRel.holderPerson["`**membership.partnerRel.holderPerson**`"]
direction TB
style membership.partnerRel.holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px
subgraph membership.partnerRel.holderPerson:roles[ ]
style membership.partnerRel.holderPerson:roles fill:#99bcdb,stroke:white
role:membership.partnerRel.holderPerson:owner[[membership.partnerRel.holderPerson:owner]]
role:membership.partnerRel.holderPerson:admin[[membership.partnerRel.holderPerson:admin]]
role:membership.partnerRel.holderPerson:referrer[[membership.partnerRel.holderPerson:referrer]]
end
end
subgraph membership.partnerRel.anchorPerson["`**membership.partnerRel.anchorPerson**`"]
direction TB
style membership.partnerRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px
subgraph membership.partnerRel.anchorPerson:roles[ ]
style membership.partnerRel.anchorPerson:roles fill:#99bcdb,stroke:white
role:membership.partnerRel.anchorPerson:owner[[membership.partnerRel.anchorPerson:owner]]
role:membership.partnerRel.anchorPerson:admin[[membership.partnerRel.anchorPerson:admin]]
role:membership.partnerRel.anchorPerson:referrer[[membership.partnerRel.anchorPerson:referrer]]
end
end
subgraph membership.partnerRel.contact["`**membership.partnerRel.contact**`"]
direction TB
style membership.partnerRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px
subgraph membership.partnerRel.contact:roles[ ]
style membership.partnerRel.contact:roles fill:#99bcdb,stroke:white
role:membership.partnerRel.contact:owner[[membership.partnerRel.contact:owner]]
role:membership.partnerRel.contact:admin[[membership.partnerRel.contact:admin]]
role:membership.partnerRel.contact:referrer[[membership.partnerRel.contact:referrer]]
end
end
subgraph membership.partnerRel:roles[ ]
style membership.partnerRel:roles fill:#99bcdb,stroke:white
role:membership.partnerRel:owner[[membership.partnerRel:owner]]
role:membership.partnerRel:admin[[membership.partnerRel:admin]]
role:membership.partnerRel:agent[[membership.partnerRel:agent]]
role:membership.partnerRel:tenant[[membership.partnerRel:tenant]]
end
end
subgraph membership.partnerRel.contact["`**membership.partnerRel.contact**`"]
direction TB
style membership.partnerRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px
subgraph membership.partnerRel.contact:roles[ ]
style membership.partnerRel.contact:roles fill:#99bcdb,stroke:white
role:membership.partnerRel.contact:owner[[membership.partnerRel.contact:owner]]
role:membership.partnerRel.contact:admin[[membership.partnerRel.contact:admin]]
role:membership.partnerRel.contact:referrer[[membership.partnerRel.contact:referrer]]
end
end
%% granting roles to roles
role:global:admin -.-> role:membership.partnerRel.anchorPerson:owner
role:membership.partnerRel.anchorPerson:owner -.-> role:membership.partnerRel.anchorPerson:admin
role:membership.partnerRel.anchorPerson:admin -.-> role:membership.partnerRel.anchorPerson:referrer
role:global:admin -.-> role:membership.partnerRel.holderPerson:owner
role:membership.partnerRel.holderPerson:owner -.-> role:membership.partnerRel.holderPerson:admin
role:membership.partnerRel.holderPerson:admin -.-> role:membership.partnerRel.holderPerson:referrer
role:global:admin -.-> role:membership.partnerRel.contact:owner
role:membership.partnerRel.contact:owner -.-> role:membership.partnerRel.contact:admin
role:membership.partnerRel.contact:admin -.-> role:membership.partnerRel.contact:referrer
role:global:admin -.-> role:membership.partnerRel:owner
role:membership.partnerRel:owner -.-> role:membership.partnerRel:admin
role:membership.partnerRel.anchorPerson:admin -.-> role:membership.partnerRel:admin
role:membership.partnerRel:admin -.-> role:membership.partnerRel:agent
role:membership.partnerRel.holderPerson:admin -.-> role:membership.partnerRel:agent
role:membership.partnerRel:agent -.-> role:membership.partnerRel:tenant
role:membership.partnerRel.holderPerson:admin -.-> role:membership.partnerRel:tenant
role:membership.partnerRel.contact:admin -.-> role:membership.partnerRel:tenant
role:membership.partnerRel:tenant -.-> role:membership.partnerRel.anchorPerson:referrer
role:membership.partnerRel:tenant -.-> role:membership.partnerRel.holderPerson:referrer
role:membership.partnerRel:tenant -.-> role:membership.partnerRel.contact:referrer
role:membership.partnerRel:admin -.-> role:membership:owner
role:membership:owner -.-> role:membership:admin
role:membership.partnerRel:agent -.-> role:membership:admin
role:membership:admin -.-> role:membership:referrer
role:membership:referrer -.-> role:membership.partnerRel:tenant
%% granting permissions to roles
role:membership:admin ==> perm:coopSharesTransaction:INSERT
role:membership:admin ==> perm:coopSharesTransaction:UPDATE
role:membership:admin ==> perm:coopSharesTransaction:SELECT
```

View File

@ -1,125 +1,151 @@
--liquibase formatted sql
-- This code generated was by RbacViewPostgresGenerator, do not amend manually.
-- ============================================================================
--changeset hs-office-coopSharesTransaction-rbac-OBJECT:1 endDelimiter:--//
--changeset hs-office-coopsharestransaction-rbac-OBJECT:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
call generateRelatedRbacObject('hs_office_coopSharesTransaction');
call generateRelatedRbacObject('hs_office_coopsharestransaction');
--//
-- ============================================================================
--changeset hs-office-coopSharesTransaction-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--//
--changeset hs-office-coopsharestransaction-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
call generateRbacRoleDescriptors('hsOfficeCoopSharesTransaction', 'hs_office_coopSharesTransaction');
call generateRbacRoleDescriptors('hsOfficeCoopSharesTransaction', 'hs_office_coopsharestransaction');
--//
-- ============================================================================
--changeset hs-office-coopSharesTransaction-rbac-ROLES-CREATION:1 endDelimiter:--//
--changeset hs-office-coopsharestransaction-rbac-insert-trigger:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Creates and updates the permissions for coopSharesTransaction entities.
Creates the roles, grants and permission for the AFTER INSERT TRIGGER.
*/
create or replace function hsOfficeCoopSharesTransactionRbacRolesTrigger()
returns trigger
language plpgsql
strict as $$
create or replace procedure buildRbacSystemForHsOfficeCoopSharesTransaction(
NEW hs_office_coopsharestransaction
)
language plpgsql as $$
declare
newHsOfficeMembership hs_office_membership;
newMembership hs_office_membership;
begin
call enterTriggerForObjectUuid(NEW.uuid);
select * from hs_office_membership as p where p.uuid = NEW.membershipUuid into newHsOfficeMembership;
SELECT * FROM hs_office_membership WHERE uuid = NEW.membershipUuid INTO newMembership;
assert newMembership.uuid is not null, format('newMembership must not be null for NEW.membershipUuid = %s', NEW.membershipUuid);
if TG_OP = 'INSERT' then
-- Each coopSharesTransaction entity belong exactly to one membership entity
-- and it makes little sense just to delegate coopSharesTransaction roles.
-- Therefore, we do not create coopSharesTransaction roles at all,
-- but instead just assign extra permissions to existing membership-roles.
-- coopsharestransactions cannot be edited nor deleted, just created+viewed
call grantPermissionsToRole(
getRoleId(hsOfficeMembershipReferrer(newHsOfficeMembership)),
createPermissions(NEW.uuid, array ['SELECT'])
);
else
raise exception 'invalid usage of TRIGGER';
end if;
call grantPermissionToRole(createPermission(NEW.uuid, 'SELECT'), hsOfficeMembershipAdmin(newMembership));
call grantPermissionToRole(createPermission(NEW.uuid, 'UPDATE'), hsOfficeMembershipAdmin(newMembership));
call leaveTriggerForObjectUuid(NEW.uuid);
end; $$;
/*
AFTER INSERT TRIGGER to create the role+grant structure for a new hs_office_coopsharestransaction row.
*/
create or replace function insertTriggerForHsOfficeCoopSharesTransaction_tf()
returns trigger
language plpgsql
strict as $$
begin
call buildRbacSystemForHsOfficeCoopSharesTransaction(NEW);
return NEW;
end; $$;
/*
An AFTER INSERT TRIGGER which creates the role structure for a new customer.
*/
create trigger createRbacRolesForHsOfficeCoopSharesTransaction_Trigger
after insert
on hs_office_coopSharesTransaction
create trigger insertTriggerForHsOfficeCoopSharesTransaction_tg
after insert on hs_office_coopsharestransaction
for each row
execute procedure hsOfficeCoopSharesTransactionRbacRolesTrigger();
execute procedure insertTriggerForHsOfficeCoopSharesTransaction_tf();
--//
-- ============================================================================
--changeset hs-office-coopSharesTransaction-rbac-IDENTITY-VIEW:1 endDelimiter:--//
--changeset hs-office-coopsharestransaction-rbac-INSERT:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
call generateRbacIdentityViewFromProjection('hs_office_coopSharesTransaction', 'target.reference');
--//
-- ============================================================================
--changeset hs-office-coopSharesTransaction-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
call generateRbacRestrictedView('hs_office_coopSharesTransaction', orderby => 'target.reference');
--//
-- ============================================================================
--changeset hs-office-coopSharesTransaction-rbac-NEW-CoopSharesTransaction:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Creates a global permission for new-coopSharesTransaction and assigns it to the hostsharing admins role.
Creates INSERT INTO hs_office_coopsharestransaction permissions for the related hs_office_membership rows.
*/
do language plpgsql $$
declare
addCustomerPermissions uuid[];
globalObjectUuid uuid;
globalAdminRoleUuid uuid ;
row hs_office_membership;
begin
call defineContext('granting global new-coopSharesTransaction permission to global admin role', null, null, null);
call defineContext('create INSERT INTO hs_office_coopsharestransaction permissions for the related hs_office_membership rows');
globalAdminRoleUuid := findRoleId(globalAdmin());
globalObjectUuid := (select uuid from global);
addCustomerPermissions := createPermissions(globalObjectUuid, array ['new-coopsharestransaction']);
call grantPermissionsToRole(globalAdminRoleUuid, addCustomerPermissions);
end;
FOR row IN SELECT * FROM hs_office_membership
LOOP
call grantPermissionToRole(
createPermission(row.uuid, 'INSERT', 'hs_office_coopsharestransaction'),
hsOfficeMembershipAdmin(row));
END LOOP;
END;
$$;
/**
Used by the trigger to prevent the add-customer to current user respectively assumed roles.
*/
create or replace function addHsOfficeCoopSharesTransactionNotAllowedForCurrentSubjects()
Adds hs_office_coopsharestransaction INSERT permission to specified role of new hs_office_membership rows.
*/
create or replace function hs_office_coopsharestransaction_hs_office_membership_insert_tf()
returns trigger
language PLPGSQL
as $$
language plpgsql
strict as $$
begin
raise exception '[403] new-coopsharestransaction not permitted for %',
array_to_string(currentSubjects(), ';', 'null');
call grantPermissionToRole(
createPermission(NEW.uuid, 'INSERT', 'hs_office_coopsharestransaction'),
hsOfficeMembershipAdmin(NEW));
return NEW;
end; $$;
/**
Checks if the user or assumed roles are allowed to create a new customer.
*/
create trigger hs_office_coopSharesTransaction_insert_trigger
before insert
on hs_office_coopSharesTransaction
-- z_... is to put it at the end of after insert triggers, to make sure the roles exist
create trigger z_hs_office_coopsharestransaction_hs_office_membership_insert_tg
after insert on hs_office_membership
for each row
when ( not hasAssumedRole() )
execute procedure addHsOfficeCoopSharesTransactionNotAllowedForCurrentSubjects();
execute procedure hs_office_coopsharestransaction_hs_office_membership_insert_tf();
/**
Checks if the user or assumed roles are allowed to insert a row to hs_office_coopsharestransaction,
where the check is performed by a direct role.
A direct role is a role depending on a foreign key directly available in the NEW row.
*/
create or replace function hs_office_coopsharestransaction_insert_permission_missing_tf()
returns trigger
language plpgsql as $$
begin
raise exception '[403] insert into hs_office_coopsharestransaction not allowed for current subjects % (%)',
currentSubjects(), currentSubjectsUuids();
end; $$;
create trigger hs_office_coopsharestransaction_insert_permission_check_tg
before insert on hs_office_coopsharestransaction
for each row
when ( not hasInsertPermission(NEW.membershipUuid, 'INSERT', 'hs_office_coopsharestransaction') )
execute procedure hs_office_coopsharestransaction_insert_permission_missing_tf();
--//
-- ============================================================================
--changeset hs-office-coopsharestransaction-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
call generateRbacIdentityViewFromProjection('hs_office_coopsharestransaction',
$idName$
reference
$idName$);
--//
-- ============================================================================
--changeset hs-office-coopsharestransaction-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
call generateRbacRestrictedView('hs_office_coopsharestransaction',
$orderBy$
reference
$orderBy$,
$updates$
comment = new.comment
$updates$);
--//

View File

@ -111,7 +111,8 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase
.map(s -> s.replace("hs_office_", ""))
.containsExactlyInAnyOrder(Array.fromFormatted(
initialGrantNames,
"{ grant perm SELECT on coopsharestransaction#temprefB to role membership#M-1000101.referrer by system and assume }",
"{ grant perm SELECT on coopsharestransaction#temprefB to role membership#M-1000101.admin by system and assume }",
"{ grant perm UPDATE on coopsharestransaction#temprefB to role membership#M-1000101.admin by system and assume }",
null));
}