move Parter+Debitor person+contact to related Relationsship #20
@ -12,6 +12,8 @@ import net.hostsharing.hsadminng.stringify.Stringify;
|
||||
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.JoinFormula;
|
||||
import org.hibernate.annotations.NotFound;
|
||||
import org.hibernate.annotations.NotFoundAction;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.io.IOException;
|
||||
@ -65,6 +67,7 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
|
||||
WHERE pRel.relHolderUuid = dRel.relAnchorUuid
|
||||
)
|
||||
""")
|
||||
@NotFound(action = NotFoundAction.IGNORE)
|
||||
private HsOfficePartnerEntity partner;
|
||||
|
||||
@Column(name = "debitornumbersuffix", columnDefinition = "numeric(2)")
|
||||
@ -160,8 +163,8 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
|
||||
dependsOnColumn("refundBankAccountUuid"),
|
||||
fetchedBySql("""
|
||||
SELECT *
|
||||
FROM hs_office_relationship AS r
|
||||
WHERE r.relType = 'ACCOUNTING' AND r.relHolderUuid = ${REF}.debitorRelUuid
|
||||
FROM hs_office_bankaccount AS b
|
||||
WHERE b.uuid = ${REF}.refundBankAccountUuid
|
||||
"""),
|
||||
NULLABLE
|
||||
)
|
||||
|
@ -21,6 +21,8 @@ import static net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantsDiagramService.
|
||||
@Service
|
||||
public class RbacGrantsDiagramService {
|
||||
|
||||
private static final int GRANT_LIMIT = 500;
|
||||
|
||||
public static void writeToFile(final String title, final String graph, final String fileName) {
|
||||
|
||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))) {
|
||||
@ -59,7 +61,7 @@ public class RbacGrantsDiagramService {
|
||||
private EntityManager em;
|
||||
|
||||
public String allGrantsToCurrentUser(final EnumSet<Include> includes) {
|
||||
final var graph = new HashSet<RawRbacGrantEntity>();
|
||||
final var graph = new LimitedHashSet<RawRbacGrantEntity>();
|
||||
for ( UUID subjectUuid: context.currentSubjectsUuids() ) {
|
||||
traverseGrantsTo(graph, subjectUuid, includes);
|
||||
}
|
||||
@ -96,7 +98,7 @@ public class RbacGrantsDiagramService {
|
||||
.setParameter("targetObject", targetObject)
|
||||
.setParameter("op", op)
|
||||
.getSingleResult();
|
||||
final var graph = new HashSet<RawRbacGrantEntity>();
|
||||
final var graph = new LimitedHashSet<RawRbacGrantEntity>();
|
||||
traverseGrantsFrom(graph, refUuid, includes);
|
||||
return toMermaidFlowchart(graph, includes);
|
||||
}
|
||||
@ -143,6 +145,7 @@ public class RbacGrantsDiagramService {
|
||||
|
||||
final var avoidCroppedNodeLabels = "%%{init:{'flowchart':{'htmlLabels':false}}}%%\n\n";
|
||||
return (includes.contains(DETAILS) ? avoidCroppedNodeLabels : "")
|
||||
+ (grants.length() > GRANT_LIMIT ? "%% too many grants, graph is cropped\n" : "")
|
||||
+ "flowchart TB\n\n"
|
||||
+ entities
|
||||
+ grants;
|
||||
@ -208,6 +211,20 @@ public class RbacGrantsDiagramService {
|
||||
return idName.replace(" ", ":").replaceAll("@.*", "")
|
||||
.replace("[", "").replace("]", "").replace("(", "").replace(")", "").replace(",", "");
|
||||
}
|
||||
|
||||
|
||||
class LimitedHashSet<T> extends HashSet<T> {
|
||||
|
||||
@Override
|
||||
public boolean add(final T t) {
|
||||
if (size() < GRANT_LIMIT ) {
|
||||
return super.add(t);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
record Node(String idName, UUID uuid) {
|
||||
|
@ -53,8 +53,8 @@ begin
|
||||
assert newDebitorRel.uuid is not null, format('newDebitorRel must not be null for NEW.debitorRelUuid = %s', NEW.debitorRelUuid);
|
||||
|
||||
SELECT *
|
||||
FROM hs_office_relationship AS r
|
||||
WHERE r.relType = 'ACCOUNTING' AND r.relHolderUuid = NEW.debitorRelUuid
|
||||
FROM hs_office_bankaccount AS b
|
||||
WHERE b.uuid = NEW.refundbankaccountuuid
|
||||
INTO newRefundBankAccount;
|
||||
|
||||
call grantRoleToRole(hsOfficeBankAccountReferrer(newRefundBankAccount), hsOfficeRelationshipAgent(newDebitorRel));
|
||||
@ -113,103 +113,9 @@ declare
|
||||
newRefundBankAccount hs_office_bankaccount;
|
||||
|
||||
begin
|
||||
call enterTriggerForObjectUuid(NEW.uuid);
|
||||
delete from rbacgrants g where g.grantedbytriggerof = OLD.uuid;
|
||||
|
||||
SELECT partnerRel.*
|
||||
FROM hs_office_relationship AS partnerRel
|
||||
JOIN hs_office_relationship AS debitorRel
|
||||
ON debitorRel.relType = 'ACCOUNTING' AND debitorRel.relAnchorUuid = partnerRel.relHolderUuid
|
||||
WHERE partnerRel.relType = 'PARTNER'
|
||||
AND OLD.debitorRelUuid = debitorRel.uuid
|
||||
INTO oldPartnerRel;
|
||||
assert oldPartnerRel.uuid is not null, format('oldPartnerRel must not be null for OLD.debitorRelUuid = %s', OLD.debitorRelUuid);
|
||||
|
||||
SELECT partnerRel.*
|
||||
FROM hs_office_relationship AS partnerRel
|
||||
JOIN hs_office_relationship AS debitorRel
|
||||
ON debitorRel.relType = 'ACCOUNTING' AND debitorRel.relAnchorUuid = partnerRel.relHolderUuid
|
||||
WHERE partnerRel.relType = '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_relationship AS r
|
||||
WHERE r.relType = 'ACCOUNTING' AND r.uuid = OLD.debitorRelUuid
|
||||
INTO oldDebitorRel;
|
||||
assert oldDebitorRel.uuid is not null, format('oldDebitorRel must not be null for OLD.debitorRelUuid = %s', OLD.debitorRelUuid);
|
||||
|
||||
SELECT *
|
||||
FROM hs_office_relationship AS r
|
||||
WHERE r.relType = 'ACCOUNTING' AND r.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_relationship AS r
|
||||
WHERE r.relType = 'ACCOUNTING' AND r.relHolderUuid = OLD.debitorRelUuid
|
||||
INTO oldRefundBankAccount;
|
||||
SELECT *
|
||||
FROM hs_office_relationship AS r
|
||||
WHERE r.relType = 'ACCOUNTING' AND r.relHolderUuid = NEW.debitorRelUuid
|
||||
INTO newRefundBankAccount;
|
||||
|
||||
if NEW.debitorRelUuid <> OLD.debitorRelUuid then
|
||||
assert OLD.uuid=NEW.uuid, 'NEW vs. OLD uuids must be equal';
|
||||
|
||||
call revokePermissionFromRole(getPermissionId(OLD.uuid, 'DELETE'), hsOfficeRelationshipOwner(oldDebitorRel));
|
||||
call grantPermissionToRole(getPermissionId(NEW.uuid, 'DELETE'), hsOfficeRelationshipOwner(newDebitorRel));
|
||||
|
||||
call revokePermissionFromRole(getPermissionId(OLD.uuid, 'UPDATE'), hsOfficeRelationshipAdmin(oldDebitorRel));
|
||||
call grantPermissionToRole(getPermissionId(NEW.uuid, 'UPDATE'), hsOfficeRelationshipAdmin(newDebitorRel));
|
||||
|
||||
call revokePermissionFromRole(getPermissionId(OLD.uuid, 'SELECT'), hsOfficeRelationshipTenant(oldDebitorRel));
|
||||
call grantPermissionToRole(getPermissionId(NEW.uuid, 'SELECT'), hsOfficeRelationshipTenant(newDebitorRel));
|
||||
|
||||
if oldRefundBankAccount is not null then
|
||||
call revokeRoleFromRole(hsOfficeRelationshipAgent(oldDebitorRel), hsOfficeBankAccountAdmin(oldRefundBankAccount));
|
||||
end if;
|
||||
if newRefundBankAccount is not null then
|
||||
call grantRoleToRole(hsOfficeRelationshipAgent(newDebitorRel), hsOfficeBankAccountAdmin(newRefundBankAccount));
|
||||
end if;
|
||||
|
||||
if oldRefundBankAccount is not null then
|
||||
call revokeRoleFromRole(hsOfficeBankAccountReferrer(oldRefundBankAccount), hsOfficeRelationshipAgent(oldDebitorRel));
|
||||
end if;
|
||||
if newRefundBankAccount is not null then
|
||||
call grantRoleToRole(hsOfficeBankAccountReferrer(newRefundBankAccount), hsOfficeRelationshipAgent(newDebitorRel));
|
||||
end if;
|
||||
|
||||
call revokeRoleFromRole(hsOfficeRelationshipAdmin(oldDebitorRel), hsOfficeRelationshipAdmin(oldPartnerRel));
|
||||
call grantRoleToRole(hsOfficeRelationshipAdmin(newDebitorRel), hsOfficeRelationshipAdmin(newPartnerRel));
|
||||
|
||||
call revokeRoleFromRole(hsOfficeRelationshipAgent(oldDebitorRel), hsOfficeRelationshipAgent(oldPartnerRel));
|
||||
call grantRoleToRole(hsOfficeRelationshipAgent(newDebitorRel), hsOfficeRelationshipAgent(newPartnerRel));
|
||||
|
||||
call revokeRoleFromRole(hsOfficeRelationshipTenant(oldPartnerRel), hsOfficeRelationshipAgent(oldDebitorRel));
|
||||
call grantRoleToRole(hsOfficeRelationshipTenant(newPartnerRel), hsOfficeRelationshipAgent(newDebitorRel));
|
||||
|
||||
end if;
|
||||
|
||||
if NEW.refundBankAccountUuid <> OLD.refundBankAccountUuid then
|
||||
|
||||
if oldRefundBankAccount is not null then
|
||||
call revokeRoleFromRole(hsOfficeRelationshipAgent(oldDebitorRel), hsOfficeBankAccountAdmin(oldRefundBankAccount));
|
||||
end if;
|
||||
if newRefundBankAccount is not null then
|
||||
call grantRoleToRole(hsOfficeRelationshipAgent(newDebitorRel), hsOfficeBankAccountAdmin(newRefundBankAccount));
|
||||
end if;
|
||||
|
||||
if oldRefundBankAccount is not null then
|
||||
call revokeRoleFromRole(hsOfficeBankAccountReferrer(oldRefundBankAccount), hsOfficeRelationshipAgent(oldDebitorRel));
|
||||
end if;
|
||||
if newRefundBankAccount is not null then
|
||||
call grantRoleToRole(hsOfficeBankAccountReferrer(newRefundBankAccount), hsOfficeRelationshipAgent(newDebitorRel));
|
||||
end if;
|
||||
|
||||
end if;
|
||||
|
||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||
call buildRbacSystemForHsOfficeDebitor(NEW);
|
||||
end; $$;
|
||||
|
||||
/*
|
||||
|
@ -319,6 +319,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
||||
givenDebitor,
|
||||
"hs_office_relationship#FourtheG-with-ACCOUNTING-FourtheG.admin");
|
||||
final var givenNewPartnerPerson = one(personRepo.findPersonByOptionalNameLike("First"));
|
||||
final var givenNewBillingPerson = one(personRepo.findPersonByOptionalNameLike("Firby"));
|
||||
final var givenNewContact = one(contactRepo.findContactByOptionalLabelLike("sixth contact"));
|
||||
final var givenNewBankAccount = one(bankAccountRepo.findByOptionalHolderLike("first"));
|
||||
final String givenNewVatId = "NEW-VAT-ID";
|
||||
@ -331,7 +332,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
||||
givenDebitor.setDebitorRel(HsOfficeRelationshipEntity.builder()
|
||||
.relType(HsOfficeRelationshipType.ACCOUNTING)
|
||||
.relAnchor(givenNewPartnerPerson)
|
||||
.relHolder(givenNewPartnerPerson)
|
||||
.relHolder(givenNewBillingPerson)
|
||||
.contact(givenNewContact)
|
||||
.build());
|
||||
givenDebitor.setRefundBankAccount(givenNewBankAccount);
|
||||
@ -353,7 +354,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
||||
"hs_office_relationship#FourtheG-with-ACCOUNTING-FourtheG.admin");
|
||||
assertThatDebitorIsVisibleForUserWithRole(
|
||||
result.returnedValue(),
|
||||
"hs_office_relationship#FirstGmbH-with-ACCOUNTING-FirstGmbH.agent");
|
||||
"hs_office_relationship#FirstGmbH-with-ACCOUNTING-FirbySusan.agent");
|
||||
|
||||
// ... contact role was reassigned:
|
||||
assertThatDebitorIsNotVisibleForUserWithRole(
|
||||
@ -366,10 +367,10 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
||||
// ... bank-account role was reassigned:
|
||||
assertThatDebitorIsNotVisibleForUserWithRole(
|
||||
result.returnedValue(),
|
||||
"hs_office_bankaccount#FourtheG.admin");
|
||||
"hs_office_bankaccount#DE02200505501015871393.admin");
|
||||
assertThatDebitorIsVisibleForUserWithRole(
|
||||
result.returnedValue(),
|
||||
"hs_office_bankaccount#FirstGmbH.admin");
|
||||
"hs_office_bankaccount#DE02120300000000202051.admin");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -379,7 +380,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
||||
final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "fifth contact", null, "fig");
|
||||
assertThatDebitorIsVisibleForUserWithRole(
|
||||
givenDebitor,
|
||||
"hs_office_partner#10004:FourtheG-fourthcontact.admin");
|
||||
"hs_office_relationship#FourtheG-with-ACCOUNTING-FourtheG.admin");
|
||||
assertThatDebitorActuallyInDatabase(givenDebitor);
|
||||
final var givenNewBankAccount = one(bankAccountRepo.findByOptionalHolderLike("first"));
|
||||
|
||||
@ -399,7 +400,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
||||
// ... bank-account role was assigned:
|
||||
assertThatDebitorIsVisibleForUserWithRole(
|
||||
result.returnedValue(),
|
||||
"hs_office_bankaccount#FirstGmbH.admin");
|
||||
"hs_office_bankaccount#DE02120300000000202051.admin");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -409,7 +410,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
||||
final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "fifth contact", "Fourth", "fih");
|
||||
assertThatDebitorIsVisibleForUserWithRole(
|
||||
givenDebitor,
|
||||
"hs_office_partner#10004:FourtheG-fourthcontact.admin");
|
||||
"hs_office_relationship#HostsharingeG-with-PARTNER-FourtheG.agent");
|
||||
assertThatDebitorActuallyInDatabase(givenDebitor);
|
||||
|
||||
// when
|
||||
@ -428,33 +429,29 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
||||
// ... bank-account role was removed from previous bank-account admin:
|
||||
assertThatDebitorIsNotVisibleForUserWithRole(
|
||||
result.returnedValue(),
|
||||
"hs_office_bankaccount#FourtheG.admin");
|
||||
"hs_office_bankaccount#DE02200505501015871393.admin");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void partnerAdmin_canNotUpdateRelatedDebitor() {
|
||||
public void partnerAgent_canNotUpdateRelatedDebitor() {
|
||||
// given
|
||||
context("superuser-alex@hostsharing.net");
|
||||
final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "eighth", "Fourth", "eig");
|
||||
assertThatDebitorIsVisibleForUserWithRole(
|
||||
givenDebitor,
|
||||
"hs_office_relationship#HostsharingeG-with-PARTNER-FourtheG.admin");
|
||||
"hs_office_relationship#HostsharingeG-with-PARTNER-FourtheG.agent");
|
||||
assertThatDebitorActuallyInDatabase(givenDebitor);
|
||||
|
||||
// when
|
||||
final var result = jpaAttempt.transacted(() -> {
|
||||
context("superuser-alex@hostsharing.net", "hs_office_relationship#HostsharingeG-with-PARTNER-FourtheG.admin");
|
||||
context("superuser-alex@hostsharing.net", "hs_office_relationship#HostsharingeG-with-PARTNER-FourtheG.agent");
|
||||
givenDebitor.setVatId("NEW-VAT-ID");
|
||||
return toCleanup(debitorRepo.save(givenDebitor));
|
||||
});
|
||||
|
||||
// then
|
||||
// FIXME: This error message would be better:
|
||||
// result.assertExceptionWithRootCauseMessage(JpaSystemException.class,
|
||||
// "[403] Subject ", " is not allowed to update hs_office_debitor uuid");
|
||||
result.assertExceptionWithRootCauseMessage(
|
||||
JpaObjectRetrievalFailureException.class,
|
||||
"Unable to find net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity with id ");
|
||||
result.assertExceptionWithRootCauseMessage(JpaSystemException.class,
|
||||
"[403] Subject ", " is not allowed to update hs_office_debitor uuid");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -489,7 +486,9 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
|
||||
found.ifPresent(foundEntity -> {
|
||||
em.refresh(foundEntity);
|
||||
assertThat(foundEntity).isNotSameAs(saved);
|
||||
//assertThat(foundEntity.getPartner()).isNotNull();
|
||||
if ( saved.getPartner() != null) { // FIXME: check, why there is no partner for the updated contact
|
||||
assertThat(foundEntity.getPartner()).isNotNull();
|
||||
}
|
||||
assertThat(foundEntity.getDebitorRel()).extracting(HsOfficeRelationshipEntity::toString)
|
||||
.isEqualTo(saved.getDebitorRel().toString());
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user