move Parter+Debitor person+contact to related Relationsship (#20)
Co-authored-by: Michael Hoennig <michael@hoennig.de> Reviewed-on: #20 Reviewed-by: Timotheus Pokorra <timotheus.pokorra@hostsharing.net>
This commit is contained in:
parent
4572c6bda0
commit
d3ca2b7e23
82
doc/ideas/rbac-schema-f.md
Normal file
82
doc/ideas/rbac-schema-f.md
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
*(this is just a scribbled draft, that's why it's still in German)*
|
||||||
|
|
||||||
|
### *Schema-F* für Permissions, Rollen und Grants
|
||||||
|
|
||||||
|
Permissions, Rollen und Grants werden in den INSERT/UPDATE/DELETE-Triggern von Geschäftsobjekten erzeugt und gelöscht. Das Löschen erfolgt meistens automatisch über das zugehörige RbacObject, die INSERT- und UPDATE-Trigger müssen jedoch in *pl/pgsql* ausprogrammiert werden.
|
||||||
|
|
||||||
|
Das folgende Schema soll dabei unterstützen, die richtigen Permissions, Rollen und Grants festzulegen.
|
||||||
|
|
||||||
|
An einigen Stellen ist vom *Initiator* die Rede. Als *Initiator* gilt derjenige User, der die Operation (INSERT oder UPDATE) durchführt bzw. dessen primary assumed Rol. (TODO: bisher gibt es nur assumed roles, das Konzept einer primary assumed Role müsste noch eingeführt werden, derzeit nehmen wir dafür immer den `globalAdmin()`. Bevor Kunden aber selbst Objekte anlegen können, muss das geklärt sein.)
|
||||||
|
|
||||||
|
#### Typ Root: Objekte, welche nur eine Spezialisierung bzw. Zusatzdaten für andere Objekte bereitstellen (z.B. Partner für Relations vom Typ Partner oder Partner Details für Partner)
|
||||||
|
|
||||||
|
Objektorientiert gedacht, enthalten solche Objekte die Zusatzdaten einer Subklasse; die Daten im Partner erweitern also eine Relation vom Typ `partner`.
|
||||||
|
|
||||||
|
- Dann muss dieses Objekt zeitlich nach dem Objekt erzeugt werden, auf dass es sich bezieht, also z.B. zeitlich nach der Relation.
|
||||||
|
- Es werden Delete (\*), Edit und View Permissions für dieses Objekt erzeugt.
|
||||||
|
- Es werden **keine** Rollen für dieses Objekt erzeugt.
|
||||||
|
- Statt eigener Rollen werden die o.g. Permissions passenden Rollen des Hauptobjekts zugewiesen (granted) bzw. aus denen entfernt (revoked).
|
||||||
|
- Handelt es sich um Zusatzdaten zum Zwecke der Spezialisierung, dann z.B. so:
|
||||||
|
- Delete (\*) <-- Owner des Hauptobjektes
|
||||||
|
- Edit <-- **Admin** des Hauptobjektes
|
||||||
|
- View <-- Agent des Hauptobjektes
|
||||||
|
- Handelt es sich um Zusatzdaten, für die sich Edit-Rechte delegieren lassen sollen (wie im Falle der Partner-Details eines Partners), dann z.B. so:
|
||||||
|
- Delete (\*) <-- Owner des Hauptobjektes
|
||||||
|
- Edit <-- **Agent** des Hauptobjektes
|
||||||
|
- View <-- Agent des Hauptobjektes
|
||||||
|
- Für die Rollenzuordnung zwischen referenzierten Objekten gilt:
|
||||||
|
- Für Objekte vom Typ Root werden die Rollen des zugehörigen Aggregator-Objektes verwendet.
|
||||||
|
- Gibt es Referenzen auf hierarchisch verbundene Objekte (z.B. Debitor.refundBankAccount) gilt folgende Faustregel:
|
||||||
|
***Nach oben absteigen, nach unten halten oder aufsteigen.*** An einem fachlich übergeordneten Objekt wird also eine niedrigere Rolle (z.B. Debitor-admin -> Partner.agent), einem fachlich untergeordneten Objekt eine gleichwertige Rolle (z.B. Partner.admin -> Debitor.admin) zugewiesen oder sogar aufgestiegen (Debitor.admin -> Package.tenant).
|
||||||
|
- Für Referenzen zwischen Objekten, die nicht hierarchisch zueinander stehen (z.B. Debitor und Bankverbindung), wird auf beiden seiten abgestiegen (also Debitor.admin -> BankAccount.referrer und BankAccount.admin -> Debitor.tenant).
|
||||||
|
|
||||||
|
Anmerkung: Der Typ-Begriff *Root* bezieht sich auf die Rolle im fachlichen Datenmodell. Im Bezug auf den Teilgraphen eines fachlichen Kontexts ist dies auch eine Wurzel im Sinne der Graphentheorie. Aber in anderen fachlichen Kontexten können auch diese Objekte von anderen Teilgraphen referenziert werden und werden dann zum inneren Knoten.
|
||||||
|
|
||||||
|
|
||||||
|
#### Typ Aggregator: Objekte, welche weitere Objekte zusammenfassen (z.B. Relation fasst zwei Persons und einen Contact zusammen)
|
||||||
|
|
||||||
|
Solche Objekte verweisen üblicherweise auf Objekte vom Typ Leaf und werden oft von Objekten des Typs Root referenziert.
|
||||||
|
|
||||||
|
- Es werden i.d.R. folgende Rollen für diese Objekte erzeugt:
|
||||||
|
- Owner, Admin, Agent, Tenent(, Guest?)
|
||||||
|
- Es werden Delete (\*), Edit und View Permissions für dieses Objekt erzeugt.
|
||||||
|
- Die Permissions werden den Rollen sinnvoll zugewiesen, z.B.:
|
||||||
|
- Owner -> Delete (\*)
|
||||||
|
- Admin --> Edit
|
||||||
|
- Tenant (oder ggf. Guest) --> View
|
||||||
|
- Außerdem werden folgende Grants erstellt bzw. entzogen:
|
||||||
|
- Initiator --> Owner
|
||||||
|
- Owner --> Admin
|
||||||
|
- Admin --> Referrer
|
||||||
|
- Admins der referenzierten Objekte werden Agent des Aggregators
|
||||||
|
- Tenants des Aggregators werden Referrer der referenzierten Objekte
|
||||||
|
|
||||||
|
### Typ Leaf: Handelt es sich um ein Objekt, welches (außer zur Modellierung separater Permissions) keine Unterobjekte enthält (z.B. Person, Customer)?
|
||||||
|
|
||||||
|
Solche Objekte werden üblicherweise von Objekten des Typs Aggregator, manchmal auch von Objekten des Typs Root, referenziert.
|
||||||
|
|
||||||
|
- Es werden i.d.R. folgende Rollen für diese Objekte erzeugt:
|
||||||
|
- Owner, Admin, Referrer
|
||||||
|
- Es werden Delete (\*), Edit und View Permissions für dieses Objekt erzeugt.
|
||||||
|
- Die Permissions werden den Rollen sinnvoll zugewiesen, z.B.:
|
||||||
|
- Delete (\*) <-- Owner
|
||||||
|
- Edit <-- Admin
|
||||||
|
- View <-- Referrer
|
||||||
|
- Außerdem werden folgende Grants erstellt bzw. entzogen:
|
||||||
|
- Owner --> Admin
|
||||||
|
- Admin --> Referrer
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
|
||||||
|
subgraph partnerDetails
|
||||||
|
direction TB
|
||||||
|
style partnerDetails fill:#eee
|
||||||
|
|
||||||
|
perm:partnerDetails.*{{partnerDetails.*}}
|
||||||
|
role:partnerDetails.edit{{partnerDetails.edit}}
|
||||||
|
role:partnerDetails.view{{partnerDetails.view}}
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
```
|
29
doc/ideas/simplified-grant-structure.md
Normal file
29
doc/ideas/simplified-grant-structure.md
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
(this is just a scribbled idea, that's why it's still in German)
|
||||||
|
|
||||||
|
Ich habe mal wieder vom RBAC-System geträumt 🙈 Ok, im Halbschlaf darüber nachgedacht trifft es wohl besser. Und jetzt frage ich mich, ob wir viel zu kompliziert gedacht haben.
|
||||||
|
|
||||||
|
Bislang gingen wir ja davon aus, dass, wenn komplexe Entitäten (z.B. Partner) erzeugt werden, wir wir über den INSERT-Trigger den Rollen der verknüpften Entitäten (z.B. den Rollen der Personendaten des Partners) auch Rechte an den komplexeren Entitäten und umgekehrt geben müssen.
|
||||||
|
|
||||||
|
Da die komplexen Entitäten nur mit gewissen verbundenen Entitäten überhaupt sinnvoll nutzbar sind und diese daher über INNSER JOINs mitladen, könnte sonst auch nur jemand diese Entitäten, der auch die SELECT-Permission an den verküpften Entitäten hat.
|
||||||
|
|
||||||
|
Vor einigen Wochen hatten wir schon einmal darüber geredet, ob wir dieses Geflecht wirklich komplett durchplanen müssen, also über mehrere Stufen hinweg, oder ob sehr warscheinlich eh dieselben Leuten an den weiter entfernten Entitäten die nötien Rechte haben, weil dahinter dieselben User stehen. Also z.B. dass gewährleistet ist, dass jemand mit ADMIN-Recht an den Personendaten des Partners auch bis in die SEPA-Mandate eines Debitors hineinsehen kann.
|
||||||
|
|
||||||
|
Und nun gehe ich noch einen Schritt weiter: Könnte es nicht auch andersherum sein? Also wenn jemand z.B. SELECT-Recht am Partner hat, dass wir davon ausgehen können, dass derjenige auch die Partner-Personen- und Kontaktdaten sehen darf, und zwar implizit durch seine Partner-SELECT-Permission und ohne dass er explizit Rollen für diese Partner-Personen oder Kontaktdaten inne hat?
|
||||||
|
|
||||||
|
Im Halbschlaf kam mir nur die Idee, warum wir nicht einfach die komplexen JPA-Entitäten zwar auf die restricted View setzen, wie bisher, aber für die verknüpften Entitäten auf die direkten (bisher "Raw..." genannt) Entitäten gehen. Dann könnte jemand mit einer Rolle, welche die SELECT-Permission auf die komplexe JPA-Entität (z.B.) Partner inne hat, auch die dazugehörige Relation(ship) ["Relation" wurde vor kurzem auf kurz "Relation" umbenannt] und die wiederum dazu gehörigen Personen- und Kontaktdaten lesen, ohne dass in einem INSERT- und UPDATE-Trigger der Partner-Entität die ganzen Grants mit den verknüpften Entäten aufgebaut und aktualisiert werden müssen.
|
||||||
|
|
||||||
|
Beim Debitor ist das nämlich selbst mit Generator die Hölle, zumal eben auch Querverbindungen gegranted werden müssen, z.B. von der Debitor-Person zum Sema-Mandat - jedenfalls wenn man nicht Gefahr laufen wollte, dass jemand mit Admin-Rechten an der Partner-Person (also z.B. ein Repräsentant des Partners) die Sepa-Mandate der Debitoren gar nicht mehr sehen kann. Natürlich bräuchte man immer noch die Agent-Rolle am Partner und Debitor (evtl. repräsentiert durch die jeweils zugehörigen Relation - falls dieser Trick überhaupt noch nötig wäre), sowie ein Grant vom Partner-Agent auf den Debitor-Agent und vom Debitor-Agent auf die Sepa-Mandate-Admins, aber eben ohne filigran die ganzen Neben-Entäten (Personen- und Kontaktdaten von Partner und Debitor sowie Bank-Account) in jedem Trigger berücksichtigen zu müssen. Beim Refund-Bank-Account sogar besonders ätzend, weil der optional ist und dadurch zig "if ...refundBankAccountUuid is not null then ..." im Code enstehen (wenn der auch generiert ist).
|
||||||
|
|
||||||
|
Mit anderen Worten, um als Repräsentant eines Geschäftspartners auf den Bank-Account der Sepa-Mandate sehen zu dürfen, wird derzeut folgende Grant-Kette durchlaufen (bzw. eben noch nicht, weil es noch nicht funktioniert):
|
||||||
|
|
||||||
|
User -> Partner-Holder-Person:Admin -> Partner-Relation:Agent -> Debitor-Relation:Agent -> Sepa-Mandat:Admin -> BankAccount:Admin -> BankAccount:SELECT
|
||||||
|
|
||||||
|
Daraus würde:
|
||||||
|
|
||||||
|
User -> Partner-Relation:Agent -> Debitor-Relation:Agent -> Sepa-Mandat:Admin -> Sepa-Mandat:SELECT*
|
||||||
|
|
||||||
|
(*mit JOIN auf RawBankAccount, also implizitem Leserecht)
|
||||||
|
|
||||||
|
Das klingt zunächst nach nur einer marginalen Vereinfachung, die eigentlich Vereinfachung liegt aber im Erzeugen der Grants in den Triggern, denn da sind zudem noch Partner-Anchor-Person, Debitor-Holder- und Anchor-Person, Partner- und Debitor-Contact sowie der RefundBankAccount zu berücksichtigen. Und genau diese Grants würden großteils wegfallen, und durch implizite Persmissions über die JOINs auf die Raw-Tables ersetzt werden. Den refundBankAccound müssten wir dann, analog zu den Sepa-Mandataten, umgedreht modellieren, da den sonst
|
||||||
|
|
||||||
|
Man könnte das Ganze auch als "Entwicklung der Rechtestruktur für Hosting-Entitäten auf der obersten Ebene" (Manged Webspace, Managed Server, Cloud Server etc.) sehen, denn die hängen alle unter dem Mega-komplexen Debitor.
|
@ -1,6 +1,6 @@
|
|||||||
## *hsadmin-ng*'s Role-Based-Access-Management (RBAC)
|
## *hsadmin-ng*'s Role-Based-Access-Management (RBAC)
|
||||||
|
|
||||||
The requirements of *hsadmin-ng* include table-m row- and column-level-security for read and write access to business-objects.
|
The requirements of *hsadmin-ng* include table-, row- and column-level-security for read and write access to business-objects.
|
||||||
More precisely, any access has to be controlled according to given rules depending on the accessing users, their roles and the accessed business-object.
|
More precisely, any access has to be controlled according to given rules depending on the accessing users, their roles and the accessed business-object.
|
||||||
Further, roles and business-objects are hierarchical.
|
Further, roles and business-objects are hierarchical.
|
||||||
|
|
||||||
|
@ -33,8 +33,8 @@ import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
|||||||
public class HsOfficeBankAccountEntity implements HasUuid, Stringifyable {
|
public class HsOfficeBankAccountEntity implements HasUuid, Stringifyable {
|
||||||
|
|
||||||
private static Stringify<HsOfficeBankAccountEntity> toString = stringify(HsOfficeBankAccountEntity.class, "bankAccount")
|
private static Stringify<HsOfficeBankAccountEntity> toString = stringify(HsOfficeBankAccountEntity.class, "bankAccount")
|
||||||
|
.withIdProp(HsOfficeBankAccountEntity::getIban)
|
||||||
.withProp(Fields.holder, HsOfficeBankAccountEntity::getHolder)
|
.withProp(Fields.holder, HsOfficeBankAccountEntity::getHolder)
|
||||||
.withProp(Fields.iban, HsOfficeBankAccountEntity::getIban)
|
|
||||||
.withProp(Fields.bic, HsOfficeBankAccountEntity::getBic);
|
.withProp(Fields.bic, HsOfficeBankAccountEntity::getBic);
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@ -59,8 +59,11 @@ public class HsOfficeBankAccountEntity implements HasUuid, Stringifyable {
|
|||||||
|
|
||||||
public static RbacView rbac() {
|
public static RbacView rbac() {
|
||||||
return rbacViewFor("bankAccount", HsOfficeBankAccountEntity.class)
|
return rbacViewFor("bankAccount", HsOfficeBankAccountEntity.class)
|
||||||
.withIdentityView(SQL.projection("iban || ':' || holder"))
|
.withIdentityView(SQL.projection("iban"))
|
||||||
.withUpdatableColumns("holder", "iban", "bic")
|
.withUpdatableColumns("holder", "iban", "bic")
|
||||||
|
|
||||||
|
.toRole("global", GUEST).grantPermission(INSERT)
|
||||||
|
|
||||||
.createRole(OWNER, (with) -> {
|
.createRole(OWNER, (with) -> {
|
||||||
with.owningUser(CREATOR);
|
with.owningUser(CREATOR);
|
||||||
with.incomingSuperRole(GLOBAL, ADMIN);
|
with.incomingSuperRole(GLOBAL, ADMIN);
|
||||||
@ -75,6 +78,6 @@ public class HsOfficeBankAccountEntity implements HasUuid, Stringifyable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
rbac().generateWithBaseFileName("243-hs-office-bankaccount-rbac-generated");
|
rbac().generateWithBaseFileName("243-hs-office-bankaccount-rbac");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,10 +75,11 @@ public class HsOfficeContactEntity implements Stringifyable, HasUuid {
|
|||||||
})
|
})
|
||||||
.createSubRole(REFERRER, (with) -> {
|
.createSubRole(REFERRER, (with) -> {
|
||||||
with.permission(SELECT);
|
with.permission(SELECT);
|
||||||
});
|
})
|
||||||
|
.toRole(GLOBAL, GUEST).grantPermission(INSERT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
rbac().generateWithBaseFileName("203-hs-office-contact-rbac-generated");
|
rbac().generateWithBaseFileName("203-hs-office-contact-rbac");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import org.hibernate.annotations.GenericGenerator;
|
|||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import static java.util.Optional.ofNullable;
|
import static java.util.Optional.ofNullable;
|
||||||
@ -28,13 +29,12 @@ import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
|||||||
public class HsOfficeCoopAssetsTransactionEntity implements Stringifyable, HasUuid {
|
public class HsOfficeCoopAssetsTransactionEntity implements Stringifyable, HasUuid {
|
||||||
|
|
||||||
private static Stringify<HsOfficeCoopAssetsTransactionEntity> stringify = stringify(HsOfficeCoopAssetsTransactionEntity.class)
|
private static Stringify<HsOfficeCoopAssetsTransactionEntity> stringify = stringify(HsOfficeCoopAssetsTransactionEntity.class)
|
||||||
.withProp(HsOfficeCoopAssetsTransactionEntity::getMemberNumber)
|
.withIdProp(HsOfficeCoopAssetsTransactionEntity::getTaggedMemberNumber)
|
||||||
.withProp(HsOfficeCoopAssetsTransactionEntity::getValueDate)
|
.withProp(HsOfficeCoopAssetsTransactionEntity::getValueDate)
|
||||||
.withProp(HsOfficeCoopAssetsTransactionEntity::getTransactionType)
|
.withProp(HsOfficeCoopAssetsTransactionEntity::getTransactionType)
|
||||||
.withProp(HsOfficeCoopAssetsTransactionEntity::getAssetValue)
|
.withProp(HsOfficeCoopAssetsTransactionEntity::getAssetValue)
|
||||||
.withProp(HsOfficeCoopAssetsTransactionEntity::getReference)
|
.withProp(HsOfficeCoopAssetsTransactionEntity::getReference)
|
||||||
.withProp(HsOfficeCoopAssetsTransactionEntity::getComment)
|
.withProp(HsOfficeCoopAssetsTransactionEntity::getComment)
|
||||||
.withSeparator(", ")
|
|
||||||
.quotedValues(false);
|
.quotedValues(false);
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@ -76,8 +76,8 @@ public class HsOfficeCoopAssetsTransactionEntity implements Stringifyable, HasUu
|
|||||||
private String comment;
|
private String comment;
|
||||||
|
|
||||||
|
|
||||||
public Integer getMemberNumber() {
|
public String getTaggedMemberNumber() {
|
||||||
return ofNullable(membership).map(HsOfficeMembershipEntity::getMemberNumber).orElse(null);
|
return ofNullable(membership).map(HsOfficeMembershipEntity::toShortString).orElse("M-?????");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -87,6 +87,6 @@ public class HsOfficeCoopAssetsTransactionEntity implements Stringifyable, HasUu
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toShortString() {
|
public String toShortString() {
|
||||||
return "%s%+1.2f".formatted(getMemberNumber(), assetValue);
|
return "%s:%+1.2f".formatted(getTaggedMemberNumber(), Optional.ofNullable(assetValue).orElse(BigDecimal.ZERO));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,6 @@ public class HsOfficeCoopSharesTransactionEntity implements Stringifyable, HasUu
|
|||||||
.withProp(HsOfficeCoopSharesTransactionEntity::getShareCount)
|
.withProp(HsOfficeCoopSharesTransactionEntity::getShareCount)
|
||||||
.withProp(HsOfficeCoopSharesTransactionEntity::getReference)
|
.withProp(HsOfficeCoopSharesTransactionEntity::getReference)
|
||||||
.withProp(HsOfficeCoopSharesTransactionEntity::getComment)
|
.withProp(HsOfficeCoopSharesTransactionEntity::getComment)
|
||||||
.withSeparator(", ")
|
|
||||||
.quotedValues(false);
|
.quotedValues(false);
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
|
@ -5,7 +5,11 @@ import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeDebitors
|
|||||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeDebitorInsertResource;
|
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeDebitorInsertResource;
|
||||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeDebitorPatchResource;
|
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeDebitorPatchResource;
|
||||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeDebitorResource;
|
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeDebitorResource;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationEntity;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRepository;
|
||||||
import net.hostsharing.hsadminng.mapper.Mapper;
|
import net.hostsharing.hsadminng.mapper.Mapper;
|
||||||
|
import org.apache.commons.lang3.Validate;
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@ -13,10 +17,13 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
|
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
|
||||||
|
|
||||||
import jakarta.persistence.EntityManager;
|
import jakarta.persistence.EntityManager;
|
||||||
|
import jakarta.persistence.EntityNotFoundException;
|
||||||
import jakarta.persistence.PersistenceContext;
|
import jakarta.persistence.PersistenceContext;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationType.DEBITOR;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
|
|
||||||
public class HsOfficeDebitorController implements HsOfficeDebitorsApi {
|
public class HsOfficeDebitorController implements HsOfficeDebitorsApi {
|
||||||
@ -30,6 +37,9 @@ public class HsOfficeDebitorController implements HsOfficeDebitorsApi {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private HsOfficeDebitorRepository debitorRepo;
|
private HsOfficeDebitorRepository debitorRepo;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private HsOfficeRelationRepository relRepo;
|
||||||
|
|
||||||
@PersistenceContext
|
@PersistenceContext
|
||||||
private EntityManager em;
|
private EntityManager em;
|
||||||
|
|
||||||
@ -53,22 +63,44 @@ public class HsOfficeDebitorController implements HsOfficeDebitorsApi {
|
|||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public ResponseEntity<HsOfficeDebitorResource> addDebitor(
|
public ResponseEntity<HsOfficeDebitorResource> addDebitor(
|
||||||
final String currentUser,
|
String currentUser,
|
||||||
final String assumedRoles,
|
String assumedRoles,
|
||||||
final HsOfficeDebitorInsertResource body) {
|
HsOfficeDebitorInsertResource body) {
|
||||||
|
|
||||||
context.define(currentUser, assumedRoles);
|
context.define(currentUser, assumedRoles);
|
||||||
|
|
||||||
final var entityToSave = mapper.map(body, HsOfficeDebitorEntity.class);
|
Validate.isTrue(body.getDebitorRel() == null || body.getDebitorRelUuid() == null,
|
||||||
|
"ERROR: [400] exactly one of debitorRel and debitorRelUuid must be supplied, but found both");
|
||||||
|
Validate.isTrue(body.getDebitorRel() != null || body.getDebitorRelUuid() != null,
|
||||||
|
"ERROR: [400] exactly one of debitorRel and debitorRelUuid must be supplied, but found none");
|
||||||
|
Validate.isTrue(body.getDebitorRel() == null ||
|
||||||
|
body.getDebitorRel().getType() == null || DEBITOR.name().equals(body.getDebitorRel().getType()),
|
||||||
|
"ERROR: [400] debitorRel.type must be '"+DEBITOR.name()+"' or null for default");
|
||||||
|
Validate.isTrue(body.getDebitorRel() == null || body.getDebitorRel().getMark() == null,
|
||||||
|
"ERROR: [400] debitorRel.mark must be null");
|
||||||
|
|
||||||
final var saved = debitorRepo.save(entityToSave);
|
final var entityToSave = mapper.map(body, HsOfficeDebitorEntity.class);
|
||||||
|
if ( body.getDebitorRel() != null ) {
|
||||||
|
body.getDebitorRel().setType(DEBITOR.name());
|
||||||
|
final var debitorRel = mapper.map(body.getDebitorRel(), HsOfficeRelationEntity.class);
|
||||||
|
entityToSave.setDebitorRel(relRepo.save(debitorRel));
|
||||||
|
} else {
|
||||||
|
final var debitorRelOptional = relRepo.findByUuid(body.getDebitorRelUuid());
|
||||||
|
debitorRelOptional.ifPresentOrElse(
|
||||||
|
debitorRel -> {entityToSave.setDebitorRel(relRepo.save(debitorRel));},
|
||||||
|
() -> { throw new EntityNotFoundException("ERROR: [400] debitorRelUuid not found: " + body.getDebitorRelUuid());});
|
||||||
|
}
|
||||||
|
|
||||||
|
final var savedEntity = debitorRepo.save(entityToSave);
|
||||||
|
em.flush();
|
||||||
|
em.refresh(savedEntity);
|
||||||
|
|
||||||
final var uri =
|
final var uri =
|
||||||
MvcUriComponentsBuilder.fromController(getClass())
|
MvcUriComponentsBuilder.fromController(getClass())
|
||||||
.path("/api/hs/office/debitors/{id}")
|
.path("/api/hs/office/debitors/{id}")
|
||||||
.buildAndExpand(saved.getUuid())
|
.buildAndExpand(savedEntity.getUuid())
|
||||||
.toUri();
|
.toUri();
|
||||||
final var mapped = mapper.map(saved, HsOfficeDebitorResource.class);
|
final var mapped = mapper.map(savedEntity, HsOfficeDebitorResource.class);
|
||||||
return ResponseEntity.created(uri).body(mapped);
|
return ResponseEntity.created(uri).body(mapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,6 +151,7 @@ public class HsOfficeDebitorController implements HsOfficeDebitorsApi {
|
|||||||
new HsOfficeDebitorEntityPatcher(em, current).apply(body);
|
new HsOfficeDebitorEntityPatcher(em, current).apply(body);
|
||||||
|
|
||||||
final var saved = debitorRepo.save(current);
|
final var saved = debitorRepo.save(current);
|
||||||
|
Hibernate.initialize(saved);
|
||||||
final var mapped = mapper.map(saved, HsOfficeDebitorResource.class);
|
final var mapped = mapper.map(saved, HsOfficeDebitorResource.class);
|
||||||
return ResponseEntity.ok(mapped);
|
return ResponseEntity.ok(mapped);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package net.hostsharing.hsadminng.hs.office.debitor;
|
|||||||
import lombok.*;
|
import lombok.*;
|
||||||
import net.hostsharing.hsadminng.errors.DisplayName;
|
import net.hostsharing.hsadminng.errors.DisplayName;
|
||||||
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity;
|
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity;
|
||||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
|
|
||||||
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
|
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
|
||||||
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationEntity;
|
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationEntity;
|
||||||
import net.hostsharing.hsadminng.persistence.HasUuid;
|
import net.hostsharing.hsadminng.persistence.HasUuid;
|
||||||
@ -12,17 +11,26 @@ import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL;
|
|||||||
import net.hostsharing.hsadminng.stringify.Stringify;
|
import net.hostsharing.hsadminng.stringify.Stringify;
|
||||||
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
||||||
import org.hibernate.annotations.GenericGenerator;
|
import org.hibernate.annotations.GenericGenerator;
|
||||||
|
import org.hibernate.annotations.JoinFormula;
|
||||||
|
import org.hibernate.annotations.NotFound;
|
||||||
|
import org.hibernate.annotations.NotFoundAction;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static jakarta.persistence.CascadeType.DETACH;
|
||||||
|
import static jakarta.persistence.CascadeType.MERGE;
|
||||||
|
import static jakarta.persistence.CascadeType.PERSIST;
|
||||||
|
import static jakarta.persistence.CascadeType.REFRESH;
|
||||||
|
import static java.util.Optional.ofNullable;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn;
|
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.Nullable.NULLABLE;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Nullable.NULLABLE;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
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.SQL.directlyFetchedByDependsOnColumn;
|
||||||
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.fetchedBySql;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
|
||||||
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
||||||
|
|
||||||
@ -30,7 +38,7 @@ import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
|||||||
@Table(name = "hs_office_debitor_rv")
|
@Table(name = "hs_office_debitor_rv")
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@Builder
|
@Builder(toBuilder = true)
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@DisplayName("Debitor")
|
@DisplayName("Debitor")
|
||||||
@ -38,15 +46,11 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
|
|||||||
|
|
||||||
public static final String DEBITOR_NUMBER_TAG = "D-";
|
public static final String DEBITOR_NUMBER_TAG = "D-";
|
||||||
|
|
||||||
// TODO: I would rather like to generate something matching this example:
|
|
||||||
// debitor(1234500: Test AG, tes)
|
|
||||||
// maybe remove withSepararator (always use ', ') and add withBusinessIdProp (with ': ' afterwards)?
|
|
||||||
private static Stringify<HsOfficeDebitorEntity> stringify =
|
private static Stringify<HsOfficeDebitorEntity> stringify =
|
||||||
stringify(HsOfficeDebitorEntity.class, "debitor")
|
stringify(HsOfficeDebitorEntity.class, "debitor")
|
||||||
.withProp(e -> DEBITOR_NUMBER_TAG + e.getDebitorNumber())
|
.withIdProp(HsOfficeDebitorEntity::toShortString)
|
||||||
.withProp(HsOfficeDebitorEntity::getPartner)
|
.withProp(e -> ofNullable(e.getDebitorRel()).map(HsOfficeRelationEntity::toShortString).orElse(null))
|
||||||
.withProp(HsOfficeDebitorEntity::getDefaultPrefix)
|
.withProp(HsOfficeDebitorEntity::getDefaultPrefix)
|
||||||
.withSeparator(": ")
|
|
||||||
.quotedValues(false);
|
.quotedValues(false);
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@ -55,15 +59,28 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
|
|||||||
private UUID uuid;
|
private UUID uuid;
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
@JoinColumn(name = "partneruuid")
|
@JoinFormula(
|
||||||
|
referencedColumnName = "uuid",
|
||||||
|
value = """
|
||||||
|
(
|
||||||
|
SELECT DISTINCT partner.uuid
|
||||||
|
FROM hs_office_partner_rv partner
|
||||||
|
JOIN hs_office_relation_rv dRel
|
||||||
|
ON dRel.uuid = debitorreluuid AND dRel.type = 'DEBITOR'
|
||||||
|
JOIN hs_office_relation_rv pRel
|
||||||
|
ON pRel.uuid = partner.partnerRelUuid AND pRel.type = 'PARTNER'
|
||||||
|
WHERE pRel.holderUuid = dRel.anchorUuid
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
@NotFound(action = NotFoundAction.IGNORE)
|
||||||
private HsOfficePartnerEntity partner;
|
private HsOfficePartnerEntity partner;
|
||||||
|
|
||||||
@Column(name = "debitornumbersuffix", columnDefinition = "numeric(2)")
|
@Column(name = "debitornumbersuffix", columnDefinition = "numeric(2)")
|
||||||
private Byte debitorNumberSuffix; // TODO maybe rather as a formatted String?
|
private Byte debitorNumberSuffix; // TODO maybe rather as a formatted String?
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne(cascade = { PERSIST, MERGE, REFRESH, DETACH }, optional = false)
|
||||||
@JoinColumn(name = "billingcontactuuid")
|
@JoinColumn(name = "debitorreluuid", nullable = false)
|
||||||
private HsOfficeContactEntity billingContact; // TODO: migrate to billingPerson
|
private HsOfficeRelationEntity debitorRel;
|
||||||
|
|
||||||
@Column(name = "billable", nullable = false)
|
@Column(name = "billable", nullable = false)
|
||||||
private Boolean billable; // not a primitive because otherwise the default would be false
|
private Boolean billable; // not a primitive because otherwise the default would be false
|
||||||
@ -88,14 +105,16 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
|
|||||||
private String defaultPrefix;
|
private String defaultPrefix;
|
||||||
|
|
||||||
private String getDebitorNumberString() {
|
private String getDebitorNumberString() {
|
||||||
if (partner == null || partner.getPartnerNumber() == null || debitorNumberSuffix == null) {
|
return ofNullable(partner)
|
||||||
return null;
|
.filter(partner -> debitorNumberSuffix != null)
|
||||||
}
|
.map(HsOfficePartnerEntity::getPartnerNumber)
|
||||||
return partner.getPartnerNumber() + String.format("%02d", debitorNumberSuffix);
|
.map(Object::toString)
|
||||||
|
.map(partnerNumber -> partnerNumber + String.format("%02d", debitorNumberSuffix))
|
||||||
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getDebitorNumber() {
|
public Integer getDebitorNumber() {
|
||||||
return Optional.ofNullable(getDebitorNumberString()).map(Integer::parseInt).orElse(null);
|
return ofNullable(getDebitorNumberString()).map(Integer::parseInt).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -111,28 +130,28 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
|
|||||||
public static RbacView rbac() {
|
public static RbacView rbac() {
|
||||||
return rbacViewFor("debitor", HsOfficeDebitorEntity.class)
|
return rbacViewFor("debitor", HsOfficeDebitorEntity.class)
|
||||||
.withIdentityView(SQL.query("""
|
.withIdentityView(SQL.query("""
|
||||||
SELECT debitor.uuid,
|
SELECT debitor.uuid AS uuid,
|
||||||
'D-' || (SELECT partner.partnerNumber
|
'D-' || (SELECT partner.partnerNumber
|
||||||
FROM hs_office_partner partner
|
FROM hs_office_partner partner
|
||||||
JOIN hs_office_relation partnerRel
|
JOIN hs_office_relation partnerRel
|
||||||
ON partnerRel.uuid = partner.partnerRelUUid AND partnerRel.type = 'PARTNER'
|
ON partnerRel.uuid = partner.partnerRelUUid AND partnerRel.type = 'PARTNER'
|
||||||
JOIN hs_office_relation debitorRel
|
JOIN hs_office_relation debitorRel
|
||||||
ON debitorRel.anchorUuid = partnerRel.holderUuid AND partnerRel.type = 'DEBITOR'
|
ON debitorRel.anchorUuid = partnerRel.holderUuid AND debitorRel.type = 'DEBITOR'
|
||||||
WHERE debitorRel.uuid = debitor.debitorRelUuid)
|
WHERE debitorRel.uuid = debitor.debitorRelUuid)
|
||||||
|| to_char(debitorNumberSuffix, 'fm00')
|
|| to_char(debitorNumberSuffix, 'fm00') as idName
|
||||||
from hs_office_debitor as debitor
|
FROM hs_office_debitor AS debitor
|
||||||
"""))
|
"""))
|
||||||
|
.withRestrictedViewOrderBy(SQL.projection("defaultPrefix"))
|
||||||
.withUpdatableColumns(
|
.withUpdatableColumns(
|
||||||
"debitorRel",
|
"debitorRelUuid",
|
||||||
"billable",
|
"billable",
|
||||||
"debitorUuid",
|
|
||||||
"refundBankAccountUuid",
|
"refundBankAccountUuid",
|
||||||
"vatId",
|
"vatId",
|
||||||
"vatCountryCode",
|
"vatCountryCode",
|
||||||
"vatBusiness",
|
"vatBusiness",
|
||||||
"vatReverseCharge",
|
"vatReverseCharge",
|
||||||
"defaultPrefix" /* TODO: do we want that updatable? */)
|
"defaultPrefix" /* TODO: do we want that updatable? */)
|
||||||
.createPermission(INSERT).grantedTo("global", ADMIN)
|
.toRole("global", ADMIN).grantPermission(INSERT)
|
||||||
|
|
||||||
.importRootEntityAliasProxy("debitorRel", HsOfficeRelationEntity.class,
|
.importRootEntityAliasProxy("debitorRel", HsOfficeRelationEntity.class,
|
||||||
directlyFetchedByDependsOnColumn(),
|
directlyFetchedByDependsOnColumn(),
|
||||||
@ -149,9 +168,16 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
|
|||||||
.toRole("debitorRel", AGENT).grantRole("refundBankAccount", REFERRER)
|
.toRole("debitorRel", AGENT).grantRole("refundBankAccount", REFERRER)
|
||||||
|
|
||||||
.importEntityAlias("partnerRel", HsOfficeRelationEntity.class,
|
.importEntityAlias("partnerRel", HsOfficeRelationEntity.class,
|
||||||
dependsOnColumn("partnerRelUuid"),
|
dependsOnColumn("debitorRelUuid"),
|
||||||
directlyFetchedByDependsOnColumn(),
|
fetchedBySql("""
|
||||||
NULLABLE)
|
SELECT ${columns}
|
||||||
|
FROM hs_office_relation AS partnerRel
|
||||||
|
JOIN hs_office_relation AS debitorRel
|
||||||
|
ON debitorRel.type = 'DEBITOR' AND debitorRel.anchorUuid = partnerRel.holderUuid
|
||||||
|
WHERE partnerRel.type = 'PARTNER'
|
||||||
|
AND ${REF}.debitorRelUuid = debitorRel.uuid
|
||||||
|
"""),
|
||||||
|
NOT_NULL)
|
||||||
.toRole("partnerRel", ADMIN).grantRole("debitorRel", ADMIN)
|
.toRole("partnerRel", ADMIN).grantRole("debitorRel", ADMIN)
|
||||||
.toRole("partnerRel", AGENT).grantRole("debitorRel", AGENT)
|
.toRole("partnerRel", AGENT).grantRole("debitorRel", AGENT)
|
||||||
.toRole("debitorRel", AGENT).grantRole("partnerRel", TENANT)
|
.toRole("debitorRel", AGENT).grantRole("partnerRel", TENANT)
|
||||||
@ -162,6 +188,6 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
rbac().generateWithBaseFileName("273-hs-office-debitor-rbac-generated");
|
rbac().generateWithBaseFileName("273-hs-office-debitor-rbac");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package net.hostsharing.hsadminng.hs.office.debitor;
|
package net.hostsharing.hsadminng.hs.office.debitor;
|
||||||
|
|
||||||
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity;
|
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity;
|
||||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
|
|
||||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeDebitorPatchResource;
|
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeDebitorPatchResource;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationEntity;
|
||||||
import net.hostsharing.hsadminng.mapper.EntityPatcher;
|
import net.hostsharing.hsadminng.mapper.EntityPatcher;
|
||||||
import net.hostsharing.hsadminng.mapper.OptionalFromJson;
|
import net.hostsharing.hsadminng.mapper.OptionalFromJson;
|
||||||
|
|
||||||
@ -23,9 +23,9 @@ class HsOfficeDebitorEntityPatcher implements EntityPatcher<HsOfficeDebitorPatch
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void apply(final HsOfficeDebitorPatchResource resource) {
|
public void apply(final HsOfficeDebitorPatchResource resource) {
|
||||||
OptionalFromJson.of(resource.getBillingContactUuid()).ifPresent(newValue -> {
|
OptionalFromJson.of(resource.getDebitorRelUuid()).ifPresent(newValue -> {
|
||||||
verifyNotNull(newValue, "billingContact");
|
verifyNotNull(newValue, "debitorRel");
|
||||||
entity.setBillingContact(em.getReference(HsOfficeContactEntity.class, newValue));
|
entity.setDebitorRel(em.getReference(HsOfficeRelationEntity.class, newValue));
|
||||||
});
|
});
|
||||||
Optional.ofNullable(resource.getBillable()).ifPresent(entity::setBillable);
|
Optional.ofNullable(resource.getBillable()).ifPresent(entity::setBillable);
|
||||||
OptionalFromJson.of(resource.getVatId()).ifPresent(entity::setVatId);
|
OptionalFromJson.of(resource.getVatId()).ifPresent(entity::setVatId);
|
||||||
|
@ -13,7 +13,10 @@ public interface HsOfficeDebitorRepository extends Repository<HsOfficeDebitorEnt
|
|||||||
|
|
||||||
@Query("""
|
@Query("""
|
||||||
SELECT debitor FROM HsOfficeDebitorEntity debitor
|
SELECT debitor FROM HsOfficeDebitorEntity debitor
|
||||||
WHERE cast(debitor.partner.partnerNumber as integer) = :partnerNumber
|
JOIN HsOfficePartnerEntity partner
|
||||||
|
ON partner.partnerRel.holder = debitor.debitorRel.anchor
|
||||||
|
AND partner.partnerRel.type = 'PARTNER' AND debitor.debitorRel.type = 'DEBITOR'
|
||||||
|
WHERE cast(partner.partnerNumber as integer) = :partnerNumber
|
||||||
AND cast(debitor.debitorNumberSuffix as integer) = :debitorNumberSuffix
|
AND cast(debitor.debitorNumberSuffix as integer) = :debitorNumberSuffix
|
||||||
""")
|
""")
|
||||||
List<HsOfficeDebitorEntity> findDebitorByDebitorNumber(int partnerNumber, byte debitorNumberSuffix);
|
List<HsOfficeDebitorEntity> findDebitorByDebitorNumber(int partnerNumber, byte debitorNumberSuffix);
|
||||||
@ -24,9 +27,15 @@ public interface HsOfficeDebitorRepository extends Repository<HsOfficeDebitorEnt
|
|||||||
|
|
||||||
@Query("""
|
@Query("""
|
||||||
SELECT debitor FROM HsOfficeDebitorEntity debitor
|
SELECT debitor FROM HsOfficeDebitorEntity debitor
|
||||||
JOIN HsOfficePartnerEntity partner ON partner.uuid = debitor.partner.uuid
|
JOIN HsOfficePartnerEntity partner
|
||||||
JOIN HsOfficePersonEntity person ON person.uuid = partner.person.uuid
|
ON partner.partnerRel.holder = debitor.debitorRel.anchor
|
||||||
JOIN HsOfficeContactEntity contact ON contact.uuid = debitor.billingContact.uuid
|
AND partner.partnerRel.type = 'PARTNER' AND debitor.debitorRel.type = 'DEBITOR'
|
||||||
|
JOIN HsOfficePersonEntity person
|
||||||
|
ON person.uuid = partner.partnerRel.holder.uuid
|
||||||
|
OR person.uuid = debitor.debitorRel.holder.uuid
|
||||||
|
JOIN HsOfficeContactEntity contact
|
||||||
|
ON contact.uuid = debitor.debitorRel.contact.uuid
|
||||||
|
OR contact.uuid = partner.partnerRel.contact.uuid
|
||||||
WHERE :name is null
|
WHERE :name is null
|
||||||
OR partner.details.birthName like concat(cast(:name as text), '%')
|
OR partner.details.birthName like concat(cast(:name as text), '%')
|
||||||
OR person.tradeName like concat(cast(:name as text), '%')
|
OR person.tradeName like concat(cast(:name as text), '%')
|
||||||
|
@ -12,8 +12,6 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
|
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
|
||||||
|
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import jakarta.persistence.PersistenceContext;
|
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -32,9 +30,6 @@ public class HsOfficeMembershipController implements HsOfficeMembershipsApi {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private HsOfficeMembershipRepository membershipRepo;
|
private HsOfficeMembershipRepository membershipRepo;
|
||||||
|
|
||||||
@PersistenceContext
|
|
||||||
private EntityManager em;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public ResponseEntity<List<HsOfficeMembershipResource>> listMemberships(
|
public ResponseEntity<List<HsOfficeMembershipResource>> listMemberships(
|
||||||
@ -121,7 +116,7 @@ public class HsOfficeMembershipController implements HsOfficeMembershipsApi {
|
|||||||
|
|
||||||
final var current = membershipRepo.findByUuid(membershipUuid).orElseThrow();
|
final var current = membershipRepo.findByUuid(membershipUuid).orElseThrow();
|
||||||
|
|
||||||
new HsOfficeMembershipEntityPatcher(em, mapper, current).apply(body);
|
new HsOfficeMembershipEntityPatcher(mapper, current).apply(body);
|
||||||
|
|
||||||
final var saved = membershipRepo.save(current);
|
final var saved = membershipRepo.save(current);
|
||||||
final var mapped = mapper.map(saved, HsOfficeMembershipResource.class, SEPA_MANDATE_ENTITY_TO_RESOURCE_POSTMAPPER);
|
final var mapped = mapper.map(saved, HsOfficeMembershipResource.class, SEPA_MANDATE_ENTITY_TO_RESOURCE_POSTMAPPER);
|
||||||
|
@ -4,20 +4,30 @@ import com.vladmihalcea.hibernate.type.range.PostgreSQLRangeType;
|
|||||||
import com.vladmihalcea.hibernate.type.range.Range;
|
import com.vladmihalcea.hibernate.type.range.Range;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import net.hostsharing.hsadminng.errors.DisplayName;
|
import net.hostsharing.hsadminng.errors.DisplayName;
|
||||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
|
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationEntity;
|
||||||
import net.hostsharing.hsadminng.persistence.HasUuid;
|
import net.hostsharing.hsadminng.persistence.HasUuid;
|
||||||
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
|
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
|
||||||
|
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.Stringify;
|
||||||
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
||||||
import org.hibernate.annotations.Fetch;
|
|
||||||
import org.hibernate.annotations.FetchMode;
|
|
||||||
import org.hibernate.annotations.Type;
|
import org.hibernate.annotations.Type;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
|
import java.io.IOException;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.*;
|
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.*;
|
||||||
|
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.SELECT;
|
||||||
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
|
||||||
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
||||||
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.REFERRER;
|
||||||
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.fetchedBySql;
|
||||||
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
|
||||||
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@ -35,10 +45,8 @@ public class HsOfficeMembershipEntity implements HasUuid, Stringifyable {
|
|||||||
private static Stringify<HsOfficeMembershipEntity> stringify = stringify(HsOfficeMembershipEntity.class)
|
private static Stringify<HsOfficeMembershipEntity> stringify = stringify(HsOfficeMembershipEntity.class)
|
||||||
.withProp(e -> MEMBER_NUMBER_TAG + e.getMemberNumber())
|
.withProp(e -> MEMBER_NUMBER_TAG + e.getMemberNumber())
|
||||||
.withProp(e -> e.getPartner().toShortString())
|
.withProp(e -> e.getPartner().toShortString())
|
||||||
.withProp(e -> e.getMainDebitor().toShortString())
|
|
||||||
.withProp(e -> e.getValidity().asString())
|
.withProp(e -> e.getValidity().asString())
|
||||||
.withProp(HsOfficeMembershipEntity::getReasonForTermination)
|
.withProp(HsOfficeMembershipEntity::getReasonForTermination)
|
||||||
.withSeparator(", ")
|
|
||||||
.quotedValues(false);
|
.quotedValues(false);
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@ -49,11 +57,6 @@ public class HsOfficeMembershipEntity implements HasUuid, Stringifyable {
|
|||||||
@JoinColumn(name = "partneruuid")
|
@JoinColumn(name = "partneruuid")
|
||||||
private HsOfficePartnerEntity partner;
|
private HsOfficePartnerEntity partner;
|
||||||
|
|
||||||
@ManyToOne
|
|
||||||
@Fetch(FetchMode.JOIN)
|
|
||||||
@JoinColumn(name = "maindebitoruuid")
|
|
||||||
private HsOfficeDebitorEntity mainDebitor;
|
|
||||||
|
|
||||||
@Column(name = "membernumbersuffix", length = 2)
|
@Column(name = "membernumbersuffix", length = 2)
|
||||||
private String memberNumberSuffix;
|
private String memberNumberSuffix;
|
||||||
|
|
||||||
@ -114,4 +117,45 @@ public class HsOfficeMembershipEntity implements HasUuid, Stringifyable {
|
|||||||
setReasonForTermination(HsOfficeReasonForTermination.NONE);
|
setReasonForTermination(HsOfficeReasonForTermination.NONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static RbacView rbac() {
|
||||||
|
return rbacViewFor("membership", HsOfficeMembershipEntity.class)
|
||||||
|
.withIdentityView(SQL.query("""
|
||||||
|
SELECT m.uuid AS uuid,
|
||||||
|
'M-' || p.partnerNumber || m.memberNumberSuffix as idName
|
||||||
|
FROM hs_office_membership AS m
|
||||||
|
JOIN hs_office_partner AS p ON p.uuid = m.partnerUuid
|
||||||
|
"""))
|
||||||
|
.withRestrictedViewOrderBy(SQL.projection("validity"))
|
||||||
|
.withUpdatableColumns("validity", "membershipFeeBillable", "reasonForTermination")
|
||||||
|
|
||||||
|
.importEntityAlias("partnerRel", HsOfficeRelationEntity.class,
|
||||||
|
dependsOnColumn("partnerUuid"),
|
||||||
|
fetchedBySql("""
|
||||||
|
SELECT ${columns}
|
||||||
|
FROM hs_office_partner AS partner
|
||||||
|
JOIN hs_office_relation AS partnerRel ON partnerRel.uuid = partner.partnerRelUuid
|
||||||
|
WHERE partner.uuid = ${REF}.partnerUuid
|
||||||
|
"""),
|
||||||
|
NOT_NULL)
|
||||||
|
.toRole("global", ADMIN).grantPermission(INSERT)
|
||||||
|
|
||||||
|
.createRole(OWNER, (with) -> {
|
||||||
|
with.owningUser(CREATOR);
|
||||||
|
with.incomingSuperRole("partnerRel", ADMIN);
|
||||||
|
with.permission(DELETE);
|
||||||
|
})
|
||||||
|
.createSubRole(ADMIN, (with) -> {
|
||||||
|
with.incomingSuperRole("partnerRel", AGENT);
|
||||||
|
with.permission(UPDATE);
|
||||||
|
})
|
||||||
|
.createSubRole(REFERRER, (with) -> {
|
||||||
|
with.outgoingSubRole("partnerRel", TENANT);
|
||||||
|
with.permission(SELECT);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException {
|
||||||
|
rbac().generateWithBaseFileName("303-hs-office-membership-rbac");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,37 +1,26 @@
|
|||||||
package net.hostsharing.hsadminng.hs.office.membership;
|
package net.hostsharing.hsadminng.hs.office.membership;
|
||||||
|
|
||||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
|
|
||||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeMembershipPatchResource;
|
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeMembershipPatchResource;
|
||||||
import net.hostsharing.hsadminng.mapper.EntityPatcher;
|
import net.hostsharing.hsadminng.mapper.EntityPatcher;
|
||||||
import net.hostsharing.hsadminng.mapper.Mapper;
|
import net.hostsharing.hsadminng.mapper.Mapper;
|
||||||
import net.hostsharing.hsadminng.mapper.OptionalFromJson;
|
import net.hostsharing.hsadminng.mapper.OptionalFromJson;
|
||||||
|
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class HsOfficeMembershipEntityPatcher implements EntityPatcher<HsOfficeMembershipPatchResource> {
|
public class HsOfficeMembershipEntityPatcher implements EntityPatcher<HsOfficeMembershipPatchResource> {
|
||||||
|
|
||||||
private final EntityManager em;
|
|
||||||
private final Mapper mapper;
|
private final Mapper mapper;
|
||||||
private final HsOfficeMembershipEntity entity;
|
private final HsOfficeMembershipEntity entity;
|
||||||
|
|
||||||
public HsOfficeMembershipEntityPatcher(
|
public HsOfficeMembershipEntityPatcher(
|
||||||
final EntityManager em,
|
|
||||||
final Mapper mapper,
|
final Mapper mapper,
|
||||||
final HsOfficeMembershipEntity entity) {
|
final HsOfficeMembershipEntity entity) {
|
||||||
this.em = em;
|
|
||||||
this.mapper = mapper;
|
this.mapper = mapper;
|
||||||
this.entity = entity;
|
this.entity = entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void apply(final HsOfficeMembershipPatchResource resource) {
|
public void apply(final HsOfficeMembershipPatchResource resource) {
|
||||||
OptionalFromJson.of(resource.getMainDebitorUuid())
|
|
||||||
.ifPresent(newValue -> {
|
|
||||||
verifyNotNull(newValue, "debitor");
|
|
||||||
entity.setMainDebitor(em.getReference(HsOfficeDebitorEntity.class, newValue));
|
|
||||||
});
|
|
||||||
OptionalFromJson.of(resource.getValidTo()).ifPresent(
|
OptionalFromJson.of(resource.getValidTo()).ifPresent(
|
||||||
entity::setValidTo);
|
entity::setValidTo);
|
||||||
Optional.ofNullable(resource.getReasonForTermination())
|
Optional.ofNullable(resource.getReasonForTermination())
|
||||||
@ -40,10 +29,4 @@ public class HsOfficeMembershipEntityPatcher implements EntityPatcher<HsOfficeMe
|
|||||||
OptionalFromJson.of(resource.getMembershipFeeBillable()).ifPresent(
|
OptionalFromJson.of(resource.getMembershipFeeBillable()).ifPresent(
|
||||||
entity::setMembershipFeeBillable);
|
entity::setMembershipFeeBillable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyNotNull(final UUID newValue, final String propertyName) {
|
|
||||||
if (newValue == null) {
|
|
||||||
throw new IllegalArgumentException("property '" + propertyName + "' must not be null");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -110,9 +110,7 @@ public class HsOfficePartnerController implements HsOfficePartnersApi {
|
|||||||
return ResponseEntity.notFound().build();
|
return ResponseEntity.notFound().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (partnerRepo.deleteByUuid(partnerUuid) != 1 ||
|
if (partnerRepo.deleteByUuid(partnerUuid) != 1) {
|
||||||
// TODO: move to after delete trigger in partner
|
|
||||||
relationRepo.deleteByUuid(partnerToDelete.get().getPartnerRel().getUuid()) != 1 ) {
|
|
||||||
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
|
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,8 +140,6 @@ public class HsOfficePartnerController implements HsOfficePartnersApi {
|
|||||||
final var entityToSave = new HsOfficePartnerEntity();
|
final var entityToSave = new HsOfficePartnerEntity();
|
||||||
entityToSave.setPartnerNumber(body.getPartnerNumber());
|
entityToSave.setPartnerNumber(body.getPartnerNumber());
|
||||||
entityToSave.setPartnerRel(persistPartnerRel(body.getPartnerRel()));
|
entityToSave.setPartnerRel(persistPartnerRel(body.getPartnerRel()));
|
||||||
entityToSave.setContact(ref(HsOfficeContactEntity.class, body.getContactUuid()));
|
|
||||||
entityToSave.setPerson(ref(HsOfficePersonEntity.class, body.getPersonUuid()));
|
|
||||||
entityToSave.setDetails(mapper.map(body.getDetails(), HsOfficePartnerDetailsEntity.class));
|
entityToSave.setDetails(mapper.map(body.getDetails(), HsOfficePartnerDetailsEntity.class));
|
||||||
return entityToSave;
|
return entityToSave;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package net.hostsharing.hsadminng.hs.office.partner;
|
|||||||
|
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import net.hostsharing.hsadminng.errors.DisplayName;
|
import net.hostsharing.hsadminng.errors.DisplayName;
|
||||||
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationEntity;
|
|
||||||
import net.hostsharing.hsadminng.persistence.HasUuid;
|
import net.hostsharing.hsadminng.persistence.HasUuid;
|
||||||
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
|
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
|
||||||
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL;
|
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL;
|
||||||
@ -14,10 +13,8 @@ import java.io.IOException;
|
|||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn;
|
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.fetchedBySql;
|
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
|
||||||
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
||||||
|
|
||||||
@ -40,7 +37,6 @@ public class HsOfficePartnerDetailsEntity implements HasUuid, Stringifyable {
|
|||||||
.withProp(HsOfficePartnerDetailsEntity::getBirthday)
|
.withProp(HsOfficePartnerDetailsEntity::getBirthday)
|
||||||
.withProp(HsOfficePartnerDetailsEntity::getBirthName)
|
.withProp(HsOfficePartnerDetailsEntity::getBirthName)
|
||||||
.withProp(HsOfficePartnerDetailsEntity::getDateOfDeath)
|
.withProp(HsOfficePartnerDetailsEntity::getDateOfDeath)
|
||||||
.withSeparator(", ")
|
|
||||||
.quotedValues(false);
|
.quotedValues(false);
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@ -72,11 +68,12 @@ public class HsOfficePartnerDetailsEntity implements HasUuid, Stringifyable {
|
|||||||
public static RbacView rbac() {
|
public static RbacView rbac() {
|
||||||
return rbacViewFor("partnerDetails", HsOfficePartnerDetailsEntity.class)
|
return rbacViewFor("partnerDetails", HsOfficePartnerDetailsEntity.class)
|
||||||
.withIdentityView(SQL.query("""
|
.withIdentityView(SQL.query("""
|
||||||
SELECT partner_iv.idName || '-details'
|
SELECT partnerDetails.uuid as uuid, partner_iv.idName || '-details' as idName
|
||||||
FROM hs_office_partner_details AS partnerDetails
|
FROM hs_office_partner_details AS partnerDetails
|
||||||
JOIN hs_office_partner partner ON partner.detailsUuid = partnerDetails.uuid
|
JOIN hs_office_partner partner ON partner.detailsUuid = partnerDetails.uuid
|
||||||
JOIN hs_office_partner_iv partner_iv ON partner_iv.uuid = partner.uuid
|
JOIN hs_office_partner_iv partner_iv ON partner_iv.uuid = partner.uuid
|
||||||
"""))
|
"""))
|
||||||
|
.withRestrictedViewOrderBy(SQL.expression("uuid"))
|
||||||
.withUpdatableColumns(
|
.withUpdatableColumns(
|
||||||
"registrationOffice",
|
"registrationOffice",
|
||||||
"registrationNumber",
|
"registrationNumber",
|
||||||
@ -84,17 +81,7 @@ public class HsOfficePartnerDetailsEntity implements HasUuid, Stringifyable {
|
|||||||
"birthName",
|
"birthName",
|
||||||
"birthday",
|
"birthday",
|
||||||
"dateOfDeath")
|
"dateOfDeath")
|
||||||
.createPermission(INSERT).grantedTo("global", ADMIN)
|
.toRole("global", ADMIN).grantPermission(INSERT)
|
||||||
|
|
||||||
.importRootEntityAliasProxy("partnerRel", HsOfficeRelationEntity.class,
|
|
||||||
fetchedBySql("""
|
|
||||||
SELECT ${columns}
|
|
||||||
FROM hs_office_relation AS partnerRel
|
|
||||||
JOIN hs_office_partner AS partner
|
|
||||||
ON partner.detailsUuid = ${ref}.uuid
|
|
||||||
WHERE partnerRel.uuid = partner.partnerRelUuid
|
|
||||||
"""),
|
|
||||||
dependsOnColumn("partnerRelUuid"))
|
|
||||||
|
|
||||||
// The grants are defined in HsOfficePartnerEntity.rbac()
|
// The grants are defined in HsOfficePartnerEntity.rbac()
|
||||||
// because they have to be changed when its partnerRel changes,
|
// because they have to be changed when its partnerRel changes,
|
||||||
@ -103,6 +90,6 @@ public class HsOfficePartnerDetailsEntity implements HasUuid, Stringifyable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
rbac().generateWithBaseFileName("234-hs-office-partner-details-rbac-generated");
|
rbac().generateWithBaseFileName("234-hs-office-partner-details-rbac");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
package net.hostsharing.hsadminng.hs.office.partner;
|
package net.hostsharing.hsadminng.hs.office.partner;
|
||||||
|
|
||||||
import lombok.*;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
import net.hostsharing.hsadminng.errors.DisplayName;
|
import net.hostsharing.hsadminng.errors.DisplayName;
|
||||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
|
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
|
||||||
import net.hostsharing.hsadminng.persistence.HasUuid;
|
|
||||||
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity;
|
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity;
|
||||||
|
import net.hostsharing.hsadminng.persistence.HasUuid;
|
||||||
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationEntity;
|
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationEntity;
|
||||||
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
|
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
|
||||||
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL;
|
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL;
|
||||||
@ -13,17 +17,24 @@ import net.hostsharing.hsadminng.stringify.Stringifyable;
|
|||||||
import org.hibernate.annotations.NotFound;
|
import org.hibernate.annotations.NotFound;
|
||||||
import org.hibernate.annotations.NotFoundAction;
|
import org.hibernate.annotations.NotFoundAction;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static jakarta.persistence.CascadeType.*;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.SELECT;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.SELECT;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
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.SQL.directlyFetchedByDependsOnColumn;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
|
||||||
|
import static java.util.Optional.ofNullable;
|
||||||
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@ -36,10 +47,18 @@ import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
|||||||
@DisplayName("Partner")
|
@DisplayName("Partner")
|
||||||
public class HsOfficePartnerEntity implements Stringifyable, HasUuid {
|
public class HsOfficePartnerEntity implements Stringifyable, HasUuid {
|
||||||
|
|
||||||
|
public static final String PARTNER_NUMBER_TAG = "P-";
|
||||||
|
|
||||||
private static Stringify<HsOfficePartnerEntity> stringify = stringify(HsOfficePartnerEntity.class, "partner")
|
private static Stringify<HsOfficePartnerEntity> stringify = stringify(HsOfficePartnerEntity.class, "partner")
|
||||||
.withProp(HsOfficePartnerEntity::getPerson)
|
.withIdProp(HsOfficePartnerEntity::toShortString)
|
||||||
.withProp(HsOfficePartnerEntity::getContact)
|
.withProp(p -> ofNullable(p.getPartnerRel())
|
||||||
.withSeparator(": ")
|
.map(HsOfficeRelationEntity::getHolder)
|
||||||
|
.map(HsOfficePersonEntity::toShortString)
|
||||||
|
.orElse(null))
|
||||||
|
.withProp(p -> ofNullable(p.getPartnerRel())
|
||||||
|
.map(HsOfficeRelationEntity::getContact)
|
||||||
|
.map(HsOfficeContactEntity::toShortString)
|
||||||
|
.orElse(null))
|
||||||
.quotedValues(false);
|
.quotedValues(false);
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@ -49,25 +68,19 @@ public class HsOfficePartnerEntity implements Stringifyable, HasUuid {
|
|||||||
@Column(name = "partnernumber", columnDefinition = "numeric(5) not null")
|
@Column(name = "partnernumber", columnDefinition = "numeric(5) not null")
|
||||||
private Integer partnerNumber;
|
private Integer partnerNumber;
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne(cascade = { PERSIST, MERGE, REFRESH, DETACH }, optional = false)
|
||||||
@JoinColumn(name = "partnerreluuid", nullable = false)
|
@JoinColumn(name = "partnerreluuid", nullable = false)
|
||||||
private HsOfficeRelationEntity partnerRel;
|
private HsOfficeRelationEntity partnerRel;
|
||||||
|
|
||||||
// TODO: remove, is replaced by partnerRel
|
@ManyToOne(cascade = { PERSIST, MERGE, REFRESH, DETACH }, optional = true)
|
||||||
@ManyToOne
|
|
||||||
@JoinColumn(name = "personuuid", nullable = false)
|
|
||||||
private HsOfficePersonEntity person;
|
|
||||||
|
|
||||||
// TODO: remove, is replaced by partnerRel
|
|
||||||
@ManyToOne
|
|
||||||
@JoinColumn(name = "contactuuid", nullable = false)
|
|
||||||
private HsOfficeContactEntity contact;
|
|
||||||
|
|
||||||
@ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DETACH }, optional = true)
|
|
||||||
@JoinColumn(name = "detailsuuid")
|
@JoinColumn(name = "detailsuuid")
|
||||||
@NotFound(action = NotFoundAction.IGNORE)
|
@NotFound(action = NotFoundAction.IGNORE)
|
||||||
private HsOfficePartnerDetailsEntity details;
|
private HsOfficePartnerDetailsEntity details;
|
||||||
|
|
||||||
|
public String getTaggedPartnerNumber() {
|
||||||
|
return PARTNER_NUMBER_TAG + partnerNumber;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return stringify.apply(this);
|
return stringify.apply(this);
|
||||||
@ -75,22 +88,14 @@ public class HsOfficePartnerEntity implements Stringifyable, HasUuid {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toShortString() {
|
public String toShortString() {
|
||||||
return Optional.ofNullable(person).map(HsOfficePersonEntity::toShortString).orElse("<person=null>");
|
return getTaggedPartnerNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RbacView rbac() {
|
public static RbacView rbac() {
|
||||||
return rbacViewFor("partner", HsOfficePartnerEntity.class)
|
return rbacViewFor("partner", HsOfficePartnerEntity.class)
|
||||||
.withIdentityView(SQL.query("""
|
.withIdentityView(SQL.projection("'P-' || partnerNumber"))
|
||||||
SELECT partner.partnerNumber
|
.withUpdatableColumns("partnerRelUuid")
|
||||||
|| ':' || (SELECT idName FROM hs_office_person_iv p WHERE p.uuid = partner.personUuid)
|
.toRole("global", ADMIN).grantPermission(INSERT)
|
||||||
|| '-' || (SELECT idName FROM hs_office_contact_iv c WHERE c.uuid = partner.contactUuid)
|
|
||||||
FROM hs_office_partner AS partner
|
|
||||||
"""))
|
|
||||||
.withUpdatableColumns(
|
|
||||||
"partnerRelUuid",
|
|
||||||
"personUuid",
|
|
||||||
"contactUuid")
|
|
||||||
.createPermission(INSERT).grantedTo("global", ADMIN)
|
|
||||||
|
|
||||||
.importRootEntityAliasProxy("partnerRel", HsOfficeRelationEntity.class,
|
.importRootEntityAliasProxy("partnerRel", HsOfficeRelationEntity.class,
|
||||||
directlyFetchedByDependsOnColumn(),
|
directlyFetchedByDependsOnColumn(),
|
||||||
@ -108,6 +113,6 @@ public class HsOfficePartnerEntity implements Stringifyable, HasUuid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
rbac().generateWithBaseFileName("233-hs-office-partner-rbac-generated");
|
rbac().generateWithBaseFileName("233-hs-office-partner-rbac");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
package net.hostsharing.hsadminng.hs.office.partner;
|
package net.hostsharing.hsadminng.hs.office.partner;
|
||||||
|
|
||||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
|
|
||||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePartnerPatchResource;
|
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePartnerPatchResource;
|
||||||
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity;
|
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationEntity;
|
||||||
import net.hostsharing.hsadminng.mapper.EntityPatcher;
|
import net.hostsharing.hsadminng.mapper.EntityPatcher;
|
||||||
import net.hostsharing.hsadminng.mapper.OptionalFromJson;
|
import net.hostsharing.hsadminng.mapper.OptionalFromJson;
|
||||||
|
|
||||||
import jakarta.persistence.EntityManager;
|
import jakarta.persistence.EntityManager;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
class HsOfficePartnerEntityPatcher implements EntityPatcher<HsOfficePartnerPatchResource> {
|
class HsOfficePartnerEntityPatcher implements EntityPatcher<HsOfficePartnerPatchResource> {
|
||||||
private final EntityManager em;
|
private final EntityManager em;
|
||||||
@ -21,19 +19,15 @@ class HsOfficePartnerEntityPatcher implements EntityPatcher<HsOfficePartnerPatch
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void apply(final HsOfficePartnerPatchResource resource) {
|
public void apply(final HsOfficePartnerPatchResource resource) {
|
||||||
OptionalFromJson.of(resource.getContactUuid()).ifPresent(newValue -> {
|
OptionalFromJson.of(resource.getPartnerRelUuid()).ifPresent(newValue -> {
|
||||||
verifyNotNull(newValue, "contact");
|
verifyNotNull(newValue, "partnerRel");
|
||||||
entity.setContact(em.getReference(HsOfficeContactEntity.class, newValue));
|
entity.setPartnerRel(em.getReference(HsOfficeRelationEntity.class, newValue));
|
||||||
});
|
|
||||||
OptionalFromJson.of(resource.getPersonUuid()).ifPresent(newValue -> {
|
|
||||||
verifyNotNull(newValue, "person");
|
|
||||||
entity.setPerson(em.getReference(HsOfficePersonEntity.class, newValue));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
new HsOfficePartnerDetailsEntityPatcher(em, entity.getDetails()).apply(resource.getDetails());
|
new HsOfficePartnerDetailsEntityPatcher(em, entity.getDetails()).apply(resource.getDetails());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyNotNull(final UUID newValue, final String propertyName) {
|
private void verifyNotNull(final Object newValue, final String propertyName) {
|
||||||
if (newValue == null) {
|
if (newValue == null) {
|
||||||
throw new IllegalArgumentException("property '" + propertyName + "' must not be null");
|
throw new IllegalArgumentException("property '" + propertyName + "' must not be null");
|
||||||
}
|
}
|
||||||
|
@ -11,10 +11,13 @@ public interface HsOfficePartnerRepository extends Repository<HsOfficePartnerEnt
|
|||||||
|
|
||||||
Optional<HsOfficePartnerEntity> findByUuid(UUID id);
|
Optional<HsOfficePartnerEntity> findByUuid(UUID id);
|
||||||
|
|
||||||
|
List<HsOfficePartnerEntity> findAll(); // TODO: move to a repo in test sources
|
||||||
|
|
||||||
@Query("""
|
@Query("""
|
||||||
SELECT partner FROM HsOfficePartnerEntity partner
|
SELECT partner FROM HsOfficePartnerEntity partner
|
||||||
JOIN HsOfficeContactEntity contact ON contact.uuid = partner.contact.uuid
|
JOIN HsOfficeRelationEntity rel ON rel.uuid = partner.partnerRel.uuid
|
||||||
JOIN HsOfficePersonEntity person ON person.uuid = partner.person.uuid
|
JOIN HsOfficeContactEntity contact ON contact.uuid = rel.contact.uuid
|
||||||
|
JOIN HsOfficePersonEntity person ON person.uuid = rel.holder.uuid
|
||||||
WHERE :name is null
|
WHERE :name is null
|
||||||
OR partner.details.birthName like concat(cast(:name as text), '%')
|
OR partner.details.birthName like concat(cast(:name as text), '%')
|
||||||
OR contact.label like concat(cast(:name as text), '%')
|
OR contact.label like concat(cast(:name as text), '%')
|
||||||
|
@ -69,6 +69,8 @@ public class HsOfficePersonEntity implements HasUuid, Stringifyable {
|
|||||||
return rbacViewFor("person", HsOfficePersonEntity.class)
|
return rbacViewFor("person", HsOfficePersonEntity.class)
|
||||||
.withIdentityView(SQL.projection("concat(tradeName, familyName, givenName)"))
|
.withIdentityView(SQL.projection("concat(tradeName, familyName, givenName)"))
|
||||||
.withUpdatableColumns("personType", "tradeName", "givenName", "familyName")
|
.withUpdatableColumns("personType", "tradeName", "givenName", "familyName")
|
||||||
|
.toRole("global", GUEST).grantPermission(INSERT)
|
||||||
|
|
||||||
.createRole(OWNER, (with) -> {
|
.createRole(OWNER, (with) -> {
|
||||||
with.permission(DELETE);
|
with.permission(DELETE);
|
||||||
with.owningUser(CREATOR);
|
with.owningUser(CREATOR);
|
||||||
@ -84,6 +86,6 @@ public class HsOfficePersonEntity implements HasUuid, Stringifyable {
|
|||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
rbac().generateWithBaseFileName("213-hs-office-person-rbac-generated");
|
rbac().generateWithBaseFileName("213-hs-office-person-rbac");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ import java.util.UUID;
|
|||||||
|
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.GLOBAL;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.GLOBAL;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Nullable.NULLABLE;
|
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.*;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
||||||
@ -92,22 +92,26 @@ public class HsOfficeRelationEntity implements HasUuid, Stringifyable {
|
|||||||
.importEntityAlias("anchorPerson", HsOfficePersonEntity.class,
|
.importEntityAlias("anchorPerson", HsOfficePersonEntity.class,
|
||||||
dependsOnColumn("anchorUuid"),
|
dependsOnColumn("anchorUuid"),
|
||||||
directlyFetchedByDependsOnColumn(),
|
directlyFetchedByDependsOnColumn(),
|
||||||
NULLABLE)
|
NOT_NULL)
|
||||||
.importEntityAlias("holderPerson", HsOfficePersonEntity.class,
|
.importEntityAlias("holderPerson", HsOfficePersonEntity.class,
|
||||||
dependsOnColumn("holderUuid"),
|
dependsOnColumn("holderUuid"),
|
||||||
directlyFetchedByDependsOnColumn(),
|
directlyFetchedByDependsOnColumn(),
|
||||||
NULLABLE)
|
NOT_NULL)
|
||||||
.importEntityAlias("contact", HsOfficeContactEntity.class,
|
.importEntityAlias("contact", HsOfficeContactEntity.class,
|
||||||
dependsOnColumn("contactUuid"),
|
dependsOnColumn("contactUuid"),
|
||||||
directlyFetchedByDependsOnColumn(),
|
directlyFetchedByDependsOnColumn(),
|
||||||
NULLABLE)
|
NOT_NULL)
|
||||||
.createRole(OWNER, (with) -> {
|
.createRole(OWNER, (with) -> {
|
||||||
with.owningUser(CREATOR);
|
with.owningUser(CREATOR);
|
||||||
with.incomingSuperRole(GLOBAL, ADMIN);
|
with.incomingSuperRole(GLOBAL, ADMIN);
|
||||||
|
// TODO: if type=REPRESENTATIIVE
|
||||||
|
// with.incomingSuperRole("holderPerson", ADMIN);
|
||||||
with.permission(DELETE);
|
with.permission(DELETE);
|
||||||
})
|
})
|
||||||
.createSubRole(ADMIN, (with) -> {
|
.createSubRole(ADMIN, (with) -> {
|
||||||
with.incomingSuperRole("anchorPerson", ADMIN);
|
with.incomingSuperRole("anchorPerson", ADMIN);
|
||||||
|
// TODO: if type=REPRESENTATIIVE
|
||||||
|
// with.outgoingSuperRole("anchorPerson", OWNER);
|
||||||
with.permission(UPDATE);
|
with.permission(UPDATE);
|
||||||
})
|
})
|
||||||
.createSubRole(AGENT, (with) -> {
|
.createSubRole(AGENT, (with) -> {
|
||||||
@ -120,10 +124,12 @@ public class HsOfficeRelationEntity implements HasUuid, Stringifyable {
|
|||||||
with.outgoingSubRole("holderPerson", REFERRER);
|
with.outgoingSubRole("holderPerson", REFERRER);
|
||||||
with.outgoingSubRole("contact", REFERRER);
|
with.outgoingSubRole("contact", REFERRER);
|
||||||
with.permission(SELECT);
|
with.permission(SELECT);
|
||||||
});
|
})
|
||||||
|
|
||||||
|
.toRole("anchorPerson", ADMIN).grantPermission(INSERT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
rbac().generateWithBaseFileName("223-hs-office-relation-rbac-generated");
|
rbac().generateWithBaseFileName("223-hs-office-relation-rbac");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,6 +132,7 @@ public class HsOfficeSepaMandateController implements HsOfficeSepaMandatesApi {
|
|||||||
if (entity.getValidity().hasUpperBound()) {
|
if (entity.getValidity().hasUpperBound()) {
|
||||||
resource.setValidTo(entity.getValidity().upper().minusDays(1));
|
resource.setValidTo(entity.getValidity().upper().minusDays(1));
|
||||||
}
|
}
|
||||||
|
resource.getDebitor().setDebitorNumber(entity.getDebitor().getDebitorNumber());
|
||||||
};
|
};
|
||||||
|
|
||||||
final BiConsumer<HsOfficeSepaMandateInsertResource, HsOfficeSepaMandateEntity> SEPA_MANDATE_RESOURCE_TO_ENTITY_POSTMAPPER = (resource, entity) -> {
|
final BiConsumer<HsOfficeSepaMandateInsertResource, HsOfficeSepaMandateEntity> SEPA_MANDATE_RESOURCE_TO_ENTITY_POSTMAPPER = (resource, entity) -> {
|
||||||
|
@ -21,6 +21,7 @@ import java.util.UUID;
|
|||||||
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.*;
|
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.*;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.GLOBAL;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.GLOBAL;
|
||||||
|
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.*;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
||||||
@ -43,7 +44,6 @@ public class HsOfficeSepaMandateEntity implements Stringifyable, HasUuid {
|
|||||||
.withProp(HsOfficeSepaMandateEntity::getReference)
|
.withProp(HsOfficeSepaMandateEntity::getReference)
|
||||||
.withProp(HsOfficeSepaMandateEntity::getAgreement)
|
.withProp(HsOfficeSepaMandateEntity::getAgreement)
|
||||||
.withProp(e -> e.getValidity().asString())
|
.withProp(e -> e.getValidity().asString())
|
||||||
.withSeparator(", ")
|
|
||||||
.quotedValues(false);
|
.quotedValues(false);
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@ -96,11 +96,27 @@ public class HsOfficeSepaMandateEntity implements Stringifyable, HasUuid {
|
|||||||
|
|
||||||
public static RbacView rbac() {
|
public static RbacView rbac() {
|
||||||
return rbacViewFor("sepaMandate", HsOfficeSepaMandateEntity.class)
|
return rbacViewFor("sepaMandate", HsOfficeSepaMandateEntity.class)
|
||||||
.withIdentityView(projection("concat(tradeName, familyName, givenName)"))
|
.withIdentityView(query("""
|
||||||
|
select sm.uuid as uuid, ba.iban || '-' || sm.validity as idName
|
||||||
|
from hs_office_sepamandate sm
|
||||||
|
join hs_office_bankaccount ba on ba.uuid = sm.bankAccountUuid
|
||||||
|
"""))
|
||||||
|
.withRestrictedViewOrderBy(expression("validity"))
|
||||||
.withUpdatableColumns("reference", "agreement", "validity")
|
.withUpdatableColumns("reference", "agreement", "validity")
|
||||||
|
|
||||||
.importEntityAlias("debitorRel", HsOfficeRelationEntity.class, dependsOnColumn("debitorRelUuid"))
|
.importEntityAlias("debitorRel", HsOfficeRelationEntity.class,
|
||||||
.importEntityAlias("bankAccount", HsOfficeBankAccountEntity.class, dependsOnColumn("bankAccountUuid"))
|
dependsOnColumn("debitorUuid"),
|
||||||
|
fetchedBySql("""
|
||||||
|
SELECT ${columns}
|
||||||
|
FROM hs_office_relation debitorRel
|
||||||
|
JOIN hs_office_debitor debitor ON debitor.debitorRelUuid = debitorRel.uuid
|
||||||
|
WHERE debitor.uuid = ${REF}.debitorUuid
|
||||||
|
"""),
|
||||||
|
NOT_NULL)
|
||||||
|
.importEntityAlias("bankAccount", HsOfficeBankAccountEntity.class,
|
||||||
|
dependsOnColumn("bankAccountUuid"),
|
||||||
|
directlyFetchedByDependsOnColumn(),
|
||||||
|
NOT_NULL)
|
||||||
|
|
||||||
.createRole(OWNER, (with) -> {
|
.createRole(OWNER, (with) -> {
|
||||||
with.owningUser(CREATOR);
|
with.owningUser(CREATOR);
|
||||||
@ -119,10 +135,12 @@ public class HsOfficeSepaMandateEntity implements Stringifyable, HasUuid {
|
|||||||
with.incomingSuperRole("debitorRel", AGENT);
|
with.incomingSuperRole("debitorRel", AGENT);
|
||||||
with.outgoingSubRole("debitorRel", TENANT);
|
with.outgoingSubRole("debitorRel", TENANT);
|
||||||
with.permission(SELECT);
|
with.permission(SELECT);
|
||||||
});
|
})
|
||||||
|
|
||||||
|
.toRole("debitorRel", ADMIN).grantPermission(INSERT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
rbac().generateWithBaseFileName("253-hs-office-sepamandate-rbac-generated");
|
rbac().generateWithBaseFileName("253-hs-office-sepamandate-rbac");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,16 +47,14 @@ public class InsertTriggerGenerator {
|
|||||||
do language plpgsql $$
|
do language plpgsql $$
|
||||||
declare
|
declare
|
||||||
row ${rawSuperTableName};
|
row ${rawSuperTableName};
|
||||||
permissionUuid uuid;
|
|
||||||
roleUuid uuid;
|
|
||||||
begin
|
begin
|
||||||
call defineContext('create INSERT INTO ${rawSubTableName} permissions for the related ${rawSuperTableName} rows');
|
call defineContext('create INSERT INTO ${rawSubTableName} permissions for the related ${rawSuperTableName} rows');
|
||||||
|
|
||||||
FOR row IN SELECT * FROM ${rawSuperTableName}
|
FOR row IN SELECT * FROM ${rawSuperTableName}
|
||||||
LOOP
|
LOOP
|
||||||
roleUuid := findRoleId(${rawSuperRoleDescriptor});
|
call grantPermissionToRole(
|
||||||
permissionUuid := createPermission(row.uuid, 'INSERT', '${rawSubTableName}');
|
createPermission(row.uuid, 'INSERT', '${rawSubTableName}'),
|
||||||
call grantPermissionToRole(permissionUuid, roleUuid);
|
${rawSuperRoleDescriptor});
|
||||||
END LOOP;
|
END LOOP;
|
||||||
END;
|
END;
|
||||||
$$;
|
$$;
|
||||||
|
@ -16,6 +16,7 @@ public final class Stringify<B> {
|
|||||||
|
|
||||||
private final Class<B> clazz;
|
private final Class<B> clazz;
|
||||||
private final String name;
|
private final String name;
|
||||||
|
private Function<B, ?> idProp;
|
||||||
private final List<Property<B>> props = new ArrayList<>();
|
private final List<Property<B>> props = new ArrayList<>();
|
||||||
private String separator = ", ";
|
private String separator = ", ";
|
||||||
private Boolean quotedValues = null;
|
private Boolean quotedValues = null;
|
||||||
@ -42,6 +43,11 @@ public final class Stringify<B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Stringify<B> withIdProp(final Function<B, ?> getter) {
|
||||||
|
idProp = getter;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Stringify<B> withProp(final String propName, final Function<B, ?> getter) {
|
public Stringify<B> withProp(final String propName, final Function<B, ?> getter) {
|
||||||
props.add(new Property<>(propName, getter));
|
props.add(new Property<>(propName, getter));
|
||||||
return this;
|
return this;
|
||||||
@ -64,7 +70,9 @@ public final class Stringify<B> {
|
|||||||
})
|
})
|
||||||
.map(propVal -> propName(propVal, "=") + optionallyQuoted(propVal))
|
.map(propVal -> propName(propVal, "=") + optionallyQuoted(propVal))
|
||||||
.collect(Collectors.joining(separator));
|
.collect(Collectors.joining(separator));
|
||||||
return name + "(" + propValues + ")";
|
return idProp != null
|
||||||
|
? name + "(" + idProp.apply(object) + ": " + propValues + ")"
|
||||||
|
: name + "(" + propValues + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stringify<B> withSeparator(final String separator) {
|
public Stringify<B> withSeparator(final String separator) {
|
||||||
|
@ -9,6 +9,8 @@ components:
|
|||||||
uuid:
|
uuid:
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
|
debitorRel:
|
||||||
|
$ref: './hs-office-relation-schemas.yaml#/components/schemas/HsOfficeRelation'
|
||||||
debitorNumber:
|
debitorNumber:
|
||||||
type: integer
|
type: integer
|
||||||
format: int32
|
format: int32
|
||||||
@ -21,8 +23,6 @@ components:
|
|||||||
maximum: 99
|
maximum: 99
|
||||||
partner:
|
partner:
|
||||||
$ref: './hs-office-partner-schemas.yaml#/components/schemas/HsOfficePartner'
|
$ref: './hs-office-partner-schemas.yaml#/components/schemas/HsOfficePartner'
|
||||||
billingContact:
|
|
||||||
$ref: './hs-office-contact-schemas.yaml#/components/schemas/HsOfficeContact'
|
|
||||||
billable:
|
billable:
|
||||||
type: boolean
|
type: boolean
|
||||||
vatId:
|
vatId:
|
||||||
@ -43,7 +43,7 @@ components:
|
|||||||
HsOfficeDebitorPatch:
|
HsOfficeDebitorPatch:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
billingContactUuid:
|
debitorRelUuid:
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
nullable: true
|
nullable: true
|
||||||
@ -75,14 +75,11 @@ components:
|
|||||||
HsOfficeDebitorInsert:
|
HsOfficeDebitorInsert:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
partnerUuid:
|
debitorRel:
|
||||||
|
$ref: './hs-office-relation-schemas.yaml#/components/schemas/HsOfficeRelationInsert'
|
||||||
|
debitorRelUuid:
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
nullable: false
|
|
||||||
billingContactUuid:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
nullable: false
|
|
||||||
debitorNumberSuffix:
|
debitorNumberSuffix:
|
||||||
type: integer
|
type: integer
|
||||||
format: int8
|
format: int8
|
||||||
@ -105,9 +102,7 @@ components:
|
|||||||
defaultPrefix:
|
defaultPrefix:
|
||||||
type: string
|
type: string
|
||||||
pattern: '^[a-z]{3}$'
|
pattern: '^[a-z]{3}$'
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- partnerUuid
|
- debitorNumberSuffix
|
||||||
- billingContactUuid
|
|
||||||
- defaultPrefix
|
- defaultPrefix
|
||||||
- billable
|
- billable
|
||||||
|
@ -46,10 +46,6 @@ components:
|
|||||||
HsOfficeMembershipPatch:
|
HsOfficeMembershipPatch:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
mainDebitorUuid:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
nullable: true
|
|
||||||
validTo:
|
validTo:
|
||||||
type: string
|
type: string
|
||||||
format: date
|
format: date
|
||||||
@ -69,10 +65,6 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
nullable: false
|
nullable: false
|
||||||
mainDebitorUuid:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
nullable: false
|
|
||||||
memberNumberSuffix:
|
memberNumberSuffix:
|
||||||
type: string
|
type: string
|
||||||
minLength: 2
|
minLength: 2
|
||||||
@ -95,7 +87,6 @@ components:
|
|||||||
required:
|
required:
|
||||||
- partnerUuid
|
- partnerUuid
|
||||||
- memberNumberSuffix
|
- memberNumberSuffix
|
||||||
- mainDebitorUuid
|
|
||||||
- validFrom
|
- validFrom
|
||||||
- membershipFeeBillable
|
- membershipFeeBillable
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
|
@ -14,10 +14,8 @@ components:
|
|||||||
format: int8
|
format: int8
|
||||||
minimum: 10000
|
minimum: 10000
|
||||||
maximum: 99999
|
maximum: 99999
|
||||||
person:
|
partnerRel:
|
||||||
$ref: './hs-office-person-schemas.yaml#/components/schemas/HsOfficePerson'
|
$ref: './hs-office-relation-schemas.yaml#/components/schemas/HsOfficeRelation'
|
||||||
contact:
|
|
||||||
$ref: './hs-office-contact-schemas.yaml#/components/schemas/HsOfficeContact'
|
|
||||||
details:
|
details:
|
||||||
$ref: '#/components/schemas/HsOfficePartnerDetails'
|
$ref: '#/components/schemas/HsOfficePartnerDetails'
|
||||||
|
|
||||||
@ -52,11 +50,7 @@ components:
|
|||||||
HsOfficePartnerPatch:
|
HsOfficePartnerPatch:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
personUuid:
|
partnerRelUuid:
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
nullable: true
|
|
||||||
contactUuid:
|
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
nullable: true
|
nullable: true
|
||||||
@ -98,18 +92,11 @@ components:
|
|||||||
maximum: 99999
|
maximum: 99999
|
||||||
partnerRel:
|
partnerRel:
|
||||||
$ref: '#/components/schemas/HsOfficePartnerRelInsert'
|
$ref: '#/components/schemas/HsOfficePartnerRelInsert'
|
||||||
personUuid:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
contactUuid:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
details:
|
details:
|
||||||
$ref: '#/components/schemas/HsOfficePartnerDetailsInsert'
|
$ref: '#/components/schemas/HsOfficePartnerDetailsInsert'
|
||||||
required:
|
required:
|
||||||
- partnerNumber
|
- partnerNumber
|
||||||
- personUuid
|
- partnerRel
|
||||||
- contactUuid
|
|
||||||
- details
|
- details
|
||||||
|
|
||||||
HsOfficePartnerRelInsert:
|
HsOfficePartnerRelInsert:
|
||||||
|
@ -19,7 +19,7 @@ get:
|
|||||||
content:
|
content:
|
||||||
'application/json':
|
'application/json':
|
||||||
schema:
|
schema:
|
||||||
$ref: './hs-office-relations-schemas.yaml#/components/schemas/HsOfficeRelation'
|
$ref: './hs-office-relation-schemas.yaml#/components/schemas/HsOfficeRelation'
|
||||||
|
|
||||||
"401":
|
"401":
|
||||||
$ref: './error-responses.yaml#/components/responses/Unauthorized'
|
$ref: './error-responses.yaml#/components/responses/Unauthorized'
|
||||||
@ -44,14 +44,14 @@ patch:
|
|||||||
content:
|
content:
|
||||||
'application/json':
|
'application/json':
|
||||||
schema:
|
schema:
|
||||||
$ref: './hs-office-relations-schemas.yaml#/components/schemas/HsOfficeRelationPatch'
|
$ref: './hs-office-relation-schemas.yaml#/components/schemas/HsOfficeRelationPatch'
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
content:
|
content:
|
||||||
'application/json':
|
'application/json':
|
||||||
schema:
|
schema:
|
||||||
$ref: './hs-office-relations-schemas.yaml#/components/schemas/HsOfficeRelation'
|
$ref: './hs-office-relation-schemas.yaml#/components/schemas/HsOfficeRelation'
|
||||||
"401":
|
"401":
|
||||||
$ref: './error-responses.yaml#/components/responses/Unauthorized'
|
$ref: './error-responses.yaml#/components/responses/Unauthorized'
|
||||||
"403":
|
"403":
|
||||||
|
@ -18,7 +18,7 @@ get:
|
|||||||
in: query
|
in: query
|
||||||
required: false
|
required: false
|
||||||
schema:
|
schema:
|
||||||
$ref: './hs-office-relations-schemas.yaml#/components/schemas/HsOfficeRelationType'
|
$ref: './hs-office-relation-schemas.yaml#/components/schemas/HsOfficeRelationType'
|
||||||
description: Prefix of name properties from holder or contact to filter the results.
|
description: Prefix of name properties from holder or contact to filter the results.
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
@ -28,7 +28,7 @@ get:
|
|||||||
schema:
|
schema:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: './hs-office-relations-schemas.yaml#/components/schemas/HsOfficeRelation'
|
$ref: './hs-office-relation-schemas.yaml#/components/schemas/HsOfficeRelation'
|
||||||
"401":
|
"401":
|
||||||
$ref: './error-responses.yaml#/components/responses/Unauthorized'
|
$ref: './error-responses.yaml#/components/responses/Unauthorized'
|
||||||
"403":
|
"403":
|
||||||
@ -46,7 +46,7 @@ post:
|
|||||||
content:
|
content:
|
||||||
'application/json':
|
'application/json':
|
||||||
schema:
|
schema:
|
||||||
$ref: './hs-office-relations-schemas.yaml#/components/schemas/HsOfficeRelationInsert'
|
$ref: './hs-office-relation-schemas.yaml#/components/schemas/HsOfficeRelationInsert'
|
||||||
required: true
|
required: true
|
||||||
responses:
|
responses:
|
||||||
"201":
|
"201":
|
||||||
@ -54,7 +54,7 @@ post:
|
|||||||
content:
|
content:
|
||||||
'application/json':
|
'application/json':
|
||||||
schema:
|
schema:
|
||||||
$ref: './hs-office-relations-schemas.yaml#/components/schemas/HsOfficeRelation'
|
$ref: './hs-office-relation-schemas.yaml#/components/schemas/HsOfficeRelation'
|
||||||
"401":
|
"401":
|
||||||
$ref: './error-responses.yaml#/components/responses/Unauthorized'
|
$ref: './error-responses.yaml#/components/responses/Unauthorized'
|
||||||
"403":
|
"403":
|
||||||
|
@ -22,5 +22,6 @@ components:
|
|||||||
- owner
|
- owner
|
||||||
- admin
|
- admin
|
||||||
- tenant
|
- tenant
|
||||||
|
- referrer
|
||||||
roleName:
|
roleName:
|
||||||
type: string
|
type: string
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
-- NUMERIC-HASH-FUNCTIONS
|
-- NUMERIC-HASH-FUNCTIONS
|
||||||
--changeset hash:1 endDelimiter:--//
|
--changeset numeric-hash-functions:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
create function bigIntHash(text) returns bigint as $$
|
create function bigIntHash(text) returns bigint as $$
|
||||||
|
@ -26,7 +26,7 @@ create or replace procedure defineContext(
|
|||||||
currentTask varchar(96),
|
currentTask varchar(96),
|
||||||
currentRequest text = null,
|
currentRequest text = null,
|
||||||
currentUser varchar(63) = null,
|
currentUser varchar(63) = null,
|
||||||
assumedRoles varchar(256) = null
|
assumedRoles varchar(1023) = null
|
||||||
)
|
)
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
begin
|
begin
|
||||||
@ -43,7 +43,7 @@ begin
|
|||||||
execute format('set local hsadminng.currentUser to %L', currentUser);
|
execute format('set local hsadminng.currentUser to %L', currentUser);
|
||||||
|
|
||||||
assumedRoles := coalesce(assumedRoles, '');
|
assumedRoles := coalesce(assumedRoles, '');
|
||||||
assert length(assumedRoles) <= 256, FORMAT('assumedRoles must not be longer than 256 characters: "%s"', assumedRoles);
|
assert length(assumedRoles) <= 1023, FORMAT('assumedRoles must not be longer than 1023 characters: "%s"', assumedRoles);
|
||||||
execute format('set local hsadminng.assumedRoles to %L', assumedRoles);
|
execute format('set local hsadminng.assumedRoles to %L', assumedRoles);
|
||||||
|
|
||||||
call contextDefined(currentTask, currentRequest, currentUser, assumedRoles);
|
call contextDefined(currentTask, currentRequest, currentUser, assumedRoles);
|
||||||
@ -87,11 +87,11 @@ end; $$;
|
|||||||
Raises exception if not set.
|
Raises exception if not set.
|
||||||
*/
|
*/
|
||||||
create or replace function currentRequest()
|
create or replace function currentRequest()
|
||||||
returns varchar(512)
|
returns text
|
||||||
stable -- leakproof
|
stable -- leakproof
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
declare
|
declare
|
||||||
currentRequest varchar(512);
|
currentRequest text;
|
||||||
begin
|
begin
|
||||||
begin
|
begin
|
||||||
currentRequest := current_setting('hsadminng.currentRequest');
|
currentRequest := current_setting('hsadminng.currentRequest');
|
||||||
@ -135,22 +135,11 @@ end; $$;
|
|||||||
or empty array, if not set.
|
or empty array, if not set.
|
||||||
*/
|
*/
|
||||||
create or replace function assumedRoles()
|
create or replace function assumedRoles()
|
||||||
returns varchar(63)[]
|
returns varchar(1023)[]
|
||||||
stable -- leakproof
|
stable -- leakproof
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
declare
|
|
||||||
currentSubject varchar(63);
|
|
||||||
begin
|
begin
|
||||||
begin
|
return string_to_array(current_setting('hsadminng.assumedRoles', true), ';');
|
||||||
currentSubject := current_setting('hsadminng.assumedRoles');
|
|
||||||
exception
|
|
||||||
when others then
|
|
||||||
return array []::varchar[];
|
|
||||||
end;
|
|
||||||
if (currentSubject = '') then
|
|
||||||
return array []::varchar[];
|
|
||||||
end if;
|
|
||||||
return string_to_array(currentSubject, ';');
|
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
create or replace function cleanIdentifier(rawIdentifier varchar)
|
create or replace function cleanIdentifier(rawIdentifier varchar)
|
||||||
@ -219,17 +208,17 @@ begin
|
|||||||
end ; $$;
|
end ; $$;
|
||||||
|
|
||||||
create or replace function currentSubjects()
|
create or replace function currentSubjects()
|
||||||
returns varchar(63)[]
|
returns varchar(1023)[]
|
||||||
stable -- leakproof
|
stable -- leakproof
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
declare
|
declare
|
||||||
assumedRoles varchar(63)[];
|
assumedRoles varchar(1023)[];
|
||||||
begin
|
begin
|
||||||
assumedRoles := assumedRoles();
|
assumedRoles := assumedRoles();
|
||||||
if array_length(assumedRoles, 1) > 0 then
|
if array_length(assumedRoles, 1) > 0 then
|
||||||
return assumedRoles();
|
return assumedRoles;
|
||||||
else
|
else
|
||||||
return array [currentUser()]::varchar(63)[];
|
return array [currentUser()]::varchar(1023)[];
|
||||||
end if;
|
end if;
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ create table tx_context
|
|||||||
txId bigint not null,
|
txId bigint not null,
|
||||||
txTimestamp timestamp not null,
|
txTimestamp timestamp not null,
|
||||||
currentUser varchar(63) not null, -- not the uuid, because users can be deleted
|
currentUser varchar(63) not null, -- not the uuid, because users can be deleted
|
||||||
assumedRoles varchar(256) not null, -- not the uuids, because roles can be deleted
|
assumedRoles varchar(1023) not null, -- not the uuids, because roles can be deleted
|
||||||
currentTask varchar(96) not null,
|
currentTask varchar(96) not null,
|
||||||
currentRequest text not null
|
currentRequest text not null
|
||||||
);
|
);
|
||||||
|
@ -63,6 +63,7 @@ create or replace view rbacgrants_ev as
|
|||||||
x.grantedByRoleUuid,
|
x.grantedByRoleUuid,
|
||||||
x.ascendantUuid as ascendantUuid,
|
x.ascendantUuid as ascendantUuid,
|
||||||
x.descendantUuid as descendantUuid,
|
x.descendantUuid as descendantUuid,
|
||||||
|
x.op as permOp, x.optablename as permOpTableName,
|
||||||
x.assumed
|
x.assumed
|
||||||
from (
|
from (
|
||||||
select g.uuid as grantUuid,
|
select g.uuid as grantUuid,
|
||||||
@ -74,12 +75,16 @@ create or replace view rbacgrants_ev as
|
|||||||
'role ' || aro.objectTable || '#' || findIdNameByObjectUuid(aro.objectTable, aro.uuid) || '.' || ar.roletype
|
'role ' || aro.objectTable || '#' || findIdNameByObjectUuid(aro.objectTable, aro.uuid) || '.' || ar.roletype
|
||||||
) as ascendingIdName,
|
) as ascendingIdName,
|
||||||
aro.objectTable, aro.uuid,
|
aro.objectTable, aro.uuid,
|
||||||
|
( case
|
||||||
coalesce(
|
when dro is not null
|
||||||
'role ' || dro.objectTable || '#' || findIdNameByObjectUuid(dro.objectTable, dro.uuid) || '.' || dr.roletype,
|
then ('role ' || dro.objectTable || '#' || findIdNameByObjectUuid(dro.objectTable, dro.uuid) || '.' || dr.roletype)
|
||||||
'perm ' || dp.op || ' on ' || dpo.objecttable || '#' || findIdNameByObjectUuid(dpo.objectTable, dpo.uuid)
|
when dp.op = 'INSERT'
|
||||||
|
then 'perm ' || dp.op || ' into ' || dp.opTableName || ' with ' || dpo.objecttable || '#' || findIdNameByObjectUuid(dpo.objectTable, dpo.uuid)
|
||||||
|
else 'perm ' || dp.op || ' on ' || dpo.objecttable || '#' || findIdNameByObjectUuid(dpo.objectTable, dpo.uuid)
|
||||||
|
end
|
||||||
) as descendingIdName,
|
) as descendingIdName,
|
||||||
dro.objectTable, dro.uuid
|
dro.objectTable, dro.uuid,
|
||||||
|
dp.op, dp.optablename
|
||||||
from rbacgrants as g
|
from rbacgrants as g
|
||||||
|
|
||||||
left outer join rbacrole as ar on ar.uuid = g.ascendantUuid
|
left outer join rbacrole as ar on ar.uuid = g.ascendantUuid
|
||||||
|
@ -86,16 +86,14 @@ execute procedure insertTriggerForTestCustomer_tf();
|
|||||||
do language plpgsql $$
|
do language plpgsql $$
|
||||||
declare
|
declare
|
||||||
row global;
|
row global;
|
||||||
permissionUuid uuid;
|
|
||||||
roleUuid uuid;
|
|
||||||
begin
|
begin
|
||||||
call defineContext('create INSERT INTO test_customer permissions for the related global rows');
|
call defineContext('create INSERT INTO test_customer permissions for the related global rows');
|
||||||
|
|
||||||
FOR row IN SELECT * FROM global
|
FOR row IN SELECT * FROM global
|
||||||
LOOP
|
LOOP
|
||||||
roleUuid := findRoleId(globalAdmin());
|
call grantPermissionToRole(
|
||||||
permissionUuid := createPermission(row.uuid, 'INSERT', 'test_customer');
|
createPermission(row.uuid, 'INSERT', 'test_customer'),
|
||||||
call grantPermissionToRole(permissionUuid, roleUuid);
|
globalAdmin());
|
||||||
END LOOP;
|
END LOOP;
|
||||||
END;
|
END;
|
||||||
$$;
|
$$;
|
||||||
|
@ -151,16 +151,14 @@ execute procedure updateTriggerForTestPackage_tf();
|
|||||||
do language plpgsql $$
|
do language plpgsql $$
|
||||||
declare
|
declare
|
||||||
row test_customer;
|
row test_customer;
|
||||||
permissionUuid uuid;
|
|
||||||
roleUuid uuid;
|
|
||||||
begin
|
begin
|
||||||
call defineContext('create INSERT INTO test_package permissions for the related test_customer rows');
|
call defineContext('create INSERT INTO test_package permissions for the related test_customer rows');
|
||||||
|
|
||||||
FOR row IN SELECT * FROM test_customer
|
FOR row IN SELECT * FROM test_customer
|
||||||
LOOP
|
LOOP
|
||||||
roleUuid := findRoleId(testCustomerAdmin(row));
|
call grantPermissionToRole(
|
||||||
permissionUuid := createPermission(row.uuid, 'INSERT', 'test_package');
|
createPermission(row.uuid, 'INSERT', 'test_package'),
|
||||||
call grantPermissionToRole(permissionUuid, roleUuid);
|
testCustomerAdmin(row));
|
||||||
END LOOP;
|
END LOOP;
|
||||||
END;
|
END;
|
||||||
$$;
|
$$;
|
||||||
|
@ -150,16 +150,14 @@ execute procedure updateTriggerForTestDomain_tf();
|
|||||||
do language plpgsql $$
|
do language plpgsql $$
|
||||||
declare
|
declare
|
||||||
row test_package;
|
row test_package;
|
||||||
permissionUuid uuid;
|
|
||||||
roleUuid uuid;
|
|
||||||
begin
|
begin
|
||||||
call defineContext('create INSERT INTO test_domain permissions for the related test_package rows');
|
call defineContext('create INSERT INTO test_domain permissions for the related test_package rows');
|
||||||
|
|
||||||
FOR row IN SELECT * FROM test_package
|
FOR row IN SELECT * FROM test_package
|
||||||
LOOP
|
LOOP
|
||||||
roleUuid := findRoleId(testPackageAdmin(row));
|
call grantPermissionToRole(
|
||||||
permissionUuid := createPermission(row.uuid, 'INSERT', 'test_domain');
|
createPermission(row.uuid, 'INSERT', 'test_domain'),
|
||||||
call grantPermissionToRole(permissionUuid, roleUuid);
|
testPackageAdmin(row));
|
||||||
END LOOP;
|
END LOOP;
|
||||||
END;
|
END;
|
||||||
$$;
|
$$;
|
||||||
|
@ -1,126 +0,0 @@
|
|||||||
--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$);
|
|
||||||
--//
|
|
||||||
|
|
@ -24,6 +24,7 @@ subgraph contact["`**contact**`"]
|
|||||||
perm:contact:DELETE{{contact:DELETE}}
|
perm:contact:DELETE{{contact:DELETE}}
|
||||||
perm:contact:UPDATE{{contact:UPDATE}}
|
perm:contact:UPDATE{{contact:UPDATE}}
|
||||||
perm:contact:SELECT{{contact:SELECT}}
|
perm:contact:SELECT{{contact:SELECT}}
|
||||||
|
perm:contact:INSERT{{contact:INSERT}}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -39,5 +40,6 @@ role:contact:admin ==> role:contact:referrer
|
|||||||
role:contact:owner ==> perm:contact:DELETE
|
role:contact:owner ==> perm:contact:DELETE
|
||||||
role:contact:admin ==> perm:contact:UPDATE
|
role:contact:admin ==> perm:contact:UPDATE
|
||||||
role:contact:referrer ==> perm:contact:SELECT
|
role:contact:referrer ==> perm:contact:SELECT
|
||||||
|
role:global:guest ==> perm:contact:INSERT
|
||||||
|
|
||||||
```
|
```
|
@ -1,4 +1,6 @@
|
|||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
|
-- This code generated was by RbacViewPostgresGenerator, do not amend manually.
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-contact-rbac-OBJECT:1 endDelimiter:--//
|
--changeset hs-office-contact-rbac-OBJECT:1 endDelimiter:--//
|
||||||
@ -15,28 +17,28 @@ call generateRbacRoleDescriptors('hsOfficeContact', 'hs_office_contact');
|
|||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-contact-rbac-ROLES-CREATION:1 endDelimiter:--//
|
--changeset hs-office-contact-rbac-insert-trigger:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Creates the roles and their assignments for a new contact for the AFTER INSERT TRIGGER.
|
Creates the roles, grants and permission for the AFTER INSERT TRIGGER.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
create or replace function createRbacRolesForHsOfficeContact()
|
create or replace procedure buildRbacSystemForHsOfficeContact(
|
||||||
returns trigger
|
NEW hs_office_contact
|
||||||
language plpgsql
|
)
|
||||||
strict as $$
|
language plpgsql as $$
|
||||||
|
|
||||||
|
declare
|
||||||
|
|
||||||
begin
|
begin
|
||||||
if TG_OP <> 'INSERT' then
|
call enterTriggerForObjectUuid(NEW.uuid);
|
||||||
raise exception 'invalid usage of TRIGGER AFTER INSERT';
|
|
||||||
end if;
|
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficeContactOwner(NEW),
|
hsOfficeContactOwner(NEW),
|
||||||
permissions => array['DELETE'],
|
permissions => array['DELETE'],
|
||||||
incomingSuperRoles => array[globalAdmin()],
|
incomingSuperRoles => array[globalAdmin()],
|
||||||
userUuids => array[currentUserUuid()],
|
userUuids => array[currentUserUuid()]
|
||||||
grantedByRole => globalAdmin()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
@ -46,96 +48,99 @@ begin
|
|||||||
);
|
);
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficeContactTenant(NEW),
|
hsOfficeContactReferrer(NEW),
|
||||||
|
permissions => array['SELECT'],
|
||||||
incomingSuperRoles => array[hsOfficeContactAdmin(NEW)]
|
incomingSuperRoles => array[hsOfficeContactAdmin(NEW)]
|
||||||
);
|
);
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||||
hsOfficeContactGuest(NEW),
|
|
||||||
permissions => array['SELECT'],
|
|
||||||
incomingSuperRoles => array[hsOfficeContactTenant(NEW)]
|
|
||||||
);
|
|
||||||
|
|
||||||
return NEW;
|
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
An AFTER INSERT TRIGGER which creates the role structure for a new customer.
|
AFTER INSERT TRIGGER to create the role+grant structure for a new hs_office_contact row.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
create trigger createRbacRolesForHsOfficeContact_Trigger
|
create or replace function insertTriggerForHsOfficeContact_tf()
|
||||||
after insert
|
returns trigger
|
||||||
on hs_office_contact
|
language plpgsql
|
||||||
|
strict as $$
|
||||||
|
begin
|
||||||
|
call buildRbacSystemForHsOfficeContact(NEW);
|
||||||
|
return NEW;
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
create trigger insertTriggerForHsOfficeContact_tg
|
||||||
|
after insert on hs_office_contact
|
||||||
for each row
|
for each row
|
||||||
execute procedure createRbacRolesForHsOfficeContact();
|
execute procedure insertTriggerForHsOfficeContact_tf();
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
--changeset hs-office-contact-rbac-INSERT:1 endDelimiter:--//
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/*
|
||||||
|
Creates INSERT INTO hs_office_contact permissions for the related global rows.
|
||||||
|
*/
|
||||||
|
do language plpgsql $$
|
||||||
|
declare
|
||||||
|
row global;
|
||||||
|
begin
|
||||||
|
call defineContext('create INSERT INTO hs_office_contact permissions for the related global rows');
|
||||||
|
|
||||||
|
FOR row IN SELECT * FROM global
|
||||||
|
LOOP
|
||||||
|
call grantPermissionToRole(
|
||||||
|
createPermission(row.uuid, 'INSERT', 'hs_office_contact'),
|
||||||
|
globalGuest());
|
||||||
|
END LOOP;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Adds hs_office_contact INSERT permission to specified role of new global rows.
|
||||||
|
*/
|
||||||
|
create or replace function hs_office_contact_global_insert_tf()
|
||||||
|
returns trigger
|
||||||
|
language plpgsql
|
||||||
|
strict as $$
|
||||||
|
begin
|
||||||
|
call grantPermissionToRole(
|
||||||
|
createPermission(NEW.uuid, 'INSERT', 'hs_office_contact'),
|
||||||
|
globalGuest());
|
||||||
|
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_contact_global_insert_tg
|
||||||
|
after insert on global
|
||||||
|
for each row
|
||||||
|
execute procedure hs_office_contact_global_insert_tf();
|
||||||
|
--//
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-contact-rbac-IDENTITY-VIEW:1 endDelimiter:--//
|
--changeset hs-office-contact-rbac-IDENTITY-VIEW:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
call generateRbacIdentityViewFromProjection('hs_office_contact', $idName$
|
call generateRbacIdentityViewFromProjection('hs_office_contact',
|
||||||
target.label
|
$idName$
|
||||||
|
label
|
||||||
$idName$);
|
$idName$);
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-contact-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
|
--changeset hs-office-contact-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
call generateRbacRestrictedView('hs_office_contact', 'target.label',
|
call generateRbacRestrictedView('hs_office_contact',
|
||||||
|
$orderBy$
|
||||||
|
label
|
||||||
|
$orderBy$,
|
||||||
$updates$
|
$updates$
|
||||||
label = new.label,
|
label = new.label,
|
||||||
postalAddress = new.postalAddress,
|
postalAddress = new.postalAddress,
|
||||||
emailAddresses = new.emailAddresses,
|
emailAddresses = new.emailAddresses,
|
||||||
phoneNumbers = new.phoneNumbers
|
phoneNumbers = new.phoneNumbers
|
||||||
$updates$);
|
$updates$);
|
||||||
--/
|
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
|
||||||
--changeset hs-office-contact-rbac-NEW-CONTACT:1 endDelimiter:--//
|
|
||||||
-- ----------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
Creates a global permission for new-contact and assigns it to the hostsharing admins role.
|
|
||||||
*/
|
|
||||||
do language plpgsql $$
|
|
||||||
declare
|
|
||||||
addCustomerPermissions uuid[];
|
|
||||||
globalObjectUuid uuid;
|
|
||||||
globalAdminRoleUuid uuid;
|
|
||||||
begin
|
|
||||||
call defineContext('granting global new-contact permission to global admin role', null, null, null);
|
|
||||||
|
|
||||||
globalAdminRoleUuid := findRoleId(globalAdmin());
|
|
||||||
globalObjectUuid := (select uuid from global);
|
|
||||||
addCustomerPermissions := createPermissions(globalObjectUuid, array ['new-contact']);
|
|
||||||
call grantPermissionsToRole(globalAdminRoleUuid, addCustomerPermissions);
|
|
||||||
end;
|
|
||||||
$$;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Used by the trigger to prevent the add-customer to current user respectively assumed roles.
|
|
||||||
*/
|
|
||||||
create or replace function addHsOfficeContactNotAllowedForCurrentSubjects()
|
|
||||||
returns trigger
|
|
||||||
language PLPGSQL
|
|
||||||
as $$
|
|
||||||
begin
|
|
||||||
raise exception '[403] new-contact not permitted for %',
|
|
||||||
array_to_string(currentSubjects(), ';', 'null');
|
|
||||||
end; $$;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Checks if the user or assumed roles are allowed to create a new customer.
|
|
||||||
*/
|
|
||||||
create trigger hs_office_contact_insert_trigger
|
|
||||||
before insert
|
|
||||||
on hs_office_contact
|
|
||||||
for each row
|
|
||||||
-- TODO.spec: who is allowed to create new contacts
|
|
||||||
when ( not hasAssumedRole() )
|
|
||||||
execute procedure addHsOfficeContactNotAllowedForCurrentSubjects();
|
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ create table if not exists hs_office_person
|
|||||||
givenName varchar(48),
|
givenName varchar(48),
|
||||||
familyName varchar(48)
|
familyName varchar(48)
|
||||||
);
|
);
|
||||||
--//
|
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
|
@ -1,126 +0,0 @@
|
|||||||
--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$);
|
|
||||||
--//
|
|
||||||
|
|
@ -21,6 +21,7 @@ subgraph person["`**person**`"]
|
|||||||
subgraph person:permissions[ ]
|
subgraph person:permissions[ ]
|
||||||
style person:permissions fill:#dd4901,stroke:white
|
style person:permissions fill:#dd4901,stroke:white
|
||||||
|
|
||||||
|
perm:person:INSERT{{person:INSERT}}
|
||||||
perm:person:DELETE{{person:DELETE}}
|
perm:person:DELETE{{person:DELETE}}
|
||||||
perm:person:UPDATE{{person:UPDATE}}
|
perm:person:UPDATE{{person:UPDATE}}
|
||||||
perm:person:SELECT{{person:SELECT}}
|
perm:person:SELECT{{person:SELECT}}
|
||||||
@ -36,6 +37,7 @@ role:person:owner ==> role:person:admin
|
|||||||
role:person:admin ==> role:person:referrer
|
role:person:admin ==> role:person:referrer
|
||||||
|
|
||||||
%% granting permissions to roles
|
%% granting permissions to roles
|
||||||
|
role:global:guest ==> perm:person:INSERT
|
||||||
role:person:owner ==> perm:person:DELETE
|
role:person:owner ==> perm:person:DELETE
|
||||||
role:person:admin ==> perm:person:UPDATE
|
role:person:admin ==> perm:person:UPDATE
|
||||||
role:person:referrer ==> perm:person:SELECT
|
role:person:referrer ==> perm:person:SELECT
|
@ -1,4 +1,6 @@
|
|||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
|
-- This code generated was by RbacViewPostgresGenerator, do not amend manually.
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-person-rbac-OBJECT:1 endDelimiter:--//
|
--changeset hs-office-person-rbac-OBJECT:1 endDelimiter:--//
|
||||||
@ -15,29 +17,30 @@ call generateRbacRoleDescriptors('hsOfficePerson', 'hs_office_person');
|
|||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-person-rbac-ROLES-CREATION:1 endDelimiter:--//
|
--changeset hs-office-person-rbac-insert-trigger:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Creates the roles and their assignments for a new person for the AFTER INSERT TRIGGER.
|
Creates the roles, grants and permission for the AFTER INSERT TRIGGER.
|
||||||
*/
|
*/
|
||||||
create or replace function createRbacRolesForHsOfficePerson()
|
|
||||||
returns trigger
|
create or replace procedure buildRbacSystemForHsOfficePerson(
|
||||||
language plpgsql
|
NEW hs_office_person
|
||||||
strict as $$
|
)
|
||||||
|
language plpgsql as $$
|
||||||
|
|
||||||
|
declare
|
||||||
|
|
||||||
begin
|
begin
|
||||||
if TG_OP <> 'INSERT' then
|
call enterTriggerForObjectUuid(NEW.uuid);
|
||||||
raise exception 'invalid usage of TRIGGER AFTER INSERT';
|
|
||||||
end if;
|
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficePersonOwner(NEW),
|
hsOfficePersonOwner(NEW),
|
||||||
permissions => array['DELETE'],
|
permissions => array['DELETE'],
|
||||||
incomingSuperRoles => array[globalAdmin()],
|
incomingSuperRoles => array[globalAdmin()],
|
||||||
userUuids => array[currentUserUuid()],
|
userUuids => array[currentUserUuid()]
|
||||||
grantedByRole => globalAdmin()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
-- TODO: who is admin? the person itself? is it allowed for the person itself or a representative to update the data?
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficePersonAdmin(NEW),
|
hsOfficePersonAdmin(NEW),
|
||||||
permissions => array['UPDATE'],
|
permissions => array['UPDATE'],
|
||||||
@ -45,44 +48,94 @@ begin
|
|||||||
);
|
);
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficePersonTenant(NEW),
|
hsOfficePersonReferrer(NEW),
|
||||||
|
permissions => array['SELECT'],
|
||||||
incomingSuperRoles => array[hsOfficePersonAdmin(NEW)]
|
incomingSuperRoles => array[hsOfficePersonAdmin(NEW)]
|
||||||
);
|
);
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||||
hsOfficePersonGuest(NEW),
|
|
||||||
permissions => array['SELECT'],
|
|
||||||
incomingSuperRoles => array[hsOfficePersonTenant(NEW)]
|
|
||||||
);
|
|
||||||
|
|
||||||
return NEW;
|
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
An AFTER INSERT TRIGGER which creates the role structure for a new customer.
|
AFTER INSERT TRIGGER to create the role+grant structure for a new hs_office_person row.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
create trigger createRbacRolesForHsOfficePerson_Trigger
|
create or replace function insertTriggerForHsOfficePerson_tf()
|
||||||
after insert
|
returns trigger
|
||||||
on hs_office_person
|
language plpgsql
|
||||||
|
strict as $$
|
||||||
|
begin
|
||||||
|
call buildRbacSystemForHsOfficePerson(NEW);
|
||||||
|
return NEW;
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
create trigger insertTriggerForHsOfficePerson_tg
|
||||||
|
after insert on hs_office_person
|
||||||
for each row
|
for each row
|
||||||
execute procedure createRbacRolesForHsOfficePerson();
|
execute procedure insertTriggerForHsOfficePerson_tf();
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
--changeset hs-office-person-rbac-INSERT:1 endDelimiter:--//
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/*
|
||||||
|
Creates INSERT INTO hs_office_person permissions for the related global rows.
|
||||||
|
*/
|
||||||
|
do language plpgsql $$
|
||||||
|
declare
|
||||||
|
row global;
|
||||||
|
begin
|
||||||
|
call defineContext('create INSERT INTO hs_office_person permissions for the related global rows');
|
||||||
|
|
||||||
|
FOR row IN SELECT * FROM global
|
||||||
|
LOOP
|
||||||
|
call grantPermissionToRole(
|
||||||
|
createPermission(row.uuid, 'INSERT', 'hs_office_person'),
|
||||||
|
globalGuest());
|
||||||
|
END LOOP;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Adds hs_office_person INSERT permission to specified role of new global rows.
|
||||||
|
*/
|
||||||
|
create or replace function hs_office_person_global_insert_tf()
|
||||||
|
returns trigger
|
||||||
|
language plpgsql
|
||||||
|
strict as $$
|
||||||
|
begin
|
||||||
|
call grantPermissionToRole(
|
||||||
|
createPermission(NEW.uuid, 'INSERT', 'hs_office_person'),
|
||||||
|
globalGuest());
|
||||||
|
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_person_global_insert_tg
|
||||||
|
after insert on global
|
||||||
|
for each row
|
||||||
|
execute procedure hs_office_person_global_insert_tf();
|
||||||
|
--//
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-person-rbac-IDENTITY-VIEW:1 endDelimiter:--//
|
--changeset hs-office-person-rbac-IDENTITY-VIEW:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
call generateRbacIdentityViewFromProjection('hs_office_person', $idName$
|
|
||||||
concat(target.tradeName, target.familyName, target.givenName)
|
call generateRbacIdentityViewFromProjection('hs_office_person',
|
||||||
|
$idName$
|
||||||
|
concat(tradeName, familyName, givenName)
|
||||||
$idName$);
|
$idName$);
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-person-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
|
--changeset hs-office-person-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
call generateRbacRestrictedView('hs_office_person', 'concat(target.tradeName, target.familyName, target.givenName)',
|
call generateRbacRestrictedView('hs_office_person',
|
||||||
|
$orderBy$
|
||||||
|
concat(tradeName, familyName, givenName)
|
||||||
|
$orderBy$,
|
||||||
$updates$
|
$updates$
|
||||||
personType = new.personType,
|
personType = new.personType,
|
||||||
tradeName = new.tradeName,
|
tradeName = new.tradeName,
|
||||||
@ -91,49 +144,3 @@ call generateRbacRestrictedView('hs_office_person', 'concat(target.tradeName, ta
|
|||||||
$updates$);
|
$updates$);
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
|
||||||
--changeset hs-office-person-rbac-NEW-PERSON:1 endDelimiter:--//
|
|
||||||
-- ----------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
Creates a global permission for new-person and assigns it to the hostsharing admins role.
|
|
||||||
*/
|
|
||||||
do language plpgsql $$
|
|
||||||
declare
|
|
||||||
addCustomerPermissions uuid[];
|
|
||||||
globalObjectUuid uuid;
|
|
||||||
globalAdminRoleUuid uuid ;
|
|
||||||
begin
|
|
||||||
call defineContext('granting global new-person permission to global admin role', null, null, null);
|
|
||||||
|
|
||||||
globalAdminRoleUuid := findRoleId(globalAdmin());
|
|
||||||
globalObjectUuid := (select uuid from global);
|
|
||||||
addCustomerPermissions := createPermissions(globalObjectUuid, array ['new-person']);
|
|
||||||
call grantPermissionsToRole(globalAdminRoleUuid, addCustomerPermissions);
|
|
||||||
end;
|
|
||||||
$$;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Used by the trigger to prevent the add-customer to current user respectively assumed roles.
|
|
||||||
*/
|
|
||||||
create or replace function addHsOfficePersonNotAllowedForCurrentSubjects()
|
|
||||||
returns trigger
|
|
||||||
language PLPGSQL
|
|
||||||
as $$
|
|
||||||
begin
|
|
||||||
raise exception '[403] new-person not permitted for %',
|
|
||||||
array_to_string(currentSubjects(), ';', 'null');
|
|
||||||
end; $$;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Checks if the user or assumed roles are allowed to create a new customer.
|
|
||||||
*/
|
|
||||||
create trigger hs_office_person_insert_trigger
|
|
||||||
before insert
|
|
||||||
on hs_office_person
|
|
||||||
for each row
|
|
||||||
-- TODO.spec: who is allowed to create new persons
|
|
||||||
when ( not hasAssumedRole() )
|
|
||||||
execute procedure addHsOfficePersonNotAllowedForCurrentSubjects();
|
|
||||||
--//
|
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ begin
|
|||||||
call defineContext(currentTask, null, emailAddr);
|
call defineContext(currentTask, null, emailAddr);
|
||||||
execute format('set local hsadminng.currentTask to %L', currentTask);
|
execute format('set local hsadminng.currentTask to %L', currentTask);
|
||||||
|
|
||||||
raise notice 'creating test person: %', fullName;
|
raise notice 'creating test person: % by %', fullName, emailAddr;
|
||||||
insert
|
insert
|
||||||
into hs_office_person (persontype, tradename, givenname, familyname)
|
into hs_office_person (persontype, tradename, givenname, familyname)
|
||||||
values (newPersonType, newTradeName, newGivenName, newFamilyName);
|
values (newPersonType, newTradeName, newGivenName, newFamilyName);
|
||||||
@ -67,9 +67,10 @@ do language plpgsql $$
|
|||||||
call createHsOfficePersonTestData('NP', null, 'Fouler', 'Ellie');
|
call createHsOfficePersonTestData('NP', null, 'Fouler', 'Ellie');
|
||||||
call createHsOfficePersonTestData('LP', 'Second e.K.', 'Smith', 'Peter');
|
call createHsOfficePersonTestData('LP', 'Second e.K.', 'Smith', 'Peter');
|
||||||
call createHsOfficePersonTestData('IF', 'Third OHG');
|
call createHsOfficePersonTestData('IF', 'Third OHG');
|
||||||
call createHsOfficePersonTestData('IF', 'Fourth eG');
|
call createHsOfficePersonTestData('LP', 'Fourth eG');
|
||||||
call createHsOfficePersonTestData('UF', 'Erben Bessler', 'Mel', 'Bessler');
|
call createHsOfficePersonTestData('UF', 'Erben Bessler', 'Mel', 'Bessler');
|
||||||
call createHsOfficePersonTestData('NP', null, 'Bessler', 'Anita');
|
call createHsOfficePersonTestData('NP', null, 'Bessler', 'Anita');
|
||||||
|
call createHsOfficePersonTestData('NP', null, 'Bessler', 'Bert');
|
||||||
call createHsOfficePersonTestData('NP', null, 'Winkler', 'Paul');
|
call createHsOfficePersonTestData('NP', null, 'Winkler', 'Paul');
|
||||||
end;
|
end;
|
||||||
$$;
|
$$;
|
||||||
|
@ -1,100 +0,0 @@
|
|||||||
### 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
|
|
||||||
|
|
||||||
```
|
|
@ -1,191 +0,0 @@
|
|||||||
--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 WHERE uuid = NEW.holderUuid INTO newHolderPerson;
|
|
||||||
|
|
||||||
SELECT * FROM hs_office_person WHERE uuid = NEW.anchorUuid INTO newAnchorPerson;
|
|
||||||
|
|
||||||
SELECT * FROM hs_office_contact WHERE uuid = NEW.contactUuid INTO newContact;
|
|
||||||
|
|
||||||
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[
|
|
||||||
hsOfficeContactAdmin(newContact),
|
|
||||||
hsOfficePersonAdmin(newHolderPerson),
|
|
||||||
hsOfficeRelationAgent(NEW)],
|
|
||||||
outgoingSubRoles => array[
|
|
||||||
hsOfficeContactReferrer(newContact),
|
|
||||||
hsOfficePersonReferrer(newAnchorPerson),
|
|
||||||
hsOfficePersonReferrer(newHolderPerson)]
|
|
||||||
);
|
|
||||||
|
|
||||||
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 $$
|
|
||||||
begin
|
|
||||||
|
|
||||||
if NEW.contactUuid is distinct from OLD.contactUuid then
|
|
||||||
delete from rbacgrants g where g.grantedbytriggerof = OLD.uuid;
|
|
||||||
call buildRbacSystemForHsOfficeRelation(NEW);
|
|
||||||
end if;
|
|
||||||
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$);
|
|
||||||
--//
|
|
||||||
|
|
@ -1,44 +1,102 @@
|
|||||||
### hs_office_relation RBAC
|
### rbac relation
|
||||||
|
|
||||||
|
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
|
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||||
flowchart TB
|
flowchart TB
|
||||||
|
|
||||||
subgraph global
|
subgraph holderPerson["`**holderPerson**`"]
|
||||||
style global fill:#eee
|
|
||||||
|
|
||||||
role:global.admin[global.admin]
|
|
||||||
end
|
|
||||||
|
|
||||||
subgraph hsOfficeContact
|
|
||||||
direction TB
|
direction TB
|
||||||
style hsOfficeContact fill:#eee
|
style holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
role:hsOfficeContact.admin[contact.admin]
|
subgraph holderPerson:roles[ ]
|
||||||
--> role:hsOfficeContact.tenant[contact.tenant]
|
style holderPerson:roles fill:#99bcdb,stroke:white
|
||||||
--> role:hsOfficeContact.guest[contact.guest]
|
|
||||||
|
role:holderPerson:owner[[holderPerson:owner]]
|
||||||
|
role:holderPerson:admin[[holderPerson:admin]]
|
||||||
|
role:holderPerson:referrer[[holderPerson:referrer]]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
subgraph hsOfficePerson
|
subgraph anchorPerson["`**anchorPerson**`"]
|
||||||
direction TB
|
direction TB
|
||||||
style hsOfficePerson fill:#eee
|
style anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
role:hsOfficePerson.admin[person.admin]
|
subgraph anchorPerson:roles[ ]
|
||||||
--> role:hsOfficePerson.tenant[person.tenant]
|
style anchorPerson:roles fill:#99bcdb,stroke:white
|
||||||
--> role:hsOfficePerson.guest[person.guest]
|
|
||||||
|
role:anchorPerson:owner[[anchorPerson:owner]]
|
||||||
|
role:anchorPerson:admin[[anchorPerson:admin]]
|
||||||
|
role:anchorPerson:referrer[[anchorPerson:referrer]]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
subgraph hsOfficeRelation
|
subgraph contact["`**contact**`"]
|
||||||
|
direction TB
|
||||||
|
style contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
role:hsOfficePerson#anchor.admin[person#anchor.admin]
|
subgraph contact:roles[ ]
|
||||||
--- role:hsOfficePerson.admin
|
style contact:roles fill:#99bcdb,stroke:white
|
||||||
|
|
||||||
role:hsOfficeRelation.owner[relation.owner]
|
role:contact:owner[[contact:owner]]
|
||||||
%% permissions
|
role:contact:admin[[contact:admin]]
|
||||||
role:hsOfficeRelation.owner --> perm:hsOfficeRelation.*{{relation.*}}
|
role:contact:referrer[[contact:referrer]]
|
||||||
%% incoming
|
|
||||||
role:global.admin ---> role:hsOfficeRelation.owner
|
|
||||||
role:hsOfficePersonAdmin#anchor.admin
|
|
||||||
end
|
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}}
|
||||||
|
perm:relation:INSERT{{relation:INSERT}}
|
||||||
|
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
|
||||||
|
role:anchorPerson:admin ==> perm:relation:INSERT
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
|
-- This code generated was by RbacViewPostgresGenerator, do not amend manually.
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-relation-rbac-OBJECT:1 endDelimiter:--//
|
--changeset hs-office-relation-rbac-OBJECT:1 endDelimiter:--//
|
||||||
@ -15,178 +17,255 @@ call generateRbacRoleDescriptors('hsOfficeRelation', 'hs_office_relation');
|
|||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-relation-rbac-ROLES-CREATION:1 endDelimiter:--//
|
--changeset hs-office-relation-rbac-insert-trigger:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Creates and updates the roles and their assignments for relation entities.
|
Creates the roles, grants and permission for the AFTER INSERT TRIGGER.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
create or replace function hsOfficeRelationRbacRolesTrigger()
|
create or replace procedure buildRbacSystemForHsOfficeRelation(
|
||||||
returns trigger
|
NEW hs_office_relation
|
||||||
language plpgsql
|
)
|
||||||
strict as $$
|
language plpgsql as $$
|
||||||
|
|
||||||
declare
|
declare
|
||||||
hsOfficeRelationTenant RbacRoleDescriptor;
|
newHolderPerson hs_office_person;
|
||||||
newAnchor hs_office_person;
|
newAnchorPerson hs_office_person;
|
||||||
newHolder hs_office_person;
|
|
||||||
oldContact hs_office_contact;
|
|
||||||
newContact hs_office_contact;
|
newContact hs_office_contact;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
call enterTriggerForObjectUuid(NEW.uuid);
|
call enterTriggerForObjectUuid(NEW.uuid);
|
||||||
|
|
||||||
hsOfficeRelationTenant := hsOfficeRelationTenant(NEW);
|
SELECT * FROM hs_office_person WHERE 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 newAnchor;
|
SELECT * FROM hs_office_person WHERE uuid = NEW.anchorUuid INTO newAnchorPerson;
|
||||||
select * from hs_office_person as p where p.uuid = NEW.holderUuid into newHolder;
|
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;
|
|
||||||
|
SELECT * FROM hs_office_contact WHERE uuid = NEW.contactUuid INTO newContact;
|
||||||
|
assert newContact.uuid is not null, format('newContact must not be null for NEW.contactUuid = %s', NEW.contactUuid);
|
||||||
|
|
||||||
if TG_OP = 'INSERT' then
|
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficeRelationOwner(NEW),
|
hsOfficeRelationOwner(NEW),
|
||||||
permissions => array['DELETE'],
|
permissions => array['DELETE'],
|
||||||
incomingSuperRoles => array[
|
incomingSuperRoles => array[globalAdmin()],
|
||||||
globalAdmin(),
|
userUuids => array[currentUserUuid()]
|
||||||
hsOfficePersonAdmin(newAnchor)]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficeRelationAdmin(NEW),
|
hsOfficeRelationAdmin(NEW),
|
||||||
permissions => array['UPDATE'],
|
permissions => array['UPDATE'],
|
||||||
incomingSuperRoles => array[hsOfficeRelationOwner(NEW)]
|
incomingSuperRoles => array[
|
||||||
|
hsOfficePersonAdmin(newAnchorPerson),
|
||||||
|
hsOfficeRelationOwner(NEW)]
|
||||||
);
|
);
|
||||||
|
|
||||||
-- the tenant role for those related users who can view the data
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficeRelationTenant,
|
hsOfficeRelationAgent(NEW),
|
||||||
|
incomingSuperRoles => array[
|
||||||
|
hsOfficePersonAdmin(newHolderPerson),
|
||||||
|
hsOfficeRelationAdmin(NEW)]
|
||||||
|
);
|
||||||
|
|
||||||
|
perform createRoleWithGrants(
|
||||||
|
hsOfficeRelationTenant(NEW),
|
||||||
permissions => array['SELECT'],
|
permissions => array['SELECT'],
|
||||||
incomingSuperRoles => array[
|
incomingSuperRoles => array[
|
||||||
hsOfficeRelationAdmin(NEW),
|
hsOfficeContactAdmin(newContact),
|
||||||
hsOfficePersonAdmin(newAnchor),
|
hsOfficePersonAdmin(newHolderPerson),
|
||||||
hsOfficePersonAdmin(newHolder),
|
hsOfficeRelationAgent(NEW)],
|
||||||
hsOfficeContactAdmin(newContact)],
|
|
||||||
outgoingSubRoles => array[
|
outgoingSubRoles => array[
|
||||||
hsOfficePersonTenant(newAnchor),
|
hsOfficeContactReferrer(newContact),
|
||||||
hsOfficePersonTenant(newHolder),
|
hsOfficePersonReferrer(newAnchorPerson),
|
||||||
hsOfficeContactTenant(newContact)]
|
hsOfficePersonReferrer(newHolderPerson)]
|
||||||
);
|
);
|
||||||
|
|
||||||
-- anchor and holder admin roles need each others tenant role
|
|
||||||
-- to be able to see the joined relation
|
|
||||||
-- TODO: this can probably be avoided through agent+guest roles
|
|
||||||
call grantRoleToRole(hsOfficePersonTenant(newAnchor), hsOfficePersonAdmin(newHolder));
|
|
||||||
call grantRoleToRole(hsOfficePersonTenant(newHolder), hsOfficePersonAdmin(newAnchor));
|
|
||||||
call grantRoleToRoleIfNotNull(hsOfficePersonTenant(newHolder), hsOfficeContactAdmin(newContact));
|
|
||||||
|
|
||||||
elsif TG_OP = 'UPDATE' then
|
|
||||||
|
|
||||||
if OLD.contactUuid <> NEW.contactUuid then
|
|
||||||
-- nothing but the contact can be updated,
|
|
||||||
-- in other cases, a new relation needs to be created and the old updated
|
|
||||||
|
|
||||||
select * from hs_office_contact as c where c.uuid = OLD.contactUuid into oldContact;
|
|
||||||
|
|
||||||
call revokeRoleFromRole( hsOfficeRelationTenant, hsOfficeContactAdmin(oldContact) );
|
|
||||||
call grantRoleToRole( hsOfficeRelationTenant, hsOfficeContactAdmin(newContact) );
|
|
||||||
|
|
||||||
call revokeRoleFromRole( hsOfficeContactTenant(oldContact), hsOfficeRelationTenant );
|
|
||||||
call grantRoleToRole( hsOfficeContactTenant(newContact), hsOfficeRelationTenant );
|
|
||||||
end if;
|
|
||||||
else
|
|
||||||
raise exception 'invalid usage of TRIGGER';
|
|
||||||
end if;
|
|
||||||
|
|
||||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||||
return NEW;
|
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
An AFTER INSERT TRIGGER which creates the role structure for a new customer.
|
AFTER INSERT TRIGGER to create the role+grant structure for a new hs_office_relation row.
|
||||||
*/
|
*/
|
||||||
create trigger createRbacRolesForHsOfficeRelation_Trigger
|
|
||||||
after insert
|
|
||||||
on hs_office_relation
|
|
||||||
for each row
|
|
||||||
execute procedure hsOfficeRelationRbacRolesTrigger();
|
|
||||||
|
|
||||||
/*
|
create or replace function insertTriggerForHsOfficeRelation_tf()
|
||||||
An AFTER UPDATE TRIGGER which updates the role structure of a customer.
|
returns trigger
|
||||||
*/
|
language plpgsql
|
||||||
create trigger updateRbacRolesForHsOfficeRelation_Trigger
|
strict as $$
|
||||||
after update
|
begin
|
||||||
on hs_office_relation
|
call buildRbacSystemForHsOfficeRelation(NEW);
|
||||||
|
return NEW;
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
create trigger insertTriggerForHsOfficeRelation_tg
|
||||||
|
after insert on hs_office_relation
|
||||||
for each row
|
for each row
|
||||||
execute procedure hsOfficeRelationRbacRolesTrigger();
|
execute procedure insertTriggerForHsOfficeRelation_tf();
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-relation-rbac-IDENTITY-VIEW:1 endDelimiter:--//
|
--changeset hs-office-relation-rbac-update-trigger:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
call generateRbacIdentityViewFromProjection('hs_office_relation', $idName$
|
|
||||||
(select idName from hs_office_person_iv p where p.uuid = target.anchorUuid)
|
/*
|
||||||
|| '-with-' || target.type || '-' ||
|
Called from the AFTER UPDATE TRIGGER to re-wire the grants.
|
||||||
(select idName from hs_office_person_iv p where p.uuid = target.holderUuid)
|
*/
|
||||||
$idName$);
|
|
||||||
|
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 WHERE 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 WHERE 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 WHERE 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 WHERE 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 WHERE 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 WHERE 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:--//
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/*
|
||||||
|
Creates INSERT INTO hs_office_relation permissions for the related hs_office_person rows.
|
||||||
|
*/
|
||||||
|
do language plpgsql $$
|
||||||
|
declare
|
||||||
|
row hs_office_person;
|
||||||
|
begin
|
||||||
|
call defineContext('create INSERT INTO hs_office_relation permissions for the related hs_office_person rows');
|
||||||
|
|
||||||
|
FOR row IN SELECT * FROM hs_office_person
|
||||||
|
LOOP
|
||||||
|
call grantPermissionToRole(
|
||||||
|
createPermission(row.uuid, 'INSERT', 'hs_office_relation'),
|
||||||
|
hsOfficePersonAdmin(row));
|
||||||
|
END LOOP;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Adds hs_office_relation INSERT permission to specified role of new hs_office_person rows.
|
||||||
|
*/
|
||||||
|
create or replace function hs_office_relation_hs_office_person_insert_tf()
|
||||||
|
returns trigger
|
||||||
|
language plpgsql
|
||||||
|
strict as $$
|
||||||
|
begin
|
||||||
|
call grantPermissionToRole(
|
||||||
|
createPermission(NEW.uuid, 'INSERT', 'hs_office_relation'),
|
||||||
|
hsOfficePersonAdmin(NEW));
|
||||||
|
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_relation_hs_office_person_insert_tg
|
||||||
|
after insert on hs_office_person
|
||||||
|
for each row
|
||||||
|
execute procedure hs_office_relation_hs_office_person_insert_tf();
|
||||||
|
|
||||||
|
/**
|
||||||
|
Checks if the user or assumed roles are allowed to insert a row to hs_office_relation,
|
||||||
|
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_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 hasInsertPermission(NEW.anchorUuid, 'INSERT', 'hs_office_relation') )
|
||||||
|
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:--//
|
--changeset hs-office-relation-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
call generateRbacRestrictedView('hs_office_relation',
|
call generateRbacRestrictedView('hs_office_relation',
|
||||||
'(select idName from hs_office_person_iv p where p.uuid = target.holderUuid)',
|
$orderBy$
|
||||||
|
(select idName from hs_office_person_iv p where p.uuid = target.holderUuid)
|
||||||
|
$orderBy$,
|
||||||
$updates$
|
$updates$
|
||||||
contactUuid = new.contactUuid
|
contactUuid = new.contactUuid
|
||||||
$updates$);
|
$updates$);
|
||||||
--//
|
--//
|
||||||
|
|
||||||
-- TODO: exception if one tries to amend any other column
|
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
|
||||||
--changeset hs-office-relation-rbac-NEW-RELATHIONSHIP:1 endDelimiter:--//
|
|
||||||
-- ----------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
Creates a global permission for new-relation and assigns it to the hostsharing admins role.
|
|
||||||
*/
|
|
||||||
do language plpgsql $$
|
|
||||||
declare
|
|
||||||
addCustomerPermissions uuid[];
|
|
||||||
globalObjectUuid uuid;
|
|
||||||
globalAdminRoleUuid uuid ;
|
|
||||||
begin
|
|
||||||
call defineContext('granting global new-relation permission to global admin role', null, null, null);
|
|
||||||
|
|
||||||
globalAdminRoleUuid := findRoleId(globalAdmin());
|
|
||||||
globalObjectUuid := (select uuid from global);
|
|
||||||
addCustomerPermissions := createPermissions(globalObjectUuid, array ['new-relation']);
|
|
||||||
call grantPermissionsToRole(globalAdminRoleUuid, addCustomerPermissions);
|
|
||||||
end;
|
|
||||||
$$;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Used by the trigger to prevent the add-customer to current user respectively assumed roles.
|
|
||||||
*/
|
|
||||||
create or replace function addHsOfficeRelationNotAllowedForCurrentSubjects()
|
|
||||||
returns trigger
|
|
||||||
language PLPGSQL
|
|
||||||
as $$
|
|
||||||
begin
|
|
||||||
raise exception '[403] new-relation not permitted for %',
|
|
||||||
array_to_string(currentSubjects(), ';', 'null');
|
|
||||||
end; $$;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Checks if the user or assumed roles are allowed to create a new customer.
|
|
||||||
*/
|
|
||||||
create trigger hs_office_relation_insert_trigger
|
|
||||||
before insert
|
|
||||||
on hs_office_relation
|
|
||||||
for each row
|
|
||||||
-- TODO.spec: who is allowed to create new relations
|
|
||||||
when ( not hasAssumedRole() )
|
|
||||||
execute procedure addHsOfficeRelationNotAllowedForCurrentSubjects();
|
|
||||||
--//
|
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
create or replace procedure createHsOfficeRelationTestData(
|
create or replace procedure createHsOfficeRelationTestData(
|
||||||
holderPersonName varchar,
|
holderPersonName varchar,
|
||||||
relationType HsOfficeRelationType,
|
relationType HsOfficeRelationType,
|
||||||
anchorPersonTradeName varchar,
|
anchorPersonName varchar,
|
||||||
contactLabel varchar,
|
contactLabel varchar,
|
||||||
mark varchar default null)
|
mark varchar default null)
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
@ -23,24 +23,28 @@ declare
|
|||||||
contact hs_office_contact;
|
contact hs_office_contact;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
idName := cleanIdentifier( anchorPersonTradeName || '-' || holderPersonName);
|
idName := cleanIdentifier( anchorPersonName || '-' || holderPersonName);
|
||||||
currentTask := 'creating relation test-data ' || idName;
|
currentTask := 'creating relation test-data ' || idName;
|
||||||
call defineContext(currentTask, null, 'superuser-alex@hostsharing.net', 'global#global.admin');
|
call defineContext(currentTask, null, 'superuser-alex@hostsharing.net', 'global#global.admin');
|
||||||
execute format('set local hsadminng.currentTask to %L', currentTask);
|
execute format('set local hsadminng.currentTask to %L', currentTask);
|
||||||
|
|
||||||
select p.* from hs_office_person p where p.tradeName = anchorPersonTradeName into anchorPerson;
|
select p.*
|
||||||
|
into anchorPerson
|
||||||
|
from hs_office_person p
|
||||||
|
where p.tradeName = anchorPersonName or p.familyName = anchorPersonName;
|
||||||
if anchorPerson is null then
|
if anchorPerson is null then
|
||||||
raise exception 'anchorPerson "%" not found', anchorPersonTradeName;
|
raise exception 'anchorPerson "%" not found', anchorPersonName;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
select p.* from hs_office_person p
|
select p.*
|
||||||
where p.tradeName = holderPersonName or p.familyName = holderPersonName
|
into holderPerson
|
||||||
into holderPerson;
|
from hs_office_person p
|
||||||
|
where p.tradeName = holderPersonName or p.familyName = holderPersonName;
|
||||||
if holderPerson is null then
|
if holderPerson is null then
|
||||||
raise exception 'holderPerson "%" not found', holderPersonName;
|
raise exception 'holderPerson "%" not found', holderPersonName;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
select c.* from hs_office_contact c where c.label = contactLabel into contact;
|
select c.* into contact from hs_office_contact c where c.label = contactLabel;
|
||||||
if contact is null then
|
if contact is null then
|
||||||
raise exception 'contact "%" not found', contactLabel;
|
raise exception 'contact "%" not found', contactLabel;
|
||||||
end if;
|
end if;
|
||||||
@ -87,17 +91,22 @@ do language plpgsql $$
|
|||||||
begin
|
begin
|
||||||
call createHsOfficeRelationTestData('First GmbH', 'PARTNER', 'Hostsharing eG', 'first contact');
|
call createHsOfficeRelationTestData('First GmbH', 'PARTNER', 'Hostsharing eG', 'first contact');
|
||||||
call createHsOfficeRelationTestData('Firby', 'REPRESENTATIVE', 'First GmbH', 'first contact');
|
call createHsOfficeRelationTestData('Firby', 'REPRESENTATIVE', 'First GmbH', 'first contact');
|
||||||
|
call createHsOfficeRelationTestData('First GmbH', 'DEBITOR', 'First GmbH', 'first contact');
|
||||||
|
|
||||||
call createHsOfficeRelationTestData('Second e.K.', 'PARTNER', 'Hostsharing eG', 'second contact');
|
call createHsOfficeRelationTestData('Second e.K.', 'PARTNER', 'Hostsharing eG', 'second contact');
|
||||||
call createHsOfficeRelationTestData('Smith', 'REPRESENTATIVE', 'Second e.K.', 'second contact');
|
call createHsOfficeRelationTestData('Smith', 'REPRESENTATIVE', 'Second e.K.', 'second contact');
|
||||||
|
call createHsOfficeRelationTestData('Second e.K.', 'DEBITOR', 'Second e.K.', 'second contact');
|
||||||
|
|
||||||
call createHsOfficeRelationTestData('Third OHG', 'PARTNER', 'Hostsharing eG', 'third contact');
|
call createHsOfficeRelationTestData('Third OHG', 'PARTNER', 'Hostsharing eG', 'third contact');
|
||||||
call createHsOfficeRelationTestData('Tucker', 'REPRESENTATIVE', 'Third OHG', 'third contact');
|
call createHsOfficeRelationTestData('Tucker', 'REPRESENTATIVE', 'Third OHG', 'third contact');
|
||||||
|
call createHsOfficeRelationTestData('Third OHG', 'DEBITOR', 'Third OHG', 'third contact');
|
||||||
|
|
||||||
call createHsOfficeRelationTestData('Fourth eG', 'PARTNER', 'Hostsharing eG', 'fourth contact');
|
call createHsOfficeRelationTestData('Fourth eG', 'PARTNER', 'Hostsharing eG', 'fourth contact');
|
||||||
call createHsOfficeRelationTestData('Fouler', 'REPRESENTATIVE', 'Third OHG', 'third contact');
|
call createHsOfficeRelationTestData('Fouler', 'REPRESENTATIVE', 'Third OHG', 'third contact');
|
||||||
|
call createHsOfficeRelationTestData('Third OHG', 'DEBITOR', 'Third OHG', 'third contact');
|
||||||
|
|
||||||
call createHsOfficeRelationTestData('Smith', 'PARTNER', 'Hostsharing eG', 'sixth contact');
|
call createHsOfficeRelationTestData('Smith', 'PARTNER', 'Hostsharing eG', 'sixth contact');
|
||||||
|
call createHsOfficeRelationTestData('Smith', 'DEBITOR', 'Smith', 'third contact');
|
||||||
call createHsOfficeRelationTestData('Smith', 'SUBSCRIBER', 'Third OHG', 'third contact', 'members-announce');
|
call createHsOfficeRelationTestData('Smith', 'SUBSCRIBER', 'Third OHG', 'third contact', 'members-announce');
|
||||||
end;
|
end;
|
||||||
$$;
|
$$;
|
||||||
|
@ -33,23 +33,20 @@ create table hs_office_partner
|
|||||||
(
|
(
|
||||||
uuid uuid unique references RbacObject (uuid) initially deferred,
|
uuid uuid unique references RbacObject (uuid) initially deferred,
|
||||||
partnerNumber numeric(5) unique not null,
|
partnerNumber numeric(5) unique not null,
|
||||||
partnerRelUuid uuid not null references hs_office_relation(uuid), -- TODO: delete in after delete trigger
|
partnerRelUuid uuid not null references hs_office_relation(uuid), -- deleted in after delete trigger
|
||||||
personUuid uuid not null references hs_office_person(uuid), -- TODO: remove, replaced by partnerRelUuid
|
|
||||||
contactUuid uuid not null references hs_office_contact(uuid), -- TODO: remove, replaced by partnerRelUuid
|
|
||||||
detailsUuid uuid not null references hs_office_partner_details(uuid) -- deleted in after delete trigger
|
detailsUuid uuid not null references hs_office_partner_details(uuid) -- deleted in after delete trigger
|
||||||
);
|
);
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-partner-DELETE-DETAILS-TRIGGER:1 endDelimiter:--//
|
--changeset hs-office-partner-DELETE-DEPENDENTS-TRIGGER:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Trigger function to delete related details of a partner to delete.
|
Trigger function to delete related details of a partner to delete.
|
||||||
*/
|
*/
|
||||||
create or replace function deleteHsOfficeDetailsOnPartnerDelete()
|
create or replace function deleteHsOfficeDependentsOnPartnerDelete()
|
||||||
returns trigger
|
returns trigger
|
||||||
language PLPGSQL
|
language PLPGSQL
|
||||||
as $$
|
as $$
|
||||||
@ -61,17 +58,24 @@ begin
|
|||||||
if counter = 0 then
|
if counter = 0 then
|
||||||
raise exception 'partner details % could not be deleted', OLD.detailsUuid;
|
raise exception 'partner details % could not be deleted', OLD.detailsUuid;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
|
DELETE FROM hs_office_relation r WHERE r.uuid = OLD.partnerRelUuid;
|
||||||
|
GET DIAGNOSTICS counter = ROW_COUNT;
|
||||||
|
if counter = 0 then
|
||||||
|
raise exception 'partner relation % could not be deleted', OLD.partnerRelUuid;
|
||||||
|
end if;
|
||||||
|
|
||||||
RETURN OLD;
|
RETURN OLD;
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Triggers deletion of related details of a partner to delete.
|
Triggers deletion of related rows of a partner to delete.
|
||||||
*/
|
*/
|
||||||
create trigger hs_office_partner_delete_details_trigger
|
create trigger hs_office_partner_delete_dependents_trigger
|
||||||
after delete
|
after delete
|
||||||
on hs_office_partner
|
on hs_office_partner
|
||||||
for each row
|
for each row
|
||||||
execute procedure deleteHsOfficeDetailsOnPartnerDelete();
|
execute procedure deleteHsOfficeDependentsOnPartnerDelete();
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-partner-MAIN-TABLE-JOURNAL:1 endDelimiter:--//
|
--changeset hs-office-partner-MAIN-TABLE-JOURNAL:1 endDelimiter:--//
|
||||||
|
@ -1,158 +0,0 @@
|
|||||||
### 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
|
|
||||||
|
|
||||||
```
|
|
@ -1,248 +0,0 @@
|
|||||||
--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 WHERE 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 WHERE 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 WHERE 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 WHERE 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 WHERE 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 WHERE 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$);
|
|
||||||
--//
|
|
||||||
|
|
@ -1,78 +1,158 @@
|
|||||||
### hs_office_partner RBAC
|
### rbac partner
|
||||||
|
|
||||||
|
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
|
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||||
flowchart TB
|
flowchart TB
|
||||||
|
|
||||||
subgraph global
|
subgraph partnerRel.contact["`**partnerRel.contact**`"]
|
||||||
style global fill:#eee
|
|
||||||
|
|
||||||
role:global.admin[global.admin]
|
|
||||||
end
|
|
||||||
|
|
||||||
subgraph hsOfficeContact
|
|
||||||
direction TB
|
direction TB
|
||||||
style hsOfficeContact fill:#eee
|
style partnerRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
role:hsOfficeContact.admin[contact.admin]
|
subgraph partnerRel.contact:roles[ ]
|
||||||
--> role:hsOfficeContact.tenant[contact.tenant]
|
style partnerRel.contact:roles fill:#99bcdb,stroke:white
|
||||||
--> role:hsOfficeContact.guest[contact.guest]
|
|
||||||
|
role:partnerRel.contact:owner[[partnerRel.contact:owner]]
|
||||||
|
role:partnerRel.contact:admin[[partnerRel.contact:admin]]
|
||||||
|
role:partnerRel.contact:referrer[[partnerRel.contact:referrer]]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
subgraph hsOfficePerson
|
subgraph partner["`**partner**`"]
|
||||||
direction TB
|
direction TB
|
||||||
style hsOfficePerson fill:#eee
|
style partner fill:#dd4901,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
role:hsOfficePerson.admin[person.admin]
|
subgraph partner:permissions[ ]
|
||||||
--> role:hsOfficePerson.tenant[person.tenant]
|
style partner:permissions fill:#dd4901,stroke:white
|
||||||
--> role:hsOfficePerson.guest[person.guest]
|
|
||||||
|
perm:partner:INSERT{{partner:INSERT}}
|
||||||
|
perm:partner:DELETE{{partner:DELETE}}
|
||||||
|
perm:partner:UPDATE{{partner:UPDATE}}
|
||||||
|
perm:partner:SELECT{{partner:SELECT}}
|
||||||
end
|
end
|
||||||
|
|
||||||
subgraph hsOfficePartnerDetails
|
subgraph partnerRel["`**partnerRel**`"]
|
||||||
direction TB
|
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
|
||||||
|
|
||||||
perm:hsOfficePartnerDetails.*{{partner.*}}
|
subgraph partnerRel.contact:roles[ ]
|
||||||
perm:hsOfficePartnerDetails.edit{{partner.edit}}
|
style partnerRel.contact:roles fill:#99bcdb,stroke:white
|
||||||
perm:hsOfficePartnerDetails.view{{partner.view}}
|
|
||||||
|
role:partnerRel.contact:owner[[partnerRel.contact:owner]]
|
||||||
|
role:partnerRel.contact:admin[[partnerRel.contact:admin]]
|
||||||
|
role:partnerRel.contact:referrer[[partnerRel.contact:referrer]]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
subgraph hsOfficePartner
|
subgraph partnerRel.anchorPerson["`**partnerRel.anchorPerson**`"]
|
||||||
|
direction TB
|
||||||
|
style partnerRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
role:hsOfficePartner.owner[partner.owner]
|
subgraph partnerRel.anchorPerson:roles[ ]
|
||||||
%% permissions
|
style partnerRel.anchorPerson:roles fill:#99bcdb,stroke:white
|
||||||
role:hsOfficePartner.owner --> perm:hsOfficePartner.*{{partner.*}}
|
|
||||||
role:hsOfficePartner.owner --> perm:hsOfficePartnerDetails.*{{partner.*}}
|
|
||||||
%% incoming
|
|
||||||
role:global.admin ---> role:hsOfficePartner.owner
|
|
||||||
|
|
||||||
role:hsOfficePartner.admin[partner.admin]
|
role:partnerRel.anchorPerson:owner[[partnerRel.anchorPerson:owner]]
|
||||||
%% permissions
|
role:partnerRel.anchorPerson:admin[[partnerRel.anchorPerson:admin]]
|
||||||
role:hsOfficePartner.admin --> perm:hsOfficePartner.edit{{partner.edit}}
|
role:partnerRel.anchorPerson:referrer[[partnerRel.anchorPerson:referrer]]
|
||||||
role:hsOfficePartner.admin --> perm:hsOfficePartnerDetails.edit{{partner.edit}}
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficePartner.owner ---> role:hsOfficePartner.admin
|
|
||||||
%% outgoing
|
|
||||||
role:hsOfficePartner.admin --> role:hsOfficePerson.tenant
|
|
||||||
role:hsOfficePartner.admin --> role:hsOfficeContact.tenant
|
|
||||||
|
|
||||||
role:hsOfficePartner.agent[partner.agent]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficePartner.agent --> perm:hsOfficePartnerDetails.view{{partner.view}}
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficePartner.admin ---> role:hsOfficePartner.agent
|
|
||||||
role:hsOfficePerson.admin --> role:hsOfficePartner.agent
|
|
||||||
role:hsOfficeContact.admin --> role:hsOfficePartner.agent
|
|
||||||
|
|
||||||
role:hsOfficePartner.tenant[partner.tenant]
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficePartner.agent --> role:hsOfficePartner.tenant
|
|
||||||
%% outgoing
|
|
||||||
role:hsOfficePartner.tenant --> role:hsOfficePerson.guest
|
|
||||||
role:hsOfficePartner.tenant --> role:hsOfficeContact.guest
|
|
||||||
|
|
||||||
role:hsOfficePartner.guest[partner.guest]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficePartner.guest --> perm:hsOfficePartner.view{{partner.view}}
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficePartner.tenant --> role:hsOfficePartner.guest
|
|
||||||
end
|
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
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
|
-- This code generated was by RbacViewPostgresGenerator, do not amend manually.
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-partner-rbac-OBJECT:1 endDelimiter:--//
|
--changeset hs-office-partner-rbac-OBJECT:1 endDelimiter:--//
|
||||||
@ -15,242 +17,222 @@ call generateRbacRoleDescriptors('hsOfficePartner', 'hs_office_partner');
|
|||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-partner-rbac-ROLES-CREATION:1 endDelimiter:--//
|
--changeset hs-office-partner-rbac-insert-trigger:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Creates and updates the roles and their assignments for partner entities.
|
Creates the roles, grants and permission for the AFTER INSERT TRIGGER.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
create or replace function hsOfficePartnerRbacRolesTrigger()
|
create or replace procedure buildRbacSystemForHsOfficePartner(
|
||||||
returns trigger
|
NEW hs_office_partner
|
||||||
language plpgsql
|
)
|
||||||
strict as $$
|
language plpgsql as $$
|
||||||
|
|
||||||
declare
|
declare
|
||||||
oldPartnerRel hs_office_relation;
|
|
||||||
newPartnerRel hs_office_relation;
|
newPartnerRel hs_office_relation;
|
||||||
|
newPartnerDetails hs_office_partner_details;
|
||||||
|
|
||||||
oldPerson hs_office_person;
|
|
||||||
newPerson hs_office_person;
|
|
||||||
|
|
||||||
oldContact hs_office_contact;
|
|
||||||
newContact hs_office_contact;
|
|
||||||
begin
|
begin
|
||||||
call enterTriggerForObjectUuid(NEW.uuid);
|
call enterTriggerForObjectUuid(NEW.uuid);
|
||||||
|
|
||||||
select * from hs_office_relation as r where r.uuid = NEW.partnerReluuid into newPartnerRel;
|
SELECT * FROM hs_office_relation WHERE uuid = NEW.partnerRelUuid INTO newPartnerRel;
|
||||||
select * from hs_office_person as p where p.uuid = NEW.personUuid into newPerson;
|
assert newPartnerRel.uuid is not null, format('newPartnerRel must not be null for NEW.partnerRelUuid = %s', NEW.partnerRelUuid);
|
||||||
select * from hs_office_contact as c where c.uuid = NEW.contactUuid into newContact;
|
|
||||||
|
|
||||||
if TG_OP = 'INSERT' then
|
SELECT * FROM hs_office_partner_details WHERE uuid = NEW.detailsUuid INTO newPartnerDetails;
|
||||||
|
assert newPartnerDetails.uuid is not null, format('newPartnerDetails must not be null for NEW.detailsUuid = %s', NEW.detailsUuid);
|
||||||
|
|
||||||
-- === ATTENTION: code generated from related Mermaid flowchart: ===
|
call grantPermissionToRole(createPermission(NEW.uuid, 'DELETE'), hsOfficeRelationAdmin(newPartnerRel));
|
||||||
|
call grantPermissionToRole(createPermission(NEW.uuid, 'SELECT'), hsOfficeRelationTenant(newPartnerRel));
|
||||||
perform createRoleWithGrants(
|
call grantPermissionToRole(createPermission(NEW.uuid, 'UPDATE'), hsOfficeRelationAgent(newPartnerRel));
|
||||||
hsOfficePartnerOwner(NEW),
|
call grantPermissionToRole(createPermission(newPartnerDetails.uuid, 'DELETE'), hsOfficeRelationAdmin(newPartnerRel));
|
||||||
permissions => array['DELETE'],
|
call grantPermissionToRole(createPermission(newPartnerDetails.uuid, 'SELECT'), hsOfficeRelationAgent(newPartnerRel));
|
||||||
incomingSuperRoles => array[globalAdmin()]
|
call grantPermissionToRole(createPermission(newPartnerDetails.uuid, 'UPDATE'), hsOfficeRelationAgent(newPartnerRel));
|
||||||
);
|
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
|
||||||
hsOfficePartnerAdmin(NEW),
|
|
||||||
permissions => array['UPDATE'],
|
|
||||||
incomingSuperRoles => array[
|
|
||||||
hsOfficePartnerOwner(NEW)],
|
|
||||||
outgoingSubRoles => array[
|
|
||||||
hsOfficeRelationTenant(newPartnerRel),
|
|
||||||
hsOfficePersonTenant(newPerson),
|
|
||||||
hsOfficeContactTenant(newContact)]
|
|
||||||
);
|
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
|
||||||
hsOfficePartnerAgent(NEW),
|
|
||||||
incomingSuperRoles => array[
|
|
||||||
hsOfficePartnerAdmin(NEW),
|
|
||||||
hsOfficeRelationAdmin(newPartnerRel),
|
|
||||||
hsOfficePersonAdmin(newPerson),
|
|
||||||
hsOfficeContactAdmin(newContact)]
|
|
||||||
);
|
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
|
||||||
hsOfficePartnerTenant(NEW),
|
|
||||||
incomingSuperRoles => array[
|
|
||||||
hsOfficePartnerAgent(NEW)],
|
|
||||||
outgoingSubRoles => array[
|
|
||||||
hsOfficeRelationTenant(newPartnerRel),
|
|
||||||
hsOfficePersonGuest(newPerson),
|
|
||||||
hsOfficeContactGuest(newContact)]
|
|
||||||
);
|
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
|
||||||
hsOfficePartnerGuest(NEW),
|
|
||||||
permissions => array['SELECT'],
|
|
||||||
incomingSuperRoles => array[hsOfficePartnerTenant(NEW)]
|
|
||||||
);
|
|
||||||
|
|
||||||
-- === END of code generated from Mermaid flowchart. ===
|
|
||||||
|
|
||||||
-- Each partner-details entity belong exactly to one partner entity
|
|
||||||
-- and it makes little sense just to delegate partner-details roles.
|
|
||||||
-- Therefore, we did not model partner-details roles,
|
|
||||||
-- but instead just assign extra permissions to existing partner-roles.
|
|
||||||
|
|
||||||
--Attention: Cannot be in partner-details because of insert order (partner is not in database yet)
|
|
||||||
|
|
||||||
call grantPermissionsToRole(
|
|
||||||
getRoleId(hsOfficePartnerOwner(NEW)),
|
|
||||||
createPermissions(NEW.detailsUuid, array ['DELETE'])
|
|
||||||
);
|
|
||||||
|
|
||||||
call grantPermissionsToRole(
|
|
||||||
getRoleId(hsOfficePartnerAdmin(NEW)),
|
|
||||||
createPermissions(NEW.detailsUuid, array ['UPDATE'])
|
|
||||||
);
|
|
||||||
|
|
||||||
call grantPermissionsToRole(
|
|
||||||
-- Yes, here hsOfficePartnerAGENT is used, not hsOfficePartnerTENANT.
|
|
||||||
-- Do NOT grant view permission on partner-details to hsOfficePartnerTENANT!
|
|
||||||
-- Otherwise package-admins etc. would be able to read the data.
|
|
||||||
getRoleId(hsOfficePartnerAgent(NEW)),
|
|
||||||
createPermissions(NEW.detailsUuid, array ['SELECT'])
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
elsif TG_OP = 'UPDATE' then
|
|
||||||
|
|
||||||
if OLD.partnerRelUuid <> NEW.partnerRelUuid then
|
|
||||||
select * from hs_office_relation as r where r.uuid = OLD.partnerRelUuid into oldPartnerRel;
|
|
||||||
|
|
||||||
call revokeRoleFromRole(hsOfficeRelationTenant(oldPartnerRel), hsOfficePartnerAdmin(OLD));
|
|
||||||
call grantRoleToRole(hsOfficeRelationTenant(newPartnerRel), hsOfficePartnerAdmin(NEW));
|
|
||||||
|
|
||||||
call revokeRoleFromRole(hsOfficePartnerAgent(OLD), hsOfficeRelationAdmin(oldPartnerRel));
|
|
||||||
call grantRoleToRole(hsOfficePartnerAgent(NEW), hsOfficeRelationAdmin(newPartnerRel));
|
|
||||||
|
|
||||||
call revokeRoleFromRole(hsOfficeRelationGuest(oldPartnerRel), hsOfficePartnerTenant(OLD));
|
|
||||||
call grantRoleToRole(hsOfficeRelationGuest(newPartnerRel), hsOfficePartnerTenant(NEW));
|
|
||||||
end if;
|
|
||||||
|
|
||||||
if OLD.personUuid <> NEW.personUuid then
|
|
||||||
select * from hs_office_person as p where p.uuid = OLD.personUuid into oldPerson;
|
|
||||||
|
|
||||||
call revokeRoleFromRole(hsOfficePersonTenant(oldPerson), hsOfficePartnerAdmin(OLD));
|
|
||||||
call grantRoleToRole(hsOfficePersonTenant(newPerson), hsOfficePartnerAdmin(NEW));
|
|
||||||
|
|
||||||
call revokeRoleFromRole(hsOfficePartnerAgent(OLD), hsOfficePersonAdmin(oldPerson));
|
|
||||||
call grantRoleToRole(hsOfficePartnerAgent(NEW), hsOfficePersonAdmin(newPerson));
|
|
||||||
|
|
||||||
call revokeRoleFromRole(hsOfficePersonGuest(oldPerson), hsOfficePartnerTenant(OLD));
|
|
||||||
call grantRoleToRole(hsOfficePersonGuest(newPerson), hsOfficePartnerTenant(NEW));
|
|
||||||
end if;
|
|
||||||
|
|
||||||
if OLD.contactUuid <> NEW.contactUuid then
|
|
||||||
select * from hs_office_contact as c where c.uuid = OLD.contactUuid into oldContact;
|
|
||||||
|
|
||||||
call revokeRoleFromRole(hsOfficeContactTenant(oldContact), hsOfficePartnerAdmin(OLD));
|
|
||||||
call grantRoleToRole(hsOfficeContactTenant(newContact), hsOfficePartnerAdmin(NEW));
|
|
||||||
|
|
||||||
call revokeRoleFromRole(hsOfficePartnerAgent(OLD), hsOfficeContactAdmin(oldContact));
|
|
||||||
call grantRoleToRole(hsOfficePartnerAgent(NEW), hsOfficeContactAdmin(newContact));
|
|
||||||
|
|
||||||
call revokeRoleFromRole(hsOfficeContactGuest(oldContact), hsOfficePartnerTenant(OLD));
|
|
||||||
call grantRoleToRole(hsOfficeContactGuest(newContact), hsOfficePartnerTenant(NEW));
|
|
||||||
end if;
|
|
||||||
else
|
|
||||||
raise exception 'invalid usage of TRIGGER';
|
|
||||||
end if;
|
|
||||||
|
|
||||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||||
return NEW;
|
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
An AFTER INSERT TRIGGER which creates the role structure for a new customer.
|
AFTER INSERT TRIGGER to create the role+grant structure for a new hs_office_partner row.
|
||||||
*/
|
*/
|
||||||
create trigger createRbacRolesForHsOfficePartner_Trigger
|
|
||||||
after insert
|
|
||||||
on hs_office_partner
|
|
||||||
for each row
|
|
||||||
execute procedure hsOfficePartnerRbacRolesTrigger();
|
|
||||||
|
|
||||||
/*
|
create or replace function insertTriggerForHsOfficePartner_tf()
|
||||||
An AFTER UPDATE TRIGGER which updates the role structure of a customer.
|
returns trigger
|
||||||
*/
|
language plpgsql
|
||||||
create trigger updateRbacRolesForHsOfficePartner_Trigger
|
strict as $$
|
||||||
after update
|
begin
|
||||||
on hs_office_partner
|
call buildRbacSystemForHsOfficePartner(NEW);
|
||||||
|
return NEW;
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
create trigger insertTriggerForHsOfficePartner_tg
|
||||||
|
after insert on hs_office_partner
|
||||||
for each row
|
for each row
|
||||||
execute procedure hsOfficePartnerRbacRolesTrigger();
|
execute procedure insertTriggerForHsOfficePartner_tf();
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-partner-rbac-IDENTITY-VIEW:1 endDelimiter:--//
|
--changeset hs-office-partner-rbac-update-trigger:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
call generateRbacIdentityViewFromProjection('hs_office_partner', $idName$
|
|
||||||
partnerNumber || ':' ||
|
/*
|
||||||
(select idName from hs_office_person_iv p where p.uuid = target.personuuid)
|
Called from the AFTER UPDATE TRIGGER to re-wire the grants.
|
||||||
|| '-' ||
|
*/
|
||||||
(select idName from hs_office_contact_iv c where c.uuid = target.contactuuid)
|
|
||||||
$idName$);
|
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 WHERE 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 WHERE 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 WHERE 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 WHERE 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;
|
||||||
|
begin
|
||||||
|
call defineContext('create INSERT INTO hs_office_partner permissions for the related global rows');
|
||||||
|
|
||||||
|
FOR row IN SELECT * FROM global
|
||||||
|
LOOP
|
||||||
|
call grantPermissionToRole(
|
||||||
|
createPermission(row.uuid, 'INSERT', 'hs_office_partner'),
|
||||||
|
globalAdmin());
|
||||||
|
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 generateRbacIdentityViewFromProjection('hs_office_partner',
|
||||||
|
$idName$
|
||||||
|
'P-' || partnerNumber
|
||||||
|
$idName$);
|
||||||
|
--//
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-partner-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
|
--changeset hs-office-partner-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
call generateRbacRestrictedView('hs_office_partner',
|
call generateRbacRestrictedView('hs_office_partner',
|
||||||
'(select idName from hs_office_person_iv p where p.uuid = target.personUuid)',
|
$orderBy$
|
||||||
|
'P-' || partnerNumber
|
||||||
|
$orderBy$,
|
||||||
$updates$
|
$updates$
|
||||||
partnerRelUuid = new.partnerRelUuid,
|
partnerRelUuid = new.partnerRelUuid
|
||||||
personUuid = new.personUuid,
|
|
||||||
contactUuid = new.contactUuid
|
|
||||||
$updates$);
|
$updates$);
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
|
||||||
--changeset hs-office-partner-rbac-NEW-PARTNER:1 endDelimiter:--//
|
|
||||||
-- ----------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
Creates a global permission for new-partner and assigns it to the Hostsharing admins role.
|
|
||||||
*/
|
|
||||||
do language plpgsql $$
|
|
||||||
declare
|
|
||||||
addCustomerPermissions uuid[];
|
|
||||||
globalObjectUuid uuid;
|
|
||||||
globalAdminRoleUuid uuid ;
|
|
||||||
begin
|
|
||||||
call defineContext('granting global new-partner permission to global admin role', null, null, null);
|
|
||||||
|
|
||||||
globalAdminRoleUuid := findRoleId(globalAdmin());
|
|
||||||
globalObjectUuid := (select uuid from global);
|
|
||||||
addCustomerPermissions := createPermissions(globalObjectUuid, array ['new-partner']);
|
|
||||||
call grantPermissionsToRole(globalAdminRoleUuid, addCustomerPermissions);
|
|
||||||
end;
|
|
||||||
$$;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Used by the trigger to prevent the add-customer to current user respectively assumed roles.
|
|
||||||
*/
|
|
||||||
create or replace function addHsOfficePartnerNotAllowedForCurrentSubjects()
|
|
||||||
returns trigger
|
|
||||||
language PLPGSQL
|
|
||||||
as $$
|
|
||||||
begin
|
|
||||||
raise exception '[403] new-partner not permitted for %',
|
|
||||||
array_to_string(currentSubjects(), ';', 'null');
|
|
||||||
end; $$;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Checks if the user or assumed roles are allowed to create a new customer.
|
|
||||||
*/
|
|
||||||
create trigger hs_office_partner_insert_trigger
|
|
||||||
before insert
|
|
||||||
on hs_office_partner
|
|
||||||
for each row
|
|
||||||
-- TODO.spec: who is allowed to create new partners
|
|
||||||
when ( not hasAssumedRole() )
|
|
||||||
execute procedure addHsOfficePartnerNotAllowedForCurrentSubjects();
|
|
||||||
--//
|
|
||||||
|
|
||||||
|
@ -1,136 +0,0 @@
|
|||||||
### 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
|
|
||||||
|
|
||||||
```
|
|
@ -1,164 +0,0 @@
|
|||||||
--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$);
|
|
||||||
--//
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
|||||||
|
### rbac partnerDetails
|
||||||
|
|
||||||
|
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||||
|
flowchart TB
|
||||||
|
|
||||||
|
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
|
||||||
|
end
|
||||||
|
|
||||||
|
%% granting permissions to roles
|
||||||
|
role:global:admin ==> perm:partnerDetails:INSERT
|
||||||
|
|
||||||
|
```
|
@ -1,4 +1,6 @@
|
|||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
|
-- This code generated was by RbacViewPostgresGenerator, do not amend manually.
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-partner-details-rbac-OBJECT:1 endDelimiter:--//
|
--changeset hs-office-partner-details-rbac-OBJECT:1 endDelimiter:--//
|
||||||
@ -8,21 +10,134 @@ call generateRelatedRbacObject('hs_office_partner_details');
|
|||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-partner-details-rbac-IDENTITY-VIEW:1 endDelimiter:--//
|
--changeset hs-office-partner-details-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
call generateRbacIdentityViewFromProjection('hs_office_partner_details', $idName$
|
call generateRbacRoleDescriptors('hsOfficePartnerDetails', 'hs_office_partner_details');
|
||||||
(select idName || '-details' from hs_office_partner_iv partner_iv
|
|
||||||
join hs_office_partner partner on (partner_iv.uuid = partner.uuid)
|
|
||||||
where partner.detailsUuid = target.uuid)
|
|
||||||
$idName$);
|
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
--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
|
||||||
|
|
||||||
|
begin
|
||||||
|
call enterTriggerForObjectUuid(NEW.uuid);
|
||||||
|
|
||||||
|
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;
|
||||||
|
begin
|
||||||
|
call defineContext('create INSERT INTO hs_office_partner_details permissions for the related global rows');
|
||||||
|
|
||||||
|
FOR row IN SELECT * FROM global
|
||||||
|
LOOP
|
||||||
|
call grantPermissionToRole(
|
||||||
|
createPermission(row.uuid, 'INSERT', 'hs_office_partner_details'),
|
||||||
|
globalAdmin());
|
||||||
|
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 % (%) assumed by user % (%)',
|
||||||
|
currentSubjects(), currentSubjectsUuids(), currentUser(), currentUserUuid();
|
||||||
|
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 partnerDetails.uuid as uuid, partner_iv.idName || '-details' as idName
|
||||||
|
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:--//
|
--changeset hs-office-partner-details-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
call generateRbacRestrictedView('hs_office_partner_details',
|
call generateRbacRestrictedView('hs_office_partner_details',
|
||||||
'target.uuid', -- no specific order required
|
$orderBy$
|
||||||
|
uuid
|
||||||
|
$orderBy$,
|
||||||
$updates$
|
$updates$
|
||||||
registrationOffice = new.registrationOffice,
|
registrationOffice = new.registrationOffice,
|
||||||
registrationNumber = new.registrationNumber,
|
registrationNumber = new.registrationNumber,
|
||||||
@ -33,51 +148,3 @@ call generateRbacRestrictedView('hs_office_partner_details',
|
|||||||
$updates$);
|
$updates$);
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
|
||||||
--changeset hs-office-partner-details-rbac-NEW-PARTNER-DETAILS:1 endDelimiter:--//
|
|
||||||
-- ----------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
Creates a global permission for new-partner-details and assigns it to the hostsharing admins role.
|
|
||||||
*/
|
|
||||||
do language plpgsql $$
|
|
||||||
declare
|
|
||||||
addCustomerPermissions uuid[];
|
|
||||||
globalObjectUuid uuid;
|
|
||||||
globalAdminRoleUuid uuid ;
|
|
||||||
begin
|
|
||||||
call defineContext('granting global new-partner-details permission to global admin role', null, null, null);
|
|
||||||
|
|
||||||
globalAdminRoleUuid := findRoleId(globalAdmin());
|
|
||||||
globalObjectUuid := (select uuid from global);
|
|
||||||
addCustomerPermissions := createPermissions(globalObjectUuid, array ['new-partner-details']);
|
|
||||||
call grantPermissionsToRole(globalAdminRoleUuid, addCustomerPermissions);
|
|
||||||
end;
|
|
||||||
$$;
|
|
||||||
|
|
||||||
-- TODO.refa: the code below could be moved to a generator, maybe even the code above.
|
|
||||||
-- Additionally, the code below is not neccesary for all entities, specifiy when it is!
|
|
||||||
|
|
||||||
/**
|
|
||||||
Used by the trigger to prevent the add-partner-details to current user respectively assumed roles.
|
|
||||||
*/
|
|
||||||
create or replace function addHsOfficePartnerDetailsNotAllowedForCurrentSubjects()
|
|
||||||
returns trigger
|
|
||||||
language PLPGSQL
|
|
||||||
as $$
|
|
||||||
begin
|
|
||||||
raise exception '[403] new-partner-details not permitted for %',
|
|
||||||
array_to_string(currentSubjects(), ';', 'null');
|
|
||||||
end; $$;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Checks if the user or assumed roles are allowed to create new partner-details.
|
|
||||||
*/
|
|
||||||
create trigger hs_office_partner_details_insert_trigger
|
|
||||||
before insert
|
|
||||||
on hs_office_partner_details
|
|
||||||
for each row
|
|
||||||
when ( not hasAssumedRole() )
|
|
||||||
execute procedure addHsOfficePartnerDetailsNotAllowedForCurrentSubjects();
|
|
||||||
--//
|
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*/
|
*/
|
||||||
create or replace procedure createHsOfficePartnerTestData(
|
create or replace procedure createHsOfficePartnerTestData(
|
||||||
mandantTradeName varchar,
|
mandantTradeName varchar,
|
||||||
partnerNumber numeric(5),
|
newPartnerNumber numeric(5),
|
||||||
partnerPersonName varchar,
|
partnerPersonName varchar,
|
||||||
contactLabel varchar )
|
contactLabel varchar )
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
@ -20,7 +20,6 @@ declare
|
|||||||
mandantPerson hs_office_person;
|
mandantPerson hs_office_person;
|
||||||
partnerRel hs_office_relation;
|
partnerRel hs_office_relation;
|
||||||
relatedPerson hs_office_person;
|
relatedPerson hs_office_person;
|
||||||
relatedContact hs_office_contact;
|
|
||||||
relatedDetailsUuid uuid;
|
relatedDetailsUuid uuid;
|
||||||
begin
|
begin
|
||||||
idName := cleanIdentifier( partnerPersonName|| '-' || contactLabel);
|
idName := cleanIdentifier( partnerPersonName|| '-' || contactLabel);
|
||||||
@ -38,9 +37,6 @@ begin
|
|||||||
select p.* from hs_office_person p
|
select p.* from hs_office_person p
|
||||||
where p.tradeName = partnerPersonName or p.familyName = partnerPersonName
|
where p.tradeName = partnerPersonName or p.familyName = partnerPersonName
|
||||||
into relatedPerson;
|
into relatedPerson;
|
||||||
select c.* from hs_office_contact c
|
|
||||||
where c.label = contactLabel
|
|
||||||
into relatedContact;
|
|
||||||
|
|
||||||
select r.* from hs_office_relation r
|
select r.* from hs_office_relation r
|
||||||
where r.type = 'PARTNER'
|
where r.type = 'PARTNER'
|
||||||
@ -53,7 +49,6 @@ begin
|
|||||||
raise notice 'creating test partner: %', idName;
|
raise notice 'creating test partner: %', idName;
|
||||||
raise notice '- using partnerRel (%): %', partnerRel.uuid, partnerRel;
|
raise notice '- using partnerRel (%): %', partnerRel.uuid, partnerRel;
|
||||||
raise notice '- using person (%): %', relatedPerson.uuid, relatedPerson;
|
raise notice '- using person (%): %', relatedPerson.uuid, relatedPerson;
|
||||||
raise notice '- using contact (%): %', relatedContact.uuid, relatedContact;
|
|
||||||
|
|
||||||
if relatedPerson.persontype = 'NP' then
|
if relatedPerson.persontype = 'NP' then
|
||||||
insert
|
insert
|
||||||
@ -68,8 +63,8 @@ begin
|
|||||||
end if;
|
end if;
|
||||||
|
|
||||||
insert
|
insert
|
||||||
into hs_office_partner (uuid, partnerNumber, partnerRelUuid, personuuid, contactuuid, detailsUuid)
|
into hs_office_partner (uuid, partnerNumber, partnerRelUuid, detailsUuid)
|
||||||
values (uuid_generate_v4(), partnerNumber, partnerRel.uuid, relatedPerson.uuid, relatedContact.uuid, relatedDetailsUuid);
|
values (uuid_generate_v4(), newPartnerNumber, partnerRel.uuid, relatedDetailsUuid);
|
||||||
end; $$;
|
end; $$;
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
### 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
|
|
||||||
|
|
||||||
```
|
|
@ -1,125 +0,0 @@
|
|||||||
--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$);
|
|
||||||
--//
|
|
||||||
|
|
@ -1,40 +1,45 @@
|
|||||||
### hs_office_bankaccount RBAC Roles
|
### rbac bankAccount
|
||||||
|
|
||||||
|
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
|
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||||
flowchart TB
|
flowchart TB
|
||||||
|
|
||||||
subgraph global
|
subgraph bankAccount["`**bankAccount**`"]
|
||||||
style global fill: lightgray
|
|
||||||
|
|
||||||
role:global.admin[global.admin]
|
|
||||||
end
|
|
||||||
|
|
||||||
subgraph hsOfficeBankAccount
|
|
||||||
direction TB
|
direction TB
|
||||||
style hsOfficeBankAccount fill: lightgreen
|
style bankAccount fill:#dd4901,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
user:hsOfficeBankAccount.creator([bankAccount.creator])
|
subgraph bankAccount:roles[ ]
|
||||||
|
style bankAccount:roles fill:#dd4901,stroke:white
|
||||||
|
|
||||||
role:hsOfficeBankAccount.owner[[bankAccount.owner]]
|
role:bankAccount:owner[[bankAccount:owner]]
|
||||||
%% permissions
|
role:bankAccount:admin[[bankAccount:admin]]
|
||||||
role:hsOfficeBankAccount.owner --> perm:hsOfficeBankAccount.*{{hsOfficeBankAccount.delete}}
|
role:bankAccount:referrer[[bankAccount:referrer]]
|
||||||
%% incoming
|
|
||||||
role:global.admin --> role:hsOfficeBankAccount.owner
|
|
||||||
user:hsOfficeBankAccount.creator ---> role:hsOfficeBankAccount.owner
|
|
||||||
|
|
||||||
role:hsOfficeBankAccount.admin[[bankAccount.admin]]
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeBankAccount.owner ---> role:hsOfficeBankAccount.admin
|
|
||||||
|
|
||||||
role:hsOfficeBankAccount.tenant[[bankAccount.tenant]]
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeBankAccount.admin ---> role:hsOfficeBankAccount.tenant
|
|
||||||
|
|
||||||
role:hsOfficeBankAccount.guest[[bankAccount.guest]]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficeBankAccount.guest --> perm:hsOfficeBankAccount.view{{hsOfficeBankAccount.view}}
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeBankAccount.tenant ---> role:hsOfficeBankAccount.guest
|
|
||||||
end
|
end
|
||||||
```
|
|
||||||
|
|
||||||
|
subgraph bankAccount:permissions[ ]
|
||||||
|
style bankAccount:permissions fill:#dd4901,stroke:white
|
||||||
|
|
||||||
|
perm:bankAccount:INSERT{{bankAccount:INSERT}}
|
||||||
|
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:global:guest ==> perm:bankAccount:INSERT
|
||||||
|
role:bankAccount:owner ==> perm:bankAccount:DELETE
|
||||||
|
role:bankAccount:admin ==> perm:bankAccount:UPDATE
|
||||||
|
role:bankAccount:referrer ==> perm:bankAccount:SELECT
|
||||||
|
|
||||||
|
```
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
|
-- This code generated was by RbacViewPostgresGenerator, do not amend manually.
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-bankaccount-rbac-OBJECT:1 endDelimiter:--//
|
--changeset hs-office-bankaccount-rbac-OBJECT:1 endDelimiter:--//
|
||||||
@ -15,125 +17,129 @@ call generateRbacRoleDescriptors('hsOfficeBankAccount', 'hs_office_bankaccount')
|
|||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-bankaccount-rbac-ROLES-CREATION:1 endDelimiter:--//
|
--changeset hs-office-bankaccount-rbac-insert-trigger:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Creates the roles and their assignments for a new bankaccount for the AFTER INSERT TRIGGER.
|
Creates the roles, grants and permission for the AFTER INSERT TRIGGER.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
create or replace function createRbacRolesForHsOfficeBankAccount()
|
create or replace procedure buildRbacSystemForHsOfficeBankAccount(
|
||||||
returns trigger
|
NEW hs_office_bankaccount
|
||||||
language plpgsql
|
)
|
||||||
strict as $$
|
language plpgsql as $$
|
||||||
|
|
||||||
|
declare
|
||||||
|
|
||||||
begin
|
begin
|
||||||
if TG_OP <> 'INSERT' then
|
call enterTriggerForObjectUuid(NEW.uuid);
|
||||||
raise exception 'invalid usage of TRIGGER AFTER INSERT';
|
|
||||||
end if;
|
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficeBankAccountOwner(NEW),
|
hsOfficeBankAccountOwner(NEW),
|
||||||
permissions => array['DELETE'],
|
permissions => array['DELETE'],
|
||||||
incomingSuperRoles => array[globalAdmin()],
|
incomingSuperRoles => array[globalAdmin()],
|
||||||
userUuids => array[currentUserUuid()],
|
userUuids => array[currentUserUuid()]
|
||||||
grantedByRole => globalAdmin()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficeBankAccountAdmin(NEW),
|
hsOfficeBankAccountAdmin(NEW),
|
||||||
|
permissions => array['UPDATE'],
|
||||||
incomingSuperRoles => array[hsOfficeBankAccountOwner(NEW)]
|
incomingSuperRoles => array[hsOfficeBankAccountOwner(NEW)]
|
||||||
);
|
);
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficeBankAccountTenant(NEW),
|
hsOfficeBankAccountReferrer(NEW),
|
||||||
|
permissions => array['SELECT'],
|
||||||
incomingSuperRoles => array[hsOfficeBankAccountAdmin(NEW)]
|
incomingSuperRoles => array[hsOfficeBankAccountAdmin(NEW)]
|
||||||
);
|
);
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||||
hsOfficeBankAccountGuest(NEW),
|
|
||||||
permissions => array['SELECT'],
|
|
||||||
incomingSuperRoles => array[hsOfficeBankAccountTenant(NEW)]
|
|
||||||
);
|
|
||||||
|
|
||||||
return NEW;
|
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
An AFTER INSERT TRIGGER which creates the role structure for a new customer.
|
AFTER INSERT TRIGGER to create the role+grant structure for a new hs_office_bankaccount row.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
create trigger createRbacRolesForHsOfficeBankAccount_Trigger
|
create or replace function insertTriggerForHsOfficeBankAccount_tf()
|
||||||
after insert
|
returns trigger
|
||||||
on hs_office_bankaccount
|
language plpgsql
|
||||||
|
strict as $$
|
||||||
|
begin
|
||||||
|
call buildRbacSystemForHsOfficeBankAccount(NEW);
|
||||||
|
return NEW;
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
create trigger insertTriggerForHsOfficeBankAccount_tg
|
||||||
|
after insert on hs_office_bankaccount
|
||||||
for each row
|
for each row
|
||||||
execute procedure createRbacRolesForHsOfficeBankAccount();
|
execute procedure insertTriggerForHsOfficeBankAccount_tf();
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
--changeset hs-office-bankaccount-rbac-INSERT:1 endDelimiter:--//
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/*
|
||||||
|
Creates INSERT INTO hs_office_bankaccount permissions for the related global rows.
|
||||||
|
*/
|
||||||
|
do language plpgsql $$
|
||||||
|
declare
|
||||||
|
row global;
|
||||||
|
begin
|
||||||
|
call defineContext('create INSERT INTO hs_office_bankaccount permissions for the related global rows');
|
||||||
|
|
||||||
|
FOR row IN SELECT * FROM global
|
||||||
|
LOOP
|
||||||
|
call grantPermissionToRole(
|
||||||
|
createPermission(row.uuid, 'INSERT', 'hs_office_bankaccount'),
|
||||||
|
globalGuest());
|
||||||
|
END LOOP;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Adds hs_office_bankaccount INSERT permission to specified role of new global rows.
|
||||||
|
*/
|
||||||
|
create or replace function hs_office_bankaccount_global_insert_tf()
|
||||||
|
returns trigger
|
||||||
|
language plpgsql
|
||||||
|
strict as $$
|
||||||
|
begin
|
||||||
|
call grantPermissionToRole(
|
||||||
|
createPermission(NEW.uuid, 'INSERT', 'hs_office_bankaccount'),
|
||||||
|
globalGuest());
|
||||||
|
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_bankaccount_global_insert_tg
|
||||||
|
after insert on global
|
||||||
|
for each row
|
||||||
|
execute procedure hs_office_bankaccount_global_insert_tf();
|
||||||
|
--//
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-bankaccount-rbac-IDENTITY-VIEW:1 endDelimiter:--//
|
--changeset hs-office-bankaccount-rbac-IDENTITY-VIEW:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
call generateRbacIdentityViewFromProjection('hs_office_bankaccount', $idName$
|
call generateRbacIdentityViewFromProjection('hs_office_bankaccount',
|
||||||
target.holder
|
$idName$
|
||||||
|
iban
|
||||||
$idName$);
|
$idName$);
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-bankaccount-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
|
--changeset hs-office-bankaccount-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
call generateRbacRestrictedView('hs_office_bankaccount', 'target.holder',
|
call generateRbacRestrictedView('hs_office_bankaccount',
|
||||||
|
$orderBy$
|
||||||
|
iban
|
||||||
|
$orderBy$,
|
||||||
$updates$
|
$updates$
|
||||||
holder = new.holder,
|
holder = new.holder,
|
||||||
iban = new.iban,
|
iban = new.iban,
|
||||||
bic = new.bic
|
bic = new.bic
|
||||||
$updates$);
|
$updates$);
|
||||||
--/
|
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
|
||||||
--changeset hs-office-bankaccount-rbac-NEW-BANKACCOUNT:1 endDelimiter:--//
|
|
||||||
-- ----------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
Creates a global permission for new-bankaccount and assigns it to the hostsharing admins role.
|
|
||||||
*/
|
|
||||||
do language plpgsql $$
|
|
||||||
declare
|
|
||||||
addCustomerPermissions uuid[];
|
|
||||||
globalObjectUuid uuid;
|
|
||||||
globalAdminRoleUuid uuid ;
|
|
||||||
begin
|
|
||||||
call defineContext('granting global new-bankaccount permission to global admin role', null, null, null);
|
|
||||||
|
|
||||||
globalAdminRoleUuid := findRoleId(globalAdmin());
|
|
||||||
globalObjectUuid := (select uuid from global);
|
|
||||||
addCustomerPermissions := createPermissions(globalObjectUuid, array ['new-bankaccount']);
|
|
||||||
call grantPermissionsToRole(globalAdminRoleUuid, addCustomerPermissions);
|
|
||||||
end;
|
|
||||||
$$;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Used by the trigger to prevent the add-customer to current user respectively assumed roles.
|
|
||||||
*/
|
|
||||||
create or replace function addHsOfficeBankAccountNotAllowedForCurrentSubjects()
|
|
||||||
returns trigger
|
|
||||||
language PLPGSQL
|
|
||||||
as $$
|
|
||||||
begin
|
|
||||||
raise exception '[403] new-bankaccount not permitted for %',
|
|
||||||
array_to_string(currentSubjects(), ';', 'null');
|
|
||||||
end; $$;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Checks if the user or assumed roles are allowed to create a new customer.
|
|
||||||
*/
|
|
||||||
create trigger hs_office_bankaccount_insert_trigger
|
|
||||||
before insert
|
|
||||||
on hs_office_bankaccount
|
|
||||||
for each row
|
|
||||||
-- TODO.spec: who is allowed to create new bankaccounts
|
|
||||||
when ( not hasAssumedRole() )
|
|
||||||
execute procedure addHsOfficeBankAccountNotAllowedForCurrentSubjects();
|
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
@ -1,178 +0,0 @@
|
|||||||
### 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
|
|
||||||
|
|
||||||
```
|
|
@ -1,143 +0,0 @@
|
|||||||
--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[
|
|
||||||
hsOfficeBankAccountAdmin(newBankAccount),
|
|
||||||
hsOfficeRelationAgent(newDebitorRel),
|
|
||||||
hsOfficeSepaMandateAgent(NEW)],
|
|
||||||
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$);
|
|
||||||
--//
|
|
||||||
|
|
@ -1,71 +1,180 @@
|
|||||||
### hs_office_sepaMandate RBAC
|
### rbac sepaMandate
|
||||||
|
|
||||||
|
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
|
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||||
flowchart TB
|
flowchart TB
|
||||||
|
|
||||||
subgraph global
|
subgraph bankAccount["`**bankAccount**`"]
|
||||||
style global fill:#eee
|
|
||||||
|
|
||||||
role:global.admin[global.admin]
|
|
||||||
end
|
|
||||||
|
|
||||||
subgraph hsOfficeBankAccount
|
|
||||||
direction TB
|
direction TB
|
||||||
style hsOfficeBankAccount fill:#eee
|
style bankAccount fill:#99bcdb,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
role:hsOfficeBankAccount.owner[bankAccount.owner]
|
subgraph bankAccount:roles[ ]
|
||||||
--> role:hsOfficeBankAccount.admin[bankAccount.admin]
|
style bankAccount:roles fill:#99bcdb,stroke:white
|
||||||
--> role:hsOfficeBankAccount.tenant[bankAccount.tenant]
|
|
||||||
--> role:hsOfficeBankAccount.guest[bankAccount.guest]
|
role:bankAccount:owner[[bankAccount:owner]]
|
||||||
|
role:bankAccount:admin[[bankAccount:admin]]
|
||||||
|
role:bankAccount:referrer[[bankAccount:referrer]]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
subgraph hsOfficeDebitor
|
subgraph debitorRel.contact["`**debitorRel.contact**`"]
|
||||||
direction TB
|
direction TB
|
||||||
style hsOfficeDebitor fill:#eee
|
style debitorRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
role:hsOfficeDebitor.owner[debitor.admin]
|
subgraph debitorRel.contact:roles[ ]
|
||||||
--> role:hsOfficeDebitor.admin[debitor.admin]
|
style debitorRel.contact:roles fill:#99bcdb,stroke:white
|
||||||
--> role:hsOfficeDebitor.agent[debitor.agent]
|
|
||||||
--> role:hsOfficeDebitor.tenant[debitor.tenant]
|
role:debitorRel.contact:owner[[debitorRel.contact:owner]]
|
||||||
--> role:hsOfficeDebitor.guest[debitor.guest]
|
role:debitorRel.contact:admin[[debitorRel.contact:admin]]
|
||||||
|
role:debitorRel.contact:referrer[[debitorRel.contact:referrer]]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
subgraph hsOfficeSepaMandate
|
subgraph debitorRel.anchorPerson["`**debitorRel.anchorPerson**`"]
|
||||||
|
direction TB
|
||||||
|
style debitorRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
role:hsOfficeSepaMandate.owner[sepaMandate.owner]
|
subgraph debitorRel.anchorPerson:roles[ ]
|
||||||
%% permissions
|
style debitorRel.anchorPerson:roles fill:#99bcdb,stroke:white
|
||||||
role:hsOfficeSepaMandate.owner --> perm:hsOfficeSepaMandate.*{{sepaMandate.*}}
|
|
||||||
%% incoming
|
|
||||||
role:global.admin ---> role:hsOfficeSepaMandate.owner
|
|
||||||
|
|
||||||
role:hsOfficeSepaMandate.admin[sepaMandate.admin]
|
role:debitorRel.anchorPerson:owner[[debitorRel.anchorPerson:owner]]
|
||||||
%% permissions
|
role:debitorRel.anchorPerson:admin[[debitorRel.anchorPerson:admin]]
|
||||||
role:hsOfficeSepaMandate.admin --> perm:hsOfficeSepaMandate.edit{{sepaMandate.edit}}
|
role:debitorRel.anchorPerson:referrer[[debitorRel.anchorPerson:referrer]]
|
||||||
%% incoming
|
end
|
||||||
role:hsOfficeSepaMandate.owner ---> role:hsOfficeSepaMandate.admin
|
|
||||||
|
|
||||||
role:hsOfficeSepaMandate.agent[sepaMandate.agent]
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeSepaMandate.admin ---> role:hsOfficeSepaMandate.agent
|
|
||||||
role:hsOfficeDebitor.admin --> role:hsOfficeSepaMandate.agent
|
|
||||||
role:hsOfficeBankAccount.admin --> role:hsOfficeSepaMandate.agent
|
|
||||||
%% outgoing
|
|
||||||
role:hsOfficeSepaMandate.agent --> role:hsOfficeDebitor.tenant
|
|
||||||
role:hsOfficeSepaMandate.admin --> role:hsOfficeBankAccount.tenant
|
|
||||||
|
|
||||||
role:hsOfficeSepaMandate.tenant[sepaMandate.tenant]
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeSepaMandate.agent --> role:hsOfficeSepaMandate.tenant
|
|
||||||
%% outgoing
|
|
||||||
role:hsOfficeSepaMandate.tenant --> role:hsOfficeDebitor.guest
|
|
||||||
role:hsOfficeSepaMandate.tenant --> role:hsOfficeBankAccount.guest
|
|
||||||
|
|
||||||
role:hsOfficeSepaMandate.guest[sepaMandate.guest]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficeSepaMandate.guest --> perm:hsOfficeSepaMandate.view{{sepaMandate.view}}
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeSepaMandate.tenant --> role:hsOfficeSepaMandate.guest
|
|
||||||
end
|
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}}
|
||||||
|
perm:sepaMandate:INSERT{{sepaMandate:INSERT}}
|
||||||
|
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
|
||||||
|
role:debitorRel:admin ==> perm:sepaMandate:INSERT
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
|
-- This code generated was by RbacViewPostgresGenerator, do not amend manually.
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-sepamandate-rbac-OBJECT:1 endDelimiter:--//
|
--changeset hs-office-sepamandate-rbac-OBJECT:1 endDelimiter:--//
|
||||||
@ -15,144 +17,191 @@ call generateRbacRoleDescriptors('hsOfficeSepaMandate', 'hs_office_sepamandate')
|
|||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-sepamandate-rbac-ROLES-CREATION:1 endDelimiter:--//
|
--changeset hs-office-sepamandate-rbac-insert-trigger:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Creates and updates the roles and their assignments for sepaMandate entities.
|
Creates the roles, grants and permission for the AFTER INSERT TRIGGER.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
create or replace function hsOfficeSepaMandateRbacRolesTrigger()
|
create or replace procedure buildRbacSystemForHsOfficeSepaMandate(
|
||||||
returns trigger
|
NEW hs_office_sepamandate
|
||||||
language plpgsql
|
)
|
||||||
strict as $$
|
language plpgsql as $$
|
||||||
|
|
||||||
declare
|
declare
|
||||||
newHsOfficeDebitor hs_office_debitor;
|
newBankAccount hs_office_bankaccount;
|
||||||
newHsOfficeBankAccount hs_office_bankAccount;
|
newDebitorRel hs_office_relation;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
call enterTriggerForObjectUuid(NEW.uuid);
|
call enterTriggerForObjectUuid(NEW.uuid);
|
||||||
|
|
||||||
select * from hs_office_debitor as p where p.uuid = NEW.debitorUuid into newHsOfficeDebitor;
|
SELECT * FROM hs_office_bankaccount WHERE uuid = NEW.bankAccountUuid INTO newBankAccount;
|
||||||
select * from hs_office_bankAccount as c where c.uuid = NEW.bankAccountUuid into newHsOfficeBankAccount;
|
assert newBankAccount.uuid is not null, format('newBankAccount must not be null for NEW.bankAccountUuid = %s', NEW.bankAccountUuid);
|
||||||
|
|
||||||
if TG_OP = 'INSERT' then
|
SELECT debitorRel.*
|
||||||
|
FROM hs_office_relation debitorRel
|
||||||
|
JOIN hs_office_debitor debitor ON debitor.debitorRelUuid = debitorRel.uuid
|
||||||
|
WHERE debitor.uuid = NEW.debitorUuid
|
||||||
|
INTO newDebitorRel;
|
||||||
|
assert newDebitorRel.uuid is not null, format('newDebitorRel must not be null for NEW.debitorUuid = %s', NEW.debitorUuid);
|
||||||
|
|
||||||
-- === ATTENTION: code generated from related Mermaid flowchart: ===
|
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficeSepaMandateOwner(NEW),
|
hsOfficeSepaMandateOwner(NEW),
|
||||||
permissions => array['DELETE'],
|
permissions => array['DELETE'],
|
||||||
incomingSuperRoles => array[globalAdmin()]
|
incomingSuperRoles => array[globalAdmin()],
|
||||||
|
userUuids => array[currentUserUuid()]
|
||||||
);
|
);
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficeSepaMandateAdmin(NEW),
|
hsOfficeSepaMandateAdmin(NEW),
|
||||||
permissions => array['UPDATE'],
|
permissions => array['UPDATE'],
|
||||||
incomingSuperRoles => array[hsOfficeSepaMandateOwner(NEW)],
|
incomingSuperRoles => array[hsOfficeSepaMandateOwner(NEW)]
|
||||||
outgoingSubRoles => array[hsOfficeBankAccountTenant(newHsOfficeBankAccount)]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficeSepaMandateAgent(NEW),
|
hsOfficeSepaMandateAgent(NEW),
|
||||||
incomingSuperRoles => array[hsOfficeSepaMandateAdmin(NEW), hsOfficeDebitorAdmin(newHsOfficeDebitor), hsOfficeBankAccountAdmin(newHsOfficeBankAccount)],
|
incomingSuperRoles => array[hsOfficeSepaMandateAdmin(NEW)],
|
||||||
outgoingSubRoles => array[hsOfficeDebitorTenant(newHsOfficeDebitor)]
|
outgoingSubRoles => array[
|
||||||
|
hsOfficeBankAccountReferrer(newBankAccount),
|
||||||
|
hsOfficeRelationAgent(newDebitorRel)]
|
||||||
);
|
);
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficeSepaMandateTenant(NEW),
|
hsOfficeSepaMandateReferrer(NEW),
|
||||||
incomingSuperRoles => array[hsOfficeSepaMandateAgent(NEW)],
|
|
||||||
outgoingSubRoles => array[hsOfficeDebitorGuest(newHsOfficeDebitor), hsOfficeBankAccountGuest(newHsOfficeBankAccount)]
|
|
||||||
);
|
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
|
||||||
hsOfficeSepaMandateGuest(NEW),
|
|
||||||
permissions => array['SELECT'],
|
permissions => array['SELECT'],
|
||||||
incomingSuperRoles => array[hsOfficeSepaMandateTenant(NEW)]
|
incomingSuperRoles => array[
|
||||||
|
hsOfficeBankAccountAdmin(newBankAccount),
|
||||||
|
hsOfficeRelationAgent(newDebitorRel),
|
||||||
|
hsOfficeSepaMandateAgent(NEW)],
|
||||||
|
outgoingSubRoles => array[hsOfficeRelationTenant(newDebitorRel)]
|
||||||
);
|
);
|
||||||
|
|
||||||
-- === END of code generated from Mermaid flowchart. ===
|
|
||||||
|
|
||||||
else
|
|
||||||
raise exception 'invalid usage of TRIGGER';
|
|
||||||
end if;
|
|
||||||
|
|
||||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||||
return NEW;
|
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
An AFTER INSERT TRIGGER which creates the role structure for a new customer.
|
AFTER INSERT TRIGGER to create the role+grant structure for a new hs_office_sepamandate row.
|
||||||
*/
|
*/
|
||||||
create trigger createRbacRolesForHsOfficeSepaMandate_Trigger
|
|
||||||
after insert
|
create or replace function insertTriggerForHsOfficeSepaMandate_tf()
|
||||||
on hs_office_sepamandate
|
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
|
for each row
|
||||||
execute procedure hsOfficeSepaMandateRbacRolesTrigger();
|
execute procedure insertTriggerForHsOfficeSepaMandate_tf();
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-sepamandate-rbac-IDENTITY-VIEW:1 endDelimiter:--//
|
--changeset hs-office-sepamandate-rbac-INSERT:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
call generateRbacIdentityViewFromProjection('hs_office_sepamandate', 'target.reference');
|
|
||||||
|
/*
|
||||||
|
Creates INSERT INTO hs_office_sepamandate permissions for the related hs_office_relation rows.
|
||||||
|
*/
|
||||||
|
do language plpgsql $$
|
||||||
|
declare
|
||||||
|
row hs_office_relation;
|
||||||
|
begin
|
||||||
|
call defineContext('create INSERT INTO hs_office_sepamandate permissions for the related hs_office_relation rows');
|
||||||
|
|
||||||
|
FOR row IN SELECT * FROM hs_office_relation
|
||||||
|
LOOP
|
||||||
|
call grantPermissionToRole(
|
||||||
|
createPermission(row.uuid, 'INSERT', 'hs_office_sepamandate'),
|
||||||
|
hsOfficeRelationAdmin(row));
|
||||||
|
END LOOP;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Adds hs_office_sepamandate INSERT permission to specified role of new hs_office_relation rows.
|
||||||
|
*/
|
||||||
|
create or replace function hs_office_sepamandate_hs_office_relation_insert_tf()
|
||||||
|
returns trigger
|
||||||
|
language plpgsql
|
||||||
|
strict as $$
|
||||||
|
begin
|
||||||
|
call grantPermissionToRole(
|
||||||
|
createPermission(NEW.uuid, 'INSERT', 'hs_office_sepamandate'),
|
||||||
|
hsOfficeRelationAdmin(NEW));
|
||||||
|
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_sepamandate_hs_office_relation_insert_tg
|
||||||
|
after insert on hs_office_relation
|
||||||
|
for each row
|
||||||
|
execute procedure hs_office_sepamandate_hs_office_relation_insert_tf();
|
||||||
|
|
||||||
|
/**
|
||||||
|
Checks if the user or assumed roles are allowed to insert a row to hs_office_sepamandate,
|
||||||
|
where the check is performed by an indirect role.
|
||||||
|
|
||||||
|
An indirect role is a role which depends on an object uuid which is not a direct foreign key
|
||||||
|
of the source entity, but needs to be fetched via joined tables.
|
||||||
|
*/
|
||||||
|
create or replace function hs_office_sepamandate_insert_permission_check_tf()
|
||||||
|
returns trigger
|
||||||
|
language plpgsql as $$
|
||||||
|
|
||||||
|
declare
|
||||||
|
superRoleObjectUuid uuid;
|
||||||
|
|
||||||
|
begin
|
||||||
|
superRoleObjectUuid := (SELECT debitorRel.uuid
|
||||||
|
FROM hs_office_relation debitorRel
|
||||||
|
JOIN hs_office_debitor debitor ON debitor.debitorRelUuid = debitorRel.uuid
|
||||||
|
WHERE debitor.uuid = NEW.debitorUuid
|
||||||
|
);
|
||||||
|
assert superRoleObjectUuid is not null, 'superRoleObjectUuid must not be null';
|
||||||
|
|
||||||
|
if ( not hasInsertPermission(superRoleObjectUuid, 'INSERT', 'hs_office_sepamandate') ) then
|
||||||
|
raise exception
|
||||||
|
'[403] insert into hs_office_sepamandate not allowed for current subjects % (%)',
|
||||||
|
currentSubjects(), currentSubjectsUuids();
|
||||||
|
end if;
|
||||||
|
return NEW;
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
create trigger hs_office_sepamandate_insert_permission_check_tg
|
||||||
|
before insert on hs_office_sepamandate
|
||||||
|
for each row
|
||||||
|
execute procedure hs_office_sepamandate_insert_permission_check_tf();
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
--changeset hs-office-sepamandate-rbac-IDENTITY-VIEW:1 endDelimiter:--//
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
call generateRbacIdentityViewFromQuery('hs_office_sepamandate',
|
||||||
|
$idName$
|
||||||
|
select sm.uuid as uuid, ba.iban || '-' || sm.validity as idName
|
||||||
|
from hs_office_sepamandate sm
|
||||||
|
join hs_office_bankaccount ba on ba.uuid = sm.bankAccountUuid
|
||||||
|
$idName$);
|
||||||
|
--//
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-sepamandate-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
|
--changeset hs-office-sepamandate-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
call generateRbacRestrictedView('hs_office_sepamandate',
|
call generateRbacRestrictedView('hs_office_sepamandate',
|
||||||
orderby => 'target.reference',
|
$orderBy$
|
||||||
columnUpdates => $updates$
|
validity
|
||||||
|
$orderBy$,
|
||||||
|
$updates$
|
||||||
reference = new.reference,
|
reference = new.reference,
|
||||||
agreement = new.agreement,
|
agreement = new.agreement,
|
||||||
validity = new.validity
|
validity = new.validity
|
||||||
$updates$);
|
$updates$);
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
|
||||||
--changeset hs-office-sepamandate-rbac-NEW-SepaMandate:1 endDelimiter:--//
|
|
||||||
-- ----------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
Creates a global permission for new-sepaMandate and assigns it to the hostsharing admins role.
|
|
||||||
*/
|
|
||||||
do language plpgsql $$
|
|
||||||
declare
|
|
||||||
addCustomerPermissions uuid[];
|
|
||||||
globalObjectUuid uuid;
|
|
||||||
globalAdminRoleUuid uuid ;
|
|
||||||
begin
|
|
||||||
call defineContext('granting global new-sepaMandate permission to global admin role', null, null, null);
|
|
||||||
|
|
||||||
globalAdminRoleUuid := findRoleId(globalAdmin());
|
|
||||||
globalObjectUuid := (select uuid from global);
|
|
||||||
addCustomerPermissions := createPermissions(globalObjectUuid, array ['new-sepamandate']);
|
|
||||||
call grantPermissionsToRole(globalAdminRoleUuid, addCustomerPermissions);
|
|
||||||
end;
|
|
||||||
$$;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Used by the trigger to prevent the add-customer to current user respectively assumed roles.
|
|
||||||
*/
|
|
||||||
create or replace function addHsOfficeSepaMandateNotAllowedForCurrentSubjects()
|
|
||||||
returns trigger
|
|
||||||
language PLPGSQL
|
|
||||||
as $$
|
|
||||||
begin
|
|
||||||
raise exception '[403] new-sepaMandate not permitted for %',
|
|
||||||
array_to_string(currentSubjects(), ';', 'null');
|
|
||||||
end; $$;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Checks if the user or assumed roles are allowed to create a new customer.
|
|
||||||
*/
|
|
||||||
create trigger hs_office_sepamandate_insert_trigger
|
|
||||||
before insert
|
|
||||||
on hs_office_sepamandate
|
|
||||||
for each row
|
|
||||||
-- TODO.spec: who is allowed to create new sepaMandates
|
|
||||||
when ( not hasAssumedRole() )
|
|
||||||
execute procedure addHsOfficeSepaMandateNotAllowedForCurrentSubjects();
|
|
||||||
--//
|
|
||||||
|
|
||||||
|
@ -8,31 +8,36 @@
|
|||||||
/*
|
/*
|
||||||
Creates a single sepaMandate test record.
|
Creates a single sepaMandate test record.
|
||||||
*/
|
*/
|
||||||
create or replace procedure createHsOfficeSepaMandateTestData( tradeNameAndHolderName varchar )
|
create or replace procedure createHsOfficeSepaMandateTestData(
|
||||||
|
forPartnerNumber numeric(5),
|
||||||
|
forDebitorSuffix numeric(2),
|
||||||
|
forIban varchar,
|
||||||
|
withReference varchar)
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
declare
|
declare
|
||||||
currentTask varchar;
|
currentTask varchar;
|
||||||
idName varchar;
|
|
||||||
relatedDebitor hs_office_debitor;
|
relatedDebitor hs_office_debitor;
|
||||||
relatedBankAccount hs_office_bankAccount;
|
relatedBankAccount hs_office_bankAccount;
|
||||||
begin
|
begin
|
||||||
idName := cleanIdentifier( tradeNameAndHolderName);
|
currentTask := 'creating SEPA-mandate test-data ' || forPartnerNumber::text || forDebitorSuffix::text;
|
||||||
currentTask := 'creating SEPA-mandate test-data ' || idName;
|
|
||||||
call defineContext(currentTask, null, 'superuser-alex@hostsharing.net', 'global#global.admin');
|
call defineContext(currentTask, null, 'superuser-alex@hostsharing.net', 'global#global.admin');
|
||||||
execute format('set local hsadminng.currentTask to %L', currentTask);
|
execute format('set local hsadminng.currentTask to %L', currentTask);
|
||||||
|
|
||||||
select debitor.* from hs_office_debitor debitor
|
select debitor.* into relatedDebitor
|
||||||
join hs_office_partner parter on parter.uuid = debitor.partnerUuid
|
from hs_office_debitor debitor
|
||||||
join hs_office_person person on person.uuid = parter.personUuid
|
join hs_office_relation debitorRel on debitorRel.uuid = debitor.debitorRelUuid
|
||||||
where person.tradeName = tradeNameAndHolderName into relatedDebitor;
|
join hs_office_relation partnerRel on partnerRel.holderUuid = debitorRel.anchorUuid
|
||||||
select c.* from hs_office_bankAccount c where c.holder = tradeNameAndHolderName into relatedBankAccount;
|
join hs_office_partner partner on partner.partnerRelUuid = partnerRel.uuid
|
||||||
|
where partner.partnerNumber = forPartnerNumber and debitor.debitorNumberSuffix = forDebitorSuffix;
|
||||||
|
select b.* into relatedBankAccount
|
||||||
|
from hs_office_bankAccount b where b.iban = forIban;
|
||||||
|
|
||||||
raise notice 'creating test SEPA-mandate: %', idName;
|
raise notice 'creating test SEPA-mandate: %', forPartnerNumber::text || forDebitorSuffix::text;
|
||||||
raise notice '- using debitor (%): %', relatedDebitor.uuid, relatedDebitor;
|
raise notice '- using debitor (%): %', relatedDebitor.uuid, relatedDebitor;
|
||||||
raise notice '- using bankAccount (%): %', relatedBankAccount.uuid, relatedBankAccount;
|
raise notice '- using bankAccount (%): %', relatedBankAccount.uuid, relatedBankAccount;
|
||||||
insert
|
insert
|
||||||
into hs_office_sepamandate (uuid, debitoruuid, bankAccountuuid, reference, agreement, validity)
|
into hs_office_sepamandate (uuid, debitoruuid, bankAccountuuid, reference, agreement, validity)
|
||||||
values (uuid_generate_v4(), relatedDebitor.uuid, relatedBankAccount.uuid, 'ref'||idName, '20220930', daterange('20221001' , '20261231', '[]'));
|
values (uuid_generate_v4(), relatedDebitor.uuid, relatedBankAccount.uuid, withReference, '20220930', daterange('20221001' , '20261231', '[]'));
|
||||||
end; $$;
|
end; $$;
|
||||||
--//
|
--//
|
||||||
|
|
||||||
@ -43,9 +48,9 @@ end; $$;
|
|||||||
|
|
||||||
do language plpgsql $$
|
do language plpgsql $$
|
||||||
begin
|
begin
|
||||||
call createHsOfficeSepaMandateTestData('First GmbH');
|
call createHsOfficeSepaMandateTestData(10001, 11, 'DE02120300000000202051', 'ref-10001-11');
|
||||||
call createHsOfficeSepaMandateTestData('Second e.K.');
|
call createHsOfficeSepaMandateTestData(10002, 12, 'DE02100500000054540402', 'ref-10002-12');
|
||||||
call createHsOfficeSepaMandateTestData('Third OHG');
|
call createHsOfficeSepaMandateTestData(10003, 13, 'DE02300209000106531065', 'ref-10003-13');
|
||||||
end;
|
end;
|
||||||
$$;
|
$$;
|
||||||
--//
|
--//
|
||||||
|
@ -7,10 +7,9 @@
|
|||||||
create table hs_office_debitor
|
create table hs_office_debitor
|
||||||
(
|
(
|
||||||
uuid uuid unique references RbacObject (uuid) initially deferred,
|
uuid uuid unique references RbacObject (uuid) initially deferred,
|
||||||
partnerUuid uuid not null references hs_office_partner(uuid),
|
|
||||||
billable boolean not null default true,
|
|
||||||
debitorNumberSuffix numeric(2) not null,
|
debitorNumberSuffix numeric(2) not null,
|
||||||
billingContactUuid uuid not null references hs_office_contact(uuid),
|
debitorRelUuid uuid not null references hs_office_relation(uuid),
|
||||||
|
billable boolean not null default true,
|
||||||
vatId varchar(24), -- TODO.spec: here or in person?
|
vatId varchar(24), -- TODO.spec: here or in person?
|
||||||
vatCountryCode varchar(2),
|
vatCountryCode varchar(2),
|
||||||
vatBusiness boolean not null,
|
vatBusiness boolean not null,
|
||||||
@ -20,11 +19,43 @@ create table hs_office_debitor
|
|||||||
constraint check_default_prefix check (
|
constraint check_default_prefix check (
|
||||||
defaultPrefix::text ~ '^([a-z]{3}|al0|bh1|c4s|f3k|k8i|l3d|mh1|o13|p2m|s80|t4w)$'
|
defaultPrefix::text ~ '^([a-z]{3}|al0|bh1|c4s|f3k|k8i|l3d|mh1|o13|p2m|s80|t4w)$'
|
||||||
)
|
)
|
||||||
-- TODO.impl: SEPA-mandate
|
|
||||||
);
|
);
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
--changeset hs-office-debitor-DELETE-DEPENDENTS-TRIGGER:1 endDelimiter:--//
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
Trigger function to delete related rows of a debitor to delete.
|
||||||
|
*/
|
||||||
|
create or replace function deleteHsOfficeDependentsOnDebitorDelete()
|
||||||
|
returns trigger
|
||||||
|
language PLPGSQL
|
||||||
|
as $$
|
||||||
|
declare
|
||||||
|
counter integer;
|
||||||
|
begin
|
||||||
|
DELETE FROM hs_office_relation r WHERE r.uuid = OLD.debitorRelUuid;
|
||||||
|
GET DIAGNOSTICS counter = ROW_COUNT;
|
||||||
|
if counter = 0 then
|
||||||
|
raise exception 'debitor relation % could not be deleted', OLD.debitorRelUuid;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
RETURN OLD;
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Triggers deletion of related details of a debitor to delete.
|
||||||
|
*/
|
||||||
|
create trigger hs_office_debitor_delete_dependents_trigger
|
||||||
|
after delete
|
||||||
|
on hs_office_debitor
|
||||||
|
for each row
|
||||||
|
execute procedure deleteHsOfficeDependentsOnDebitorDelete();
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-debitor-MAIN-TABLE-JOURNAL:1 endDelimiter:--//
|
--changeset hs-office-debitor-MAIN-TABLE-JOURNAL:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
|
@ -1,275 +0,0 @@
|
|||||||
### 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
|
|
||||||
|
|
||||||
```
|
|
@ -1,231 +0,0 @@
|
|||||||
--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 WHERE uuid = NEW.partnerRelUuid INTO newPartnerRel;
|
|
||||||
|
|
||||||
SELECT * FROM hs_office_relation WHERE uuid = 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_bankaccount WHERE uuid = NEW.refundBankAccountUuid INTO newRefundBankAccount;
|
|
||||||
|
|
||||||
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 $$
|
|
||||||
begin
|
|
||||||
|
|
||||||
if NEW.refundBankAccountUuid is distinct from OLD.refundBankAccountUuid then
|
|
||||||
delete from rbacgrants g where g.grantedbytriggerof = OLD.uuid;
|
|
||||||
call buildRbacSystemForHsOfficeDebitor(NEW);
|
|
||||||
end if;
|
|
||||||
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$);
|
|
||||||
--//
|
|
||||||
|
|
@ -1,250 +1,275 @@
|
|||||||
### hs_office_debitor RBAC Roles
|
### rbac debitor
|
||||||
|
|
||||||
|
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
|
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||||
flowchart TB
|
flowchart TB
|
||||||
|
|
||||||
subgraph global
|
subgraph debitorRel.anchorPerson["`**debitorRel.anchorPerson**`"]
|
||||||
style global fill:#eee
|
direction TB
|
||||||
|
style debitorRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
role:global.admin[global.admin]
|
subgraph debitorRel.anchorPerson:roles[ ]
|
||||||
end
|
style debitorRel.anchorPerson:roles fill:#99bcdb,stroke:white
|
||||||
|
|
||||||
subgraph office
|
role:debitorRel.anchorPerson:owner[[debitorRel.anchorPerson:owner]]
|
||||||
style office fill:#eee
|
role:debitorRel.anchorPerson:admin[[debitorRel.anchorPerson:admin]]
|
||||||
|
role:debitorRel.anchorPerson:referrer[[debitorRel.anchorPerson:referrer]]
|
||||||
subgraph sepa
|
|
||||||
|
|
||||||
subgraph bankaccount
|
|
||||||
style bankaccount fill: #e9f7ef
|
|
||||||
|
|
||||||
user:hsOfficeBankAccount.creator([bankaccount.creator])
|
|
||||||
|
|
||||||
role:hsOfficeBankAccount.owner[bankaccount.owner]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficeBankAccount.owner --> perm:hsOfficeBankAccount.*{{bankaccount.*}}
|
|
||||||
%% incoming
|
|
||||||
role:global.admin --> role:hsOfficeBankAccount.owner
|
|
||||||
user:hsOfficeBankAccount.creator ---> role:hsOfficeBankAccount.owner
|
|
||||||
|
|
||||||
role:hsOfficeBankAccount.admin[bankaccount.admin]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficeBankAccount.admin --> perm:hsOfficeBankAccount.edit{{bankaccount.edit}}
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeBankAccount.owner ---> role:hsOfficeBankAccount.admin
|
|
||||||
|
|
||||||
role:hsOfficeBankAccount.tenant[bankaccount.tenant]
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeBankAccount.admin ---> role:hsOfficeBankAccount.tenant
|
|
||||||
|
|
||||||
role:hsOfficeBankAccount.guest[bankaccount.guest]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficeBankAccount.guest --> perm:hsOfficeBankAccount.view{{bankaccount.view}}
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeBankAccount.tenant ---> role:hsOfficeBankAccount.guest
|
|
||||||
end
|
|
||||||
|
|
||||||
subgraph hsOfficeSepaMandate
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
subgraph contact
|
|
||||||
style contact fill: #e9f7ef
|
|
||||||
|
|
||||||
user:hsOfficeContact.creator([contact.creator])
|
|
||||||
|
|
||||||
role:hsOfficeContact.owner[contact.owner]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficeContact.owner --> perm:hsOfficeContact.*{{contact.*}}
|
|
||||||
%% incoming
|
|
||||||
role:global.admin --> role:hsOfficeContact.owner
|
|
||||||
user:hsOfficeContact.creator ---> role:hsOfficeContact.owner
|
|
||||||
|
|
||||||
role:hsOfficeContact.admin[contact.admin]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficeContact.admin ---> perm:hsOfficeContact.edit{{contact.edit}}
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeContact.owner ---> role:hsOfficeContact.admin
|
|
||||||
|
|
||||||
role:hsOfficeContact.tenant[contact.tenant]
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeContact.admin ----> role:hsOfficeContact.tenant
|
|
||||||
|
|
||||||
role:hsOfficeContact.guest[contact.guest]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficeContact.guest --> perm:hsOfficeContact.view{{contact.view}}
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeContact.tenant ---> role:hsOfficeContact.guest
|
|
||||||
end
|
|
||||||
|
|
||||||
subgraph partner-person
|
|
||||||
|
|
||||||
subgraph person
|
|
||||||
style person fill: #e9f7ef
|
|
||||||
|
|
||||||
user:hsOfficePerson.creator([personcreator])
|
|
||||||
|
|
||||||
role:hsOfficePerson.owner[person.owner]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficePerson.owner --> perm:hsOfficePerson.*{{person.*}}
|
|
||||||
%% incoming
|
|
||||||
user:hsOfficePerson.creator ---> role:hsOfficePerson.owner
|
|
||||||
role:global.admin --> role:hsOfficePerson.owner
|
|
||||||
|
|
||||||
role:hsOfficePerson.admin[person.admin]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficePerson.admin --> perm:hsOfficePerson.edit{{person.edit}}
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficePerson.owner ---> role:hsOfficePerson.admin
|
|
||||||
|
|
||||||
role:hsOfficePerson.tenant[person.tenant]
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficePerson.admin -----> role:hsOfficePerson.tenant
|
|
||||||
|
|
||||||
role:hsOfficePerson.guest[person.guest]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficePerson.guest --> perm:hsOfficePerson.edit{{person.view}}
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficePerson.tenant ---> role:hsOfficePerson.guest
|
|
||||||
end
|
|
||||||
|
|
||||||
subgraph partner
|
|
||||||
|
|
||||||
role:hsOfficePartner.owner[partner.owner]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficePartner.owner --> perm:hsOfficePartner.*{{partner.*}}
|
|
||||||
%% incoming
|
|
||||||
role:global.admin ---> role:hsOfficePartner.owner
|
|
||||||
|
|
||||||
role:hsOfficePartner.admin[partner.admin]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficePartner.admin --> perm:hsOfficePartner.edit{{partner.edit}}
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficePartner.owner ---> role:hsOfficePartner.admin
|
|
||||||
%% outgoing
|
|
||||||
role:hsOfficePartner.admin --> role:hsOfficePerson.tenant
|
|
||||||
role:hsOfficePartner.admin --> role:hsOfficeContact.tenant
|
|
||||||
|
|
||||||
role:hsOfficePartner.agent[partner.agent]
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficePartner.admin --> role:hsOfficePartner.agent
|
|
||||||
role:hsOfficePerson.admin --> role:hsOfficePartner.agent
|
|
||||||
role:hsOfficeContact.admin --> role:hsOfficePartner.agent
|
|
||||||
|
|
||||||
role:hsOfficePartner.tenant[partner.tenant]
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficePartner.agent ---> role:hsOfficePartner.tenant
|
|
||||||
%% outgoing
|
|
||||||
role:hsOfficePartner.tenant --> role:hsOfficePerson.guest
|
|
||||||
role:hsOfficePartner.tenant --> role:hsOfficeContact.guest
|
|
||||||
|
|
||||||
role:hsOfficePartner.guest[partner.guest]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficePartner.guest --> perm:hsOfficePartner.view{{partner.view}}
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficePartner.tenant ---> role:hsOfficePartner.guest
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
subgraph debitor
|
|
||||||
style debitor stroke-width:6px
|
|
||||||
|
|
||||||
user:hsOfficeDebitor.creator([debitor.creator])
|
|
||||||
%% created by role
|
|
||||||
user:hsOfficeDebitor.creator --> role:hsOfficePartner.agent
|
|
||||||
|
|
||||||
role:hsOfficeDebitor.owner[debitor.owner]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficeDebitor.owner --> perm:hsOfficeDebitor.*{{debitor.*}}
|
|
||||||
%% incoming
|
|
||||||
user:hsOfficeDebitor.creator --> role:hsOfficeDebitor.owner
|
|
||||||
role:global.admin --> role:hsOfficeDebitor.owner
|
|
||||||
|
|
||||||
role:hsOfficeDebitor.admin[debitor.admin]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficeDebitor.admin --> perm:hsOfficeDebitor.edit{{debitor.edit}}
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeDebitor.owner ---> role:hsOfficeDebitor.admin
|
|
||||||
|
|
||||||
role:hsOfficeDebitor.agent[debitor.agent]
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeDebitor.admin ---> role:hsOfficeDebitor.agent
|
|
||||||
role:hsOfficePartner.admin --> role:hsOfficeDebitor.agent
|
|
||||||
%% outgoing
|
|
||||||
role:hsOfficeDebitor.agent --> role:hsOfficeBankAccount.tenant
|
|
||||||
|
|
||||||
role:hsOfficeDebitor.tenant[debitor.tenant]
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeDebitor.agent ---> role:hsOfficeDebitor.tenant
|
|
||||||
role:hsOfficePartner.agent --> role:hsOfficeDebitor.tenant
|
|
||||||
role:hsOfficeBankAccount.admin --> role:hsOfficeDebitor.tenant
|
|
||||||
%% outgoing
|
|
||||||
role:hsOfficeDebitor.tenant --> role:hsOfficePartner.tenant
|
|
||||||
role:hsOfficeDebitor.tenant --> role:hsOfficeContact.guest
|
|
||||||
|
|
||||||
role:hsOfficeDebitor.guest[debitor.guest]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficeDebitor.guest --> perm:hsOfficeDebitor.view{{debitor.view}}
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeDebitor.tenant --> role:hsOfficeDebitor.guest
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
subgraph hsOfficeSepaMandate
|
|
||||||
|
|
||||||
role:hsOfficeSepaMandate.owner[sepaMandate.owner]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficeSepaMandate.owner --> perm:hsOfficeSepaMandate.*{{sepaMandate.*}}
|
|
||||||
%% incoming
|
|
||||||
role:global.admin ---> role:hsOfficeSepaMandate.owner
|
|
||||||
|
|
||||||
role:hsOfficeSepaMandate.admin[sepaMandate.admin]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficeSepaMandate.admin --> perm:hsOfficeSepaMandate.edit{{sepaMandate.edit}}
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeSepaMandate.owner ---> role:hsOfficeSepaMandate.admin
|
|
||||||
|
|
||||||
role:hsOfficeSepaMandate.agent[sepaMandate.agent]
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeSepaMandate.admin ---> role:hsOfficeSepaMandate.agent
|
|
||||||
role:hsOfficeDebitor.admin --> role:hsOfficeSepaMandate.agent
|
|
||||||
role:hsOfficeBankAccount.admin --> role:hsOfficeSepaMandate.agent
|
|
||||||
%% outgoing
|
|
||||||
role:hsOfficeSepaMandate.agent --> role:hsOfficeDebitor.tenant
|
|
||||||
role:hsOfficeSepaMandate.admin --> role:hsOfficeBankAccount.tenant
|
|
||||||
|
|
||||||
role:hsOfficeSepaMandate.tenant[sepaMandate.tenant]
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeSepaMandate.agent --> role:hsOfficeSepaMandate.tenant
|
|
||||||
%% outgoing
|
|
||||||
role:hsOfficeSepaMandate.tenant --> role:hsOfficeDebitor.guest
|
|
||||||
role:hsOfficeSepaMandate.tenant --> role:hsOfficeBankAccount.guest
|
|
||||||
|
|
||||||
role:hsOfficeSepaMandate.guest[sepaMandate.guest]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficeSepaMandate.guest --> perm:hsOfficeSepaMandate.view{{sepaMandate.view}}
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeSepaMandate.tenant --> role:hsOfficeSepaMandate.guest
|
|
||||||
end
|
|
||||||
|
|
||||||
subgraph hosting
|
|
||||||
style hosting fill:#eee
|
|
||||||
|
|
||||||
subgraph package
|
|
||||||
style package fill: #e9f7ef
|
|
||||||
|
|
||||||
role:package.owner[package.owner]
|
|
||||||
--> role:package.admin[package.admin]
|
|
||||||
--> role:package.tenant[package.tenant]
|
|
||||||
|
|
||||||
role:hsOfficeDebitor.agent --> role:package.owner
|
|
||||||
role:package.admin --> role:hsOfficeDebitor.tenant
|
|
||||||
role:hsOfficePartner.tenant --> role:hsOfficeDebitor.guest
|
|
||||||
end
|
end
|
||||||
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
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
|
-- This code generated was by RbacViewPostgresGenerator, do not amend manually.
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-debitor-rbac-OBJECT:1 endDelimiter:--//
|
--changeset hs-office-debitor-rbac-OBJECT:1 endDelimiter:--//
|
||||||
@ -15,233 +17,211 @@ call generateRbacRoleDescriptors('hsOfficeDebitor', 'hs_office_debitor');
|
|||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-debitor-rbac-ROLES-CREATION:1 endDelimiter:--//
|
--changeset hs-office-debitor-rbac-insert-trigger:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Creates and updates the roles and their assignments for debitor entities.
|
Creates the roles, grants and permission for the AFTER INSERT TRIGGER.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
create or replace function hsOfficeDebitorRbacRolesTrigger()
|
create or replace procedure buildRbacSystemForHsOfficeDebitor(
|
||||||
returns trigger
|
NEW hs_office_debitor
|
||||||
language plpgsql
|
)
|
||||||
strict as $$
|
language plpgsql as $$
|
||||||
|
|
||||||
declare
|
declare
|
||||||
hsOfficeDebitorTenant RbacRoleDescriptor;
|
newPartnerRel hs_office_relation;
|
||||||
oldPartner hs_office_partner;
|
newDebitorRel hs_office_relation;
|
||||||
newPartner hs_office_partner;
|
newRefundBankAccount hs_office_bankaccount;
|
||||||
newPerson hs_office_person;
|
|
||||||
oldContact hs_office_contact;
|
|
||||||
newContact hs_office_contact;
|
|
||||||
newBankAccount hs_office_bankaccount;
|
|
||||||
oldBankAccount hs_office_bankaccount;
|
|
||||||
begin
|
begin
|
||||||
call enterTriggerForObjectUuid(NEW.uuid);
|
call enterTriggerForObjectUuid(NEW.uuid);
|
||||||
|
|
||||||
hsOfficeDebitorTenant := hsOfficeDebitorTenant(NEW);
|
SELECT partnerRel.*
|
||||||
|
FROM hs_office_relation AS partnerRel
|
||||||
|
JOIN hs_office_relation AS debitorRel
|
||||||
|
ON debitorRel.type = 'DEBITOR' AND debitorRel.anchorUuid = partnerRel.holderUuid
|
||||||
|
WHERE partnerRel.type = 'PARTNER'
|
||||||
|
AND NEW.debitorRelUuid = debitorRel.uuid
|
||||||
|
INTO newPartnerRel;
|
||||||
|
assert newPartnerRel.uuid is not null, format('newPartnerRel must not be null for NEW.debitorRelUuid = %s', NEW.debitorRelUuid);
|
||||||
|
|
||||||
select * from hs_office_partner as p where p.uuid = NEW.partnerUuid into newPartner;
|
SELECT * FROM hs_office_relation WHERE uuid = NEW.debitorRelUuid INTO newDebitorRel;
|
||||||
select * from hs_office_person as p where p.uuid = newPartner.personUuid into newPerson;
|
assert newDebitorRel.uuid is not null, format('newDebitorRel must not be null for NEW.debitorRelUuid = %s', NEW.debitorRelUuid);
|
||||||
select * from hs_office_contact as c where c.uuid = NEW.billingContactUuid into newContact;
|
|
||||||
select * from hs_office_bankaccount as b where b.uuid = NEW.refundBankAccountUuid into newBankAccount;
|
|
||||||
if TG_OP = 'INSERT' then
|
|
||||||
|
|
||||||
|
SELECT * FROM hs_office_bankaccount WHERE uuid = NEW.refundBankAccountUuid INTO newRefundBankAccount;
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
call grantRoleToRole(hsOfficeBankAccountReferrer(newRefundBankAccount), hsOfficeRelationAgent(newDebitorRel));
|
||||||
hsOfficeDebitorOwner(NEW),
|
call grantRoleToRole(hsOfficeRelationAdmin(newDebitorRel), hsOfficeRelationAdmin(newPartnerRel));
|
||||||
permissions => array['DELETE'],
|
call grantRoleToRole(hsOfficeRelationAgent(newDebitorRel), hsOfficeBankAccountAdmin(newRefundBankAccount));
|
||||||
incomingSuperRoles => array[globalAdmin()],
|
call grantRoleToRole(hsOfficeRelationAgent(newDebitorRel), hsOfficeRelationAgent(newPartnerRel));
|
||||||
userUuids => array[currentUserUuid()],
|
call grantRoleToRole(hsOfficeRelationTenant(newPartnerRel), hsOfficeRelationAgent(newDebitorRel));
|
||||||
grantedByRole => globalAdmin()
|
|
||||||
);
|
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
call grantPermissionToRole(createPermission(NEW.uuid, 'DELETE'), hsOfficeRelationOwner(newDebitorRel));
|
||||||
hsOfficeDebitorAdmin(NEW),
|
call grantPermissionToRole(createPermission(NEW.uuid, 'SELECT'), hsOfficeRelationTenant(newDebitorRel));
|
||||||
permissions => array['UPDATE'],
|
call grantPermissionToRole(createPermission(NEW.uuid, 'UPDATE'), hsOfficeRelationAdmin(newDebitorRel));
|
||||||
incomingSuperRoles => array[hsOfficeDebitorOwner(NEW)]
|
|
||||||
);
|
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
|
||||||
hsOfficeDebitorAgent(NEW),
|
|
||||||
incomingSuperRoles => array[
|
|
||||||
hsOfficeDebitorAdmin(NEW),
|
|
||||||
hsOfficePartnerAdmin(newPartner),
|
|
||||||
hsOfficeContactAdmin(newContact)],
|
|
||||||
outgoingSubRoles => array[
|
|
||||||
hsOfficeBankAccountTenant(newBankaccount)]
|
|
||||||
);
|
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
|
||||||
hsOfficeDebitorTenant(NEW),
|
|
||||||
incomingSuperRoles => array[
|
|
||||||
hsOfficeDebitorAgent(NEW),
|
|
||||||
hsOfficePartnerAgent(newPartner),
|
|
||||||
hsOfficeBankAccountAdmin(newBankaccount)],
|
|
||||||
outgoingSubRoles => array[
|
|
||||||
hsOfficePartnerTenant(newPartner),
|
|
||||||
hsOfficeContactGuest(newContact),
|
|
||||||
hsOfficeBankAccountGuest(newBankaccount)]
|
|
||||||
);
|
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
|
||||||
hsOfficeDebitorGuest(NEW),
|
|
||||||
permissions => array['SELECT'],
|
|
||||||
incomingSuperRoles => array[
|
|
||||||
hsOfficeDebitorTenant(NEW)]
|
|
||||||
);
|
|
||||||
|
|
||||||
elsif TG_OP = 'UPDATE' then
|
|
||||||
|
|
||||||
if OLD.partnerUuid <> NEW.partnerUuid then
|
|
||||||
select * from hs_office_partner as p where p.uuid = OLD.partnerUuid into oldPartner;
|
|
||||||
|
|
||||||
call revokeRoleFromRole(hsOfficeDebitorAgent(OLD), hsOfficePartnerAdmin(oldPartner));
|
|
||||||
call grantRoleToRole(hsOfficeDebitorAgent(NEW), hsOfficePartnerAdmin(newPartner));
|
|
||||||
|
|
||||||
call revokeRoleFromRole(hsOfficeDebitorTenant(OLD), hsOfficePartnerAgent(oldPartner));
|
|
||||||
call grantRoleToRole(hsOfficeDebitorTenant(NEW), hsOfficePartnerAgent(newPartner));
|
|
||||||
|
|
||||||
call revokeRoleFromRole(hsOfficePartnerTenant(oldPartner), hsOfficeDebitorTenant(OLD));
|
|
||||||
call grantRoleToRole(hsOfficePartnerTenant(newPartner), hsOfficeDebitorTenant(NEW));
|
|
||||||
end if;
|
|
||||||
|
|
||||||
if OLD.billingContactUuid <> NEW.billingContactUuid then
|
|
||||||
select * from hs_office_contact as c where c.uuid = OLD.billingContactUuid into oldContact;
|
|
||||||
|
|
||||||
call revokeRoleFromRole(hsOfficeDebitorAgent(OLD), hsOfficeContactAdmin(oldContact));
|
|
||||||
call grantRoleToRole(hsOfficeDebitorAgent(NEW), hsOfficeContactAdmin(newContact));
|
|
||||||
|
|
||||||
call revokeRoleFromRole(hsOfficeContactGuest(oldContact), hsOfficeDebitorTenant(OLD));
|
|
||||||
call grantRoleToRole(hsOfficeContactGuest(newContact), hsOfficeDebitorTenant(NEW));
|
|
||||||
end if;
|
|
||||||
|
|
||||||
if (OLD.refundBankAccountUuid is not null or NEW.refundBankAccountUuid is not null) and
|
|
||||||
( OLD.refundBankAccountUuid is null or NEW.refundBankAccountUuid is null or
|
|
||||||
OLD.refundBankAccountUuid <> NEW.refundBankAccountUuid ) then
|
|
||||||
|
|
||||||
select * from hs_office_bankaccount as b where b.uuid = OLD.refundBankAccountUuid into oldBankAccount;
|
|
||||||
|
|
||||||
if oldBankAccount is not null then
|
|
||||||
call revokeRoleFromRole(hsOfficeBankAccountTenant(oldBankaccount), hsOfficeDebitorAgent(OLD));
|
|
||||||
end if;
|
|
||||||
if newBankAccount is not null then
|
|
||||||
call grantRoleToRole(hsOfficeBankAccountTenant(newBankaccount), hsOfficeDebitorAgent(NEW));
|
|
||||||
end if;
|
|
||||||
|
|
||||||
if oldBankAccount is not null then
|
|
||||||
call revokeRoleFromRole(hsOfficeDebitorTenant(OLD), hsOfficeBankAccountAdmin(oldBankaccount));
|
|
||||||
end if;
|
|
||||||
if newBankAccount is not null then
|
|
||||||
call grantRoleToRole(hsOfficeDebitorTenant(NEW), hsOfficeBankAccountAdmin(newBankaccount));
|
|
||||||
end if;
|
|
||||||
|
|
||||||
if oldBankAccount is not null then
|
|
||||||
call revokeRoleFromRole(hsOfficeBankAccountGuest(oldBankaccount), hsOfficeDebitorTenant(OLD));
|
|
||||||
end if;
|
|
||||||
if newBankAccount is not null then
|
|
||||||
call grantRoleToRole(hsOfficeBankAccountGuest(newBankaccount), hsOfficeDebitorTenant(NEW));
|
|
||||||
end if;
|
|
||||||
end if;
|
|
||||||
else
|
|
||||||
raise exception 'invalid usage of TRIGGER';
|
|
||||||
end if;
|
|
||||||
|
|
||||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||||
return NEW;
|
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
An AFTER INSERT TRIGGER which creates the role structure for a new debitor.
|
AFTER INSERT TRIGGER to create the role+grant structure for a new hs_office_debitor row.
|
||||||
*/
|
*/
|
||||||
create trigger createRbacRolesForHsOfficeDebitor_Trigger
|
|
||||||
after insert
|
|
||||||
on hs_office_debitor
|
|
||||||
for each row
|
|
||||||
execute procedure hsOfficeDebitorRbacRolesTrigger();
|
|
||||||
|
|
||||||
/*
|
create or replace function insertTriggerForHsOfficeDebitor_tf()
|
||||||
An AFTER UPDATE TRIGGER which updates the role structure of a debitor.
|
returns trigger
|
||||||
*/
|
language plpgsql
|
||||||
create trigger updateRbacRolesForHsOfficeDebitor_Trigger
|
strict as $$
|
||||||
after update
|
begin
|
||||||
on hs_office_debitor
|
call buildRbacSystemForHsOfficeDebitor(NEW);
|
||||||
|
return NEW;
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
create trigger insertTriggerForHsOfficeDebitor_tg
|
||||||
|
after insert on hs_office_debitor
|
||||||
for each row
|
for each row
|
||||||
execute procedure hsOfficeDebitorRbacRolesTrigger();
|
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 $$
|
||||||
|
begin
|
||||||
|
|
||||||
|
if NEW.debitorRelUuid is distinct from OLD.debitorRelUuid
|
||||||
|
or NEW.refundBankAccountUuid is distinct from OLD.refundBankAccountUuid then
|
||||||
|
delete from rbacgrants g where g.grantedbytriggerof = OLD.uuid;
|
||||||
|
call buildRbacSystemForHsOfficeDebitor(NEW);
|
||||||
|
end if;
|
||||||
|
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;
|
||||||
|
begin
|
||||||
|
call defineContext('create INSERT INTO hs_office_debitor permissions for the related global rows');
|
||||||
|
|
||||||
|
FOR row IN SELECT * FROM global
|
||||||
|
LOOP
|
||||||
|
call grantPermissionToRole(
|
||||||
|
createPermission(row.uuid, 'INSERT', 'hs_office_debitor'),
|
||||||
|
globalAdmin());
|
||||||
|
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:--//
|
--changeset hs-office-debitor-rbac-IDENTITY-VIEW:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
call generateRbacIdentityViewFromProjection('hs_office_debitor', $idName$
|
|
||||||
'#' ||
|
call generateRbacIdentityViewFromQuery('hs_office_debitor',
|
||||||
(select partnerNumber from hs_office_partner p where p.uuid = target.partnerUuid) ||
|
$idName$
|
||||||
to_char(debitorNumberSuffix, 'fm00') ||
|
SELECT debitor.uuid AS uuid,
|
||||||
':' || (select split_part(idName, ':', 2) from hs_office_partner_iv pi where pi.uuid = target.partnerUuid)
|
'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 debitorRel.type = 'DEBITOR'
|
||||||
|
WHERE debitorRel.uuid = debitor.debitorRelUuid)
|
||||||
|
|| to_char(debitorNumberSuffix, 'fm00') as idName
|
||||||
|
FROM hs_office_debitor AS debitor
|
||||||
$idName$);
|
$idName$);
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-debitor-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
|
--changeset hs-office-debitor-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
call generateRbacRestrictedView('hs_office_debitor', 'target.debitorNumberSuffix',
|
call generateRbacRestrictedView('hs_office_debitor',
|
||||||
|
$orderBy$
|
||||||
|
defaultPrefix
|
||||||
|
$orderBy$,
|
||||||
$updates$
|
$updates$
|
||||||
partnerUuid = new.partnerUuid, -- TODO: remove? should never do anything
|
debitorRelUuid = new.debitorRelUuid,
|
||||||
billable = new.billable,
|
billable = new.billable,
|
||||||
billingContactUuid = new.billingContactUuid,
|
|
||||||
debitorNumberSuffix = new.debitorNumberSuffix, -- TODO: Should it be allowed to updated this value?
|
|
||||||
refundBankAccountUuid = new.refundBankAccountUuid,
|
refundBankAccountUuid = new.refundBankAccountUuid,
|
||||||
vatId = new.vatId,
|
vatId = new.vatId,
|
||||||
vatCountryCode = new.vatCountryCode,
|
vatCountryCode = new.vatCountryCode,
|
||||||
vatBusiness = new.vatBusiness,
|
vatBusiness = new.vatBusiness,
|
||||||
vatreversecharge = new.vatreversecharge,
|
vatReverseCharge = new.vatReverseCharge,
|
||||||
defaultPrefix = new.defaultPrefix -- TODO: Should it be allowed to updated this value?
|
defaultPrefix = new.defaultPrefix
|
||||||
$updates$);
|
$updates$);
|
||||||
--//
|
--//
|
||||||
|
|
||||||
-- ============================================================================
|
|
||||||
--changeset hs-office-debitor-rbac-NEW-DEBITOR:1 endDelimiter:--//
|
|
||||||
-- ----------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
Creates a global permission for new-debitor and assigns it to the hostsharing admins role.
|
|
||||||
*/
|
|
||||||
do language plpgsql $$
|
|
||||||
declare
|
|
||||||
addDebitorPermissions uuid[];
|
|
||||||
globalObjectUuid uuid;
|
|
||||||
globalAdminRoleUuid uuid ;
|
|
||||||
begin
|
|
||||||
call defineContext('granting global new-debitor permission to global admin role', null, null, null);
|
|
||||||
|
|
||||||
globalAdminRoleUuid := findRoleId(globalAdmin());
|
|
||||||
globalObjectUuid := (select uuid from global);
|
|
||||||
addDebitorPermissions := createPermissions(globalObjectUuid, array ['new-debitor']);
|
|
||||||
call grantPermissionsToRole(globalAdminRoleUuid, addDebitorPermissions);
|
|
||||||
end;
|
|
||||||
$$;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Used by the trigger to prevent the add-debitor to current user respectively assumed roles.
|
|
||||||
*/
|
|
||||||
create or replace function addHsOfficeDebitorNotAllowedForCurrentSubjects()
|
|
||||||
returns trigger
|
|
||||||
language PLPGSQL
|
|
||||||
as $$
|
|
||||||
begin
|
|
||||||
raise exception '[403] new-debitor not permitted for %',
|
|
||||||
array_to_string(currentSubjects(), ';', 'null');
|
|
||||||
end; $$;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Checks if the user or assumed roles are allowed to create a new debitor.
|
|
||||||
*/
|
|
||||||
create trigger hs_office_debitor_insert_trigger
|
|
||||||
before insert
|
|
||||||
on hs_office_debitor
|
|
||||||
for each row
|
|
||||||
-- TODO.spec: who is allowed to create new debitors
|
|
||||||
when ( not hasAssumedRole() )
|
|
||||||
execute procedure addHsOfficeDebitorNotAllowedForCurrentSubjects();
|
|
||||||
--//
|
|
||||||
|
|
||||||
|
@ -9,36 +9,41 @@
|
|||||||
Creates a single debitor test record.
|
Creates a single debitor test record.
|
||||||
*/
|
*/
|
||||||
create or replace procedure createHsOfficeDebitorTestData(
|
create or replace procedure createHsOfficeDebitorTestData(
|
||||||
debitorNumberSuffix numeric(5),
|
withDebitorNumberSuffix numeric(5),
|
||||||
partnerTradeName varchar,
|
forPartnerPersonName varchar,
|
||||||
billingContactLabel varchar,
|
forBillingContactLabel varchar,
|
||||||
defaultPrefix varchar
|
withDefaultPrefix varchar
|
||||||
)
|
)
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
declare
|
declare
|
||||||
currentTask varchar;
|
currentTask varchar;
|
||||||
idName varchar;
|
idName varchar;
|
||||||
relatedPartner hs_office_partner;
|
relatedDebitorRelUuid uuid;
|
||||||
relatedContact hs_office_contact;
|
|
||||||
relatedBankAccountUuid uuid;
|
relatedBankAccountUuid uuid;
|
||||||
begin
|
begin
|
||||||
idName := cleanIdentifier( partnerTradeName|| '-' || billingContactLabel);
|
idName := cleanIdentifier( forPartnerPersonName|| '-' || forBillingContactLabel);
|
||||||
currentTask := 'creating debitor test-data ' || idName;
|
currentTask := 'creating debitor test-data ' || idName;
|
||||||
call defineContext(currentTask, null, 'superuser-alex@hostsharing.net', 'global#global.admin');
|
call defineContext(currentTask, null, 'superuser-alex@hostsharing.net', 'global#global.admin');
|
||||||
execute format('set local hsadminng.currentTask to %L', currentTask);
|
execute format('set local hsadminng.currentTask to %L', currentTask);
|
||||||
|
|
||||||
select partner.* from hs_office_partner partner
|
select debitorRel.uuid
|
||||||
join hs_office_person person on person.uuid = partner.personUuid
|
into relatedDebitorRelUuid
|
||||||
where person.tradeName = partnerTradeName into relatedPartner;
|
from hs_office_relation debitorRel
|
||||||
select c.* from hs_office_contact c where c.label = billingContactLabel into relatedContact;
|
join hs_office_person person on person.uuid = debitorRel.holderUuid
|
||||||
select b.uuid from hs_office_bankaccount b where b.holder = partnerTradeName into relatedBankAccountUuid;
|
and (person.tradeName = forPartnerPersonName or person.familyName = forPartnerPersonName)
|
||||||
|
where debitorRel.type = 'DEBITOR';
|
||||||
|
|
||||||
raise notice 'creating test debitor: % (#%)', idName, debitorNumberSuffix;
|
select b.uuid
|
||||||
raise notice '- using partner (%): %', relatedPartner.uuid, relatedPartner;
|
into relatedBankAccountUuid
|
||||||
raise notice '- using billingContact (%): %', relatedContact.uuid, relatedContact;
|
from hs_office_bankaccount b
|
||||||
|
where b.holder = forPartnerPersonName;
|
||||||
|
|
||||||
|
raise notice 'creating test debitor: % (#%)', idName, withDebitorNumberSuffix;
|
||||||
|
-- raise exception 'creating test debitor: (uuid=%, debitorRelUuid=%, debitornumbersuffix=%, billable=%, vatbusiness=%, vatreversecharge=%, refundbankaccountuuid=%, defaultprefix=%)',
|
||||||
|
-- uuid_generate_v4(), relatedDebitorRelUuid, withDebitorNumberSuffix, true, true, false, relatedBankAccountUuid, withDefaultPrefix;
|
||||||
insert
|
insert
|
||||||
into hs_office_debitor (uuid, partneruuid, debitornumbersuffix, billable, billingcontactuuid, vatbusiness, vatreversecharge, refundbankaccountuuid, defaultprefix)
|
into hs_office_debitor (uuid, debitorRelUuid, debitornumbersuffix, billable, vatbusiness, vatreversecharge, refundbankaccountuuid, defaultprefix)
|
||||||
values (uuid_generate_v4(), relatedPartner.uuid, debitorNumberSuffix, true, relatedContact.uuid, true, false, relatedBankAccountUuid, defaultPrefix);
|
values (uuid_generate_v4(), relatedDebitorRelUuid, withDebitorNumberSuffix, true, true, false, relatedBankAccountUuid, withDefaultPrefix);
|
||||||
end; $$;
|
end; $$;
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
@ -12,7 +12,6 @@ create table if not exists hs_office_membership
|
|||||||
(
|
(
|
||||||
uuid uuid unique references RbacObject (uuid) initially deferred,
|
uuid uuid unique references RbacObject (uuid) initially deferred,
|
||||||
partnerUuid uuid not null references hs_office_partner(uuid),
|
partnerUuid uuid not null references hs_office_partner(uuid),
|
||||||
mainDebitorUuid uuid not null references hs_office_debitor(uuid),
|
|
||||||
memberNumberSuffix char(2) not null check (
|
memberNumberSuffix char(2) not null check (
|
||||||
memberNumberSuffix::text ~ '^[0-9][0-9]$'),
|
memberNumberSuffix::text ~ '^[0-9][0-9]$'),
|
||||||
validity daterange not null,
|
validity daterange not null,
|
||||||
|
@ -1,75 +1,159 @@
|
|||||||
### hs_office_membership RBAC
|
### rbac membership
|
||||||
|
|
||||||
|
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
|
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||||
flowchart TB
|
flowchart TB
|
||||||
|
|
||||||
subgraph global
|
subgraph partnerRel["`**partnerRel**`"]
|
||||||
style global fill:#eee
|
|
||||||
|
|
||||||
role:global.admin[global.admin]
|
|
||||||
end
|
|
||||||
|
|
||||||
subgraph hsOfficeDebitor
|
|
||||||
direction TB
|
direction TB
|
||||||
style hsOfficeDebitor fill:#eee
|
style partnerRel fill:#99bcdb,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
role:hsOfficeDebitor.owner[debitor.owner]
|
subgraph partnerRel.contact["`**partnerRel.contact**`"]
|
||||||
--> role:hsOfficeDebitor.admin[debitor.admin]
|
|
||||||
--> role:hsOfficeDebitor.tenant[debitor.tenant]
|
|
||||||
--> role:hsOfficeDebitor.guest[debitor.guest]
|
|
||||||
end
|
|
||||||
|
|
||||||
subgraph hsOfficePartner
|
|
||||||
direction TB
|
direction TB
|
||||||
style hsOfficePartner fill:#eee
|
style partnerRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
role:hsOfficePartner.owner[partner.admin]
|
subgraph partnerRel.contact:roles[ ]
|
||||||
--> role:hsOfficePartner.admin[partner.admin]
|
style partnerRel.contact:roles fill:#99bcdb,stroke:white
|
||||||
--> role:hsOfficePartner.agent[partner.agent]
|
|
||||||
--> role:hsOfficePartner.tenant[partner.tenant]
|
role:partnerRel.contact:owner[[partnerRel.contact:owner]]
|
||||||
--> role:hsOfficePartner.guest[partner.guest]
|
role:partnerRel.contact:admin[[partnerRel.contact:admin]]
|
||||||
|
role:partnerRel.contact:referrer[[partnerRel.contact:referrer]]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
subgraph hsOfficeMembership
|
subgraph partnerRel.anchorPerson["`**partnerRel.anchorPerson**`"]
|
||||||
|
direction TB
|
||||||
|
style partnerRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
role:hsOfficeMembership.owner[membership.owner]
|
subgraph partnerRel.anchorPerson:roles[ ]
|
||||||
%% permissions
|
style partnerRel.anchorPerson:roles fill:#99bcdb,stroke:white
|
||||||
role:hsOfficeMembership.owner --> perm:hsOfficeMembership.*{{membership.*}}
|
|
||||||
%% incoming
|
|
||||||
role:global.admin ---> role:hsOfficeMembership.owner
|
|
||||||
|
|
||||||
role:hsOfficeMembership.admin[membership.admin]
|
role:partnerRel.anchorPerson:owner[[partnerRel.anchorPerson:owner]]
|
||||||
%% permissions
|
role:partnerRel.anchorPerson:admin[[partnerRel.anchorPerson:admin]]
|
||||||
role:hsOfficeMembership.admin --> perm:hsOfficeMembership.edit{{membership.edit}}
|
role:partnerRel.anchorPerson:referrer[[partnerRel.anchorPerson:referrer]]
|
||||||
%% incoming
|
end
|
||||||
role:hsOfficeMembership.owner ---> role:hsOfficeMembership.admin
|
|
||||||
|
|
||||||
role:hsOfficeMembership.agent[membership.agent]
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeMembership.admin ---> role:hsOfficeMembership.agent
|
|
||||||
role:hsOfficePartner.admin --> role:hsOfficeMembership.agent
|
|
||||||
role:hsOfficeDebitor.admin --> role:hsOfficeMembership.agent
|
|
||||||
%% outgoing
|
|
||||||
role:hsOfficeMembership.agent --> role:hsOfficePartner.tenant
|
|
||||||
role:hsOfficeMembership.agent --> role:hsOfficeDebitor.tenant
|
|
||||||
|
|
||||||
role:hsOfficeMembership.tenant[membership.tenant]
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeMembership.agent --> role:hsOfficeMembership.tenant
|
|
||||||
role:hsOfficePartner.agent --> role:hsOfficeMembership.tenant
|
|
||||||
role:hsOfficeDebitor.agent --> role:hsOfficeMembership.tenant
|
|
||||||
%% outgoing
|
|
||||||
role:hsOfficeMembership.tenant --> role:hsOfficePartner.guest
|
|
||||||
role:hsOfficeMembership.tenant --> role:hsOfficeDebitor.guest
|
|
||||||
|
|
||||||
role:hsOfficeMembership.guest[membership.guest]
|
|
||||||
%% permissions
|
|
||||||
role:hsOfficeMembership.guest --> perm:hsOfficeMembership.view{{membership.view}}
|
|
||||||
%% incoming
|
|
||||||
role:hsOfficeMembership.tenant --> role:hsOfficeMembership.guest
|
|
||||||
role:hsOfficePartner.tenant --> role:hsOfficeMembership.guest
|
|
||||||
role:hsOfficeDebitor.tenant --> role:hsOfficeMembership.guest
|
|
||||||
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
|
||||||
|
|
||||||
|
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 membership["`**membership**`"]
|
||||||
|
direction TB
|
||||||
|
style membership fill:#dd4901,stroke:#274d6e,stroke-width:8px
|
||||||
|
|
||||||
|
subgraph membership:roles[ ]
|
||||||
|
style membership:roles fill:#dd4901,stroke:white
|
||||||
|
|
||||||
|
role:membership:owner[[membership:owner]]
|
||||||
|
role:membership:admin[[membership:admin]]
|
||||||
|
role:membership:referrer[[membership:referrer]]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph membership:permissions[ ]
|
||||||
|
style membership:permissions fill:#dd4901,stroke:white
|
||||||
|
|
||||||
|
perm:membership:INSERT{{membership:INSERT}}
|
||||||
|
perm:membership:DELETE{{membership:DELETE}}
|
||||||
|
perm:membership:UPDATE{{membership:UPDATE}}
|
||||||
|
perm:membership:SELECT{{membership: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 users
|
||||||
|
user:creator ==> role:membership:owner
|
||||||
|
|
||||||
|
%% 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
|
||||||
|
role:partnerRel:admin ==> role:membership:owner
|
||||||
|
role:membership:owner ==> role:membership:admin
|
||||||
|
role:partnerRel:agent ==> role:membership:admin
|
||||||
|
role:membership:admin ==> role:membership:referrer
|
||||||
|
role:membership:referrer ==> role:partnerRel:tenant
|
||||||
|
|
||||||
|
%% granting permissions to roles
|
||||||
|
role:global:admin ==> perm:membership:INSERT
|
||||||
|
role:membership:owner ==> perm:membership:DELETE
|
||||||
|
role:membership:admin ==> perm:membership:UPDATE
|
||||||
|
role:membership:referrer ==> perm:membership:SELECT
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
|
-- This code generated was by RbacViewPostgresGenerator, do not amend manually.
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-membership-rbac-OBJECT:1 endDelimiter:--//
|
--changeset hs-office-membership-rbac-OBJECT:1 endDelimiter:--//
|
||||||
@ -15,148 +17,162 @@ call generateRbacRoleDescriptors('hsOfficeMembership', 'hs_office_membership');
|
|||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-membership-rbac-ROLES-CREATION:1 endDelimiter:--//
|
--changeset hs-office-membership-rbac-insert-trigger:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Creates and updates the roles and their assignments for membership entities.
|
Creates the roles, grants and permission for the AFTER INSERT TRIGGER.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
create or replace function hsOfficeMembershipRbacRolesTrigger()
|
create or replace procedure buildRbacSystemForHsOfficeMembership(
|
||||||
returns trigger
|
NEW hs_office_membership
|
||||||
language plpgsql
|
)
|
||||||
strict as $$
|
language plpgsql as $$
|
||||||
|
|
||||||
declare
|
declare
|
||||||
newHsOfficePartner hs_office_partner;
|
newPartnerRel hs_office_relation;
|
||||||
newHsOfficeDebitor hs_office_debitor;
|
|
||||||
begin
|
begin
|
||||||
call enterTriggerForObjectUuid(NEW.uuid);
|
call enterTriggerForObjectUuid(NEW.uuid);
|
||||||
|
|
||||||
select * from hs_office_partner as p where p.uuid = NEW.partnerUuid into newHsOfficePartner;
|
SELECT partnerRel.*
|
||||||
select * from hs_office_debitor as c where c.uuid = NEW.mainDebitorUuid into newHsOfficeDebitor;
|
FROM hs_office_partner AS partner
|
||||||
|
JOIN hs_office_relation AS partnerRel ON partnerRel.uuid = partner.partnerRelUuid
|
||||||
|
WHERE partner.uuid = NEW.partnerUuid
|
||||||
|
INTO newPartnerRel;
|
||||||
|
assert newPartnerRel.uuid is not null, format('newPartnerRel must not be null for NEW.partnerUuid = %s', NEW.partnerUuid);
|
||||||
|
|
||||||
if TG_OP = 'INSERT' then
|
|
||||||
|
|
||||||
-- === ATTENTION: code generated from related Mermaid flowchart: ===
|
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficeMembershipOwner(NEW),
|
hsOfficeMembershipOwner(NEW),
|
||||||
permissions => array['DELETE'],
|
permissions => array['DELETE'],
|
||||||
incomingSuperRoles => array[globalAdmin()]
|
incomingSuperRoles => array[hsOfficeRelationAdmin(newPartnerRel)],
|
||||||
|
userUuids => array[currentUserUuid()]
|
||||||
);
|
);
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficeMembershipAdmin(NEW),
|
hsOfficeMembershipAdmin(NEW),
|
||||||
permissions => array['UPDATE'],
|
permissions => array['UPDATE'],
|
||||||
incomingSuperRoles => array[hsOfficeMembershipOwner(NEW)]
|
incomingSuperRoles => array[
|
||||||
|
hsOfficeMembershipOwner(NEW),
|
||||||
|
hsOfficeRelationAgent(newPartnerRel)]
|
||||||
);
|
);
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficeMembershipAgent(NEW),
|
hsOfficeMembershipReferrer(NEW),
|
||||||
incomingSuperRoles => array[hsOfficeMembershipAdmin(NEW), hsOfficePartnerAdmin(newHsOfficePartner), hsOfficeDebitorAdmin(newHsOfficeDebitor)],
|
|
||||||
outgoingSubRoles => array[hsOfficePartnerTenant(newHsOfficePartner), hsOfficeDebitorTenant(newHsOfficeDebitor)]
|
|
||||||
);
|
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
|
||||||
hsOfficeMembershipTenant(NEW),
|
|
||||||
incomingSuperRoles => array[hsOfficeMembershipAgent(NEW), hsOfficePartnerAgent(newHsOfficePartner), hsOfficeDebitorAgent(newHsOfficeDebitor)],
|
|
||||||
outgoingSubRoles => array[hsOfficePartnerGuest(newHsOfficePartner), hsOfficeDebitorGuest(newHsOfficeDebitor)]
|
|
||||||
);
|
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
|
||||||
hsOfficeMembershipGuest(NEW),
|
|
||||||
permissions => array['SELECT'],
|
permissions => array['SELECT'],
|
||||||
incomingSuperRoles => array[hsOfficeMembershipTenant(NEW), hsOfficePartnerTenant(newHsOfficePartner), hsOfficeDebitorTenant(newHsOfficeDebitor)]
|
incomingSuperRoles => array[hsOfficeMembershipAdmin(NEW)],
|
||||||
|
outgoingSubRoles => array[hsOfficeRelationTenant(newPartnerRel)]
|
||||||
);
|
);
|
||||||
|
|
||||||
-- === END of code generated from Mermaid flowchart. ===
|
|
||||||
|
|
||||||
else
|
|
||||||
raise exception 'invalid usage of TRIGGER';
|
|
||||||
end if;
|
|
||||||
|
|
||||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||||
return NEW;
|
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
An AFTER INSERT TRIGGER which creates the role structure for a new customer.
|
AFTER INSERT TRIGGER to create the role+grant structure for a new hs_office_membership row.
|
||||||
*/
|
*/
|
||||||
create trigger createRbacRolesForHsOfficeMembership_Trigger
|
|
||||||
after insert
|
create or replace function insertTriggerForHsOfficeMembership_tf()
|
||||||
on hs_office_membership
|
returns trigger
|
||||||
|
language plpgsql
|
||||||
|
strict as $$
|
||||||
|
begin
|
||||||
|
call buildRbacSystemForHsOfficeMembership(NEW);
|
||||||
|
return NEW;
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
create trigger insertTriggerForHsOfficeMembership_tg
|
||||||
|
after insert on hs_office_membership
|
||||||
for each row
|
for each row
|
||||||
execute procedure hsOfficeMembershipRbacRolesTrigger();
|
execute procedure insertTriggerForHsOfficeMembership_tf();
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-membership-rbac-IDENTITY-VIEW:1 endDelimiter:--//
|
--changeset hs-office-membership-rbac-INSERT:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
call generateRbacIdentityViewFromProjection('hs_office_membership', $idName$
|
|
||||||
'#' ||
|
/*
|
||||||
(select partnerNumber from hs_office_partner p where p.uuid = target.partnerUuid) ||
|
Creates INSERT INTO hs_office_membership permissions for the related global rows.
|
||||||
memberNumberSuffix ||
|
*/
|
||||||
':' || (select split_part(idName, ':', 2) from hs_office_partner_iv p where p.uuid = target.partnerUuid)
|
do language plpgsql $$
|
||||||
$idName$);
|
declare
|
||||||
|
row global;
|
||||||
|
begin
|
||||||
|
call defineContext('create INSERT INTO hs_office_membership permissions for the related global rows');
|
||||||
|
|
||||||
|
FOR row IN SELECT * FROM global
|
||||||
|
LOOP
|
||||||
|
call grantPermissionToRole(
|
||||||
|
createPermission(row.uuid, 'INSERT', 'hs_office_membership'),
|
||||||
|
globalAdmin());
|
||||||
|
END LOOP;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Adds hs_office_membership INSERT permission to specified role of new global rows.
|
||||||
|
*/
|
||||||
|
create or replace function hs_office_membership_global_insert_tf()
|
||||||
|
returns trigger
|
||||||
|
language plpgsql
|
||||||
|
strict as $$
|
||||||
|
begin
|
||||||
|
call grantPermissionToRole(
|
||||||
|
createPermission(NEW.uuid, 'INSERT', 'hs_office_membership'),
|
||||||
|
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_membership_global_insert_tg
|
||||||
|
after insert on global
|
||||||
|
for each row
|
||||||
|
execute procedure hs_office_membership_global_insert_tf();
|
||||||
|
|
||||||
|
/**
|
||||||
|
Checks if the user or assumed roles are allowed to insert a row to hs_office_membership,
|
||||||
|
where only global-admin has that permission.
|
||||||
|
*/
|
||||||
|
create or replace function hs_office_membership_insert_permission_missing_tf()
|
||||||
|
returns trigger
|
||||||
|
language plpgsql as $$
|
||||||
|
begin
|
||||||
|
raise exception '[403] insert into hs_office_membership not allowed for current subjects % (%)',
|
||||||
|
currentSubjects(), currentSubjectsUuids();
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
create trigger hs_office_membership_insert_permission_check_tg
|
||||||
|
before insert on hs_office_membership
|
||||||
|
for each row
|
||||||
|
when ( not isGlobalAdmin() )
|
||||||
|
execute procedure hs_office_membership_insert_permission_missing_tf();
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
--changeset hs-office-membership-rbac-IDENTITY-VIEW:1 endDelimiter:--//
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
call generateRbacIdentityViewFromQuery('hs_office_membership',
|
||||||
|
$idName$
|
||||||
|
SELECT m.uuid AS uuid,
|
||||||
|
'M-' || p.partnerNumber || m.memberNumberSuffix as idName
|
||||||
|
FROM hs_office_membership AS m
|
||||||
|
JOIN hs_office_partner AS p ON p.uuid = m.partnerUuid
|
||||||
|
$idName$);
|
||||||
|
--//
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset hs-office-membership-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
|
--changeset hs-office-membership-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
call generateRbacRestrictedView('hs_office_membership',
|
call generateRbacRestrictedView('hs_office_membership',
|
||||||
orderby => 'target.memberNumberSuffix',
|
$orderBy$
|
||||||
columnUpdates => $updates$
|
validity
|
||||||
|
$orderBy$,
|
||||||
|
$updates$
|
||||||
validity = new.validity,
|
validity = new.validity,
|
||||||
reasonForTermination = new.reasonForTermination,
|
membershipFeeBillable = new.membershipFeeBillable,
|
||||||
membershipFeeBillable = new.membershipFeeBillable
|
reasonForTermination = new.reasonForTermination
|
||||||
$updates$);
|
$updates$);
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
|
||||||
--changeset hs-office-membership-rbac-NEW-Membership:1 endDelimiter:--//
|
|
||||||
-- ----------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
Creates a global permission for new-membership and assigns it to the hostsharing admins role.
|
|
||||||
*/
|
|
||||||
do language plpgsql $$
|
|
||||||
declare
|
|
||||||
addCustomerPermissions uuid[];
|
|
||||||
globalObjectUuid uuid;
|
|
||||||
globalAdminRoleUuid uuid ;
|
|
||||||
begin
|
|
||||||
call defineContext('granting global new-membership permission to global admin role', null, null, null);
|
|
||||||
|
|
||||||
globalAdminRoleUuid := findRoleId(globalAdmin());
|
|
||||||
globalObjectUuid := (select uuid from global);
|
|
||||||
addCustomerPermissions := createPermissions(globalObjectUuid, array ['new-membership']);
|
|
||||||
call grantPermissionsToRole(globalAdminRoleUuid, addCustomerPermissions);
|
|
||||||
end;
|
|
||||||
$$;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Used by the trigger to prevent the add-customer to current user respectively assumed roles.
|
|
||||||
*/
|
|
||||||
create or replace function addHsOfficeMembershipNotAllowedForCurrentSubjects()
|
|
||||||
returns trigger
|
|
||||||
language PLPGSQL
|
|
||||||
as $$
|
|
||||||
begin
|
|
||||||
raise exception '[403] new-membership not permitted for %',
|
|
||||||
array_to_string(currentSubjects(), ';', 'null');
|
|
||||||
end; $$;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Checks if the user or assumed roles are allowed to create a new customer.
|
|
||||||
*/
|
|
||||||
create trigger hs_office_membership_insert_trigger
|
|
||||||
before insert
|
|
||||||
on hs_office_membership
|
|
||||||
for each row
|
|
||||||
-- TODO.spec: who is allowed to create new memberships
|
|
||||||
when ( not hasAssumedRole() )
|
|
||||||
execute procedure addHsOfficeMembershipNotAllowedForCurrentSubjects();
|
|
||||||
--//
|
|
||||||
|
|
||||||
|
@ -9,35 +9,27 @@
|
|||||||
Creates a single membership test record.
|
Creates a single membership test record.
|
||||||
*/
|
*/
|
||||||
create or replace procedure createHsOfficeMembershipTestData(
|
create or replace procedure createHsOfficeMembershipTestData(
|
||||||
forPartnerTradeName varchar,
|
forPartnerNumber numeric(5),
|
||||||
forMainDebitorNumberSuffix numeric,
|
|
||||||
newMemberNumberSuffix char(2) )
|
newMemberNumberSuffix char(2) )
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
declare
|
declare
|
||||||
currentTask varchar;
|
currentTask varchar;
|
||||||
idName varchar;
|
|
||||||
relatedPartner hs_office_partner;
|
relatedPartner hs_office_partner;
|
||||||
relatedDebitor hs_office_debitor;
|
|
||||||
begin
|
begin
|
||||||
idName := cleanIdentifier( forPartnerTradeName || '#' || forMainDebitorNumberSuffix);
|
currentTask := 'creating Membership test-data ' ||
|
||||||
currentTask := 'creating Membership test-data ' || idName;
|
'P-' || forPartnerNumber::text ||
|
||||||
|
'M-...' || newMemberNumberSuffix;
|
||||||
call defineContext(currentTask, null, 'superuser-alex@hostsharing.net', 'global#global.admin');
|
call defineContext(currentTask, null, 'superuser-alex@hostsharing.net', 'global#global.admin');
|
||||||
execute format('set local hsadminng.currentTask to %L', currentTask);
|
execute format('set local hsadminng.currentTask to %L', currentTask);
|
||||||
|
|
||||||
select partner.* from hs_office_partner partner
|
select partner.* from hs_office_partner partner
|
||||||
join hs_office_person person on person.uuid = partner.personUuid
|
where partner.partnerNumber = forPartnerNumber into relatedPartner;
|
||||||
where person.tradeName = forPartnerTradeName into relatedPartner;
|
|
||||||
select d.* from hs_office_debitor d
|
|
||||||
where d.partneruuid = relatedPartner.uuid
|
|
||||||
and d.debitorNumberSuffix = forMainDebitorNumberSuffix
|
|
||||||
into relatedDebitor;
|
|
||||||
|
|
||||||
raise notice 'creating test Membership: %', idName;
|
raise notice 'creating test Membership: M-% %', forPartnerNumber, newMemberNumberSuffix;
|
||||||
raise notice '- using partner (%): %', relatedPartner.uuid, relatedPartner;
|
raise notice '- using partner (%): %', relatedPartner.uuid, relatedPartner;
|
||||||
raise notice '- using debitor (%): %', relatedDebitor.uuid, relatedDebitor;
|
|
||||||
insert
|
insert
|
||||||
into hs_office_membership (uuid, partneruuid, maindebitoruuid, memberNumberSuffix, validity, reasonfortermination)
|
into hs_office_membership (uuid, partneruuid, memberNumberSuffix, validity, reasonfortermination)
|
||||||
values (uuid_generate_v4(), relatedPartner.uuid, relatedDebitor.uuid, newMemberNumberSuffix, daterange('20221001' , null, '[]'), 'NONE');
|
values (uuid_generate_v4(), relatedPartner.uuid, newMemberNumberSuffix, daterange('20221001' , null, '[]'), 'NONE');
|
||||||
end; $$;
|
end; $$;
|
||||||
--//
|
--//
|
||||||
|
|
||||||
@ -48,9 +40,9 @@ end; $$;
|
|||||||
|
|
||||||
do language plpgsql $$
|
do language plpgsql $$
|
||||||
begin
|
begin
|
||||||
call createHsOfficeMembershipTestData('First GmbH', 11, '01');
|
call createHsOfficeMembershipTestData(10001, '01');
|
||||||
call createHsOfficeMembershipTestData('Second e.K.', 12, '02');
|
call createHsOfficeMembershipTestData(10002, '02');
|
||||||
call createHsOfficeMembershipTestData('Third OHG', 13, '03');
|
call createHsOfficeMembershipTestData(10003, '03');
|
||||||
end;
|
end;
|
||||||
$$;
|
$$;
|
||||||
--//
|
--//
|
||||||
|
@ -42,7 +42,7 @@ begin
|
|||||||
|
|
||||||
-- coopsharestransactions cannot be edited nor deleted, just created+viewed
|
-- coopsharestransactions cannot be edited nor deleted, just created+viewed
|
||||||
call grantPermissionsToRole(
|
call grantPermissionsToRole(
|
||||||
getRoleId(hsOfficeMembershipTenant(newHsOfficeMembership)),
|
getRoleId(hsOfficeMembershipReferrer(newHsOfficeMembership)),
|
||||||
createPermissions(NEW.uuid, array ['SELECT'])
|
createPermissions(NEW.uuid, array ['SELECT'])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ begin
|
|||||||
|
|
||||||
-- coopassetstransactions cannot be edited nor deleted, just created+viewed
|
-- coopassetstransactions cannot be edited nor deleted, just created+viewed
|
||||||
call grantPermissionsToRole(
|
call grantPermissionsToRole(
|
||||||
getRoleId(hsOfficeMembershipTenant(newHsOfficeMembership)),
|
getRoleId(hsOfficeMembershipReferrer(newHsOfficeMembership)),
|
||||||
createPermissions(NEW.uuid, array ['SELECT'])
|
createPermissions(NEW.uuid, array ['SELECT'])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -129,7 +129,8 @@ public class ArchitectureTest {
|
|||||||
public static final ArchRule hsOfficeBankAccountPackageRule = classes()
|
public static final ArchRule hsOfficeBankAccountPackageRule = classes()
|
||||||
.that().resideInAPackage("..hs.office.bankaccount..")
|
.that().resideInAPackage("..hs.office.bankaccount..")
|
||||||
.should().onlyBeAccessed().byClassesThat()
|
.should().onlyBeAccessed().byClassesThat()
|
||||||
.resideInAnyPackage("..hs.office.bankaccount..",
|
.resideInAnyPackage(
|
||||||
|
"..hs.office.bankaccount..",
|
||||||
"..hs.office.sepamandate..",
|
"..hs.office.sepamandate..",
|
||||||
"..hs.office.debitor..",
|
"..hs.office.debitor..",
|
||||||
"..hs.office.migration..");
|
"..hs.office.migration..");
|
||||||
@ -139,7 +140,8 @@ public class ArchitectureTest {
|
|||||||
public static final ArchRule hsOfficeSepaMandatePackageRule = classes()
|
public static final ArchRule hsOfficeSepaMandatePackageRule = classes()
|
||||||
.that().resideInAPackage("..hs.office.sepamandate..")
|
.that().resideInAPackage("..hs.office.sepamandate..")
|
||||||
.should().onlyBeAccessed().byClassesThat()
|
.should().onlyBeAccessed().byClassesThat()
|
||||||
.resideInAnyPackage("..hs.office.sepamandate..",
|
.resideInAnyPackage(
|
||||||
|
"..hs.office.sepamandate..",
|
||||||
"..hs.office.debitor..",
|
"..hs.office.debitor..",
|
||||||
"..hs.office.migration..");
|
"..hs.office.migration..");
|
||||||
|
|
||||||
@ -148,7 +150,9 @@ public class ArchitectureTest {
|
|||||||
public static final ArchRule hsOfficeContactPackageRule = classes()
|
public static final ArchRule hsOfficeContactPackageRule = classes()
|
||||||
.that().resideInAPackage("..hs.office.contact..")
|
.that().resideInAPackage("..hs.office.contact..")
|
||||||
.should().onlyBeAccessed().byClassesThat()
|
.should().onlyBeAccessed().byClassesThat()
|
||||||
.resideInAnyPackage("..hs.office.contact..", "..hs.office.relation..",
|
.resideInAnyPackage(
|
||||||
|
"..hs.office.contact..",
|
||||||
|
"..hs.office.relation..",
|
||||||
"..hs.office.partner..",
|
"..hs.office.partner..",
|
||||||
"..hs.office.debitor..",
|
"..hs.office.debitor..",
|
||||||
"..hs.office.membership..",
|
"..hs.office.membership..",
|
||||||
@ -159,37 +163,46 @@ public class ArchitectureTest {
|
|||||||
public static final ArchRule hsOfficePersonPackageRule = classes()
|
public static final ArchRule hsOfficePersonPackageRule = classes()
|
||||||
.that().resideInAPackage("..hs.office.person..")
|
.that().resideInAPackage("..hs.office.person..")
|
||||||
.should().onlyBeAccessed().byClassesThat()
|
.should().onlyBeAccessed().byClassesThat()
|
||||||
.resideInAnyPackage("..hs.office.person..", "..hs.office.relation..",
|
.resideInAnyPackage(
|
||||||
|
"..hs.office.person..",
|
||||||
|
"..hs.office.relation..",
|
||||||
"..hs.office.partner..",
|
"..hs.office.partner..",
|
||||||
"..hs.office.debitor..",
|
"..hs.office.debitor..",
|
||||||
"..hs.office.membership..",
|
"..hs.office.membership..",
|
||||||
"..hs.office.migration..");
|
"..hs.office.migration..")
|
||||||
|
.orShould().haveNameNotMatching(".*Test$");
|
||||||
|
|
||||||
|
|
||||||
@ArchTest
|
@ArchTest
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static final ArchRule hsOfficeRelationPackageRule = classes()
|
public static final ArchRule hsOfficeRelationPackageRule = classes()
|
||||||
.that().resideInAPackage("..hs.office.relation..")
|
.that().resideInAPackage("..hs.office.relation..")
|
||||||
.should().onlyBeAccessed().byClassesThat()
|
.should().onlyBeAccessed().byClassesThat()
|
||||||
.resideInAnyPackage("..hs.office.relation..",
|
.resideInAnyPackage(
|
||||||
|
"..hs.office.relation..",
|
||||||
"..hs.office.partner..",
|
"..hs.office.partner..",
|
||||||
"..hs.office.migration..");
|
"..hs.office.migration..")
|
||||||
|
.orShould().haveNameNotMatching(".*Test$");
|
||||||
|
|
||||||
@ArchTest
|
@ArchTest
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static final ArchRule hsOfficePartnerPackageRule = classes()
|
public static final ArchRule hsOfficePartnerPackageRule = classes()
|
||||||
.that().resideInAPackage("..hs.office.partner..")
|
.that().resideInAPackage("..hs.office.partner..")
|
||||||
.should().onlyBeAccessed().byClassesThat()
|
.should().onlyBeAccessed().byClassesThat()
|
||||||
.resideInAnyPackage("..hs.office.partner..",
|
.resideInAnyPackage(
|
||||||
|
"..hs.office.partner..",
|
||||||
"..hs.office.debitor..",
|
"..hs.office.debitor..",
|
||||||
"..hs.office.membership..",
|
"..hs.office.membership..",
|
||||||
"..hs.office.migration..");
|
"..hs.office.migration..")
|
||||||
|
.orShould().haveNameNotMatching(".*Test$");
|
||||||
|
|
||||||
@ArchTest
|
@ArchTest
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static final ArchRule hsOfficeMembershipPackageRule = classes()
|
public static final ArchRule hsOfficeMembershipPackageRule = classes()
|
||||||
.that().resideInAPackage("..hs.office.membership..")
|
.that().resideInAPackage("..hs.office.membership..")
|
||||||
.should().onlyBeAccessed().byClassesThat()
|
.should().onlyBeAccessed().byClassesThat()
|
||||||
.resideInAnyPackage("..hs.office.membership..",
|
.resideInAnyPackage(
|
||||||
|
"..hs.office.membership..",
|
||||||
"..hs.office.coopassets..",
|
"..hs.office.coopassets..",
|
||||||
"..hs.office.coopshares..",
|
"..hs.office.coopshares..",
|
||||||
"..hs.office.migration..");
|
"..hs.office.migration..");
|
||||||
|
@ -19,7 +19,7 @@ class HsOfficeBankAccountEntityUnitTest {
|
|||||||
.iban("DE02370502990000684712")
|
.iban("DE02370502990000684712")
|
||||||
.bic("COKSDE33")
|
.bic("COKSDE33")
|
||||||
.build();
|
.build();
|
||||||
assertThat("" + givenBankAccount).isEqualTo("bankAccount(holder='given holder', iban='DE02370502990000684712', bic='COKSDE33')");
|
assertThat(givenBankAccount.toString()).isEqualTo("bankAccount(DE02370502990000684712: holder='given holder', bic='COKSDE33')");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -102,23 +102,21 @@ class HsOfficeBankAccountRepositoryIntegrationTest extends ContextBasedTestWithC
|
|||||||
final var roles = rawRoleRepo.findAll();
|
final var roles = rawRoleRepo.findAll();
|
||||||
assertThat(distinctRoleNamesOf(roles)).containsExactlyInAnyOrder(Array.from(
|
assertThat(distinctRoleNamesOf(roles)).containsExactlyInAnyOrder(Array.from(
|
||||||
initialRoleNames,
|
initialRoleNames,
|
||||||
"hs_office_bankaccount#sometempaccC.owner",
|
"hs_office_bankaccount#DE25500105176934832579.owner",
|
||||||
"hs_office_bankaccount#sometempaccC.admin",
|
"hs_office_bankaccount#DE25500105176934832579.admin",
|
||||||
"hs_office_bankaccount#sometempaccC.tenant",
|
"hs_office_bankaccount#DE25500105176934832579.referrer"
|
||||||
"hs_office_bankaccount#sometempaccC.guest"
|
|
||||||
));
|
));
|
||||||
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(Array.fromFormatted(
|
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(Array.fromFormatted(
|
||||||
initialGrantNames,
|
initialGrantNames,
|
||||||
"{ grant perm DELETE on hs_office_bankaccount#sometempaccC to role hs_office_bankaccount#sometempaccC.owner by system and assume }",
|
"{ grant perm DELETE on hs_office_bankaccount#DE25500105176934832579 to role hs_office_bankaccount#DE25500105176934832579.owner by system and assume }",
|
||||||
"{ grant role hs_office_bankaccount#sometempaccC.owner to role global#global.admin by system and assume }",
|
"{ grant role hs_office_bankaccount#DE25500105176934832579.owner to role global#global.admin by system and assume }",
|
||||||
"{ grant role hs_office_bankaccount#sometempaccC.owner to user selfregistered-user-drew@hostsharing.org by global#global.admin and assume }",
|
"{ grant role hs_office_bankaccount#DE25500105176934832579.owner to user selfregistered-user-drew@hostsharing.org by hs_office_bankaccount#DE25500105176934832579.owner and assume }",
|
||||||
|
|
||||||
"{ grant role hs_office_bankaccount#sometempaccC.admin to role hs_office_bankaccount#sometempaccC.owner by system and assume }",
|
"{ grant role hs_office_bankaccount#DE25500105176934832579.admin to role hs_office_bankaccount#DE25500105176934832579.owner by system and assume }",
|
||||||
|
"{ grant perm UPDATE on hs_office_bankaccount#DE25500105176934832579 to role hs_office_bankaccount#DE25500105176934832579.admin by system and assume }",
|
||||||
|
|
||||||
"{ grant role hs_office_bankaccount#sometempaccC.tenant to role hs_office_bankaccount#sometempaccC.admin by system and assume }",
|
"{ grant perm SELECT on hs_office_bankaccount#DE25500105176934832579 to role hs_office_bankaccount#DE25500105176934832579.referrer by system and assume }",
|
||||||
|
"{ grant role hs_office_bankaccount#DE25500105176934832579.referrer to role hs_office_bankaccount#DE25500105176934832579.admin by system and assume }",
|
||||||
"{ grant perm SELECT on hs_office_bankaccount#sometempaccC to role hs_office_bankaccount#sometempaccC.guest by system and assume }",
|
|
||||||
"{ grant role hs_office_bankaccount#sometempaccC.guest to role hs_office_bankaccount#sometempaccC.tenant by system and assume }",
|
|
||||||
null
|
null
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -241,10 +239,6 @@ class HsOfficeBankAccountRepositoryIntegrationTest extends ContextBasedTestWithC
|
|||||||
final var initialRoleNames = distinctRoleNamesOf(rawRoleRepo.findAll());
|
final var initialRoleNames = distinctRoleNamesOf(rawRoleRepo.findAll());
|
||||||
final var initialGrantNames = distinctGrantDisplaysOf(rawGrantRepo.findAll());
|
final var initialGrantNames = distinctGrantDisplaysOf(rawGrantRepo.findAll());
|
||||||
final var givenBankAccount = givenSomeTemporaryBankAccount("selfregistered-user-drew@hostsharing.org");
|
final var givenBankAccount = givenSomeTemporaryBankAccount("selfregistered-user-drew@hostsharing.org");
|
||||||
assertThat(distinctRoleNamesOf(rawRoleRepo.findAll()).size()).as("unexpected number of roles created")
|
|
||||||
.isEqualTo(initialRoleNames.size() + 4);
|
|
||||||
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll()).size()).as("unexpected number of grants created")
|
|
||||||
.isEqualTo(initialGrantNames.size() + 7);
|
|
||||||
|
|
||||||
// when
|
// when
|
||||||
final var result = jpaAttempt.transacted(() -> {
|
final var result = jpaAttempt.transacted(() -> {
|
||||||
|
@ -105,19 +105,18 @@ class HsOfficeContactRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
initialRoleNames,
|
initialRoleNames,
|
||||||
"hs_office_contact#anothernewcontact.owner",
|
"hs_office_contact#anothernewcontact.owner",
|
||||||
"hs_office_contact#anothernewcontact.admin",
|
"hs_office_contact#anothernewcontact.admin",
|
||||||
"hs_office_contact#anothernewcontact.tenant",
|
"hs_office_contact#anothernewcontact.referrer"
|
||||||
"hs_office_contact#anothernewcontact.guest"
|
|
||||||
));
|
));
|
||||||
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(Array.from(
|
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(Array.fromFormatted(
|
||||||
initialGrantNames,
|
initialGrantNames,
|
||||||
"{ grant role hs_office_contact#anothernewcontact.owner to role global#global.admin by system and assume }",
|
"{ grant role hs_office_contact#anothernewcontact.owner to role global#global.admin by system and assume }",
|
||||||
"{ grant perm UPDATE on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.admin by system and assume }",
|
"{ grant perm UPDATE on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.admin by system and assume }",
|
||||||
"{ grant role hs_office_contact#anothernewcontact.tenant to role hs_office_contact#anothernewcontact.admin by system and assume }",
|
"{ grant role hs_office_contact#anothernewcontact.owner to user selfregistered-user-drew@hostsharing.org by hs_office_contact#anothernewcontact.owner and assume }",
|
||||||
"{ grant perm DELETE on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.owner by system and assume }",
|
"{ grant perm DELETE on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.owner by system and assume }",
|
||||||
"{ grant role hs_office_contact#anothernewcontact.admin to role hs_office_contact#anothernewcontact.owner by system and assume }",
|
"{ grant role hs_office_contact#anothernewcontact.admin to role hs_office_contact#anothernewcontact.owner by system and assume }",
|
||||||
"{ grant perm SELECT on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.guest by system and assume }",
|
|
||||||
"{ grant role hs_office_contact#anothernewcontact.guest to role hs_office_contact#anothernewcontact.tenant by system and assume }",
|
"{ grant perm SELECT on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.referrer by system and assume }",
|
||||||
"{ grant role hs_office_contact#anothernewcontact.owner to user selfregistered-user-drew@hostsharing.org by global#global.admin and assume }"
|
"{ grant role hs_office_contact#anothernewcontact.referrer to role hs_office_contact#anothernewcontact.admin by system and assume }"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,7 +276,7 @@ class HsOfficeCoopAssetsTransactionControllerAcceptanceTest extends ContextBased
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Accepts({ "CoopAssetTransaction:X(Access Control)" })
|
@Accepts({ "CoopAssetTransaction:X(Access Control)" })
|
||||||
void contactAdminUser_canGetRelatedCoopAssetTransaction() {
|
void partnerPersonUser_canGetRelatedCoopAssetTransaction() {
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
final var givenCoopAssetTransactionUuid = coopAssetsTransactionRepo.findCoopAssetsTransactionByOptionalMembershipUuidAndDateRange(
|
final var givenCoopAssetTransactionUuid = coopAssetsTransactionRepo.findCoopAssetsTransactionByOptionalMembershipUuidAndDateRange(
|
||||||
null,
|
null,
|
||||||
@ -285,7 +285,7 @@ class HsOfficeCoopAssetsTransactionControllerAcceptanceTest extends ContextBased
|
|||||||
|
|
||||||
RestAssured // @formatter:off
|
RestAssured // @formatter:off
|
||||||
.given()
|
.given()
|
||||||
.header("current-user", "contact-admin@firstcontact.example.com")
|
.header("current-user", "person-FirstGmbH@example.com")
|
||||||
.port(port)
|
.port(port)
|
||||||
.when()
|
.when()
|
||||||
.get("http://localhost/api/hs/office/coopassetstransactions/" + givenCoopAssetTransactionUuid)
|
.get("http://localhost/api/hs/office/coopassetstransactions/" + givenCoopAssetTransactionUuid)
|
||||||
|
@ -23,27 +23,27 @@ class HsOfficeCoopAssetsTransactionEntityUnitTest {
|
|||||||
void toStringContainsAlmostAllPropertiesAccount() {
|
void toStringContainsAlmostAllPropertiesAccount() {
|
||||||
final var result = givenCoopAssetTransaction.toString();
|
final var result = givenCoopAssetTransaction.toString();
|
||||||
|
|
||||||
assertThat(result).isEqualTo("CoopAssetsTransaction(1000101, 2020-01-01, DEPOSIT, 128.00, some-ref)");
|
assertThat(result).isEqualTo("CoopAssetsTransaction(M-1000101: 2020-01-01, DEPOSIT, 128.00, some-ref)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void toShortStringContainsOnlyMemberNumberSuffixAndSharesCountOnly() {
|
void toShortStringContainsOnlyMemberNumberSuffixAndSharesCountOnly() {
|
||||||
final var result = givenCoopAssetTransaction.toShortString();
|
final var result = givenCoopAssetTransaction.toShortString();
|
||||||
|
|
||||||
assertThat(result).isEqualTo("1000101+128.00");
|
assertThat(result).isEqualTo("M-1000101:+128.00");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void toStringWithEmptyTransactionDoesNotThrowException() {
|
void toStringWithEmptyTransactionDoesNotThrowException() {
|
||||||
final var result = givenEmptyCoopAssetsTransaction.toString();
|
final var result = givenEmptyCoopAssetsTransaction.toString();
|
||||||
|
|
||||||
assertThat(result).isEqualTo("CoopAssetsTransaction()");
|
assertThat(result).isEqualTo("CoopAssetsTransaction(M-?????: )");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void toShortStringEmptyTransactionDoesNotThrowException() {
|
void toShortStringEmptyTransactionDoesNotThrowException() {
|
||||||
final var result = givenEmptyCoopAssetsTransaction.toShortString();
|
final var result = givenEmptyCoopAssetsTransaction.toShortString();
|
||||||
|
|
||||||
assertThat(result).isEqualTo("nullnu");
|
assertThat(result).isEqualTo("M-?????:+0.00");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase
|
|||||||
.map(s -> s.replace("hs_office_", ""))
|
.map(s -> s.replace("hs_office_", ""))
|
||||||
.containsExactlyInAnyOrder(Array.fromFormatted(
|
.containsExactlyInAnyOrder(Array.fromFormatted(
|
||||||
initialGrantNames,
|
initialGrantNames,
|
||||||
"{ grant perm SELECT on coopassetstransaction#temprefB to role membership#1000101:....tenant by system and assume }",
|
"{ grant perm SELECT on coopassetstransaction#temprefB to role membership#M-1000101.referrer by system and assume }",
|
||||||
null));
|
null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,17 +141,17 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase
|
|||||||
// then
|
// then
|
||||||
allTheseCoopAssetsTransactionsAreReturned(
|
allTheseCoopAssetsTransactionsAreReturned(
|
||||||
result,
|
result,
|
||||||
"CoopAssetsTransaction(1000101, 2010-03-15, DEPOSIT, 320.00, ref 1000101-1, initial deposit)",
|
"CoopAssetsTransaction(M-1000101: 2010-03-15, DEPOSIT, 320.00, ref 1000101-1, initial deposit)",
|
||||||
"CoopAssetsTransaction(1000101, 2021-09-01, DISBURSAL, -128.00, ref 1000101-2, partial disbursal)",
|
"CoopAssetsTransaction(M-1000101: 2021-09-01, DISBURSAL, -128.00, ref 1000101-2, partial disbursal)",
|
||||||
"CoopAssetsTransaction(1000101, 2022-10-20, ADJUSTMENT, 128.00, ref 1000101-3, some adjustment)",
|
"CoopAssetsTransaction(M-1000101: 2022-10-20, ADJUSTMENT, 128.00, ref 1000101-3, some adjustment)",
|
||||||
|
|
||||||
"CoopAssetsTransaction(1000202, 2010-03-15, DEPOSIT, 320.00, ref 1000202-1, initial deposit)",
|
"CoopAssetsTransaction(M-1000202: 2010-03-15, DEPOSIT, 320.00, ref 1000202-1, initial deposit)",
|
||||||
"CoopAssetsTransaction(1000202, 2021-09-01, DISBURSAL, -128.00, ref 1000202-2, partial disbursal)",
|
"CoopAssetsTransaction(M-1000202: 2021-09-01, DISBURSAL, -128.00, ref 1000202-2, partial disbursal)",
|
||||||
"CoopAssetsTransaction(1000202, 2022-10-20, ADJUSTMENT, 128.00, ref 1000202-3, some adjustment)",
|
"CoopAssetsTransaction(M-1000202: 2022-10-20, ADJUSTMENT, 128.00, ref 1000202-3, some adjustment)",
|
||||||
|
|
||||||
"CoopAssetsTransaction(1000303, 2010-03-15, DEPOSIT, 320.00, ref 1000303-1, initial deposit)",
|
"CoopAssetsTransaction(M-1000303: 2010-03-15, DEPOSIT, 320.00, ref 1000303-1, initial deposit)",
|
||||||
"CoopAssetsTransaction(1000303, 2021-09-01, DISBURSAL, -128.00, ref 1000303-2, partial disbursal)",
|
"CoopAssetsTransaction(M-1000303: 2021-09-01, DISBURSAL, -128.00, ref 1000303-2, partial disbursal)",
|
||||||
"CoopAssetsTransaction(1000303, 2022-10-20, ADJUSTMENT, 128.00, ref 1000303-3, some adjustment)");
|
"CoopAssetsTransaction(M-1000303: 2022-10-20, ADJUSTMENT, 128.00, ref 1000303-3, some adjustment)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -169,9 +169,9 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase
|
|||||||
// then
|
// then
|
||||||
allTheseCoopAssetsTransactionsAreReturned(
|
allTheseCoopAssetsTransactionsAreReturned(
|
||||||
result,
|
result,
|
||||||
"CoopAssetsTransaction(1000202, 2010-03-15, DEPOSIT, 320.00, ref 1000202-1, initial deposit)",
|
"CoopAssetsTransaction(M-1000202: 2010-03-15, DEPOSIT, 320.00, ref 1000202-1, initial deposit)",
|
||||||
"CoopAssetsTransaction(1000202, 2021-09-01, DISBURSAL, -128.00, ref 1000202-2, partial disbursal)",
|
"CoopAssetsTransaction(M-1000202: 2021-09-01, DISBURSAL, -128.00, ref 1000202-2, partial disbursal)",
|
||||||
"CoopAssetsTransaction(1000202, 2022-10-20, ADJUSTMENT, 128.00, ref 1000202-3, some adjustment)");
|
"CoopAssetsTransaction(M-1000202: 2022-10-20, ADJUSTMENT, 128.00, ref 1000202-3, some adjustment)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -189,13 +189,13 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase
|
|||||||
// then
|
// then
|
||||||
allTheseCoopAssetsTransactionsAreReturned(
|
allTheseCoopAssetsTransactionsAreReturned(
|
||||||
result,
|
result,
|
||||||
"CoopAssetsTransaction(1000202, 2021-09-01, DISBURSAL, -128.00, ref 1000202-2, partial disbursal)");
|
"CoopAssetsTransaction(M-1000202: 2021-09-01, DISBURSAL, -128.00, ref 1000202-2, partial disbursal)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void normalUser_canViewOnlyRelatedCoopAssetsTransactions() {
|
public void partnerPersonAdmin_canViewRelatedCoopAssetsTransactions() {
|
||||||
// given:
|
// given:
|
||||||
context("superuser-alex@hostsharing.net", "hs_office_partner#10001:FirstGmbH-firstcontact.admin");
|
context("superuser-alex@hostsharing.net", "hs_office_person#FirstGmbH.admin");
|
||||||
|
|
||||||
// when:
|
// when:
|
||||||
final var result = coopAssetsTransactionRepo.findCoopAssetsTransactionByOptionalMembershipUuidAndDateRange(
|
final var result = coopAssetsTransactionRepo.findCoopAssetsTransactionByOptionalMembershipUuidAndDateRange(
|
||||||
@ -206,9 +206,9 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase
|
|||||||
// then:
|
// then:
|
||||||
exactlyTheseCoopAssetsTransactionsAreReturned(
|
exactlyTheseCoopAssetsTransactionsAreReturned(
|
||||||
result,
|
result,
|
||||||
"CoopAssetsTransaction(1000101, 2010-03-15, DEPOSIT, 320.00, ref 1000101-1, initial deposit)",
|
"CoopAssetsTransaction(M-1000101: 2010-03-15, DEPOSIT, 320.00, ref 1000101-1, initial deposit)",
|
||||||
"CoopAssetsTransaction(1000101, 2021-09-01, DISBURSAL, -128.00, ref 1000101-2, partial disbursal)",
|
"CoopAssetsTransaction(M-1000101: 2021-09-01, DISBURSAL, -128.00, ref 1000101-2, partial disbursal)",
|
||||||
"CoopAssetsTransaction(1000101, 2022-10-20, ADJUSTMENT, 128.00, ref 1000101-3, some adjustment)");
|
"CoopAssetsTransaction(M-1000101: 2022-10-20, ADJUSTMENT, 128.00, ref 1000101-3, some adjustment)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,12 +218,22 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest extends ContextBased
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Accepts({"CoopShareTransaction:X(Access Control)"})
|
@Accepts({"CoopShareTransaction:X(Access Control)"})
|
||||||
void contactAdminUser_canGetRelatedCoopShareTransaction() {
|
void partnerPersonUser_canGetRelatedCoopShareTransaction() {
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
final var givenCoopShareTransactionUuid = coopSharesTransactionRepo.findCoopSharesTransactionByOptionalMembershipUuidAndDateRange(null, LocalDate.of(2010, 3, 15), LocalDate.of(2010, 3, 15)).get(0).getUuid();
|
final var givenCoopShareTransactionUuid = coopSharesTransactionRepo.findCoopSharesTransactionByOptionalMembershipUuidAndDateRange(null, LocalDate.of(2010, 3, 15), LocalDate.of(2010, 3, 15)).get(0).getUuid();
|
||||||
|
|
||||||
RestAssured // @formatter:off
|
RestAssured // @formatter:off
|
||||||
.given().header("current-user", "contact-admin@firstcontact.example.com").port(port).when().get("http://localhost/api/hs/office/coopsharestransactions/" + givenCoopShareTransactionUuid).then().log().body().assertThat().statusCode(200).contentType("application/json").body("", lenientlyEquals("""
|
.given()
|
||||||
|
.header("current-user", "person-FirstGmbH@example.com")
|
||||||
|
.port(port)
|
||||||
|
.when()
|
||||||
|
.get("http://localhost/api/hs/office/coopsharestransactions/" + givenCoopShareTransactionUuid)
|
||||||
|
.then()
|
||||||
|
.log().body()
|
||||||
|
.assertThat()
|
||||||
|
.statusCode(200)
|
||||||
|
.contentType("application/json")
|
||||||
|
.body("", lenientlyEquals("""
|
||||||
{
|
{
|
||||||
"transactionType": "SUBSCRIPTION",
|
"transactionType": "SUBSCRIPTION",
|
||||||
"shareCount": 4
|
"shareCount": 4
|
||||||
|
@ -88,7 +88,6 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase
|
|||||||
context("superuser-alex@hostsharing.net");
|
context("superuser-alex@hostsharing.net");
|
||||||
final var initialRoleNames = distinctRoleNamesOf(rawRoleRepo.findAll());
|
final var initialRoleNames = distinctRoleNamesOf(rawRoleRepo.findAll());
|
||||||
final var initialGrantNames = distinctGrantDisplaysOf(rawGrantRepo.findAll()).stream()
|
final var initialGrantNames = distinctGrantDisplaysOf(rawGrantRepo.findAll()).stream()
|
||||||
.map(s -> s.replace("FirstGmbH-firstcontact", "..."))
|
|
||||||
.map(s -> s.replace("hs_office_", ""))
|
.map(s -> s.replace("hs_office_", ""))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
@ -109,11 +108,10 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase
|
|||||||
final var all = rawRoleRepo.findAll();
|
final var all = rawRoleRepo.findAll();
|
||||||
assertThat(distinctRoleNamesOf(all)).containsExactlyInAnyOrder(Array.from(initialRoleNames)); // no new roles created
|
assertThat(distinctRoleNamesOf(all)).containsExactlyInAnyOrder(Array.from(initialRoleNames)); // no new roles created
|
||||||
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll()))
|
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll()))
|
||||||
.map(s -> s.replace("FirstGmbH-firstcontact", "..."))
|
|
||||||
.map(s -> s.replace("hs_office_", ""))
|
.map(s -> s.replace("hs_office_", ""))
|
||||||
.containsExactlyInAnyOrder(Array.fromFormatted(
|
.containsExactlyInAnyOrder(Array.fromFormatted(
|
||||||
initialGrantNames,
|
initialGrantNames,
|
||||||
"{ grant perm SELECT on coopsharestransaction#temprefB to role membership#1000101:....tenant by system and assume }",
|
"{ grant perm SELECT on coopsharestransaction#temprefB to role membership#M-1000101.referrer by system and assume }",
|
||||||
null));
|
null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,7 +192,7 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase
|
|||||||
@Test
|
@Test
|
||||||
public void normalUser_canViewOnlyRelatedCoopSharesTransactions() {
|
public void normalUser_canViewOnlyRelatedCoopSharesTransactions() {
|
||||||
// given:
|
// given:
|
||||||
context("superuser-alex@hostsharing.net", "hs_office_partner#10001:FirstGmbH-firstcontact.admin");
|
context("superuser-alex@hostsharing.net", "hs_office_membership#M-1000101.admin");
|
||||||
|
|
||||||
// when:
|
// when:
|
||||||
final var result = coopSharesTransactionRepo.findCoopSharesTransactionByOptionalMembershipUuidAndDateRange(
|
final var result = coopSharesTransactionRepo.findCoopSharesTransactionByOptionalMembershipUuidAndDateRange(
|
||||||
|
@ -7,6 +7,9 @@ import net.hostsharing.hsadminng.context.Context;
|
|||||||
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository;
|
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository;
|
||||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRepository;
|
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRepository;
|
||||||
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRepository;
|
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRepository;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRepository;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationEntity;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRepository;
|
||||||
import net.hostsharing.hsadminng.hs.office.test.ContextBasedTestWithCleanup;
|
import net.hostsharing.hsadminng.hs.office.test.ContextBasedTestWithCleanup;
|
||||||
import net.hostsharing.test.Accepts;
|
import net.hostsharing.test.Accepts;
|
||||||
import net.hostsharing.test.JpaAttempt;
|
import net.hostsharing.test.JpaAttempt;
|
||||||
@ -24,6 +27,7 @@ import jakarta.persistence.EntityManager;
|
|||||||
import jakarta.persistence.PersistenceContext;
|
import jakarta.persistence.PersistenceContext;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationType.DEBITOR;
|
||||||
import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid;
|
import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid;
|
||||||
import static net.hostsharing.test.JsonMatcher.lenientlyEquals;
|
import static net.hostsharing.test.JsonMatcher.lenientlyEquals;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@ -57,6 +61,12 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
|||||||
@Autowired
|
@Autowired
|
||||||
HsOfficeBankAccountRepository bankAccountRepo;
|
HsOfficeBankAccountRepository bankAccountRepo;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
HsOfficePersonRepository personRepo;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
HsOfficeRelationRepository relRepo;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
JpaAttempt jpaAttempt;
|
JpaAttempt jpaAttempt;
|
||||||
|
|
||||||
@ -82,34 +92,132 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
|||||||
.body("", lenientlyEquals("""
|
.body("", lenientlyEquals("""
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
"debitorRel": {
|
||||||
|
"anchor": {
|
||||||
|
"personType": "LEGAL_PERSON",
|
||||||
|
"tradeName": "First GmbH",
|
||||||
|
"givenName": null,
|
||||||
|
"familyName": null
|
||||||
|
},
|
||||||
|
"holder": {
|
||||||
|
"personType": "LEGAL_PERSON",
|
||||||
|
"tradeName": "First GmbH",
|
||||||
|
"givenName": null,
|
||||||
|
"familyName": null
|
||||||
|
},
|
||||||
|
"type": "DEBITOR",
|
||||||
|
"mark": null,
|
||||||
|
"contact": {
|
||||||
|
"label": "first contact",
|
||||||
|
"emailAddresses": "contact-admin@firstcontact.example.com",
|
||||||
|
"phoneNumbers": "+49 123 1234567"
|
||||||
|
}
|
||||||
|
},
|
||||||
"debitorNumber": 1000111,
|
"debitorNumber": 1000111,
|
||||||
"debitorNumberSuffix": 11,
|
"debitorNumberSuffix": 11,
|
||||||
"partner": { "person": { "personType": "LEGAL_PERSON" } },
|
"partner": {
|
||||||
"billingContact": { "label": "first contact" },
|
"partnerNumber": 10001,
|
||||||
|
"partnerRel": {
|
||||||
|
"anchor": {
|
||||||
|
"personType": "LEGAL_PERSON",
|
||||||
|
"tradeName": "Hostsharing eG",
|
||||||
|
"givenName": null,
|
||||||
|
"familyName": null
|
||||||
|
},
|
||||||
|
"holder": {
|
||||||
|
"personType": "LEGAL_PERSON",
|
||||||
|
"tradeName": "First GmbH",
|
||||||
|
"givenName": null,
|
||||||
|
"familyName": null
|
||||||
|
},
|
||||||
|
"type": "PARTNER",
|
||||||
|
"mark": null,
|
||||||
|
"contact": {
|
||||||
|
"label": "first contact",
|
||||||
|
"emailAddresses": "contact-admin@firstcontact.example.com",
|
||||||
|
"phoneNumbers": "+49 123 1234567"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"details": {
|
||||||
|
"registrationOffice": "Hamburg",
|
||||||
|
"registrationNumber": "RegNo123456789",
|
||||||
|
"birthName": null,
|
||||||
|
"birthPlace": null,
|
||||||
|
"birthday": null,
|
||||||
|
"dateOfDeath": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"billable": true,
|
||||||
"vatId": null,
|
"vatId": null,
|
||||||
"vatCountryCode": null,
|
"vatCountryCode": null,
|
||||||
"vatBusiness": true,
|
"vatBusiness": true,
|
||||||
"refundBankAccount": { "holder": "First GmbH" }
|
"vatReverseCharge": false,
|
||||||
|
"refundBankAccount": {
|
||||||
|
"holder": "First GmbH",
|
||||||
|
"iban": "DE02120300000000202051",
|
||||||
|
"bic": "BYLADEM1001"
|
||||||
|
},
|
||||||
|
"defaultPrefix": "fir"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"debitorRel": {
|
||||||
|
"anchor": {"tradeName": "Second e.K."},
|
||||||
|
"holder": {"tradeName": "Second e.K."},
|
||||||
|
"type": "DEBITOR",
|
||||||
|
"contact": {"emailAddresses": "contact-admin@secondcontact.example.com"}
|
||||||
|
},
|
||||||
"debitorNumber": 1000212,
|
"debitorNumber": 1000212,
|
||||||
"debitorNumberSuffix": 12,
|
"debitorNumberSuffix": 12,
|
||||||
"partner": { "person": { "tradeName": "Second e.K." } },
|
"partner": {
|
||||||
"billingContact": { "label": "second contact" },
|
"partnerNumber": 10002,
|
||||||
|
"partnerRel": {
|
||||||
|
"anchor": {"tradeName": "Hostsharing eG"},
|
||||||
|
"holder": {"tradeName": "Second e.K."},
|
||||||
|
"type": "PARTNER",
|
||||||
|
"contact": {"emailAddresses": "contact-admin@secondcontact.example.com"}
|
||||||
|
},
|
||||||
|
"details": {
|
||||||
|
"registrationOffice": "Hamburg",
|
||||||
|
"registrationNumber": "RegNo123456789"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"billable": true,
|
||||||
"vatId": null,
|
"vatId": null,
|
||||||
"vatCountryCode": null,
|
"vatCountryCode": null,
|
||||||
"vatBusiness": true,
|
"vatBusiness": true,
|
||||||
"refundBankAccount": { "holder": "Second e.K." }
|
"vatReverseCharge": false,
|
||||||
|
"refundBankAccount": {"iban": "DE02100500000054540402"},
|
||||||
|
"defaultPrefix": "sec"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"debitorRel": {
|
||||||
|
"anchor": {"tradeName": "Third OHG"},
|
||||||
|
"holder": {"tradeName": "Third OHG"},
|
||||||
|
"type": "DEBITOR",
|
||||||
|
"contact": {"emailAddresses": "contact-admin@thirdcontact.example.com"}
|
||||||
|
},
|
||||||
"debitorNumber": 1000313,
|
"debitorNumber": 1000313,
|
||||||
"debitorNumberSuffix": 13,
|
"debitorNumberSuffix": 13,
|
||||||
"partner": { "person": { "tradeName": "Third OHG" } },
|
"partner": {
|
||||||
"billingContact": { "label": "third contact" },
|
"partnerNumber": 10003,
|
||||||
|
"partnerRel": {
|
||||||
|
"anchor": {"tradeName": "Hostsharing eG"},
|
||||||
|
"holder": {"tradeName": "Third OHG"},
|
||||||
|
"type": "PARTNER",
|
||||||
|
"contact": {"emailAddresses": "contact-admin@thirdcontact.example.com"}
|
||||||
|
},
|
||||||
|
"details": {
|
||||||
|
"registrationOffice": "Hamburg",
|
||||||
|
"registrationNumber": "RegNo123456789"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"billable": true,
|
||||||
"vatId": null,
|
"vatId": null,
|
||||||
"vatCountryCode": null,
|
"vatCountryCode": null,
|
||||||
"vatBusiness": true,
|
"vatBusiness": true,
|
||||||
"refundBankAccount": { "holder": "Third OHG" }
|
"vatReverseCharge": false,
|
||||||
|
"refundBankAccount": {"iban": "DE02300209000106531065"},
|
||||||
|
"defaultPrefix": "thi"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
"""));
|
"""));
|
||||||
@ -132,8 +240,10 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"debitorNumber": 1000212,
|
"debitorNumber": 1000212,
|
||||||
"partner": { "person": { "tradeName": "Second e.K." } },
|
"partner": { "partnerNumber": 10002 },
|
||||||
"billingContact": { "label": "second contact" },
|
"debitorRel": {
|
||||||
|
"contact": { "label": "second contact" }
|
||||||
|
},
|
||||||
"vatId": null,
|
"vatId": null,
|
||||||
"vatCountryCode": null,
|
"vatCountryCode": null,
|
||||||
"vatBusiness": true
|
"vatBusiness": true
|
||||||
@ -154,6 +264,17 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
|||||||
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("Third").get(0);
|
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("Third").get(0);
|
||||||
final var givenContact = contactRepo.findContactByOptionalLabelLike("fourth").get(0);
|
final var givenContact = contactRepo.findContactByOptionalLabelLike("fourth").get(0);
|
||||||
final var givenBankAccount = bankAccountRepo.findByOptionalHolderLike("Fourth").get(0);
|
final var givenBankAccount = bankAccountRepo.findByOptionalHolderLike("Fourth").get(0);
|
||||||
|
final var givenBillingPerson = personRepo.findPersonByOptionalNameLike("Fourth").get(0);
|
||||||
|
|
||||||
|
final var givenDebitorRelUUid = jpaAttempt.transacted(() -> {
|
||||||
|
context.define("superuser-alex@hostsharing.net");
|
||||||
|
return relRepo.save(HsOfficeRelationEntity.builder()
|
||||||
|
.type(DEBITOR)
|
||||||
|
.anchor(givenPartner.getPartnerRel().getHolder())
|
||||||
|
.holder(givenBillingPerson)
|
||||||
|
.contact(givenContact)
|
||||||
|
.build()).getUuid();
|
||||||
|
}).assertSuccessful().returnedValue();
|
||||||
|
|
||||||
final var location = RestAssured // @formatter:off
|
final var location = RestAssured // @formatter:off
|
||||||
.given()
|
.given()
|
||||||
@ -161,8 +282,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
|||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.body("""
|
.body("""
|
||||||
{
|
{
|
||||||
"partnerUuid": "%s",
|
"debitorRelUuid": "%s",
|
||||||
"billingContactUuid": "%s",
|
|
||||||
"debitorNumberSuffix": "%s",
|
"debitorNumberSuffix": "%s",
|
||||||
"billable": "true",
|
"billable": "true",
|
||||||
"vatId": "VAT123456",
|
"vatId": "VAT123456",
|
||||||
@ -172,7 +292,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
|||||||
"refundBankAccountUuid": "%s",
|
"refundBankAccountUuid": "%s",
|
||||||
"defaultPrefix": "for"
|
"defaultPrefix": "for"
|
||||||
}
|
}
|
||||||
""".formatted( givenPartner.getUuid(), givenContact.getUuid(), ++nextDebitorSuffix, givenBankAccount.getUuid()))
|
""".formatted( givenDebitorRelUUid, ++nextDebitorSuffix, givenBankAccount.getUuid()))
|
||||||
.port(port)
|
.port(port)
|
||||||
.when()
|
.when()
|
||||||
.post("http://localhost/api/hs/office/debitors")
|
.post("http://localhost/api/hs/office/debitors")
|
||||||
@ -182,8 +302,8 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
|||||||
.body("uuid", isUuidValid())
|
.body("uuid", isUuidValid())
|
||||||
.body("vatId", is("VAT123456"))
|
.body("vatId", is("VAT123456"))
|
||||||
.body("defaultPrefix", is("for"))
|
.body("defaultPrefix", is("for"))
|
||||||
.body("billingContact.label", is(givenContact.getLabel()))
|
.body("debitorRel.contact.label", is(givenContact.getLabel()))
|
||||||
.body("partner.person.tradeName", is(givenPartner.getPerson().getTradeName()))
|
.body("debitorRel.holder.tradeName", is(givenBillingPerson.getTradeName()))
|
||||||
.body("refundBankAccount.holder", is(givenBankAccount.getHolder()))
|
.body("refundBankAccount.holder", is(givenBankAccount.getHolder()))
|
||||||
.header("Location", startsWith("http://localhost"))
|
.header("Location", startsWith("http://localhost"))
|
||||||
.extract().header("Location"); // @formatter:on
|
.extract().header("Location"); // @formatter:on
|
||||||
@ -207,14 +327,22 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
|||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.body("""
|
.body("""
|
||||||
{
|
{
|
||||||
"partnerUuid": "%s",
|
"debitorRel": {
|
||||||
"billingContactUuid": "%s",
|
"type": "DEBITOR",
|
||||||
|
"anchorUuid": "%s",
|
||||||
|
"holderUuid": "%s",
|
||||||
|
"contactUuid": "%s"
|
||||||
|
},
|
||||||
"debitorNumberSuffix": "%s",
|
"debitorNumberSuffix": "%s",
|
||||||
"defaultPrefix": "for",
|
"defaultPrefix": "for",
|
||||||
"billable": "true",
|
"billable": "true",
|
||||||
"vatReverseCharge": "false"
|
"vatReverseCharge": "false"
|
||||||
}
|
}
|
||||||
""".formatted( givenPartner.getUuid(), givenContact.getUuid(), ++nextDebitorSuffix))
|
""".formatted(
|
||||||
|
givenPartner.getPartnerRel().getHolder().getUuid(),
|
||||||
|
givenPartner.getPartnerRel().getHolder().getUuid(),
|
||||||
|
givenContact.getUuid(),
|
||||||
|
++nextDebitorSuffix))
|
||||||
.port(port)
|
.port(port)
|
||||||
.when()
|
.when()
|
||||||
.post("http://localhost/api/hs/office/debitors")
|
.post("http://localhost/api/hs/office/debitors")
|
||||||
@ -222,8 +350,8 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
|||||||
.statusCode(201)
|
.statusCode(201)
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.body("uuid", isUuidValid())
|
.body("uuid", isUuidValid())
|
||||||
.body("billingContact.label", is(givenContact.getLabel()))
|
.body("debitorRel.contact.label", is(givenContact.getLabel()))
|
||||||
.body("partner.person.tradeName", is(givenPartner.getPerson().getTradeName()))
|
.body("partner.partnerRel.holder.tradeName", is(givenPartner.getPartnerRel().getHolder().getTradeName()))
|
||||||
.body("vatId", equalTo(null))
|
.body("vatId", equalTo(null))
|
||||||
.body("vatCountryCode", equalTo(null))
|
.body("vatCountryCode", equalTo(null))
|
||||||
.body("vatBusiness", equalTo(false))
|
.body("vatBusiness", equalTo(false))
|
||||||
@ -251,18 +379,21 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
|||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.body("""
|
.body("""
|
||||||
{
|
{
|
||||||
"partnerUuid": "%s",
|
"debitorRel": {
|
||||||
"billingContactUuid": "%s",
|
"type": "DEBITOR",
|
||||||
|
"anchorUuid": "%s",
|
||||||
|
"holderUuid": "%s",
|
||||||
|
"contactUuid": "%s"
|
||||||
|
},
|
||||||
"debitorNumberSuffix": "%s",
|
"debitorNumberSuffix": "%s",
|
||||||
|
"defaultPrefix": "for",
|
||||||
"billable": "true",
|
"billable": "true",
|
||||||
"vatId": "VAT123456",
|
"vatReverseCharge": "false"
|
||||||
"vatCountryCode": "DE",
|
|
||||||
"vatBusiness": true,
|
|
||||||
"vatReverseCharge": "false",
|
|
||||||
"defaultPrefix": "thi"
|
|
||||||
}
|
}
|
||||||
"""
|
""".formatted(
|
||||||
.formatted( givenPartner.getUuid(), givenContactUuid, ++nextDebitorSuffix))
|
givenPartner.getPartnerRel().getAnchor().getUuid(),
|
||||||
|
givenPartner.getPartnerRel().getAnchor().getUuid(),
|
||||||
|
givenContactUuid, ++nextDebitorSuffix))
|
||||||
.port(port)
|
.port(port)
|
||||||
.when()
|
.when()
|
||||||
.post("http://localhost/api/hs/office/debitors")
|
.post("http://localhost/api/hs/office/debitors")
|
||||||
@ -273,10 +404,10 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void globalAdmin_canNotAddDebitor_ifPartnerDoesNotExist() {
|
void globalAdmin_canNotAddDebitor_ifDebitorRelDoesNotExist() {
|
||||||
|
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
final var givenPartnerUuid = UUID.fromString("00000000-0000-0000-0000-000000000000");
|
final var givenDebitorRelUuid = UUID.fromString("00000000-0000-0000-0000-000000000000");
|
||||||
final var givenContact = contactRepo.findContactByOptionalLabelLike("fourth").get(0);
|
final var givenContact = contactRepo.findContactByOptionalLabelLike("fourth").get(0);
|
||||||
|
|
||||||
final var location = RestAssured // @formatter:off
|
final var location = RestAssured // @formatter:off
|
||||||
@ -285,23 +416,19 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
|||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.body("""
|
.body("""
|
||||||
{
|
{
|
||||||
"partnerUuid": "%s",
|
"debitorRelUuid": "%s",
|
||||||
"billingContactUuid": "%s",
|
|
||||||
"debitorNumberSuffix": "%s",
|
"debitorNumberSuffix": "%s",
|
||||||
|
"defaultPrefix": "for",
|
||||||
"billable": "true",
|
"billable": "true",
|
||||||
"vatId": "VAT123456",
|
"vatReverseCharge": "false"
|
||||||
"vatCountryCode": "DE",
|
|
||||||
"vatBusiness": true,
|
|
||||||
"vatReverseCharge": "false",
|
|
||||||
"defaultPrefix": "for"
|
|
||||||
}
|
}
|
||||||
""".formatted( givenPartnerUuid, givenContact.getUuid(), ++nextDebitorSuffix))
|
""".formatted(givenDebitorRelUuid, ++nextDebitorSuffix))
|
||||||
.port(port)
|
.port(port)
|
||||||
.when()
|
.when()
|
||||||
.post("http://localhost/api/hs/office/debitors")
|
.post("http://localhost/api/hs/office/debitors")
|
||||||
.then().log().all().assertThat()
|
.then().log().all().assertThat()
|
||||||
.statusCode(400)
|
.statusCode(400)
|
||||||
.body("message", is("Unable to find Partner with uuid 00000000-0000-0000-0000-000000000000"));
|
.body("message", is("Unable to find HsOfficeRelationEntity with uuid 00000000-0000-0000-0000-000000000000"));
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -321,13 +448,52 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
|||||||
.port(port)
|
.port(port)
|
||||||
.when()
|
.when()
|
||||||
.get("http://localhost/api/hs/office/debitors/" + givenDebitorUuid)
|
.get("http://localhost/api/hs/office/debitors/" + givenDebitorUuid)
|
||||||
.then().log().body().assertThat()
|
.then().log().all().assertThat()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.contentType("application/json")
|
.contentType("application/json")
|
||||||
.body("", lenientlyEquals("""
|
.body("", lenientlyEquals("""
|
||||||
{
|
{
|
||||||
"partner": { person: { "tradeName": "First GmbH" } },
|
"debitorRel": {
|
||||||
"billingContact": { "label": "first contact" }
|
"anchor": { "personType": "LEGAL_PERSON", "tradeName": "First GmbH"},
|
||||||
|
"holder": { "personType": "LEGAL_PERSON", "tradeName": "First GmbH"},
|
||||||
|
"type": "DEBITOR",
|
||||||
|
"contact": {
|
||||||
|
"label": "first contact",
|
||||||
|
"postalAddress": "\\nVorname Nachname\\nStraße Hnr\\nPLZ Stadt\\n",
|
||||||
|
"emailAddresses": "contact-admin@firstcontact.example.com",
|
||||||
|
"phoneNumbers": "+49 123 1234567"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"debitorNumber": 1000111,
|
||||||
|
"debitorNumberSuffix": 11,
|
||||||
|
"partner": {
|
||||||
|
"partnerNumber": 10001,
|
||||||
|
"partnerRel": {
|
||||||
|
"anchor": { "personType": "LEGAL_PERSON", "tradeName": "Hostsharing eG"},
|
||||||
|
"holder": { "personType": "LEGAL_PERSON", "tradeName": "First GmbH"},
|
||||||
|
"type": "PARTNER",
|
||||||
|
"mark": null,
|
||||||
|
"contact": {
|
||||||
|
"label": "first contact",
|
||||||
|
"postalAddress": "\\nVorname Nachname\\nStraße Hnr\\nPLZ Stadt\\n",
|
||||||
|
"emailAddresses": "contact-admin@firstcontact.example.com",
|
||||||
|
"phoneNumbers": "+49 123 1234567"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"details": {
|
||||||
|
"registrationOffice": "Hamburg",
|
||||||
|
"registrationNumber": "RegNo123456789"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"billable": true,
|
||||||
|
"vatBusiness": true,
|
||||||
|
"vatReverseCharge": false,
|
||||||
|
"refundBankAccount": {
|
||||||
|
"holder": "First GmbH",
|
||||||
|
"iban": "DE02120300000000202051",
|
||||||
|
"bic": "BYLADEM1001"
|
||||||
|
},
|
||||||
|
"defaultPrefix": "fir"
|
||||||
}
|
}
|
||||||
""")); // @formatter:on
|
""")); // @formatter:on
|
||||||
}
|
}
|
||||||
@ -350,7 +516,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Accepts({ "Debitor:X(Access Control)" })
|
@Accepts({ "Debitor:X(Access Control)" })
|
||||||
void contactAdminUser_canGetRelatedDebitor() {
|
void contactAdminUser_canGetRelatedDebitorExceptRefundBankAccount() {
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
final var givenDebitorUuid = debitorRepo.findDebitorByOptionalNameLike("first contact").get(0).getUuid();
|
final var givenDebitorUuid = debitorRepo.findDebitorByOptionalNameLike("first contact").get(0).getUuid();
|
||||||
|
|
||||||
@ -365,9 +531,10 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
|||||||
.contentType("application/json")
|
.contentType("application/json")
|
||||||
.body("", lenientlyEquals("""
|
.body("", lenientlyEquals("""
|
||||||
{
|
{
|
||||||
"partner": { person: { "tradeName": "First GmbH" } },
|
"debitorNumber": 1000111,
|
||||||
"billingContact": { "label": "first contact" },
|
"partner": { "partnerNumber": 10001 },
|
||||||
"refundBankAccount": { "holder": "First GmbH" }
|
"debitorRel": { "contact": { "label": "first contact" } },
|
||||||
|
"refundBankAccount": null
|
||||||
}
|
}
|
||||||
""")); // @formatter:on
|
""")); // @formatter:on
|
||||||
}
|
}
|
||||||
@ -378,7 +545,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
|||||||
class PatchDebitor {
|
class PatchDebitor {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void globalAdmin_withoutAssumedRole_canPatchAllPropertiesOfArbitraryDebitor() {
|
void globalAdmin_withoutAssumedRole_canPatchArbitraryDebitor() {
|
||||||
|
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
final var givenDebitor = givenSomeTemporaryDebitor();
|
final var givenDebitor = givenSomeTemporaryDebitor();
|
||||||
@ -400,77 +567,90 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
|||||||
.port(port)
|
.port(port)
|
||||||
.when()
|
.when()
|
||||||
.patch("http://localhost/api/hs/office/debitors/" + givenDebitor.getUuid())
|
.patch("http://localhost/api/hs/office/debitors/" + givenDebitor.getUuid())
|
||||||
.then().assertThat()
|
.then().log().all().assertThat()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.body("uuid", isUuidValid())
|
.body("", lenientlyEquals("""
|
||||||
.body("vatId", is("VAT222222"))
|
{
|
||||||
.body("vatCountryCode", is("AA"))
|
"debitorRel": {
|
||||||
.body("vatBusiness", is(true))
|
"anchor": { "tradeName": "Fourth eG" },
|
||||||
.body("defaultPrefix", is("for"))
|
"holder": { "tradeName": "Fourth eG" },
|
||||||
.body("billingContact.label", is(givenContact.getLabel()))
|
"type": "DEBITOR",
|
||||||
.body("partner.person.tradeName", is(givenDebitor.getPartner().getPerson().getTradeName()));
|
"mark": null,
|
||||||
|
"contact": { "label": "fourth contact" }
|
||||||
|
},
|
||||||
|
"debitorNumber": 10004${debitorNumberSuffix},
|
||||||
|
"debitorNumberSuffix": ${debitorNumberSuffix},
|
||||||
|
"partner": {
|
||||||
|
"partnerNumber": 10004,
|
||||||
|
"partnerRel": {
|
||||||
|
"anchor": { "tradeName": "Hostsharing eG" },
|
||||||
|
"holder": { "tradeName": "Fourth eG" },
|
||||||
|
"type": "PARTNER",
|
||||||
|
"mark": null,
|
||||||
|
"contact": { "label": "fourth contact" }
|
||||||
|
},
|
||||||
|
"details": {
|
||||||
|
"registrationOffice": "Hamburg",
|
||||||
|
"registrationNumber": "RegNo123456789",
|
||||||
|
"birthName": null,
|
||||||
|
"birthPlace": null,
|
||||||
|
"birthday": null,
|
||||||
|
"dateOfDeath": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"billable": true,
|
||||||
|
"vatId": "VAT222222",
|
||||||
|
"vatCountryCode": "AA",
|
||||||
|
"vatBusiness": true,
|
||||||
|
"vatReverseCharge": false,
|
||||||
|
"defaultPrefix": "for"
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.replace("${debitorNumberSuffix}", givenDebitor.getDebitorNumberSuffix().toString()))
|
||||||
|
);
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
|
||||||
// finally, the debitor is actually updated
|
// finally, the debitor is actually updated
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
assertThat(debitorRepo.findByUuid(givenDebitor.getUuid())).isPresent().get()
|
assertThat(debitorRepo.findByUuid(givenDebitor.getUuid())).isPresent().get()
|
||||||
.matches(partner -> {
|
.matches(debitor -> {
|
||||||
assertThat(partner.getPartner().getPerson().getTradeName()).isEqualTo(givenDebitor.getPartner()
|
assertThat(debitor.getDebitorRel().getHolder().getTradeName())
|
||||||
.getPerson()
|
.isEqualTo(givenDebitor.getDebitorRel().getHolder().getTradeName());
|
||||||
.getTradeName());
|
assertThat(debitor.getDebitorRel().getContact().getLabel()).isEqualTo("fourth contact");
|
||||||
assertThat(partner.getBillingContact().getLabel()).isEqualTo("fourth contact");
|
assertThat(debitor.getVatId()).isEqualTo("VAT222222");
|
||||||
assertThat(partner.getVatId()).isEqualTo("VAT222222");
|
assertThat(debitor.getVatCountryCode()).isEqualTo("AA");
|
||||||
assertThat(partner.getVatCountryCode()).isEqualTo("AA");
|
assertThat(debitor.isVatBusiness()).isEqualTo(true);
|
||||||
assertThat(partner.isVatBusiness()).isEqualTo(true);
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void globalAdmin_withoutAssumedRole_canPatchPartialPropertiesOfArbitraryDebitor() {
|
void theContactOwner_canNotPatchARelatedDebitor() {
|
||||||
|
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
final var givenDebitor = givenSomeTemporaryDebitor();
|
final var givenDebitor = givenSomeTemporaryDebitor();
|
||||||
final var newBillingContact = contactRepo.findContactByOptionalLabelLike("sixth").get(0);
|
|
||||||
|
|
||||||
final var location = RestAssured // @formatter:off
|
// @formatter:on
|
||||||
|
RestAssured // @formatter:off
|
||||||
.given()
|
.given()
|
||||||
.header("current-user", "superuser-alex@hostsharing.net")
|
.header("current-user", "superuser-alex@hostsharing.net")
|
||||||
|
.header("assumed-roles", "hs_office_contact#fourthcontact.admin")
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.body("""
|
.body("""
|
||||||
{
|
{
|
||||||
"billingContactUuid": "%s",
|
|
||||||
"vatId": "VAT999999"
|
"vatId": "VAT999999"
|
||||||
}
|
}
|
||||||
""".formatted(newBillingContact.getUuid()))
|
""")
|
||||||
.port(port)
|
.port(port)
|
||||||
.when()
|
.when()
|
||||||
.patch("http://localhost/api/hs/office/debitors/" + givenDebitor.getUuid())
|
.patch("http://localhost/api/hs/office/debitors/" + givenDebitor.getUuid())
|
||||||
.then().assertThat()
|
.then().log().all().assertThat()
|
||||||
.statusCode(200)
|
.statusCode(403)
|
||||||
.contentType(ContentType.JSON)
|
.body("message", containsString("ERROR: [403] Subject"))
|
||||||
.body("uuid", isUuidValid())
|
.body("message", containsString("is not allowed to update hs_office_debitor uuid "));
|
||||||
.body("billingContact.label", is("sixth contact"))
|
|
||||||
.body("vatId", is("VAT999999"))
|
|
||||||
.body("vatCountryCode", is(givenDebitor.getVatCountryCode()))
|
|
||||||
.body("vatBusiness", is(givenDebitor.isVatBusiness()));
|
|
||||||
// @formatter:on
|
|
||||||
|
|
||||||
// finally, the debitor is actually updated
|
|
||||||
assertThat(debitorRepo.findByUuid(givenDebitor.getUuid())).isPresent().get()
|
|
||||||
.matches(partner -> {
|
|
||||||
assertThat(partner.getPartner().getPerson().getTradeName()).isEqualTo(givenDebitor.getPartner()
|
|
||||||
.getPerson()
|
|
||||||
.getTradeName());
|
|
||||||
assertThat(partner.getBillingContact().getLabel()).isEqualTo("sixth contact");
|
|
||||||
assertThat(partner.getVatId()).isEqualTo("VAT999999");
|
|
||||||
assertThat(partner.getVatCountryCode()).isEqualTo(givenDebitor.getVatCountryCode());
|
|
||||||
assertThat(partner.isVatBusiness()).isEqualTo(givenDebitor.isVatBusiness());
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@ -500,7 +680,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
|||||||
void contactAdminUser_canNotDeleteRelatedDebitor() {
|
void contactAdminUser_canNotDeleteRelatedDebitor() {
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
final var givenDebitor = givenSomeTemporaryDebitor();
|
final var givenDebitor = givenSomeTemporaryDebitor();
|
||||||
assertThat(givenDebitor.getBillingContact().getLabel()).isEqualTo("fourth contact");
|
assertThat(givenDebitor.getDebitorRel().getContact().getLabel()).isEqualTo("fourth contact");
|
||||||
|
|
||||||
RestAssured // @formatter:off
|
RestAssured // @formatter:off
|
||||||
.given()
|
.given()
|
||||||
@ -520,7 +700,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
|||||||
void normalUser_canNotDeleteUnrelatedDebitor() {
|
void normalUser_canNotDeleteUnrelatedDebitor() {
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
final var givenDebitor = givenSomeTemporaryDebitor();
|
final var givenDebitor = givenSomeTemporaryDebitor();
|
||||||
assertThat(givenDebitor.getBillingContact().getLabel()).isEqualTo("fourth contact");
|
assertThat(givenDebitor.getDebitorRel().getContact().getLabel()).isEqualTo("fourth contact");
|
||||||
|
|
||||||
RestAssured // @formatter:off
|
RestAssured // @formatter:off
|
||||||
.given()
|
.given()
|
||||||
@ -544,8 +724,14 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
|
|||||||
final var newDebitor = HsOfficeDebitorEntity.builder()
|
final var newDebitor = HsOfficeDebitorEntity.builder()
|
||||||
.debitorNumberSuffix(++nextDebitorSuffix)
|
.debitorNumberSuffix(++nextDebitorSuffix)
|
||||||
.billable(true)
|
.billable(true)
|
||||||
.partner(givenPartner)
|
.debitorRel(
|
||||||
.billingContact(givenContact)
|
HsOfficeRelationEntity.builder()
|
||||||
|
.type(DEBITOR)
|
||||||
|
.anchor(givenPartner.getPartnerRel().getHolder())
|
||||||
|
.holder(givenPartner.getPartnerRel().getHolder())
|
||||||
|
.contact(givenContact)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
.defaultPrefix("abc")
|
.defaultPrefix("abc")
|
||||||
.vatReverseCharge(false)
|
.vatReverseCharge(false)
|
||||||
.build();
|
.build();
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
package net.hostsharing.hsadminng.hs.office.debitor;
|
package net.hostsharing.hsadminng.hs.office.debitor;
|
||||||
|
|
||||||
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity;
|
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity;
|
||||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
|
|
||||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeDebitorPatchResource;
|
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeDebitorPatchResource;
|
||||||
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
|
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationEntity;
|
||||||
import net.hostsharing.test.PatchUnitTestBase;
|
import net.hostsharing.test.PatchUnitTestBase;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.TestInstance;
|
import org.junit.jupiter.api.TestInstance;
|
||||||
@ -28,9 +27,8 @@ class HsOfficeDebitorEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
> {
|
> {
|
||||||
|
|
||||||
private static final UUID INITIAL_DEBITOR_UUID = UUID.randomUUID();
|
private static final UUID INITIAL_DEBITOR_UUID = UUID.randomUUID();
|
||||||
private static final UUID INITIAL_PARTNER_UUID = UUID.randomUUID();
|
private static final UUID INITIAL_DEBITOR_REL_UUID = UUID.randomUUID();
|
||||||
private static final UUID INITIAL_CONTACT_UUID = UUID.randomUUID();
|
private static final UUID PATCHED_DEBITOR_REL_UUID = UUID.randomUUID();
|
||||||
private static final UUID PATCHED_CONTACT_UUID = UUID.randomUUID();
|
|
||||||
|
|
||||||
private static final String PATCHED_DEFAULT_PREFIX = "xyz";
|
private static final String PATCHED_DEFAULT_PREFIX = "xyz";
|
||||||
private static final String PATCHED_VAT_COUNTRY_CODE = "ZZ";
|
private static final String PATCHED_VAT_COUNTRY_CODE = "ZZ";
|
||||||
@ -46,12 +44,8 @@ class HsOfficeDebitorEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
private static final UUID INITIAL_REFUND_BANK_ACCOUNT_UUID = UUID.randomUUID();
|
private static final UUID INITIAL_REFUND_BANK_ACCOUNT_UUID = UUID.randomUUID();
|
||||||
private static final UUID PATCHED_REFUND_BANK_ACCOUNT_UUID = UUID.randomUUID();
|
private static final UUID PATCHED_REFUND_BANK_ACCOUNT_UUID = UUID.randomUUID();
|
||||||
|
|
||||||
private final HsOfficePartnerEntity givenInitialPartner = HsOfficePartnerEntity.builder()
|
private final HsOfficeRelationEntity givenInitialDebitorRel = HsOfficeRelationEntity.builder()
|
||||||
.uuid(INITIAL_PARTNER_UUID)
|
.uuid(INITIAL_DEBITOR_REL_UUID)
|
||||||
.build();
|
|
||||||
|
|
||||||
private final HsOfficeContactEntity givenInitialContact = HsOfficeContactEntity.builder()
|
|
||||||
.uuid(INITIAL_CONTACT_UUID)
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
private final HsOfficeBankAccountEntity givenInitialBankAccount = HsOfficeBankAccountEntity.builder()
|
private final HsOfficeBankAccountEntity givenInitialBankAccount = HsOfficeBankAccountEntity.builder()
|
||||||
@ -62,8 +56,8 @@ class HsOfficeDebitorEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void initMocks() {
|
void initMocks() {
|
||||||
lenient().when(em.getReference(eq(HsOfficeContactEntity.class), any())).thenAnswer(invocation ->
|
lenient().when(em.getReference(eq(HsOfficeRelationEntity.class), any())).thenAnswer(invocation ->
|
||||||
HsOfficeContactEntity.builder().uuid(invocation.getArgument(1)).build());
|
HsOfficeRelationEntity.builder().uuid(invocation.getArgument(1)).build());
|
||||||
lenient().when(em.getReference(eq(HsOfficeBankAccountEntity.class), any())).thenAnswer(invocation ->
|
lenient().when(em.getReference(eq(HsOfficeBankAccountEntity.class), any())).thenAnswer(invocation ->
|
||||||
HsOfficeBankAccountEntity.builder().uuid(invocation.getArgument(1)).build());
|
HsOfficeBankAccountEntity.builder().uuid(invocation.getArgument(1)).build());
|
||||||
}
|
}
|
||||||
@ -72,8 +66,7 @@ class HsOfficeDebitorEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
protected HsOfficeDebitorEntity newInitialEntity() {
|
protected HsOfficeDebitorEntity newInitialEntity() {
|
||||||
final var entity = new HsOfficeDebitorEntity();
|
final var entity = new HsOfficeDebitorEntity();
|
||||||
entity.setUuid(INITIAL_DEBITOR_UUID);
|
entity.setUuid(INITIAL_DEBITOR_UUID);
|
||||||
entity.setPartner(givenInitialPartner);
|
entity.setDebitorRel(givenInitialDebitorRel);
|
||||||
entity.setBillingContact(givenInitialContact);
|
|
||||||
entity.setBillable(INITIAL_BILLABLE);
|
entity.setBillable(INITIAL_BILLABLE);
|
||||||
entity.setVatId("initial VAT-ID");
|
entity.setVatId("initial VAT-ID");
|
||||||
entity.setVatCountryCode("AA");
|
entity.setVatCountryCode("AA");
|
||||||
@ -98,11 +91,11 @@ class HsOfficeDebitorEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
protected Stream<Property> propertyTestDescriptors() {
|
protected Stream<Property> propertyTestDescriptors() {
|
||||||
return Stream.of(
|
return Stream.of(
|
||||||
new JsonNullableProperty<>(
|
new JsonNullableProperty<>(
|
||||||
"billingContact",
|
"debitorRel",
|
||||||
HsOfficeDebitorPatchResource::setBillingContactUuid,
|
HsOfficeDebitorPatchResource::setDebitorRelUuid,
|
||||||
PATCHED_CONTACT_UUID,
|
PATCHED_DEBITOR_REL_UUID,
|
||||||
HsOfficeDebitorEntity::setBillingContact,
|
HsOfficeDebitorEntity::setDebitorRel,
|
||||||
newBillingContact(PATCHED_CONTACT_UUID))
|
newDebitorRel(PATCHED_DEBITOR_REL_UUID))
|
||||||
.notNullable(),
|
.notNullable(),
|
||||||
new SimpleProperty<>(
|
new SimpleProperty<>(
|
||||||
"billable",
|
"billable",
|
||||||
@ -129,7 +122,7 @@ class HsOfficeDebitorEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
new SimpleProperty<>(
|
new SimpleProperty<>(
|
||||||
"vatReverseCharge",
|
"vatReverseCharge",
|
||||||
HsOfficeDebitorPatchResource::setVatReverseCharge,
|
HsOfficeDebitorPatchResource::setVatReverseCharge,
|
||||||
PATCHED_BILLABLE,
|
PATCHED_VAT_REVERSE_CHARGE,
|
||||||
HsOfficeDebitorEntity::setVatReverseCharge)
|
HsOfficeDebitorEntity::setVatReverseCharge)
|
||||||
.notNullable(),
|
.notNullable(),
|
||||||
new JsonNullableProperty<>(
|
new JsonNullableProperty<>(
|
||||||
@ -148,15 +141,15 @@ class HsOfficeDebitorEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private HsOfficeContactEntity newBillingContact(final UUID uuid) {
|
private HsOfficeRelationEntity newDebitorRel(final UUID uuid) {
|
||||||
final var newContact = new HsOfficeContactEntity();
|
return HsOfficeRelationEntity.builder()
|
||||||
newContact.setUuid(uuid);
|
.uuid(uuid)
|
||||||
return newContact;
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private HsOfficeBankAccountEntity newBankAccount(final UUID uuid) {
|
private HsOfficeBankAccountEntity newBankAccount(final UUID uuid) {
|
||||||
final var newBankAccount = new HsOfficeBankAccountEntity();
|
return HsOfficeBankAccountEntity.builder()
|
||||||
newBankAccount.setUuid(uuid);
|
.uuid(uuid)
|
||||||
return newBankAccount;
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,61 +1,52 @@
|
|||||||
package net.hostsharing.hsadminng.hs.office.debitor;
|
package net.hostsharing.hsadminng.hs.office.debitor;
|
||||||
|
|
||||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
|
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
|
||||||
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerDetailsEntity;
|
|
||||||
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
|
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
|
||||||
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity;
|
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity;
|
||||||
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType;
|
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationEntity;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
class HsOfficeDebitorEntityUnitTest {
|
class HsOfficeDebitorEntityUnitTest {
|
||||||
|
|
||||||
|
private HsOfficeRelationEntity givenDebitorRel = HsOfficeRelationEntity.builder()
|
||||||
|
.anchor(HsOfficePersonEntity.builder()
|
||||||
|
.personType(HsOfficePersonType.LEGAL_PERSON)
|
||||||
|
.tradeName("some partner trade name")
|
||||||
|
.build())
|
||||||
|
.holder(HsOfficePersonEntity.builder()
|
||||||
|
.personType(HsOfficePersonType.LEGAL_PERSON)
|
||||||
|
.tradeName("some billing trade name")
|
||||||
|
.build())
|
||||||
|
.contact(HsOfficeContactEntity.builder().label("some label").build())
|
||||||
|
.build();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void toStringContainsPartnerAndContact() {
|
void toStringContainsPartnerAndContact() {
|
||||||
final var given = HsOfficeDebitorEntity.builder()
|
final var given = HsOfficeDebitorEntity.builder()
|
||||||
.debitorNumberSuffix((byte)67)
|
.debitorNumberSuffix((byte)67)
|
||||||
.partner(HsOfficePartnerEntity.builder()
|
.debitorRel(givenDebitorRel)
|
||||||
.person(HsOfficePersonEntity.builder()
|
|
||||||
.personType(HsOfficePersonType.LEGAL_PERSON)
|
|
||||||
.tradeName("some trade name")
|
|
||||||
.build())
|
|
||||||
.details(HsOfficePartnerDetailsEntity.builder().birthName("some birth name").build())
|
|
||||||
.partnerNumber(12345)
|
|
||||||
.build())
|
|
||||||
.billingContact(HsOfficeContactEntity.builder().label("some label").build())
|
|
||||||
.defaultPrefix("som")
|
.defaultPrefix("som")
|
||||||
.build();
|
|
||||||
|
|
||||||
final var result = given.toString();
|
|
||||||
|
|
||||||
assertThat(result).isEqualTo("debitor(D-1234567: LP some trade name: som)");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void toStringWithoutPersonContainsDebitorNumber() {
|
|
||||||
final var given = HsOfficeDebitorEntity.builder()
|
|
||||||
.debitorNumberSuffix((byte)67)
|
|
||||||
.partner(HsOfficePartnerEntity.builder()
|
.partner(HsOfficePartnerEntity.builder()
|
||||||
.person(null)
|
|
||||||
.details(HsOfficePartnerDetailsEntity.builder().birthName("some birth name").build())
|
|
||||||
.partnerNumber(12345)
|
.partnerNumber(12345)
|
||||||
.build())
|
.build())
|
||||||
.billingContact(HsOfficeContactEntity.builder().label("some label").build())
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final var result = given.toString();
|
final var result = given.toString();
|
||||||
|
|
||||||
assertThat(result).isEqualTo("debitor(D-1234567: <person=null>)");
|
assertThat(result).isEqualTo("debitor(D-1234567: rel(anchor='LP some partner trade name', holder='LP some billing trade name'), som)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void toShortStringContainsDebitorNumber() {
|
void toShortStringContainsDebitorNumber() {
|
||||||
final var given = HsOfficeDebitorEntity.builder()
|
final var given = HsOfficeDebitorEntity.builder()
|
||||||
|
.debitorRel(givenDebitorRel)
|
||||||
|
.debitorNumberSuffix((byte)67)
|
||||||
.partner(HsOfficePartnerEntity.builder()
|
.partner(HsOfficePartnerEntity.builder()
|
||||||
.partnerNumber(12345)
|
.partnerNumber(12345)
|
||||||
.build())
|
.build())
|
||||||
.debitorNumberSuffix((byte)67)
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final var result = given.toShortString();
|
final var result = given.toShortString();
|
||||||
@ -66,10 +57,11 @@ class HsOfficeDebitorEntityUnitTest {
|
|||||||
@Test
|
@Test
|
||||||
void getDebitorNumberWithPartnerNumberAndDebitorNumberSuffix() {
|
void getDebitorNumberWithPartnerNumberAndDebitorNumberSuffix() {
|
||||||
final var given = HsOfficeDebitorEntity.builder()
|
final var given = HsOfficeDebitorEntity.builder()
|
||||||
|
.debitorRel(givenDebitorRel)
|
||||||
|
.debitorNumberSuffix((byte)67)
|
||||||
.partner(HsOfficePartnerEntity.builder()
|
.partner(HsOfficePartnerEntity.builder()
|
||||||
.partnerNumber(12345)
|
.partnerNumber(12345)
|
||||||
.build())
|
.build())
|
||||||
.debitorNumberSuffix((byte)67)
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final var result = given.getDebitorNumber();
|
final var result = given.getDebitorNumber();
|
||||||
@ -80,8 +72,9 @@ class HsOfficeDebitorEntityUnitTest {
|
|||||||
@Test
|
@Test
|
||||||
void getDebitorNumberWithoutPartnerReturnsNull() {
|
void getDebitorNumberWithoutPartnerReturnsNull() {
|
||||||
final var given = HsOfficeDebitorEntity.builder()
|
final var given = HsOfficeDebitorEntity.builder()
|
||||||
.partner(null)
|
.debitorRel(givenDebitorRel)
|
||||||
.debitorNumberSuffix((byte)67)
|
.debitorNumberSuffix((byte)67)
|
||||||
|
.partner(null)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final var result = given.getDebitorNumber();
|
final var result = given.getDebitorNumber();
|
||||||
@ -92,10 +85,9 @@ class HsOfficeDebitorEntityUnitTest {
|
|||||||
@Test
|
@Test
|
||||||
void getDebitorNumberWithoutPartnerNumberReturnsNull() {
|
void getDebitorNumberWithoutPartnerNumberReturnsNull() {
|
||||||
final var given = HsOfficeDebitorEntity.builder()
|
final var given = HsOfficeDebitorEntity.builder()
|
||||||
.partner(HsOfficePartnerEntity.builder()
|
.debitorRel(givenDebitorRel)
|
||||||
.partnerNumber(null)
|
|
||||||
.build())
|
|
||||||
.debitorNumberSuffix((byte)67)
|
.debitorNumberSuffix((byte)67)
|
||||||
|
.partner(HsOfficePartnerEntity.builder().build())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final var result = given.getDebitorNumber();
|
final var result = given.getDebitorNumber();
|
||||||
@ -106,10 +98,11 @@ class HsOfficeDebitorEntityUnitTest {
|
|||||||
@Test
|
@Test
|
||||||
void getDebitorNumberWithoutDebitorNumberSuffixReturnsNull() {
|
void getDebitorNumberWithoutDebitorNumberSuffixReturnsNull() {
|
||||||
final var given = HsOfficeDebitorEntity.builder()
|
final var given = HsOfficeDebitorEntity.builder()
|
||||||
|
.debitorRel(givenDebitorRel)
|
||||||
|
.debitorNumberSuffix(null)
|
||||||
.partner(HsOfficePartnerEntity.builder()
|
.partner(HsOfficePartnerEntity.builder()
|
||||||
.partnerNumber(12345)
|
.partnerNumber(12345)
|
||||||
.build())
|
.build())
|
||||||
.debitorNumberSuffix(null)
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final var result = given.getDebitorNumber();
|
final var result = given.getDebitorNumber();
|
||||||
|
@ -4,11 +4,16 @@ import net.hostsharing.hsadminng.context.Context;
|
|||||||
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository;
|
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository;
|
||||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRepository;
|
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRepository;
|
||||||
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRepository;
|
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRepository;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRepository;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationEntity;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationType;
|
||||||
import net.hostsharing.hsadminng.hs.office.test.ContextBasedTestWithCleanup;
|
import net.hostsharing.hsadminng.hs.office.test.ContextBasedTestWithCleanup;
|
||||||
import net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantRepository;
|
import net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantRepository;
|
||||||
|
import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantsDiagramService;
|
||||||
import net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleRepository;
|
import net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleRepository;
|
||||||
import net.hostsharing.test.Array;
|
import net.hostsharing.test.Array;
|
||||||
import net.hostsharing.test.JpaAttempt;
|
import net.hostsharing.test.JpaAttempt;
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
import org.junit.jupiter.api.Disabled;
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Nested;
|
import org.junit.jupiter.api.Nested;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -18,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.orm.jpa.JpaObjectRetrievalFailureException;
|
||||||
import org.springframework.orm.jpa.JpaSystemException;
|
import org.springframework.orm.jpa.JpaSystemException;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@ -27,13 +33,14 @@ import jakarta.servlet.http.HttpServletRequest;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static net.hostsharing.hsadminng.hs.office.test.EntityList.one;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.distinctGrantDisplaysOf;
|
import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.distinctGrantDisplaysOf;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.distinctRoleNamesOf;
|
import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.distinctRoleNamesOf;
|
||||||
import static net.hostsharing.test.JpaAttempt.attempt;
|
import static net.hostsharing.test.JpaAttempt.attempt;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
@DataJpaTest
|
@DataJpaTest
|
||||||
@Import( { Context.class, JpaAttempt.class })
|
@Import( { Context.class, JpaAttempt.class, RbacGrantsDiagramService.class })
|
||||||
class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithCleanup {
|
class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithCleanup {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@ -45,6 +52,9 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
@Autowired
|
@Autowired
|
||||||
HsOfficeContactRepository contactRepo;
|
HsOfficeContactRepository contactRepo;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
HsOfficePersonRepository personRepo;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
HsOfficeBankAccountRepository bankAccountRepo;
|
HsOfficeBankAccountRepository bankAccountRepo;
|
||||||
|
|
||||||
@ -60,9 +70,11 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
@Autowired
|
@Autowired
|
||||||
JpaAttempt jpaAttempt;
|
JpaAttempt jpaAttempt;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
RbacGrantsDiagramService mermaidService;
|
||||||
|
|
||||||
@MockBean
|
@MockBean
|
||||||
HttpServletRequest request;
|
HttpServletRequest request;
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
class CreateDebitor {
|
class CreateDebitor {
|
||||||
|
|
||||||
@ -71,15 +83,19 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
// given
|
// given
|
||||||
context("superuser-alex@hostsharing.net");
|
context("superuser-alex@hostsharing.net");
|
||||||
final var count = debitorRepo.count();
|
final var count = debitorRepo.count();
|
||||||
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("First GmbH").get(0);
|
final var givenPartnerPerson = one(personRepo.findPersonByOptionalNameLike("First GmbH"));
|
||||||
final var givenContact = contactRepo.findContactByOptionalLabelLike("first contact").get(0);
|
final var givenContact = one(contactRepo.findContactByOptionalLabelLike("first contact"));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
final var result = attempt(em, () -> {
|
final var result = attempt(em, () -> {
|
||||||
final var newDebitor = HsOfficeDebitorEntity.builder()
|
final var newDebitor = HsOfficeDebitorEntity.builder()
|
||||||
.debitorNumberSuffix((byte)21)
|
.debitorNumberSuffix((byte)21)
|
||||||
.partner(givenPartner)
|
.debitorRel(HsOfficeRelationEntity.builder()
|
||||||
.billingContact(givenContact)
|
.type(HsOfficeRelationType.DEBITOR)
|
||||||
|
.anchor(givenPartnerPerson)
|
||||||
|
.holder(givenPartnerPerson)
|
||||||
|
.contact(givenContact)
|
||||||
|
.build())
|
||||||
.defaultPrefix("abc")
|
.defaultPrefix("abc")
|
||||||
.billable(false)
|
.billable(false)
|
||||||
.build();
|
.build();
|
||||||
@ -99,16 +115,19 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
public void canNotCreateNewDebitorWithInvalidDefaultPrefix(final String givenPrefix) {
|
public void canNotCreateNewDebitorWithInvalidDefaultPrefix(final String givenPrefix) {
|
||||||
// given
|
// given
|
||||||
context("superuser-alex@hostsharing.net");
|
context("superuser-alex@hostsharing.net");
|
||||||
final var count = debitorRepo.count();
|
final var givenPartnerPerson = one(personRepo.findPersonByOptionalNameLike("First GmbH"));
|
||||||
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("First GmbH").get(0);
|
final var givenContact = one(contactRepo.findContactByOptionalLabelLike("first contact"));
|
||||||
final var givenContact = contactRepo.findContactByOptionalLabelLike("first contact").get(0);
|
|
||||||
|
|
||||||
// when
|
// when
|
||||||
final var result = attempt(em, () -> {
|
final var result = attempt(em, () -> {
|
||||||
final var newDebitor = HsOfficeDebitorEntity.builder()
|
final var newDebitor = HsOfficeDebitorEntity.builder()
|
||||||
.debitorNumberSuffix((byte)21)
|
.debitorNumberSuffix((byte)21)
|
||||||
.partner(givenPartner)
|
.debitorRel(HsOfficeRelationEntity.builder()
|
||||||
.billingContact(givenContact)
|
.type(HsOfficeRelationType.DEBITOR)
|
||||||
|
.anchor(givenPartnerPerson)
|
||||||
|
.holder(givenPartnerPerson)
|
||||||
|
.contact(givenContact)
|
||||||
|
.build())
|
||||||
.billable(true)
|
.billable(true)
|
||||||
.vatReverseCharge(false)
|
.vatReverseCharge(false)
|
||||||
.vatBusiness(false)
|
.vatBusiness(false)
|
||||||
@ -128,21 +147,22 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
final var initialRoleNames = distinctRoleNamesOf(rawRoleRepo.findAll());
|
final var initialRoleNames = distinctRoleNamesOf(rawRoleRepo.findAll());
|
||||||
final var initialGrantNames = distinctGrantDisplaysOf(rawGrantRepo.findAll()).stream()
|
final var initialGrantNames = distinctGrantDisplaysOf(rawGrantRepo.findAll()).stream()
|
||||||
// some search+replace to make the output fit into the screen width
|
// some search+replace to make the output fit into the screen width
|
||||||
.map(s -> s.replace("superuser-alex@hostsharing.net", "superuser-alex"))
|
|
||||||
.map(s -> s.replace("22FourtheG-fourthcontact", "FeG"))
|
|
||||||
.map(s -> s.replace("FourtheG-fourthcontact", "FeG"))
|
|
||||||
.map(s -> s.replace("fourthcontact", "4th"))
|
|
||||||
.map(s -> s.replace("hs_office_", ""))
|
.map(s -> s.replace("hs_office_", ""))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
attempt(em, () -> {
|
attempt(em, () -> {
|
||||||
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("Fourth").get(0);
|
final var givenPartnerPerson = one(personRepo.findPersonByOptionalNameLike("First GmbH"));
|
||||||
final var givenContact = contactRepo.findContactByOptionalLabelLike("fourth contact").get(0);
|
final var givenDebitorPerson = one(personRepo.findPersonByOptionalNameLike("Fourth eG"));
|
||||||
|
final var givenContact = one(contactRepo.findContactByOptionalLabelLike("fourth contact"));
|
||||||
final var newDebitor = HsOfficeDebitorEntity.builder()
|
final var newDebitor = HsOfficeDebitorEntity.builder()
|
||||||
.debitorNumberSuffix((byte)22)
|
.debitorNumberSuffix((byte)22)
|
||||||
.partner(givenPartner)
|
.debitorRel(HsOfficeRelationEntity.builder()
|
||||||
.billingContact(givenContact)
|
.type(HsOfficeRelationType.DEBITOR)
|
||||||
|
.anchor(givenPartnerPerson)
|
||||||
|
.holder(givenDebitorPerson)
|
||||||
|
.contact(givenContact)
|
||||||
|
.build())
|
||||||
.defaultPrefix("abc")
|
.defaultPrefix("abc")
|
||||||
.billable(false)
|
.billable(false)
|
||||||
.build();
|
.build();
|
||||||
@ -152,49 +172,52 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
// then
|
// then
|
||||||
assertThat(distinctRoleNamesOf(rawRoleRepo.findAll())).containsExactlyInAnyOrder(Array.from(
|
assertThat(distinctRoleNamesOf(rawRoleRepo.findAll())).containsExactlyInAnyOrder(Array.from(
|
||||||
initialRoleNames,
|
initialRoleNames,
|
||||||
"hs_office_debitor#1000422:FourtheG-fourthcontact.owner",
|
"hs_office_relation#FirstGmbH-with-DEBITOR-FourtheG.owner",
|
||||||
"hs_office_debitor#1000422:FourtheG-fourthcontact.admin",
|
"hs_office_relation#FirstGmbH-with-DEBITOR-FourtheG.admin",
|
||||||
"hs_office_debitor#1000422:FourtheG-fourthcontact.agent",
|
"hs_office_relation#FirstGmbH-with-DEBITOR-FourtheG.agent",
|
||||||
"hs_office_debitor#1000422:FourtheG-fourthcontact.tenant",
|
"hs_office_relation#FirstGmbH-with-DEBITOR-FourtheG.tenant"));
|
||||||
"hs_office_debitor#1000422:FourtheG-fourthcontact.guest"));
|
|
||||||
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll()))
|
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll()))
|
||||||
.map(s -> s.replace("superuser-alex@hostsharing.net", "superuser-alex"))
|
|
||||||
.map(s -> s.replace("22FourtheG-fourthcontact", "FeG"))
|
|
||||||
.map(s -> s.replace("FourtheG-fourthcontact", "FeG"))
|
|
||||||
.map(s -> s.replace("fourthcontact", "4th"))
|
|
||||||
.map(s -> s.replace("hs_office_", ""))
|
.map(s -> s.replace("hs_office_", ""))
|
||||||
.containsExactlyInAnyOrder(Array.fromFormatted(
|
.containsExactlyInAnyOrder(Array.fromFormatted(
|
||||||
initialGrantNames,
|
initialGrantNames,
|
||||||
|
"{ grant perm INSERT into sepamandate with relation#FirstGmbH-with-DEBITOR-FourtheG to role relation#FirstGmbH-with-DEBITOR-FourtheG.admin by system and assume }",
|
||||||
|
|
||||||
// owner
|
// owner
|
||||||
"{ grant perm DELETE on debitor#1000422:FeG to role debitor#1000422:FeG.owner by system and assume }",
|
"{ grant perm DELETE on debitor#D-1000122 to role relation#FirstGmbH-with-DEBITOR-FourtheG.owner by system and assume }",
|
||||||
"{ grant role debitor#1000422:FeG.owner to role global#global.admin by system and assume }",
|
"{ grant perm DELETE on relation#FirstGmbH-with-DEBITOR-FourtheG to role relation#FirstGmbH-with-DEBITOR-FourtheG.owner by system and assume }",
|
||||||
"{ grant role debitor#1000422:FeG.owner to user superuser-alex by global#global.admin and assume }",
|
"{ grant role relation#FirstGmbH-with-DEBITOR-FourtheG.owner to role global#global.admin by system and assume }",
|
||||||
|
"{ grant role relation#FirstGmbH-with-DEBITOR-FourtheG.owner to user superuser-alex@hostsharing.net by relation#FirstGmbH-with-DEBITOR-FourtheG.owner and assume }",
|
||||||
|
|
||||||
// admin
|
// admin
|
||||||
"{ grant perm UPDATE on debitor#1000422:FeG to role debitor#1000422:FeG.admin by system and assume }",
|
"{ grant perm UPDATE on debitor#D-1000122 to role relation#FirstGmbH-with-DEBITOR-FourtheG.admin by system and assume }",
|
||||||
"{ grant role debitor#1000422:FeG.admin to role debitor#1000422:FeG.owner by system and assume }",
|
"{ grant perm UPDATE on relation#FirstGmbH-with-DEBITOR-FourtheG to role relation#FirstGmbH-with-DEBITOR-FourtheG.admin by system and assume }",
|
||||||
|
"{ grant role relation#FirstGmbH-with-DEBITOR-FourtheG.admin to role relation#FirstGmbH-with-DEBITOR-FourtheG.owner by system and assume }",
|
||||||
|
"{ grant role relation#FirstGmbH-with-DEBITOR-FourtheG.admin to role person#FirstGmbH.admin by system and assume }",
|
||||||
|
"{ grant role relation#FirstGmbH-with-DEBITOR-FourtheG.admin to role relation#HostsharingeG-with-PARTNER-FirstGmbH.admin by system and assume }",
|
||||||
|
|
||||||
// agent
|
// agent
|
||||||
"{ grant role debitor#1000422:FeG.agent to role debitor#1000422:FeG.admin by system and assume }",
|
"{ grant role relation#FirstGmbH-with-DEBITOR-FourtheG.agent to role person#FourtheG.admin by system and assume }",
|
||||||
"{ grant role debitor#1000422:FeG.agent to role contact#4th.admin by system and assume }",
|
"{ grant role relation#FirstGmbH-with-DEBITOR-FourtheG.agent to role relation#FirstGmbH-with-DEBITOR-FourtheG.admin by system and assume }",
|
||||||
"{ grant role debitor#1000422:FeG.agent to role partner#10004:FeG.admin by system and assume }",
|
"{ grant role relation#FirstGmbH-with-DEBITOR-FourtheG.agent to role relation#HostsharingeG-with-PARTNER-FirstGmbH.agent by system and assume }",
|
||||||
|
|
||||||
// tenant
|
// tenant
|
||||||
"{ grant role contact#4th.guest to role debitor#1000422:FeG.tenant by system and assume }",
|
"{ grant perm SELECT on debitor#D-1000122 to role relation#FirstGmbH-with-DEBITOR-FourtheG.tenant by system and assume }",
|
||||||
"{ grant role debitor#1000422:FeG.tenant to role debitor#1000422:FeG.agent by system and assume }",
|
"{ grant perm SELECT on relation#FirstGmbH-with-DEBITOR-FourtheG to role relation#FirstGmbH-with-DEBITOR-FourtheG.tenant by system and assume }",
|
||||||
"{ grant role debitor#1000422:FeG.tenant to role partner#10004:FeG.agent by system and assume }",
|
"{ grant role relation#HostsharingeG-with-PARTNER-FirstGmbH.tenant to role relation#FirstGmbH-with-DEBITOR-FourtheG.agent by system and assume }",
|
||||||
"{ grant role partner#10004:FeG.tenant to role debitor#1000422:FeG.tenant by system and assume }",
|
"{ grant role contact#fourthcontact.referrer to role relation#FirstGmbH-with-DEBITOR-FourtheG.tenant by system and assume }",
|
||||||
|
"{ grant role person#FirstGmbH.referrer to role relation#FirstGmbH-with-DEBITOR-FourtheG.tenant by system and assume }",
|
||||||
// guest
|
"{ grant role person#FourtheG.referrer to role relation#FirstGmbH-with-DEBITOR-FourtheG.tenant by system and assume }",
|
||||||
"{ grant perm SELECT on debitor#1000422:FeG to role debitor#1000422:FeG.guest by system and assume }",
|
"{ grant role relation#FirstGmbH-with-DEBITOR-FourtheG.tenant to role contact#fourthcontact.admin by system and assume }",
|
||||||
"{ grant role debitor#1000422:FeG.guest to role debitor#1000422:FeG.tenant by system and assume }",
|
"{ grant role relation#FirstGmbH-with-DEBITOR-FourtheG.tenant to role person#FourtheG.admin by system and assume }",
|
||||||
|
"{ grant role relation#FirstGmbH-with-DEBITOR-FourtheG.tenant to role relation#FirstGmbH-with-DEBITOR-FourtheG.agent by system and assume }",
|
||||||
|
|
||||||
null));
|
null));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertThatDebitorIsPersisted(final HsOfficeDebitorEntity saved) {
|
private void assertThatDebitorIsPersisted(final HsOfficeDebitorEntity saved) {
|
||||||
|
final var savedRefreshed = refresh(saved);
|
||||||
final var found = debitorRepo.findByUuid(saved.getUuid());
|
final var found = debitorRepo.findByUuid(saved.getUuid());
|
||||||
assertThat(found).isNotEmpty().get().usingRecursiveComparison().isEqualTo(saved);
|
assertThat(found).isNotEmpty().get().usingRecursiveComparison().isEqualTo(savedRefreshed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,9 +235,9 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
// then
|
// then
|
||||||
allTheseDebitorsAreReturned(
|
allTheseDebitorsAreReturned(
|
||||||
result,
|
result,
|
||||||
"debitor(D-1000111: LP First GmbH: fir)",
|
"debitor(D-1000111: rel(anchor='LP First GmbH', type='DEBITOR', holder='LP First GmbH'), fir)",
|
||||||
"debitor(D-1000212: LP Second e.K.: sec)",
|
"debitor(D-1000212: rel(anchor='LP Second e.K.', type='DEBITOR', holder='LP Second e.K.'), sec)",
|
||||||
"debitor(D-1000313: IF Third OHG: thi)");
|
"debitor(D-1000313: rel(anchor='IF Third OHG', type='DEBITOR', holder='IF Third OHG'), thi)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@ -233,8 +256,8 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
|
|
||||||
// then:
|
// then:
|
||||||
exactlyTheseDebitorsAreReturned(result,
|
exactlyTheseDebitorsAreReturned(result,
|
||||||
"debitor(D-1000111: LP First GmbH: fir)",
|
"debitor(D-1000111: P-10001, fir)",
|
||||||
"debitor(D-1000120: LP First GmbH: fif)");
|
"debitor(D-1000120: P-10001, fif)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -262,7 +285,8 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
final var result = debitorRepo.findDebitorByDebitorNumber(1000313);
|
final var result = debitorRepo.findDebitorByDebitorNumber(1000313);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
exactlyTheseDebitorsAreReturned(result, "debitor(D-1000313: IF Third OHG: thi)");
|
exactlyTheseDebitorsAreReturned(result,
|
||||||
|
"debitor(D-1000313: rel(anchor='IF Third OHG', type='DEBITOR', holder='IF Third OHG'), thi)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,7 +302,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
final var result = debitorRepo.findDebitorByOptionalNameLike("third contact");
|
final var result = debitorRepo.findDebitorByOptionalNameLike("third contact");
|
||||||
|
|
||||||
// then
|
// then
|
||||||
exactlyTheseDebitorsAreReturned(result, "debitor(D-1000313: IF Third OHG: thi)");
|
exactlyTheseDebitorsAreReturned(result, "debitor(D-1000313: rel(anchor='IF Third OHG', type='DEBITOR', holder='IF Third OHG'), thi)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,13 +314,14 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
// given
|
// given
|
||||||
context("superuser-alex@hostsharing.net");
|
context("superuser-alex@hostsharing.net");
|
||||||
final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "fifth contact", "Fourth", "fif");
|
final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "fifth contact", "Fourth", "fif");
|
||||||
|
|
||||||
assertThatDebitorIsVisibleForUserWithRole(
|
assertThatDebitorIsVisibleForUserWithRole(
|
||||||
givenDebitor,
|
givenDebitor,
|
||||||
"hs_office_partner#10004:FourtheG-fourthcontact.admin");
|
"hs_office_relation#FourtheG-with-DEBITOR-FourtheG.admin", true);
|
||||||
assertThatDebitorActuallyInDatabase(givenDebitor);
|
final var givenNewPartnerPerson = one(personRepo.findPersonByOptionalNameLike("First"));
|
||||||
final var givenNewPartner = partnerRepo.findPartnerByOptionalNameLike("First").get(0);
|
final var givenNewBillingPerson = one(personRepo.findPersonByOptionalNameLike("Firby"));
|
||||||
final var givenNewContact = contactRepo.findContactByOptionalLabelLike("sixth contact").get(0);
|
final var givenNewContact = one(contactRepo.findContactByOptionalLabelLike("sixth contact"));
|
||||||
final var givenNewBankAccount = bankAccountRepo.findByOptionalHolderLike("first").get(0);
|
final var givenNewBankAccount = one(bankAccountRepo.findByOptionalHolderLike("first"));
|
||||||
final String givenNewVatId = "NEW-VAT-ID";
|
final String givenNewVatId = "NEW-VAT-ID";
|
||||||
final String givenNewVatCountryCode = "NC";
|
final String givenNewVatCountryCode = "NC";
|
||||||
final boolean givenNewVatBusiness = !givenDebitor.isVatBusiness();
|
final boolean givenNewVatBusiness = !givenDebitor.isVatBusiness();
|
||||||
@ -304,8 +329,12 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
// when
|
// when
|
||||||
final var result = jpaAttempt.transacted(() -> {
|
final var result = jpaAttempt.transacted(() -> {
|
||||||
context("superuser-alex@hostsharing.net");
|
context("superuser-alex@hostsharing.net");
|
||||||
givenDebitor.setPartner(givenNewPartner);
|
givenDebitor.setDebitorRel(HsOfficeRelationEntity.builder()
|
||||||
givenDebitor.setBillingContact(givenNewContact);
|
.type(HsOfficeRelationType.DEBITOR)
|
||||||
|
.anchor(givenNewPartnerPerson)
|
||||||
|
.holder(givenNewBillingPerson)
|
||||||
|
.contact(givenNewContact)
|
||||||
|
.build());
|
||||||
givenDebitor.setRefundBankAccount(givenNewBankAccount);
|
givenDebitor.setRefundBankAccount(givenNewBankAccount);
|
||||||
givenDebitor.setVatId(givenNewVatId);
|
givenDebitor.setVatId(givenNewVatId);
|
||||||
givenDebitor.setVatCountryCode(givenNewVatCountryCode);
|
givenDebitor.setVatCountryCode(givenNewVatCountryCode);
|
||||||
@ -317,15 +346,15 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
result.assertSuccessful();
|
result.assertSuccessful();
|
||||||
assertThatDebitorIsVisibleForUserWithRole(
|
assertThatDebitorIsVisibleForUserWithRole(
|
||||||
result.returnedValue(),
|
result.returnedValue(),
|
||||||
"global#global.admin");
|
"global#global.admin", true);
|
||||||
|
|
||||||
// ... partner role was reassigned:
|
// ... partner role was reassigned:
|
||||||
assertThatDebitorIsNotVisibleForUserWithRole(
|
assertThatDebitorIsNotVisibleForUserWithRole(
|
||||||
result.returnedValue(),
|
result.returnedValue(),
|
||||||
"hs_office_partner#10004:FourtheG-fourthcontact.agent");
|
"hs_office_relation#FourtheG-with-DEBITOR-FourtheG.admin");
|
||||||
assertThatDebitorIsVisibleForUserWithRole(
|
assertThatDebitorIsVisibleForUserWithRole(
|
||||||
result.returnedValue(),
|
result.returnedValue(),
|
||||||
"hs_office_partner#10001:FirstGmbH-firstcontact.agent");
|
"hs_office_relation#FirstGmbH-with-DEBITOR-FirbySusan.agent", true);
|
||||||
|
|
||||||
// ... contact role was reassigned:
|
// ... contact role was reassigned:
|
||||||
assertThatDebitorIsNotVisibleForUserWithRole(
|
assertThatDebitorIsNotVisibleForUserWithRole(
|
||||||
@ -333,15 +362,15 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
"hs_office_contact#fifthcontact.admin");
|
"hs_office_contact#fifthcontact.admin");
|
||||||
assertThatDebitorIsVisibleForUserWithRole(
|
assertThatDebitorIsVisibleForUserWithRole(
|
||||||
result.returnedValue(),
|
result.returnedValue(),
|
||||||
"hs_office_contact#sixthcontact.admin");
|
"hs_office_contact#sixthcontact.admin", false);
|
||||||
|
|
||||||
// ... bank-account role was reassigned:
|
// ... bank-account role was reassigned:
|
||||||
assertThatDebitorIsNotVisibleForUserWithRole(
|
assertThatDebitorIsNotVisibleForUserWithRole(
|
||||||
result.returnedValue(),
|
result.returnedValue(),
|
||||||
"hs_office_bankaccount#FourtheG.admin");
|
"hs_office_bankaccount#DE02200505501015871393.admin");
|
||||||
assertThatDebitorIsVisibleForUserWithRole(
|
assertThatDebitorIsVisibleForUserWithRole(
|
||||||
result.returnedValue(),
|
result.returnedValue(),
|
||||||
"hs_office_bankaccount#FirstGmbH.admin");
|
"hs_office_bankaccount#DE02120300000000202051.admin", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -351,9 +380,9 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "fifth contact", null, "fig");
|
final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "fifth contact", null, "fig");
|
||||||
assertThatDebitorIsVisibleForUserWithRole(
|
assertThatDebitorIsVisibleForUserWithRole(
|
||||||
givenDebitor,
|
givenDebitor,
|
||||||
"hs_office_partner#10004:FourtheG-fourthcontact.admin");
|
"hs_office_relation#FourtheG-with-DEBITOR-FourtheG.admin", true);
|
||||||
assertThatDebitorActuallyInDatabase(givenDebitor);
|
assertThatDebitorActuallyInDatabase(givenDebitor, true);
|
||||||
final var givenNewBankAccount = bankAccountRepo.findByOptionalHolderLike("first").get(0);
|
final var givenNewBankAccount = one(bankAccountRepo.findByOptionalHolderLike("first"));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
final var result = jpaAttempt.transacted(() -> {
|
final var result = jpaAttempt.transacted(() -> {
|
||||||
@ -366,12 +395,12 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
result.assertSuccessful();
|
result.assertSuccessful();
|
||||||
assertThatDebitorIsVisibleForUserWithRole(
|
assertThatDebitorIsVisibleForUserWithRole(
|
||||||
result.returnedValue(),
|
result.returnedValue(),
|
||||||
"global#global.admin");
|
"global#global.admin", true);
|
||||||
|
|
||||||
// ... bank-account role was assigned:
|
// ... bank-account role was assigned:
|
||||||
assertThatDebitorIsVisibleForUserWithRole(
|
assertThatDebitorIsVisibleForUserWithRole(
|
||||||
result.returnedValue(),
|
result.returnedValue(),
|
||||||
"hs_office_bankaccount#FirstGmbH.admin");
|
"hs_office_bankaccount#DE02120300000000202051.admin", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -381,8 +410,8 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "fifth contact", "Fourth", "fih");
|
final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "fifth contact", "Fourth", "fih");
|
||||||
assertThatDebitorIsVisibleForUserWithRole(
|
assertThatDebitorIsVisibleForUserWithRole(
|
||||||
givenDebitor,
|
givenDebitor,
|
||||||
"hs_office_partner#10004:FourtheG-fourthcontact.admin");
|
"hs_office_relation#HostsharingeG-with-PARTNER-FourtheG.agent", true);
|
||||||
assertThatDebitorActuallyInDatabase(givenDebitor);
|
assertThatDebitorActuallyInDatabase(givenDebitor, true);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
final var result = jpaAttempt.transacted(() -> {
|
final var result = jpaAttempt.transacted(() -> {
|
||||||
@ -395,27 +424,27 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
result.assertSuccessful();
|
result.assertSuccessful();
|
||||||
assertThatDebitorIsVisibleForUserWithRole(
|
assertThatDebitorIsVisibleForUserWithRole(
|
||||||
result.returnedValue(),
|
result.returnedValue(),
|
||||||
"global#global.admin");
|
"global#global.admin", true);
|
||||||
|
|
||||||
// ... bank-account role was removed from previous bank-account admin:
|
// ... bank-account role was removed from previous bank-account admin:
|
||||||
assertThatDebitorIsNotVisibleForUserWithRole(
|
assertThatDebitorIsNotVisibleForUserWithRole(
|
||||||
result.returnedValue(),
|
result.returnedValue(),
|
||||||
"hs_office_bankaccount#FourtheG.admin");
|
"hs_office_bankaccount#DE02200505501015871393.admin");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void partnerAdmin_canNotUpdateRelatedDebitor() {
|
public void partnerAgent_canNotUpdateRelatedDebitor() {
|
||||||
// given
|
// given
|
||||||
context("superuser-alex@hostsharing.net");
|
context("superuser-alex@hostsharing.net");
|
||||||
final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "eighth", "Fourth", "eig");
|
final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "eighth", "Fourth", "eig");
|
||||||
assertThatDebitorIsVisibleForUserWithRole(
|
assertThatDebitorIsVisibleForUserWithRole(
|
||||||
givenDebitor,
|
givenDebitor,
|
||||||
"hs_office_partner#10004:FourtheG-fourthcontact.admin");
|
"hs_office_relation#HostsharingeG-with-PARTNER-FourtheG.agent", true);
|
||||||
assertThatDebitorActuallyInDatabase(givenDebitor);
|
assertThatDebitorActuallyInDatabase(givenDebitor, true);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
final var result = jpaAttempt.transacted(() -> {
|
final var result = jpaAttempt.transacted(() -> {
|
||||||
context("superuser-alex@hostsharing.net", "hs_office_partner#10004:FourtheG-fourthcontact.admin");
|
context("superuser-alex@hostsharing.net", "hs_office_relation#HostsharingeG-with-PARTNER-FourtheG.agent");
|
||||||
givenDebitor.setVatId("NEW-VAT-ID");
|
givenDebitor.setVatId("NEW-VAT-ID");
|
||||||
return toCleanup(debitorRepo.save(givenDebitor));
|
return toCleanup(debitorRepo.save(givenDebitor));
|
||||||
});
|
});
|
||||||
@ -430,10 +459,10 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
// given
|
// given
|
||||||
context("superuser-alex@hostsharing.net");
|
context("superuser-alex@hostsharing.net");
|
||||||
final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "ninth", "Fourth", "nin");
|
final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "ninth", "Fourth", "nin");
|
||||||
|
assertThatDebitorActuallyInDatabase(givenDebitor, true);
|
||||||
assertThatDebitorIsVisibleForUserWithRole(
|
assertThatDebitorIsVisibleForUserWithRole(
|
||||||
givenDebitor,
|
givenDebitor,
|
||||||
"hs_office_contact#ninthcontact.admin");
|
"hs_office_contact#ninthcontact.admin", false);
|
||||||
assertThatDebitorActuallyInDatabase(givenDebitor);
|
|
||||||
|
|
||||||
// when
|
// when
|
||||||
final var result = jpaAttempt.transacted(() -> {
|
final var result = jpaAttempt.transacted(() -> {
|
||||||
@ -443,22 +472,34 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
});
|
});
|
||||||
|
|
||||||
// then
|
// then
|
||||||
result.assertExceptionWithRootCauseMessage(JpaSystemException.class,
|
result.assertExceptionWithRootCauseMessage(
|
||||||
"[403] Subject ", " is not allowed to update hs_office_debitor uuid");
|
JpaObjectRetrievalFailureException.class,
|
||||||
|
// this technical error message gets translated to a [403] error at the controller level
|
||||||
|
"Unable to find net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity with id ");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertThatDebitorActuallyInDatabase(final HsOfficeDebitorEntity saved) {
|
private void assertThatDebitorActuallyInDatabase(final HsOfficeDebitorEntity saved, final boolean withPartner) {
|
||||||
final var found = debitorRepo.findByUuid(saved.getUuid());
|
final var found = debitorRepo.findByUuid(saved.getUuid());
|
||||||
assertThat(found).isNotEmpty().get().isNotSameAs(saved)
|
assertThat(found).isNotEmpty();
|
||||||
.extracting(Object::toString).isEqualTo(saved.toString());
|
found.ifPresent(foundEntity -> {
|
||||||
|
em.refresh(foundEntity);
|
||||||
|
Hibernate.initialize(foundEntity);
|
||||||
|
assertThat(foundEntity).isNotSameAs(saved);
|
||||||
|
if (withPartner) {
|
||||||
|
assertThat(foundEntity.getPartner()).isNotNull();
|
||||||
|
}
|
||||||
|
assertThat(foundEntity.getDebitorRel()).extracting(HsOfficeRelationEntity::toString)
|
||||||
|
.isEqualTo(saved.getDebitorRel().toString());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertThatDebitorIsVisibleForUserWithRole(
|
private void assertThatDebitorIsVisibleForUserWithRole(
|
||||||
final HsOfficeDebitorEntity entity,
|
final HsOfficeDebitorEntity entity,
|
||||||
final String assumedRoles) {
|
final String assumedRoles,
|
||||||
|
final boolean withPartner) {
|
||||||
jpaAttempt.transacted(() -> {
|
jpaAttempt.transacted(() -> {
|
||||||
context("superuser-alex@hostsharing.net", assumedRoles);
|
context("superuser-alex@hostsharing.net", assumedRoles);
|
||||||
assertThatDebitorActuallyInDatabase(entity);
|
assertThatDebitorActuallyInDatabase(entity, withPartner);
|
||||||
}).assertSuccessful();
|
}).assertSuccessful();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -497,14 +538,14 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void relatedPerson_canNotDeleteTheirRelatedDebitor() {
|
public void debitorAgent_canViewButNotDeleteTheirRelatedDebitor() {
|
||||||
// given
|
// given
|
||||||
context("superuser-alex@hostsharing.net", null);
|
context("superuser-alex@hostsharing.net", null);
|
||||||
final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "eleventh", "Fourth", "ele");
|
final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "eleventh", "Fourth", "ele");
|
||||||
|
|
||||||
// when
|
// when
|
||||||
final var result = jpaAttempt.transacted(() -> {
|
final var result = jpaAttempt.transacted(() -> {
|
||||||
context("person-FourtheG@example.com");
|
context("superuser-alex@hostsharing.net", "hs_office_relation#FourtheG-with-DEBITOR-FourtheG.admin");
|
||||||
assertThat(debitorRepo.findByUuid(givenDebitor.getUuid())).isPresent();
|
assertThat(debitorRepo.findByUuid(givenDebitor.getUuid())).isPresent();
|
||||||
|
|
||||||
debitorRepo.deleteByUuid(givenDebitor.getUuid());
|
debitorRepo.deleteByUuid(givenDebitor.getUuid());
|
||||||
@ -561,20 +602,24 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
|||||||
}
|
}
|
||||||
|
|
||||||
private HsOfficeDebitorEntity givenSomeTemporaryDebitor(
|
private HsOfficeDebitorEntity givenSomeTemporaryDebitor(
|
||||||
final String partner,
|
final String partnerName,
|
||||||
final String contact,
|
final String contactLabel,
|
||||||
final String bankAccount,
|
final String bankAccountHolder,
|
||||||
final String defaultPrefix) {
|
final String defaultPrefix) {
|
||||||
return jpaAttempt.transacted(() -> {
|
return jpaAttempt.transacted(() -> {
|
||||||
context("superuser-alex@hostsharing.net");
|
context("superuser-alex@hostsharing.net");
|
||||||
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike(partner).get(0);
|
final var givenPartnerPerson = one(personRepo.findPersonByOptionalNameLike(partnerName));
|
||||||
final var givenContact = contactRepo.findContactByOptionalLabelLike(contact).get(0);
|
final var givenContact = one(contactRepo.findContactByOptionalLabelLike(contactLabel));
|
||||||
final var givenBankAccount =
|
final var givenBankAccount =
|
||||||
bankAccount != null ? bankAccountRepo.findByOptionalHolderLike(bankAccount).get(0) : null;
|
bankAccountHolder != null ? one(bankAccountRepo.findByOptionalHolderLike(bankAccountHolder)) : null;
|
||||||
final var newDebitor = HsOfficeDebitorEntity.builder()
|
final var newDebitor = HsOfficeDebitorEntity.builder()
|
||||||
.debitorNumberSuffix((byte)20)
|
.debitorNumberSuffix((byte)20)
|
||||||
.partner(givenPartner)
|
.debitorRel(HsOfficeRelationEntity.builder()
|
||||||
.billingContact(givenContact)
|
.type(HsOfficeRelationType.DEBITOR)
|
||||||
|
.anchor(givenPartnerPerson)
|
||||||
|
.holder(givenPartnerPerson)
|
||||||
|
.contact(givenContact)
|
||||||
|
.build())
|
||||||
.refundBankAccount(givenBankAccount)
|
.refundBankAccount(givenBankAccount)
|
||||||
.defaultPrefix(defaultPrefix)
|
.defaultPrefix(defaultPrefix)
|
||||||
.billable(true)
|
.billable(true)
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
package net.hostsharing.hsadminng.hs.office.debitor;
|
package net.hostsharing.hsadminng.hs.office.debitor;
|
||||||
|
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationEntity;
|
||||||
|
|
||||||
import static net.hostsharing.hsadminng.hs.office.contact.TestHsOfficeContact.TEST_CONTACT;
|
import static net.hostsharing.hsadminng.hs.office.contact.TestHsOfficeContact.TEST_CONTACT;
|
||||||
import static net.hostsharing.hsadminng.hs.office.partner.TestHsOfficePartner.TEST_PARTNER;
|
import static net.hostsharing.hsadminng.hs.office.partner.TestHsOfficePartner.TEST_PARTNER;
|
||||||
@ -13,7 +14,11 @@ public class TestHsOfficeDebitor {
|
|||||||
|
|
||||||
public static final HsOfficeDebitorEntity TEST_DEBITOR = HsOfficeDebitorEntity.builder()
|
public static final HsOfficeDebitorEntity TEST_DEBITOR = HsOfficeDebitorEntity.builder()
|
||||||
.debitorNumberSuffix(DEFAULT_DEBITOR_SUFFIX)
|
.debitorNumberSuffix(DEFAULT_DEBITOR_SUFFIX)
|
||||||
|
.debitorRel(HsOfficeRelationEntity.builder()
|
||||||
|
.holder(HsOfficePersonEntity.builder().build())
|
||||||
|
.anchor(HsOfficePersonEntity.builder().build())
|
||||||
|
.contact(TEST_CONTACT)
|
||||||
|
.build())
|
||||||
.partner(TEST_PARTNER)
|
.partner(TEST_PARTNER)
|
||||||
.billingContact(TEST_CONTACT)
|
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ import io.restassured.RestAssured;
|
|||||||
import io.restassured.http.ContentType;
|
import io.restassured.http.ContentType;
|
||||||
import net.hostsharing.hsadminng.HsadminNgApplication;
|
import net.hostsharing.hsadminng.HsadminNgApplication;
|
||||||
import net.hostsharing.hsadminng.context.Context;
|
import net.hostsharing.hsadminng.context.Context;
|
||||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository;
|
|
||||||
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRepository;
|
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRepository;
|
||||||
import net.hostsharing.hsadminng.hs.office.test.ContextBasedTestWithCleanup;
|
import net.hostsharing.hsadminng.hs.office.test.ContextBasedTestWithCleanup;
|
||||||
import net.hostsharing.test.Accepts;
|
import net.hostsharing.test.Accepts;
|
||||||
@ -24,6 +23,7 @@ import jakarta.persistence.PersistenceContext;
|
|||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static net.hostsharing.hsadminng.hs.office.membership.HsOfficeReasonForTermination.CANCELLATION;
|
||||||
import static net.hostsharing.hsadminng.hs.office.membership.HsOfficeReasonForTermination.NONE;
|
import static net.hostsharing.hsadminng.hs.office.membership.HsOfficeReasonForTermination.NONE;
|
||||||
import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid;
|
import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid;
|
||||||
import static net.hostsharing.test.JsonMatcher.lenientlyEquals;
|
import static net.hostsharing.test.JsonMatcher.lenientlyEquals;
|
||||||
@ -51,9 +51,6 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
@Autowired
|
@Autowired
|
||||||
HsOfficeMembershipRepository membershipRepo;
|
HsOfficeMembershipRepository membershipRepo;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
HsOfficeDebitorRepository debitorRepo;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
HsOfficePartnerRepository partnerRepo;
|
HsOfficePartnerRepository partnerRepo;
|
||||||
|
|
||||||
@ -82,8 +79,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
.body("", lenientlyEquals("""
|
.body("", lenientlyEquals("""
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"partner": { "person": { "tradeName": "First GmbH" } },
|
"partner": { "partnerNumber": 10001 },
|
||||||
"mainDebitor": { "debitorNumber": 1000111 },
|
|
||||||
"memberNumber": 1000101,
|
"memberNumber": 1000101,
|
||||||
"memberNumberSuffix": "01",
|
"memberNumberSuffix": "01",
|
||||||
"validFrom": "2022-10-01",
|
"validFrom": "2022-10-01",
|
||||||
@ -91,8 +87,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
"reasonForTermination": "NONE"
|
"reasonForTermination": "NONE"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"partner": { "person": { "tradeName": "Second e.K." } },
|
"partner": { "partnerNumber": 10002 },
|
||||||
"mainDebitor": { "debitorNumber": 1000212 },
|
|
||||||
"memberNumber": 1000202,
|
"memberNumber": 1000202,
|
||||||
"memberNumberSuffix": "02",
|
"memberNumberSuffix": "02",
|
||||||
"validFrom": "2022-10-01",
|
"validFrom": "2022-10-01",
|
||||||
@ -100,8 +95,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
"reasonForTermination": "NONE"
|
"reasonForTermination": "NONE"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"partner": { "person": { "tradeName": "Third OHG" } },
|
"partner": { "partnerNumber": 10003 },
|
||||||
"mainDebitor": { "debitorNumber": 1000313 },
|
|
||||||
"memberNumber": 1000303,
|
"memberNumber": 1000303,
|
||||||
"memberNumberSuffix": "03",
|
"memberNumberSuffix": "03",
|
||||||
"validFrom": "2022-10-01",
|
"validFrom": "2022-10-01",
|
||||||
@ -132,8 +126,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
.body("", lenientlyEquals("""
|
.body("", lenientlyEquals("""
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"partner": { "person": { "tradeName": "First GmbH" } },
|
"partner": { "partnerNumber": 10001 },
|
||||||
"mainDebitor": { "debitorNumber": 1000111 },
|
|
||||||
"memberNumber": 1000101,
|
"memberNumber": 1000101,
|
||||||
"memberNumberSuffix": "01",
|
"memberNumberSuffix": "01",
|
||||||
"validFrom": "2022-10-01",
|
"validFrom": "2022-10-01",
|
||||||
@ -161,8 +154,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
.body("", lenientlyEquals("""
|
.body("", lenientlyEquals("""
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"partner": { "person": { "tradeName": "Second e.K." } },
|
"partner": { "partnerNumber": 10002 },
|
||||||
"mainDebitor": { "debitorNumber": 1000212 },
|
|
||||||
"memberNumber": 1000202,
|
"memberNumber": 1000202,
|
||||||
"memberNumberSuffix": "02",
|
"memberNumberSuffix": "02",
|
||||||
"validFrom": "2022-10-01",
|
"validFrom": "2022-10-01",
|
||||||
@ -184,7 +176,6 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
|
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("Third").get(0);
|
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("Third").get(0);
|
||||||
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike("Third").get(0);
|
|
||||||
final var givenMemberSuffix = TEMP_MEMBER_NUMBER_SUFFIX;
|
final var givenMemberSuffix = TEMP_MEMBER_NUMBER_SUFFIX;
|
||||||
final var expectedMemberNumber = Integer.parseInt(givenPartner.getPartnerNumber() + TEMP_MEMBER_NUMBER_SUFFIX);
|
final var expectedMemberNumber = Integer.parseInt(givenPartner.getPartnerNumber() + TEMP_MEMBER_NUMBER_SUFFIX);
|
||||||
|
|
||||||
@ -195,12 +186,11 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
.body("""
|
.body("""
|
||||||
{
|
{
|
||||||
"partnerUuid": "%s",
|
"partnerUuid": "%s",
|
||||||
"mainDebitorUuid": "%s",
|
|
||||||
"memberNumberSuffix": "%s",
|
"memberNumberSuffix": "%s",
|
||||||
"validFrom": "2022-10-13",
|
"validFrom": "2022-10-13",
|
||||||
"membershipFeeBillable": "true"
|
"membershipFeeBillable": "true"
|
||||||
}
|
}
|
||||||
""".formatted(givenPartner.getUuid(), givenDebitor.getUuid(), givenMemberSuffix))
|
""".formatted(givenPartner.getUuid(), givenMemberSuffix))
|
||||||
.port(port)
|
.port(port)
|
||||||
.when()
|
.when()
|
||||||
.post("http://localhost/api/hs/office/memberships")
|
.post("http://localhost/api/hs/office/memberships")
|
||||||
@ -208,9 +198,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
.statusCode(201)
|
.statusCode(201)
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.body("uuid", isUuidValid())
|
.body("uuid", isUuidValid())
|
||||||
.body("mainDebitor.debitorNumber", is(givenDebitor.getDebitorNumber()))
|
.body("partner.partnerNumber", is(10003))
|
||||||
.body("mainDebitor.debitorNumberSuffix", is((int) givenDebitor.getDebitorNumberSuffix()))
|
|
||||||
.body("partner.person.tradeName", is("Third OHG"))
|
|
||||||
.body("memberNumber", is(expectedMemberNumber))
|
.body("memberNumber", is(expectedMemberNumber))
|
||||||
.body("memberNumberSuffix", is(givenMemberSuffix))
|
.body("memberNumberSuffix", is(givenMemberSuffix))
|
||||||
.body("validFrom", is("2022-10-13"))
|
.body("validFrom", is("2022-10-13"))
|
||||||
@ -246,8 +234,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
.contentType("application/json")
|
.contentType("application/json")
|
||||||
.body("", lenientlyEquals("""
|
.body("", lenientlyEquals("""
|
||||||
{
|
{
|
||||||
"partner": { "person": { "tradeName": "First GmbH" } },
|
"partner": { "partnerNumber": 10001 },
|
||||||
"mainDebitor": { "debitorNumber": 1000111 },
|
|
||||||
"memberNumber": 1000101,
|
"memberNumber": 1000101,
|
||||||
"memberNumberSuffix": "01",
|
"memberNumberSuffix": "01",
|
||||||
"validFrom": "2022-10-01",
|
"validFrom": "2022-10-01",
|
||||||
@ -275,14 +262,14 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Accepts({ "Membership:X(Access Control)" })
|
@Accepts({ "Membership:X(Access Control)" })
|
||||||
void debitorAgentUser_canGetRelatedMembership() {
|
void parnerRelAgent_canGetRelatedMembership() {
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
final var givenMembershipUuid = membershipRepo.findMembershipByMemberNumber(1000303).getUuid();
|
final var givenMembershipUuid = membershipRepo.findMembershipByMemberNumber(1000303).getUuid();
|
||||||
|
|
||||||
RestAssured // @formatter:off
|
RestAssured // @formatter:off
|
||||||
.given()
|
.given()
|
||||||
.header("current-user", "superuser-alex@hostsharing.net")
|
.header("current-user", "superuser-alex@hostsharing.net")
|
||||||
.header("assumed-roles", "hs_office_debitor#1000313:ThirdOHG-thirdcontact.agent")
|
.header("assumed-roles", "hs_office_relation#HostsharingeG-with-PARTNER-ThirdOHG.agent")
|
||||||
.port(port)
|
.port(port)
|
||||||
.when()
|
.when()
|
||||||
.get("http://localhost/api/hs/office/memberships/" + givenMembershipUuid)
|
.get("http://localhost/api/hs/office/memberships/" + givenMembershipUuid)
|
||||||
@ -291,11 +278,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
.contentType("application/json")
|
.contentType("application/json")
|
||||||
.body("", lenientlyEquals("""
|
.body("", lenientlyEquals("""
|
||||||
{
|
{
|
||||||
"partner": { "person": { "tradeName": "Third OHG" } },
|
"partner": { "partnerNumber": 10003 },
|
||||||
"mainDebitor": {
|
|
||||||
"debitorNumber": 1000313,
|
|
||||||
"billingContact": { "label": "third contact" }
|
|
||||||
},
|
|
||||||
"memberNumber": 1000303,
|
"memberNumber": 1000303,
|
||||||
"memberNumberSuffix": "03",
|
"memberNumberSuffix": "03",
|
||||||
"validFrom": "2022-10-01",
|
"validFrom": "2022-10-01",
|
||||||
@ -314,7 +297,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
void globalAdmin_canPatchValidToOfArbitraryMembership() {
|
void globalAdmin_canPatchValidToOfArbitraryMembership() {
|
||||||
|
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
final var givenMembership = givenSomeTemporaryMembershipBessler();
|
final var givenMembership = givenSomeTemporaryMembershipBessler("First");
|
||||||
|
|
||||||
final var location = RestAssured // @formatter:off
|
final var location = RestAssured // @formatter:off
|
||||||
.given()
|
.given()
|
||||||
@ -333,10 +316,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.body("uuid", isUuidValid())
|
.body("uuid", isUuidValid())
|
||||||
.body("partner.person.tradeName", is(givenMembership.getPartner().getPerson().getTradeName()))
|
.body("partner.partnerNumber", is(givenMembership.getPartner().getPartnerNumber()))
|
||||||
.body("mainDebitor.debitorNumber", is(givenMembership.getMainDebitor().getDebitorNumber()))
|
|
||||||
.body("mainDebitor.debitorNumberSuffix", is((int) givenMembership.getMainDebitor().getDebitorNumberSuffix()))
|
|
||||||
.body("mainDebitor.debitorNumberSuffix", is((int) givenMembership.getMainDebitor().getDebitorNumberSuffix()))
|
|
||||||
.body("memberNumberSuffix", is(givenMembership.getMemberNumberSuffix()))
|
.body("memberNumberSuffix", is(givenMembership.getMemberNumberSuffix()))
|
||||||
.body("validFrom", is("2022-11-01"))
|
.body("validFrom", is("2022-11-01"))
|
||||||
.body("validTo", is("2023-12-31"))
|
.body("validTo", is("2023-12-31"))
|
||||||
@ -346,72 +326,31 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
// finally, the Membership is actually updated
|
// finally, the Membership is actually updated
|
||||||
assertThat(membershipRepo.findByUuid(givenMembership.getUuid())).isPresent().get()
|
assertThat(membershipRepo.findByUuid(givenMembership.getUuid())).isPresent().get()
|
||||||
.matches(mandate -> {
|
.matches(mandate -> {
|
||||||
assertThat(mandate.getPartner().toShortString()).isEqualTo("LP First GmbH");
|
assertThat(mandate.getPartner().toShortString()).isEqualTo("P-10001");
|
||||||
assertThat(mandate.getMainDebitor().toString()).isEqualTo(givenMembership.getMainDebitor().toString());
|
|
||||||
assertThat(mandate.getMemberNumberSuffix()).isEqualTo(givenMembership.getMemberNumberSuffix());
|
assertThat(mandate.getMemberNumberSuffix()).isEqualTo(givenMembership.getMemberNumberSuffix());
|
||||||
assertThat(mandate.getValidity().asString()).isEqualTo("[2022-11-01,2024-01-01)");
|
assertThat(mandate.getValidity().asString()).isEqualTo("[2022-11-01,2024-01-01)");
|
||||||
assertThat(mandate.getReasonForTermination()).isEqualTo(HsOfficeReasonForTermination.CANCELLATION);
|
assertThat(mandate.getReasonForTermination()).isEqualTo(CANCELLATION);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void globalAdmin_canPatchMainDebitorOfArbitraryMembership() {
|
void partnerRelAgent_canPatchValidityOfRelatedMembership() {
|
||||||
|
|
||||||
context.define("superuser-alex@hostsharing.net");
|
// given
|
||||||
final var givenMembership = givenSomeTemporaryMembershipBessler();
|
final var givenPartnerAgent = "hs_office_relation#HostsharingeG-with-PARTNER-FirstGmbH.agent";
|
||||||
final var givenNewMainDebitor = debitorRepo.findDebitorByDebitorNumber(1000313).get(0);
|
context.define("superuser-alex@hostsharing.net", givenPartnerAgent);
|
||||||
|
final var givenMembership = givenSomeTemporaryMembershipBessler("First");
|
||||||
|
|
||||||
|
// when
|
||||||
RestAssured // @formatter:off
|
RestAssured // @formatter:off
|
||||||
.given()
|
.given()
|
||||||
.header("current-user", "superuser-alex@hostsharing.net")
|
.header("current-user", "superuser-alex@hostsharing.net")
|
||||||
|
.header("assumed-roles", givenPartnerAgent)
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.body("""
|
.body("""
|
||||||
{
|
{
|
||||||
"mainDebitorUuid": "%s"
|
"validTo": "2024-01-01",
|
||||||
}
|
|
||||||
""".formatted(givenNewMainDebitor.getUuid()))
|
|
||||||
.port(port)
|
|
||||||
.when()
|
|
||||||
.patch("http://localhost/api/hs/office/memberships/" + givenMembership.getUuid())
|
|
||||||
.then().log().all().assertThat()
|
|
||||||
.statusCode(200)
|
|
||||||
.contentType(ContentType.JSON)
|
|
||||||
.body("uuid", isUuidValid())
|
|
||||||
.body("partner.person.tradeName", is(givenMembership.getPartner().getPerson().getTradeName()))
|
|
||||||
.body("mainDebitor.debitorNumber", is(1000313))
|
|
||||||
.body("memberNumberSuffix", is(givenMembership.getMemberNumberSuffix()))
|
|
||||||
.body("validFrom", is("2022-11-01"))
|
|
||||||
.body("validTo", nullValue())
|
|
||||||
.body("reasonForTermination", is("NONE"));
|
|
||||||
// @formatter:on
|
|
||||||
|
|
||||||
// finally, the Membership is actually updated
|
|
||||||
assertThat(membershipRepo.findByUuid(givenMembership.getUuid())).isPresent().get()
|
|
||||||
.matches(mandate -> {
|
|
||||||
assertThat(mandate.getPartner().toShortString()).isEqualTo("LP First GmbH");
|
|
||||||
assertThat(mandate.getMainDebitor().toString()).isEqualTo(givenMembership.getMainDebitor().toString());
|
|
||||||
assertThat(mandate.getMemberNumberSuffix()).isEqualTo(givenMembership.getMemberNumberSuffix());
|
|
||||||
assertThat(mandate.getValidity().asString()).isEqualTo("[2022-11-01,)");
|
|
||||||
assertThat(mandate.getReasonForTermination()).isEqualTo(NONE);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void partnerAgent_canViewButNotPatchValidityOfRelatedMembership() {
|
|
||||||
|
|
||||||
context.define("superuser-alex@hostsharing.net", "hs_office_partner#10001:FirstGmbH-firstcontact.agent");
|
|
||||||
final var givenMembership = givenSomeTemporaryMembershipBessler();
|
|
||||||
|
|
||||||
final var location = RestAssured // @formatter:off
|
|
||||||
.given()
|
|
||||||
.header("current-user", "superuser-alex@hostsharing.net")
|
|
||||||
.header("assumed-roles", "hs_office_partner#10001:FirstGmbH-firstcontact.agent")
|
|
||||||
.contentType(ContentType.JSON)
|
|
||||||
.body("""
|
|
||||||
{
|
|
||||||
"validTo": "2023-12-31",
|
|
||||||
"reasonForTermination": "CANCELLATION"
|
"reasonForTermination": "CANCELLATION"
|
||||||
}
|
}
|
||||||
""")
|
""")
|
||||||
@ -419,13 +358,13 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
.when()
|
.when()
|
||||||
.patch("http://localhost/api/hs/office/memberships/" + givenMembership.getUuid())
|
.patch("http://localhost/api/hs/office/memberships/" + givenMembership.getUuid())
|
||||||
.then().assertThat()
|
.then().assertThat()
|
||||||
.statusCode(403); // @formatter:on
|
.statusCode(200); // @formatter:on
|
||||||
|
|
||||||
// finally, the Membership is actually updated
|
// finally, the Membership is actually updated
|
||||||
assertThat(membershipRepo.findByUuid(givenMembership.getUuid())).isPresent().get()
|
assertThat(membershipRepo.findByUuid(givenMembership.getUuid())).isPresent().get()
|
||||||
.matches(mandate -> {
|
.matches(mandate -> {
|
||||||
assertThat(mandate.getValidity().asString()).isEqualTo("[2022-11-01,)");
|
assertThat(mandate.getValidity().asString()).isEqualTo("[2022-11-01,2024-01-02)");
|
||||||
assertThat(mandate.getReasonForTermination()).isEqualTo(NONE);
|
assertThat(mandate.getReasonForTermination()).isEqualTo(CANCELLATION);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -438,7 +377,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
@Test
|
@Test
|
||||||
void globalAdmin_canDeleteArbitraryMembership() {
|
void globalAdmin_canDeleteArbitraryMembership() {
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
final var givenMembership = givenSomeTemporaryMembershipBessler();
|
final var givenMembership = givenSomeTemporaryMembershipBessler("First");
|
||||||
|
|
||||||
RestAssured // @formatter:off
|
RestAssured // @formatter:off
|
||||||
.given()
|
.given()
|
||||||
@ -457,12 +396,12 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
@Accepts({ "Membership:X(Access Control)" })
|
@Accepts({ "Membership:X(Access Control)" })
|
||||||
void partnerAgentUser_canNotDeleteRelatedMembership() {
|
void partnerAgentUser_canNotDeleteRelatedMembership() {
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
final var givenMembership = givenSomeTemporaryMembershipBessler();
|
final var givenMembership = givenSomeTemporaryMembershipBessler("First");
|
||||||
|
|
||||||
RestAssured // @formatter:off
|
RestAssured // @formatter:off
|
||||||
.given()
|
.given()
|
||||||
.header("current-user", "superuser-alex@hostsharing.net")
|
.header("current-user", "superuser-alex@hostsharing.net")
|
||||||
.header("assumed-roles", "hs_office_partner#10001:FirstGmbH-firstcontact.admin")
|
.header("assumed-roles", "hs_office_relation#HostsharingeG-with-PARTNER-FirstGmbH.agent")
|
||||||
.port(port)
|
.port(port)
|
||||||
.when()
|
.when()
|
||||||
.delete("http://localhost/api/hs/office/memberships/" + givenMembership.getUuid())
|
.delete("http://localhost/api/hs/office/memberships/" + givenMembership.getUuid())
|
||||||
@ -477,7 +416,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
@Accepts({ "Membership:X(Access Control)" })
|
@Accepts({ "Membership:X(Access Control)" })
|
||||||
void normalUser_canNotDeleteUnrelatedMembership() {
|
void normalUser_canNotDeleteUnrelatedMembership() {
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
final var givenMembership = givenSomeTemporaryMembershipBessler();
|
final var givenMembership = givenSomeTemporaryMembershipBessler("First");
|
||||||
|
|
||||||
RestAssured // @formatter:off
|
RestAssured // @formatter:off
|
||||||
.given()
|
.given()
|
||||||
@ -493,15 +432,13 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private HsOfficeMembershipEntity givenSomeTemporaryMembershipBessler() {
|
private HsOfficeMembershipEntity givenSomeTemporaryMembershipBessler(final String partnerName) {
|
||||||
return jpaAttempt.transacted(() -> {
|
return jpaAttempt.transacted(() -> {
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike("First").get(0);
|
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike(partnerName).get(0);
|
||||||
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("First").get(0);
|
|
||||||
final var newMembership = HsOfficeMembershipEntity.builder()
|
final var newMembership = HsOfficeMembershipEntity.builder()
|
||||||
.uuid(UUID.randomUUID())
|
.uuid(UUID.randomUUID())
|
||||||
.partner(givenPartner)
|
.partner(givenPartner)
|
||||||
.mainDebitor(givenDebitor)
|
|
||||||
.memberNumberSuffix(TEMP_MEMBER_NUMBER_SUFFIX)
|
.memberNumberSuffix(TEMP_MEMBER_NUMBER_SUFFIX)
|
||||||
.validity(Range.closedInfinite(LocalDate.parse("2022-11-01")))
|
.validity(Range.closedInfinite(LocalDate.parse("2022-11-01")))
|
||||||
.reasonForTermination(NONE)
|
.reasonForTermination(NONE)
|
||||||
|
@ -2,7 +2,6 @@ package net.hostsharing.hsadminng.hs.office.membership;
|
|||||||
|
|
||||||
import net.hostsharing.hsadminng.context.Context;
|
import net.hostsharing.hsadminng.context.Context;
|
||||||
import net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionRepository;
|
import net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionRepository;
|
||||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
|
|
||||||
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
|
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
|
||||||
import net.hostsharing.hsadminng.mapper.Mapper;
|
import net.hostsharing.hsadminng.mapper.Mapper;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
@ -28,7 +27,6 @@ import java.util.UUID;
|
|||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
@ -76,7 +74,6 @@ public class HsOfficeMembershipControllerRestTest {
|
|||||||
.content("""
|
.content("""
|
||||||
{
|
{
|
||||||
"partnerUuid": null,
|
"partnerUuid": null,
|
||||||
"mainDebitorUuid": "%s",
|
|
||||||
"memberNumberSuffix": "01",
|
"memberNumberSuffix": "01",
|
||||||
"validFrom": "2022-10-13",
|
"validFrom": "2022-10-13",
|
||||||
"membershipFeeBillable": "true"
|
"membershipFeeBillable": "true"
|
||||||
@ -91,40 +88,12 @@ public class HsOfficeMembershipControllerRestTest {
|
|||||||
.andExpect(jsonPath("message", is("[partnerUuid must not be null but is \"null\"]")));
|
.andExpect(jsonPath("message", is("[partnerUuid must not be null but is \"null\"]")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void respondBadRequest_ifDebitorUuidIsMissing() throws Exception {
|
|
||||||
|
|
||||||
// when
|
|
||||||
mockMvc.perform(MockMvcRequestBuilders
|
|
||||||
.post("/api/hs/office/memberships")
|
|
||||||
.header("current-user", "superuser-alex@hostsharing.net")
|
|
||||||
.contentType(MediaType.APPLICATION_JSON)
|
|
||||||
.content("""
|
|
||||||
{
|
|
||||||
"partnerUuid": "%s",
|
|
||||||
"mainDebitorUuid": null,
|
|
||||||
"memberNumberSuffix": "01",
|
|
||||||
"validFrom": "2022-10-13",
|
|
||||||
"membershipFeeBillable": "true"
|
|
||||||
}
|
|
||||||
""".formatted(UUID.randomUUID()))
|
|
||||||
.accept(MediaType.APPLICATION_JSON))
|
|
||||||
|
|
||||||
// then
|
|
||||||
.andExpect(status().is4xxClientError())
|
|
||||||
.andExpect(jsonPath("statusCode", is(400)))
|
|
||||||
.andExpect(jsonPath("statusPhrase", is("Bad Request")))
|
|
||||||
.andExpect(jsonPath("message", is("[mainDebitorUuid must not be null but is \"null\"]")));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void respondBadRequest_ifAnyGivenPartnerUuidCannotBeFound() throws Exception {
|
void respondBadRequest_ifAnyGivenPartnerUuidCannotBeFound() throws Exception {
|
||||||
|
|
||||||
// given
|
// given
|
||||||
final var givenPartnerUuid = UUID.randomUUID();
|
final var givenPartnerUuid = UUID.randomUUID();
|
||||||
final var givenMainDebitorUuid = UUID.randomUUID();
|
|
||||||
when(em.find(HsOfficePartnerEntity.class, givenPartnerUuid)).thenReturn(null);
|
when(em.find(HsOfficePartnerEntity.class, givenPartnerUuid)).thenReturn(null);
|
||||||
when(em.find(HsOfficeDebitorEntity.class, givenMainDebitorUuid)).thenReturn(mock(HsOfficeDebitorEntity.class));
|
|
||||||
|
|
||||||
// when
|
// when
|
||||||
mockMvc.perform(MockMvcRequestBuilders
|
mockMvc.perform(MockMvcRequestBuilders
|
||||||
@ -134,12 +103,11 @@ public class HsOfficeMembershipControllerRestTest {
|
|||||||
.content("""
|
.content("""
|
||||||
{
|
{
|
||||||
"partnerUuid": "%s",
|
"partnerUuid": "%s",
|
||||||
"mainDebitorUuid": "%s",
|
|
||||||
"memberNumberSuffix": "01",
|
"memberNumberSuffix": "01",
|
||||||
"validFrom": "2022-10-13",
|
"validFrom": "2022-10-13",
|
||||||
"membershipFeeBillable": "true"
|
"membershipFeeBillable": "true"
|
||||||
}
|
}
|
||||||
""".formatted(givenPartnerUuid, givenMainDebitorUuid))
|
""".formatted(givenPartnerUuid))
|
||||||
.accept(MediaType.APPLICATION_JSON))
|
.accept(MediaType.APPLICATION_JSON))
|
||||||
|
|
||||||
// then
|
// then
|
||||||
@ -149,38 +117,6 @@ public class HsOfficeMembershipControllerRestTest {
|
|||||||
.andExpect(jsonPath("message", is("Unable to find Partner with uuid " + givenPartnerUuid)));
|
.andExpect(jsonPath("message", is("Unable to find Partner with uuid " + givenPartnerUuid)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void respondBadRequest_ifAnyGivenDebitorUuidCannotBeFound() throws Exception {
|
|
||||||
|
|
||||||
// given
|
|
||||||
final var givenPartnerUuid = UUID.randomUUID();
|
|
||||||
final var givenMainDebitorUuid = UUID.randomUUID();
|
|
||||||
when(em.find(HsOfficePartnerEntity.class, givenPartnerUuid)).thenReturn(mock(HsOfficePartnerEntity.class));
|
|
||||||
when(em.find(HsOfficeDebitorEntity.class, givenMainDebitorUuid)).thenReturn(null);
|
|
||||||
|
|
||||||
// when
|
|
||||||
mockMvc.perform(MockMvcRequestBuilders
|
|
||||||
.post("/api/hs/office/memberships")
|
|
||||||
.header("current-user", "superuser-alex@hostsharing.net")
|
|
||||||
.contentType(MediaType.APPLICATION_JSON)
|
|
||||||
.content("""
|
|
||||||
{
|
|
||||||
"partnerUuid": "%s",
|
|
||||||
"mainDebitorUuid": "%s",
|
|
||||||
"memberNumberSuffix": "01",
|
|
||||||
"validFrom": "2022-10-13",
|
|
||||||
"membershipFeeBillable": "true"
|
|
||||||
}
|
|
||||||
""".formatted(givenPartnerUuid, givenMainDebitorUuid))
|
|
||||||
.accept(MediaType.APPLICATION_JSON))
|
|
||||||
|
|
||||||
// then
|
|
||||||
.andExpect(status().is4xxClientError())
|
|
||||||
.andExpect(jsonPath("statusCode", is(400)))
|
|
||||||
.andExpect(jsonPath("statusPhrase", is("Bad Request")))
|
|
||||||
.andExpect(jsonPath("message", is("Unable to find Debitor with uuid " + givenMainDebitorUuid)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@EnumSource(InvalidMemberSuffixVariants.class)
|
@EnumSource(InvalidMemberSuffixVariants.class)
|
||||||
void respondBadRequest_ifMemberNumberSuffixIsInvalid(final InvalidMemberSuffixVariants testCase) throws Exception {
|
void respondBadRequest_ifMemberNumberSuffixIsInvalid(final InvalidMemberSuffixVariants testCase) throws Exception {
|
||||||
@ -193,12 +129,11 @@ public class HsOfficeMembershipControllerRestTest {
|
|||||||
.content("""
|
.content("""
|
||||||
{
|
{
|
||||||
"partnerUuid": "%s",
|
"partnerUuid": "%s",
|
||||||
"mainDebitorUuid": "%s",
|
|
||||||
%s
|
%s
|
||||||
"validFrom": "2022-10-13",
|
"validFrom": "2022-10-13",
|
||||||
"membershipFeeBillable": "true"
|
"membershipFeeBillable": "true"
|
||||||
}
|
}
|
||||||
""".formatted(UUID.randomUUID(), UUID.randomUUID(), testCase.memberNumberSuffixEntry))
|
""".formatted(UUID.randomUUID(), testCase.memberNumberSuffixEntry))
|
||||||
.accept(MediaType.APPLICATION_JSON))
|
.accept(MediaType.APPLICATION_JSON))
|
||||||
|
|
||||||
// then
|
// then
|
||||||
|
@ -17,7 +17,6 @@ import java.time.LocalDate;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static net.hostsharing.hsadminng.hs.office.debitor.TestHsOfficeDebitor.TEST_DEBITOR;
|
|
||||||
import static net.hostsharing.hsadminng.hs.office.partner.TestHsOfficePartner.TEST_PARTNER;
|
import static net.hostsharing.hsadminng.hs.office.partner.TestHsOfficePartner.TEST_PARTNER;
|
||||||
import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
|
import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
@ -32,7 +31,6 @@ class HsOfficeMembershipEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
> {
|
> {
|
||||||
|
|
||||||
private static final UUID INITIAL_MEMBERSHIP_UUID = UUID.randomUUID();
|
private static final UUID INITIAL_MEMBERSHIP_UUID = UUID.randomUUID();
|
||||||
private static final UUID PATCHED_MAIN_DEBITOR_UUID = UUID.randomUUID();
|
|
||||||
private static final LocalDate GIVEN_VALID_FROM = LocalDate.parse("2020-04-15");
|
private static final LocalDate GIVEN_VALID_FROM = LocalDate.parse("2020-04-15");
|
||||||
private static final LocalDate PATCHED_VALID_TO = LocalDate.parse("2022-12-31");
|
private static final LocalDate PATCHED_VALID_TO = LocalDate.parse("2022-12-31");
|
||||||
|
|
||||||
@ -56,7 +54,6 @@ class HsOfficeMembershipEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
protected HsOfficeMembershipEntity newInitialEntity() {
|
protected HsOfficeMembershipEntity newInitialEntity() {
|
||||||
final var entity = new HsOfficeMembershipEntity();
|
final var entity = new HsOfficeMembershipEntity();
|
||||||
entity.setUuid(INITIAL_MEMBERSHIP_UUID);
|
entity.setUuid(INITIAL_MEMBERSHIP_UUID);
|
||||||
entity.setMainDebitor(TEST_DEBITOR);
|
|
||||||
entity.setPartner(TEST_PARTNER);
|
entity.setPartner(TEST_PARTNER);
|
||||||
entity.setValidity(Range.closedInfinite(GIVEN_VALID_FROM));
|
entity.setValidity(Range.closedInfinite(GIVEN_VALID_FROM));
|
||||||
entity.setMembershipFeeBillable(GIVEN_MEMBERSHIP_FEE_BILLABLE);
|
entity.setMembershipFeeBillable(GIVEN_MEMBERSHIP_FEE_BILLABLE);
|
||||||
@ -70,19 +67,12 @@ class HsOfficeMembershipEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected HsOfficeMembershipEntityPatcher createPatcher(final HsOfficeMembershipEntity membership) {
|
protected HsOfficeMembershipEntityPatcher createPatcher(final HsOfficeMembershipEntity membership) {
|
||||||
return new HsOfficeMembershipEntityPatcher(em, mapper, membership);
|
return new HsOfficeMembershipEntityPatcher(mapper, membership);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<Property> propertyTestDescriptors() {
|
protected Stream<Property> propertyTestDescriptors() {
|
||||||
return Stream.of(
|
return Stream.of(
|
||||||
new JsonNullableProperty<>(
|
|
||||||
"debitor",
|
|
||||||
HsOfficeMembershipPatchResource::setMainDebitorUuid,
|
|
||||||
PATCHED_MAIN_DEBITOR_UUID,
|
|
||||||
HsOfficeMembershipEntity::setMainDebitor,
|
|
||||||
newDebitor(PATCHED_MAIN_DEBITOR_UUID))
|
|
||||||
.notNullable(),
|
|
||||||
new JsonNullableProperty<>(
|
new JsonNullableProperty<>(
|
||||||
"valid",
|
"valid",
|
||||||
HsOfficeMembershipPatchResource::setValidTo,
|
HsOfficeMembershipPatchResource::setValidTo,
|
||||||
@ -102,10 +92,4 @@ class HsOfficeMembershipEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
HsOfficeMembershipEntity::setMembershipFeeBillable)
|
HsOfficeMembershipEntity::setMembershipFeeBillable)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HsOfficeDebitorEntity newDebitor(final UUID uuid) {
|
|
||||||
final var newDebitor = new HsOfficeDebitorEntity();
|
|
||||||
newDebitor.setUuid(uuid);
|
|
||||||
return newDebitor;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user