rbac-optimization #80

Merged
hsh-michaelhoennig merged 14 commits from rbac-optimization into master 2024-07-27 10:18:08 +02:00
12 changed files with 43 additions and 71 deletions
Showing only changes of commit b50bcbbca0 - Show all commits

View File

@ -15,9 +15,6 @@ 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.Column; import jakarta.persistence.Column;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
@ -77,22 +74,8 @@ public class HsOfficeDebitorEntity implements RbacObject, Stringifyable {
@Version @Version
private int version; private int version;
@ManyToOne @Column(name = "partnernumber", columnDefinition = "numeric(5) not null")
@JoinFormula( private Integer partnerNumber; // redundant to HsOfficePartnerEntity.partnerNumber for performance reasons
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;
@Column(name = "debitornumbersuffix", length = 2) @Column(name = "debitornumbersuffix", length = 2)
@Pattern(regexp = TWO_DECIMAL_DIGITS) @Pattern(regexp = TWO_DECIMAL_DIGITS)
@ -125,9 +108,8 @@ public class HsOfficeDebitorEntity implements RbacObject, Stringifyable {
private String defaultPrefix; private String defaultPrefix;
private String getDebitorNumberString() { private String getDebitorNumberString() {
return ofNullable(partner) return ofNullable(partnerNumber)
.filter(partner -> debitorNumberSuffix != null) .filter(partner -> debitorNumberSuffix != null)
.map(HsOfficePartnerEntity::getPartnerNumber)
.map(Object::toString) .map(Object::toString)
.map(partnerNumber -> partnerNumber + debitorNumberSuffix) .map(partnerNumber -> partnerNumber + debitorNumberSuffix)
.orElse(null); .orElse(null);

View File

@ -28,6 +28,17 @@ public interface HsOfficePartnerRepository extends Repository<HsOfficePartnerEnt
List<HsOfficePartnerEntity> findPartnerByOptionalNameLike(String name); List<HsOfficePartnerEntity> findPartnerByOptionalNameLike(String name);
HsOfficePartnerEntity findPartnerByPartnerNumber(Integer partnerNumber); HsOfficePartnerEntity findPartnerByPartnerNumber(Integer partnerNumber);
@Query("""
SELECT DISTINCT partner
FROM HsOfficePartnerEntity partner
JOIN HsOfficeRelationEntity dRel
ON dRel.uuid = :debitorUuid AND dRel.type = 'DEBITOR'
JOIN HsOfficeRelationEntity pRel
ON pRel.uuid = partner.partnerRel.uuid AND pRel.type = 'PARTNER'
WHERE pRel.holder.uuid = dRel.anchor.uuid
""")
HsOfficePartnerEntity findPartnerByDebitorUuid(UUID debitorUuid);
HsOfficePartnerEntity save(final HsOfficePartnerEntity entity); HsOfficePartnerEntity save(final HsOfficePartnerEntity entity);
long count(); long count();

View File

@ -56,15 +56,15 @@ public class HsOfficeRelationEntity implements RbacObject, Stringifyable {
@Version @Version
private int version; private int version;
@ManyToOne @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "anchoruuid") @JoinColumn(name = "anchoruuid")
private HsOfficePersonEntity anchor; private HsOfficePersonEntity anchor;
@ManyToOne @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "holderuuid") @JoinColumn(name = "holderuuid")
private HsOfficePersonEntity holder; private HsOfficePersonEntity holder;
@ManyToOne @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "contactuuid") @JoinColumn(name = "contactuuid")
private HsOfficeContactEntity contact; private HsOfficeContactEntity contact;

View File

@ -8,6 +8,7 @@ create table hs_office_debitor
( (
uuid uuid unique references RbacObject (uuid) initially deferred, uuid uuid unique references RbacObject (uuid) initially deferred,
version int not null default 0, version int not null default 0,
partnerNumber numeric(5) not null, -- redundant to hs_office_partner.partnerNumber for performance reasons
debitorNumberSuffix char(2) not null check (debitorNumberSuffix::text ~ '^[0-9][0-9]$'), debitorNumberSuffix char(2) not null check (debitorNumberSuffix::text ~ '^[0-9][0-9]$'),
debitorRelUuid uuid not null references hs_office_relation(uuid), debitorRelUuid uuid not null references hs_office_relation(uuid),
billable boolean not null default true, billable boolean not null default true,

View File

@ -9,7 +9,8 @@
Creates a single debitor test record. Creates a single debitor test record.
*/ */
create or replace procedure createHsOfficeDebitorTestData( create or replace procedure createHsOfficeDebitorTestData(
withDebitorNumberSuffix numeric(5), forPartnerNumber numeric(5),
withDebitorNumberSuffix numeric(2),
forPartnerPersonName varchar, forPartnerPersonName varchar,
forBillingContactCaption varchar, forBillingContactCaption varchar,
withDefaultPrefix varchar withDefaultPrefix varchar
@ -42,8 +43,8 @@ begin
-- raise exception 'creating test debitor: (uuid=%, debitorRelUuid=%, debitornumbersuffix=%, billable=%, vatbusiness=%, vatreversecharge=%, refundbankaccountuuid=%, defaultprefix=%)', -- raise exception 'creating test debitor: (uuid=%, debitorRelUuid=%, debitornumbersuffix=%, billable=%, vatbusiness=%, vatreversecharge=%, refundbankaccountuuid=%, defaultprefix=%)',
-- uuid_generate_v4(), relatedDebitorRelUuid, withDebitorNumberSuffix, true, true, false, relatedBankAccountUuid, withDefaultPrefix; -- uuid_generate_v4(), relatedDebitorRelUuid, withDebitorNumberSuffix, true, true, false, relatedBankAccountUuid, withDefaultPrefix;
insert insert
into hs_office_debitor (uuid, debitorRelUuid, debitornumbersuffix, billable, vatbusiness, vatreversecharge, refundbankaccountuuid, defaultprefix) into hs_office_debitor (uuid, debitorRelUuid, partnerNumber, debitornumbersuffix, billable, vatbusiness, vatreversecharge, refundbankaccountuuid, defaultprefix)
values (uuid_generate_v4(), relatedDebitorRelUuid, withDebitorNumberSuffix, true, true, false, relatedBankAccountUuid, withDefaultPrefix); values (uuid_generate_v4(), relatedDebitorRelUuid, forPartnerNumber, withDebitorNumberSuffix, true, true, false, relatedBankAccountUuid, withDefaultPrefix);
end; $$; end; $$;
--// --//
@ -54,9 +55,9 @@ end; $$;
do language plpgsql $$ do language plpgsql $$
begin begin
call createHsOfficeDebitorTestData(11, 'First GmbH', 'first contact', 'fir'); call createHsOfficeDebitorTestData( 10001, 11, 'First GmbH', 'first contact', 'fir');
call createHsOfficeDebitorTestData(12, 'Second e.K.', 'second contact', 'sec'); call createHsOfficeDebitorTestData( 10002, 12, 'Second e.K.', 'second contact', 'sec');
call createHsOfficeDebitorTestData(13, 'Third OHG', 'third contact', 'thi'); call createHsOfficeDebitorTestData( 10003, 13, 'Third OHG', 'third contact', 'thi');
end; end;
$$; $$;
--// --//

View File

@ -1,17 +1,13 @@
--liquibase formatted sql --liquibase formatted sql
-- ============================================================================ -- ============================================================================
--changeset hs-booking-debitor-RESTRICTED-VIEW:1 endDelimiter:--// --changeset hs-booking-debitor-EXTRACTED-VIEW:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
create view hs_booking_debitor_xv as create view hs_booking_debitor_xv as
select debitor.uuid, select debitor.uuid,
debitor.version, debitor.version,
(partner.partnerNumber::varchar || debitor.debitorNumberSuffix)::numeric as debitorNumber, (debitor.partnerNumber::varchar || debitor.debitorNumberSuffix)::numeric as debitorNumber,
debitor.defaultPrefix debitor.defaultPrefix
from hs_office_debitor debitor from hs_office_debitor debitor -- not from _rv for performance, nothing really secret here
-- RBAC for debitor is sufficient, for faster access we are bypassing RBAC for the join tables
join hs_office_relation debitorRel on debitor.debitorReluUid=debitorRel.uuid
join hs_office_relation partnerRel on partnerRel.holderUuid=debitorRel.anchorUuid
join hs_office_partner partner on partner.partnerReluUid=partnerRel.uuid;
--// --//

View File

@ -208,8 +208,8 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu
// then // then
exactlyTheseAssetsAreReturned( exactlyTheseAssetsAreReturned(
result, result,
"HsHostingAssetEntity(MANAGED_WEBSPACE, sec01, some Webspace, MANAGED_SERVER:vm1012, D-1000212:D-1000212 default project:separate ManagedWebspace)",
"HsHostingAssetEntity(MANAGED_WEBSPACE, fir01, some Webspace, MANAGED_SERVER:vm1011, D-1000111:D-1000111 default project:separate ManagedWebspace)", "HsHostingAssetEntity(MANAGED_WEBSPACE, fir01, some Webspace, MANAGED_SERVER:vm1011, D-1000111:D-1000111 default project:separate ManagedWebspace)",
"HsHostingAssetEntity(MANAGED_WEBSPACE, sec01, some Webspace, MANAGED_SERVER:vm1012, D-1000212:D-1000212 default project:separate ManagedWebspace)",
"HsHostingAssetEntity(MANAGED_WEBSPACE, thi01, some Webspace, MANAGED_SERVER:vm1013, D-1000313:D-1000313 default project:separate ManagedWebspace)"); "HsHostingAssetEntity(MANAGED_WEBSPACE, thi01, some Webspace, MANAGED_SERVER:vm1013, D-1000313:D-1000313 default project:separate ManagedWebspace)");
} }

View File

@ -759,7 +759,7 @@ public class ImportOfficeData extends CsvDataImport {
final var debitor = HsOfficeDebitorEntity.builder() final var debitor = HsOfficeDebitorEntity.builder()
.debitorNumberSuffix("00") .debitorNumberSuffix("00")
.partner(partner) .partnerNumber(partner.getPartnerNumber())
.debitorRel(debitorRel) .debitorRel(debitorRel)
.defaultPrefix(rec.getString("member_code").replace("hsh00-", "")) .defaultPrefix(rec.getString("member_code").replace("hsh00-", ""))
.billable(rec.isEmpty("free") || rec.getString("free").equals("f")) .billable(rec.isEmpty("free") || rec.getString("free").equals("f"))

View File

@ -29,9 +29,7 @@ class HsOfficeDebitorEntityUnitTest {
.debitorNumberSuffix("67") .debitorNumberSuffix("67")
.debitorRel(givenDebitorRel) .debitorRel(givenDebitorRel)
.defaultPrefix("som") .defaultPrefix("som")
.partner(HsOfficePartnerEntity.builder() .partnerNumber(12345)
.partnerNumber(12345)
.build())
.build(); .build();
final var result = given.toString(); final var result = given.toString();
@ -44,9 +42,7 @@ class HsOfficeDebitorEntityUnitTest {
final var given = HsOfficeDebitorEntity.builder() final var given = HsOfficeDebitorEntity.builder()
.debitorRel(givenDebitorRel) .debitorRel(givenDebitorRel)
.debitorNumberSuffix("67") .debitorNumberSuffix("67")
.partner(HsOfficePartnerEntity.builder() .partnerNumber(12345)
.partnerNumber(12345)
.build())
.build(); .build();
final var result = given.toShortString(); final var result = given.toShortString();
@ -59,9 +55,7 @@ class HsOfficeDebitorEntityUnitTest {
final var given = HsOfficeDebitorEntity.builder() final var given = HsOfficeDebitorEntity.builder()
.debitorRel(givenDebitorRel) .debitorRel(givenDebitorRel)
.debitorNumberSuffix("67") .debitorNumberSuffix("67")
.partner(HsOfficePartnerEntity.builder() .partnerNumber(12345)
.partnerNumber(12345)
.build())
.build(); .build();
final var result = given.getDebitorNumber(); final var result = given.getDebitorNumber();
@ -69,25 +63,12 @@ class HsOfficeDebitorEntityUnitTest {
assertThat(result).isEqualTo(1234567); assertThat(result).isEqualTo(1234567);
} }
@Test
void getDebitorNumberWithoutPartnerReturnsNull() {
final var given = HsOfficeDebitorEntity.builder()
.debitorRel(givenDebitorRel)
.debitorNumberSuffix("67")
.partner(null)
.build();
final var result = given.getDebitorNumber();
assertThat(result).isNull();
}
@Test @Test
void getDebitorNumberWithoutPartnerNumberReturnsNull() { void getDebitorNumberWithoutPartnerNumberReturnsNull() {
final var given = HsOfficeDebitorEntity.builder() final var given = HsOfficeDebitorEntity.builder()
.debitorRel(givenDebitorRel) .debitorRel(givenDebitorRel)
.debitorNumberSuffix("67") .debitorNumberSuffix("67")
.partner(HsOfficePartnerEntity.builder().build()) .partnerNumber(null)
.build(); .build();
final var result = given.getDebitorNumber(); final var result = given.getDebitorNumber();
@ -100,9 +81,7 @@ class HsOfficeDebitorEntityUnitTest {
final var given = HsOfficeDebitorEntity.builder() final var given = HsOfficeDebitorEntity.builder()
.debitorRel(givenDebitorRel) .debitorRel(givenDebitorRel)
.debitorNumberSuffix(null) .debitorNumberSuffix(null)
.partner(HsOfficePartnerEntity.builder() .partnerNumber(12345)
.partnerNumber(12345)
.build())
.build(); .build();
final var result = given.getDebitorNumber(); final var result = given.getDebitorNumber();

View File

@ -485,9 +485,6 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
em.refresh(foundEntity); em.refresh(foundEntity);
Hibernate.initialize(foundEntity); Hibernate.initialize(foundEntity);
assertThat(foundEntity).isNotSameAs(saved); assertThat(foundEntity).isNotSameAs(saved);
if (withPartner) {
assertThat(foundEntity.getPartner()).isNotNull();
}
assertThat(foundEntity.getDebitorRel()).extracting(HsOfficeRelationEntity::toString) assertThat(foundEntity.getDebitorRel()).extracting(HsOfficeRelationEntity::toString)
.isEqualTo(saved.getDebitorRel().toString()); .isEqualTo(saved.getDebitorRel().toString());
}); });

View File

@ -19,7 +19,7 @@ public class TestHsOfficeDebitor {
.anchor(HsOfficePersonEntity.builder().build()) .anchor(HsOfficePersonEntity.builder().build())
.contact(TEST_CONTACT) .contact(TEST_CONTACT)
.build()) .build())
.partner(TEST_PARTNER) .partnerNumber(TEST_PARTNER.getPartnerNumber())
.defaultPrefix("abc") .defaultPrefix("abc")
.build(); .build();
} }

View File

@ -6,6 +6,7 @@ import io.restassured.http.ContentType;
import net.hostsharing.hsadminng.HsadminNgApplication; import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository; import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository;
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository; import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRepository;
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup; import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt; import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import org.json.JSONException; import org.json.JSONException;
@ -42,6 +43,9 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
@Autowired @Autowired
HsOfficeSepaMandateRepository sepaMandateRepo; HsOfficeSepaMandateRepository sepaMandateRepo;
@Autowired
HsOfficePartnerRepository partnerRepo;
@Autowired @Autowired
HsOfficeDebitorRepository debitorRepo; HsOfficeDebitorRepository debitorRepo;
@ -493,8 +497,9 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
return jpaAttempt.transacted(() -> { return jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenDebitor = debitorRepo.findDebitorByDebitorNumber(debitorNumber).get(0); final var givenDebitor = debitorRepo.findDebitorByDebitorNumber(debitorNumber).get(0);
final var bankAccountHolder = ofNullable(givenDebitor.getPartner().getPartnerRel().getHolder().getTradeName()) final var givenPartner = partnerRepo.findPartnerByDebitorUuid(givenDebitor.getUuid());
.orElse(givenDebitor.getPartner().getPartnerRel().getHolder().getFamilyName()); final var bankAccountHolder = ofNullable(givenPartner.getPartnerRel().getHolder().getTradeName())
.orElse(givenPartner.getPartnerRel().getHolder().getFamilyName());
final var givenBankAccount = bankAccountRepo.findByOptionalHolderLike(bankAccountHolder).get(0); final var givenBankAccount = bankAccountRepo.findByOptionalHolderLike(bankAccountHolder).get(0);
final var newSepaMandate = HsOfficeSepaMandateEntity.builder() final var newSepaMandate = HsOfficeSepaMandateEntity.builder()
.uuid(UUID.randomUUID()) .uuid(UUID.randomUUID())