add partner business object at repo level (WIP)

This commit is contained in:
Michael Hoennig 2022-09-09 17:43:43 +02:00
parent 2f0f18182c
commit 2c5ad094f1
12 changed files with 291 additions and 85 deletions

View File

@ -3,6 +3,7 @@ package net.hostsharing.hsadminng.hs.admin.partner;
import lombok.*; import lombok.*;
import net.hostsharing.hsadminng.hs.admin.contact.HsAdminContactEntity; import net.hostsharing.hsadminng.hs.admin.contact.HsAdminContactEntity;
import net.hostsharing.hsadminng.hs.admin.person.HsAdminPersonEntity; import net.hostsharing.hsadminng.hs.admin.person.HsAdminPersonEntity;
import org.hibernate.annotations.Cascade;
import javax.persistence.*; import javax.persistence.*;
import java.time.LocalDate; import java.time.LocalDate;

View File

@ -27,4 +27,5 @@ public interface HsAdminPartnerRepository extends Repository<HsAdminPartnerEntit
HsAdminPartnerEntity save(final HsAdminPartnerEntity entity); HsAdminPartnerEntity save(final HsAdminPartnerEntity entity);
long count(); long count();
void deleteByUuid(UUID uuid);
} }

View File

@ -114,6 +114,22 @@ begin
return beingItselfA(getRoleId(roleDescriptor, 'fail')); return beingItselfA(getRoleId(roleDescriptor, 'fail'));
end; $$; end; $$;
create or replace function withSubRoles(roleDescriptors RbacRoleDescriptor[])
returns RbacSubRoles
language plpgsql
strict as $$
declare
subRoleDescriptor RbacRoleDescriptor;
subRoleUuids uuid[] := array []::uuid[];
begin
foreach subRoleDescriptor in array roleDescriptors
loop
subRoleUuids := subRoleUuids || getRoleId(subRoleDescriptor, 'fail');
end loop;
return row (subRoleUuids)::RbacSubRoles;
end; $$;
create or replace function withoutSubRoles() create or replace function withoutSubRoles()
returns RbacSubRoles returns RbacSubRoles
language plpgsql language plpgsql

View File

@ -58,13 +58,14 @@ create or replace function createRbacRolesForHsAdminContact()
strict as $$ strict as $$
declare declare
ownerRole uuid; ownerRole uuid;
adminRole uuid;
begin begin
if TG_OP <> 'INSERT' then if TG_OP <> 'INSERT' then
raise exception 'invalid usage of TRIGGER AFTER INSERT'; raise exception 'invalid usage of TRIGGER AFTER INSERT';
end if; end if;
-- the owner role with full access for the creator assigned to the current user -- the owner role with full access for the creator assigned to the current user
ownerRole = createRole( ownerRole := createRole(
hsAdminContactOwner(NEW), hsAdminContactOwner(NEW),
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['*']), grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['*']),
beneathRole(globalAdmin()), beneathRole(globalAdmin()),
@ -73,11 +74,18 @@ begin
grantedByRole(globalAdmin()) grantedByRole(globalAdmin())
); );
-- the tenant role for those related users who can view the data
adminRole := createRole(
hsAdminContactAdmin(NEW),
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['edit']),
beneathRole(ownerRole)
);
-- the tenant role for those related users who can view the data -- the tenant role for those related users who can view the data
perform createRole( perform createRole(
hsAdminContactTenant(NEW), hsAdminContactTenant(NEW),
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['view']), grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['view']),
beneathRole(ownerRole) beneathRole(adminRole)
); );
return NEW; return NEW;
@ -221,7 +229,7 @@ create or replace function deleteHsAdminContact()
returns trigger returns trigger
language plpgsql as $$ language plpgsql as $$
begin begin
if true or hasGlobalRoleGranted(currentUserUuid()) or if hasGlobalRoleGranted(currentUserUuid()) or
old.uuid in (select queryAccessibleObjectUuidsOfSubjectIds('delete', 'hs_admin_contact', currentSubjectsUuids())) then old.uuid in (select queryAccessibleObjectUuidsOfSubjectIds('delete', 'hs_admin_contact', currentSubjectsUuids())) then
delete from hs_admin_contact c where c.uuid = old.uuid; delete from hs_admin_contact c where c.uuid = old.uuid;
return old; return old;

View File

@ -15,10 +15,12 @@ declare
emailAddr varchar; emailAddr varchar;
begin begin
currentTask = 'creating RBAC test contact ' || contLabel; currentTask = 'creating RBAC test contact ' || contLabel;
call defineContext(currentTask, null, 'alex@hostsharing.net', 'global#global.admin');
execute format('set local hsadminng.currentTask to %L', currentTask); execute format('set local hsadminng.currentTask to %L', currentTask);
emailAddr = 'customer-admin@' || cleanIdentifier(contLabel) || '.example.com'; emailAddr = 'customer-admin@' || cleanIdentifier(contLabel) || '.example.com';
call defineContext(currentTask);
perform createRbacUser(emailAddr);
call defineContext(currentTask, null, emailAddr);
raise notice 'creating test contact: %', contLabel; raise notice 'creating test contact: %', contLabel;
insert insert
@ -58,6 +60,7 @@ do language plpgsql $$
call createHsAdminContactTestData('first contact'); call createHsAdminContactTestData('first contact');
call createHsAdminContactTestData('second contact'); call createHsAdminContactTestData('second contact');
call createHsAdminContactTestData('third contact'); call createHsAdminContactTestData('third contact');
call createHsAdminContactTestData('forth contact');
end; end;
$$; $$;
--// --//

View File

@ -58,13 +58,14 @@ create or replace function createRbacRolesForHsAdminPerson()
strict as $$ strict as $$
declare declare
ownerRole uuid; ownerRole uuid;
adminRole uuid;
begin begin
if TG_OP <> 'INSERT' then if TG_OP <> 'INSERT' then
raise exception 'invalid usage of TRIGGER AFTER INSERT'; raise exception 'invalid usage of TRIGGER AFTER INSERT';
end if; end if;
-- the owner role with full access for the creator assigned to the current user -- the owner role with full access for the creator assigned to the current user
ownerRole = createRole( ownerRole := createRole(
hsAdminPersonOwner(NEW), hsAdminPersonOwner(NEW),
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['*']), grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['*']),
beneathRole(globalAdmin()), beneathRole(globalAdmin()),
@ -73,11 +74,18 @@ begin
grantedByRole(globalAdmin()) grantedByRole(globalAdmin())
); );
-- the tenant role for those related users who can view the data
adminRole := createRole(
hsAdminPersonAdmin(NEW),
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['edit']),
beneathRole(ownerRole)
);
-- the tenant role for those related users who can view the data -- the tenant role for those related users who can view the data
perform createRole( perform createRole(
hsAdminPersonTenant(NEW), hsAdminPersonTenant(NEW),
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['view']), grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['view']),
beneathRole(ownerRole) beneathRole(adminRole)
); );
return NEW; return NEW;
@ -221,7 +229,7 @@ create or replace function deleteHsAdminPerson()
returns trigger returns trigger
language plpgsql as $$ language plpgsql as $$
begin begin
if true or hasGlobalRoleGranted(currentUserUuid()) or if hasGlobalRoleGranted(currentUserUuid()) or
old.uuid in (select queryAccessibleObjectUuidsOfSubjectIds('delete', 'hs_admin_person', currentSubjectsUuids())) then old.uuid in (select queryAccessibleObjectUuidsOfSubjectIds('delete', 'hs_admin_person', currentSubjectsUuids())) then
delete from hs_admin_person c where c.uuid = old.uuid; delete from hs_admin_person c where c.uuid = old.uuid;
return old; return old;

View File

@ -9,10 +9,10 @@
Creates a single person test record. Creates a single person test record.
*/ */
create or replace procedure createHsAdminPersonTestData( create or replace procedure createHsAdminPersonTestData(
personType HsAdminPersonType, newPersonType HsAdminPersonType,
tradeName varchar, newTradeName varchar,
familyName varchar = null, newFamilyName varchar = null,
givenName varchar = null newGivenName varchar = null
) )
language plpgsql as $$ language plpgsql as $$
declare declare
@ -20,7 +20,7 @@ declare
currentTask varchar; currentTask varchar;
emailAddr varchar; emailAddr varchar;
begin begin
fullName := concat_ws(', ', personType, tradename, familyName, givenName); fullName := concat_ws(', ', newTradeName, newFamilyName, newGivenName);
currentTask = 'creating RBAC test person ' || fullName; currentTask = 'creating RBAC test person ' || fullName;
emailAddr = 'person-' || left(cleanIdentifier(fullName), 32) || '@example.com'; emailAddr = 'person-' || left(cleanIdentifier(fullName), 32) || '@example.com';
call defineContext(currentTask); call defineContext(currentTask);
@ -31,7 +31,7 @@ begin
raise notice 'creating test person: %', fullName; raise notice 'creating test person: %', fullName;
insert insert
into hs_admin_person (persontype, tradename, givenname, familyname) into hs_admin_person (persontype, tradename, givenname, familyname)
values (personType, tradeName, givenName, familyName); values (newPersonType, newTradeName, newGivenName, newFamilyName);
end; $$; end; $$;
--// --//
@ -59,7 +59,7 @@ end; $$;
do language plpgsql $$ do language plpgsql $$
begin begin
call createHsAdminPersonTestData('LEGAL', 'first person'); call createHsAdminPersonTestData('LEGAL', 'First Impressions GmbH');
call createHsAdminPersonTestData('NATURAL', null, 'Peter', 'Smith'); call createHsAdminPersonTestData('NATURAL', null, 'Peter', 'Smith');
call createHsAdminPersonTestData('LEGAL', 'Rockshop e.K.', 'Sandra', 'Miller'); call createHsAdminPersonTestData('LEGAL', 'Rockshop e.K.', 'Sandra', 'Miller');
call createHsAdminPersonTestData('SOLE_REPRESENTATION', 'Ostfriesische Kuhhandel OHG'); call createHsAdminPersonTestData('SOLE_REPRESENTATION', 'Ostfriesische Kuhhandel OHG');

View File

@ -52,18 +52,23 @@ end; $$;
Creates the roles and their assignments for a new partner for the AFTER INSERT TRIGGER. Creates the roles and their assignments for a new partner for the AFTER INSERT TRIGGER.
*/ */
create or replace function createRbacRolesForHsAdminContact() create or replace function createRbacRolesForHsAdminPartner()
returns trigger returns trigger
language plpgsql language plpgsql
strict as $$ strict as $$
declare declare
ownerRole uuid; ownerRole uuid;
adminRole uuid; adminRole uuid;
person hs_admin_person;
contact hs_admin_contact;
begin begin
if TG_OP <> 'INSERT' then if TG_OP <> 'INSERT' then
raise exception 'invalid usage of TRIGGER AFTER INSERT'; raise exception 'invalid usage of TRIGGER AFTER INSERT';
end if; end if;
select * from hs_admin_person as p where p.uuid = NEW.personUuid into person;
select * from hs_admin_contact as c where c.uuid = NEW.contactUuid into contact;
-- the owner role with full access for the global admins -- the owner role with full access for the global admins
ownerRole = createRole( ownerRole = createRole(
hsAdminPartnerOwner(NEW), hsAdminPartnerOwner(NEW),
@ -75,14 +80,15 @@ begin
adminRole = createRole( adminRole = createRole(
hsAdminPartnerAdmin(NEW), hsAdminPartnerAdmin(NEW),
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['edit']), grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['edit']),
beneathRole(globalAdmin()) beneathRole(ownerRole)
); );
-- the tenant role for those related users who can view the data -- the tenant role for those related users who can view the data
perform createRole( perform createRole(
hsAdminPartnerTenant(NEW), hsAdminPartnerTenant(NEW),
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['view']), grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['view']),
beneathRole(ownerRole) beneathRoles(array[hsAdminPartnerAdmin(NEW), hsAdminPersonAdmin(person), hsAdminContactAdmin(contact)]),
withSubRoles(array[hsAdminPersonTenant(person), hsAdminContactTenant(contact)])
); );
return NEW; return NEW;
@ -92,11 +98,11 @@ end; $$;
An AFTER INSERT TRIGGER which creates the role structure for a new customer. An AFTER INSERT TRIGGER which creates the role structure for a new customer.
*/ */
create trigger createRbacRolesForHsAdminContact_Trigger create trigger createRbacRolesForHsAdminPartner_Trigger
after insert after insert
on hs_admin_partner on hs_admin_partner
for each row for each row
execute procedure createRbacRolesForHsAdminContact(); execute procedure createRbacRolesForHsAdminPartner();
--// --//
@ -107,13 +113,14 @@ execute procedure createRbacRolesForHsAdminContact();
/* /*
Deletes the roles and their assignments of a deleted partner for the BEFORE DELETE TRIGGER. Deletes the roles and their assignments of a deleted partner for the BEFORE DELETE TRIGGER.
*/ */
create or replace function deleteRbacRulesForHsAdminContact() create or replace function deleteRbacRulesForHsAdminPartner()
returns trigger returns trigger
language plpgsql language plpgsql
strict as $$ strict as $$
begin begin
if TG_OP = 'DELETE' then if TG_OP = 'DELETE' then
call deleteRole(findRoleId(hsAdminPartnerOwner(OLD))); call deleteRole(findRoleId(hsAdminPartnerOwner(OLD)));
call deleteRole(findRoleId(hsAdminPartnerAdmin(OLD)));
call deleteRole(findRoleId(hsAdminPartnerTenant(OLD))); call deleteRole(findRoleId(hsAdminPartnerTenant(OLD)));
else else
raise exception 'invalid usage of TRIGGER BEFORE DELETE'; raise exception 'invalid usage of TRIGGER BEFORE DELETE';
@ -124,11 +131,11 @@ end; $$;
/* /*
An BEFORE DELETE TRIGGER which deletes the role structure of a partner. An BEFORE DELETE TRIGGER which deletes the role structure of a partner.
*/ */
create trigger deleteRbacRulesForTestContact_Trigger create trigger deleteRbacRulesForTestPartner_Trigger
before delete before delete
on hs_admin_partner on hs_admin_partner
for each row for each row
execute procedure deleteRbacRulesForHsAdminContact(); execute procedure deleteRbacRulesForHsAdminPartner();
--// --//
-- ============================================================================ -- ============================================================================
@ -142,9 +149,9 @@ execute procedure deleteRbacRulesForHsAdminContact();
create or replace view hs_admin_partner_iv as create or replace view hs_admin_partner_iv as
select target.uuid, select target.uuid,
cleanIdentifier( cleanIdentifier(
(select idName from hs_admin_person_iv person where person.uuid = target.personuuid) (select idName from hs_admin_person_iv p where p.uuid = target.personuuid)
|| '-' || || '-' ||
(select idName from hs_admin_contact_iv contact where contact.uuid = target.contactuuid) (select idName from hs_admin_contact_iv c where c.uuid = target.contactuuid)
) )
as idName as idName
from hs_admin_partner as target; from hs_admin_partner as target;
@ -197,7 +204,7 @@ grant all privileges on hs_admin_partner_rv to restricted;
/** /**
Instead of insert trigger function for hs_admin_partner_rv. Instead of insert trigger function for hs_admin_partner_rv.
*/ */
create or replace function insertHsAdminContact() create or replace function insertHsAdminPartner()
returns trigger returns trigger
language plpgsql as $$ language plpgsql as $$
declare declare
@ -214,11 +221,11 @@ $$;
/* /*
Creates an instead of insert trigger for the hs_admin_partner_rv view. Creates an instead of insert trigger for the hs_admin_partner_rv view.
*/ */
create trigger insertHsAdminContact_Trigger create trigger insertHsAdminPartner_Trigger
instead of insert instead of insert
on hs_admin_partner_rv on hs_admin_partner_rv
for each row for each row
execute function insertHsAdminContact(); execute function insertHsAdminPartner();
--// --//
-- ============================================================================ -- ============================================================================
@ -228,11 +235,11 @@ execute function insertHsAdminContact();
/** /**
Instead of delete trigger function for hs_admin_partner_rv. Instead of delete trigger function for hs_admin_partner_rv.
*/ */
create or replace function deleteHsAdminContact() create or replace function deleteHsAdminPartner()
returns trigger returns trigger
language plpgsql as $$ language plpgsql as $$
begin begin
if true or hasGlobalRoleGranted(currentUserUuid()) or if hasGlobalRoleGranted(currentUserUuid()) or
old.uuid in (select queryAccessibleObjectUuidsOfSubjectIds('delete', 'hs_admin_partner', currentSubjectsUuids())) then old.uuid in (select queryAccessibleObjectUuidsOfSubjectIds('delete', 'hs_admin_partner', currentSubjectsUuids())) then
delete from hs_admin_partner c where c.uuid = old.uuid; delete from hs_admin_partner c where c.uuid = old.uuid;
return old; return old;
@ -243,11 +250,11 @@ end; $$;
/* /*
Creates an instead of delete trigger for the hs_admin_partner_rv view. Creates an instead of delete trigger for the hs_admin_partner_rv view.
*/ */
create trigger deleteHsAdminContact_Trigger create trigger deleteHsAdminPartner_Trigger
instead of delete instead of delete
on hs_admin_partner_rv on hs_admin_partner_rv
for each row for each row
execute function deleteHsAdminContact(); execute function deleteHsAdminPartner();
--/ --/
-- ============================================================================ -- ============================================================================
@ -274,7 +281,7 @@ $$;
/** /**
Used by the trigger to prevent the add-customer to current user respectively assumed roles. Used by the trigger to prevent the add-customer to current user respectively assumed roles.
*/ */
create or replace function addHsAdminContactNotAllowedForCurrentSubjects() create or replace function addHsAdminPartnerNotAllowedForCurrentSubjects()
returns trigger returns trigger
language PLPGSQL language PLPGSQL
as $$ as $$
@ -292,6 +299,6 @@ create trigger hs_admin_partner_insert_trigger
for each row for each row
-- TODO.spec: who is allowed to create new partners -- TODO.spec: who is allowed to create new partners
when ( not hasAssumedRole() ) when ( not hasAssumedRole() )
execute procedure addHsAdminContactNotAllowedForCurrentSubjects(); execute procedure addHsAdminPartnerNotAllowedForCurrentSubjects();
--// --//

View File

@ -13,23 +13,23 @@ create or replace procedure createHsAdminPartnerTestData( personTradeName varcha
declare declare
currentTask varchar; currentTask varchar;
idName varchar; idName varchar;
person hs_admin_person; relatedPerson hs_admin_person;
contact hs_admin_contact; relatedContact hs_admin_contact;
begin begin
idName := cleanIdentifier( personTradeName|| '-' || contactLabel); idName := cleanIdentifier( personTradeName|| '-' || contactLabel);
currentTask := 'creating RBAC test partner ' || idName; currentTask := 'creating RBAC test partner ' || idName;
call defineContext(currentTask, null, 'alex@hostsharing.net', 'global#global.admin'); call defineContext(currentTask, null, '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_admin_person p where p.tradeName = personTradeName into person; select p.* from hs_admin_person p where p.tradeName = personTradeName into relatedPerson;
select c.* from hs_admin_contact c where c.label = contactLabel into contact; select c.* from hs_admin_contact c where c.label = contactLabel into relatedContact;
raise notice 'creating test partner: %', idName; raise notice 'creating test partner: %', idName;
raise notice '- using person (%): %', person.uuid, person; raise notice '- using person (%): %', relatedPerson.uuid, relatedPerson;
raise notice '- using contact (%): %', contact.uuid, contact; raise notice '- using contact (%): %', relatedContact.uuid, relatedContact;
insert insert
into hs_admin_partner (uuid, personuuid, contactuuid) into hs_admin_partner (uuid, personuuid, contactuuid)
values (uuid_generate_v4(), person.uuid, contact.uuid); values (uuid_generate_v4(), relatedPerson.uuid, relatedContact.uuid);
end; $$; end; $$;
--// --//
@ -63,7 +63,7 @@ end; $$;
do language plpgsql $$ do language plpgsql $$
begin begin
-- call createHsAdminPartnerTestData('first person', 'first contact'); call createHsAdminPartnerTestData('First Impressions GmbH', 'first contact');
call createHsAdminPartnerTestData('Rockshop e.K.', 'second contact'); call createHsAdminPartnerTestData('Rockshop e.K.', 'second contact');

View File

@ -2,113 +2,272 @@ package net.hostsharing.hsadminng.hs.admin.partner;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.context.ContextBasedTest; import net.hostsharing.hsadminng.context.ContextBasedTest;
import net.hostsharing.hsadminng.hs.admin.contact.HsAdminContactRepository;
import net.hostsharing.hsadminng.hs.admin.person.HsAdminPersonEntity; import net.hostsharing.hsadminng.hs.admin.person.HsAdminPersonEntity;
import org.junit.jupiter.api.Disabled; import net.hostsharing.hsadminng.hs.admin.person.HsAdminPersonRepository;
import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantRepository;
import net.hostsharing.hsadminng.rbac.rbacrole.RbacRoleRepository;
import net.hostsharing.test.JpaAttempt;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; 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.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.List; import java.util.List;
import java.util.UUID;
import static net.hostsharing.hsadminng.hs.admin.partner.TestHsAdminPartner.testLtd; import static net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantDisplayExtractor.grantDisplaysOf;
import static net.hostsharing.hsadminng.rbac.rbacrole.RbacRoleNameExtractor.roleNamesOf;
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;
import static org.assertj.core.api.Assumptions.assumeThat;
@Disabled
@DataJpaTest @DataJpaTest
@ComponentScan(basePackageClasses = { Context.class, HsAdminPartnerRepository.class }) @ComponentScan(basePackageClasses = { HsAdminPartnerRepository.class, Context.class, JpaAttempt.class })
@DirtiesContext @DirtiesContext
class HsAdminPartnerRepositoryIntegrationTest extends ContextBasedTest { class HsAdminPartnerRepositoryIntegrationTest extends ContextBasedTest {
@Autowired @Autowired
HsAdminPartnerRepository partnerRepository; HsAdminPartnerRepository partnerRepo;
@Autowired
HsAdminPersonRepository personRepo;
@Autowired
HsAdminContactRepository contactRepo;
@Autowired
RbacRoleRepository roleRepo;
@Autowired
RbacGrantRepository grantRepo;
@Autowired @Autowired
EntityManager em; EntityManager em;
@Autowired
JpaAttempt jpaAttempt;
@MockBean @MockBean
HttpServletRequest request; HttpServletRequest request;
@Nested @Nested
class CreateCustomer { class CreatePartner {
@Test @Test
public void testHostsharingAdmin_withoutAssumedRole_canCreateNewCustomer() { public void testHostsharingAdmin_withoutAssumedRole_canCreateNewPartner() {
// given // given
context("alex@hostsharing.net", null); context("alex@hostsharing.net");
final var count = partnerRepository.count(); final var count = partnerRepo.count();
final var givenPerson = personRepo.findPersonByOptionalNameLike("First Impressions GmbH").get(0);
final var givenContact = contactRepo.findContactByOptionalLabelLike("first contact").get(0);
// when // when
final var result = attempt(em, () -> { final var result = attempt(em, () -> {
return partnerRepository.save(testLtd); final var newPartner = HsAdminPartnerEntity.builder()
.uuid(UUID.randomUUID())
.person(givenPerson)
.contact(givenContact)
.build();
return partnerRepo.save(newPartner);
}); });
// then // then
assertThat(result.wasSuccessful()).isTrue(); result.assertSuccessful();
assertThat(result.returnedValue()).isNotNull().extracting(HsAdminPartnerEntity::getUuid).isNotNull(); assertThat(result.returnedValue()).isNotNull().extracting(HsAdminPartnerEntity::getUuid).isNotNull();
assertThatPartnerIsPersisted(result.returnedValue()); assertThatPartnerIsPersisted(result.returnedValue());
assertThat(partnerRepository.count()).isEqualTo(count + 1); assertThat(partnerRepo.count()).isEqualTo(count + 1);
}
@Test
public void createsAndGrantsRoles() {
// given
context("alex@hostsharing.net");
final var initialRoleCount = roleRepo.findAll().size();
final var initialGrantCount = grantRepo.findAll().size();
// when
attempt(em, () -> {
final var givenPerson = personRepo.findPersonByOptionalNameLike("Erbengemeinschaft Bessler").get(0);
final var givenContact = contactRepo.findContactByOptionalLabelLike("forth contact").get(0);
final var newPartner = HsAdminPartnerEntity.builder()
.uuid(UUID.randomUUID())
.person(givenPerson)
.contact(givenContact)
.build();
return partnerRepo.save(newPartner);
});
// then
final var roles = roleRepo.findAll();
assertThat(roleNamesOf(roles)).containsAll(List.of(
"hs_admin_partner#ErbengemeinschaftBesslerMelBessler-forthcontact.admin",
"hs_admin_partner#ErbengemeinschaftBesslerMelBessler-forthcontact.owner",
"hs_admin_partner#ErbengemeinschaftBesslerMelBessler-forthcontact.tenant"));
assertThat(roles.size()).as("invalid number of roles created")
.isEqualTo(initialRoleCount + 3);
context("customer-admin@forthcontact.example.com");
assertThat(grantDisplaysOf(grantRepo.findAll())).containsAll(List.of(
"{ grant assumed role hs_admin_contact#forthcontact.owner to user customer-admin@forthcontact.example.com by role global#global.admin }"));
context("person-ErbengemeinschaftBesslerMelBessl@example.com");
assertThat(grantDisplaysOf(grantRepo.findAll())).containsAll(List.of(
"{ grant assumed role hs_admin_person#ErbengemeinschaftBesslerMelBessler.owner to user person-ErbengemeinschaftBesslerMelBessl@example.com by role global#global.admin }"));
} }
private void assertThatPartnerIsPersisted(final HsAdminPartnerEntity saved) { private void assertThatPartnerIsPersisted(final HsAdminPartnerEntity saved) {
final var found = partnerRepository.findByUuid(saved.getUuid()); final var found = partnerRepo.findByUuid(saved.getUuid());
assertThat(found).isNotEmpty().get().usingRecursiveComparison().isEqualTo(saved); assertThat(found).isNotEmpty().get().usingRecursiveComparison().isEqualTo(saved);
} }
} }
@Nested @Nested
class FindAllCustomers { class FindAllPartners {
@Test @Test
public void globalAdmin_withoutAssumedRole_canViewAllCustomers() { public void globalAdmin_withoutAssumedRole_canViewAllPartners() {
// given // given
context("alex@hostsharing.net", null); context("alex@hostsharing.net");
// when // when
final var result = partnerRepository.findPartnerByOptionalNameLike(null); final var result = partnerRepo.findPartnerByOptionalNameLike(null);
// then // then
allThesePartnersAreReturned(result, "Ixx AG", "Ypsilon GmbH", "Zett OHG"); allThesePartnersAreReturned(result, "First Impressions GmbH", "Ostfriesische Kuhhandel OHG", "Rockshop e.K.");
} }
@Test
public void normalUser_canViewOnlyRelatedPartners() {
// given:
context("person-FirstImpressionsGmbH@example.com");
// when:
final var result = partnerRepo.findPartnerByOptionalNameLike(null);
// then:
exactlyThesePartnersAreReturned(result, "First Impressions GmbH");
}
} }
@Nested @Nested
class FindByPrefixLike { class FindByNameLike {
@Test @Test
public void globalAdmin_withoutAssumedRole_canViewAllCustomers() { public void globalAdmin_withoutAssumedRole_canViewAllPartners() {
// given // given
context("alex@hostsharing.net", null); context("alex@hostsharing.net");
// when // when
final var result = partnerRepository.findPartnerByOptionalNameLike("Yps"); final var result = partnerRepo.findPartnerByOptionalNameLike("Ostfriesische");
// then // then
exactlyTheseCustomersAreReturned(result, "Ypsilon GmbH"); exactlyThesePartnersAreReturned(result, "Ostfriesische Kuhhandel OHG");
}
@Test
public void customerAdmin_withoutAssumedRole_canViewOnlyItsOwnCustomer() {
// given:
context("customer-admin@xxx.example.com", null);
// when:
final var result = partnerRepository.findPartnerByOptionalNameLike("Yps");
// then:
exactlyTheseCustomersAreReturned(result);
} }
} }
void exactlyTheseCustomersAreReturned(final List<HsAdminPartnerEntity> actualResult, final String... partnerTradeNames) { @Nested
class DeleteByUuid {
@Test
public void globalAdmin_withoutAssumedRole_canDeleteAnyPartner() {
// given
context("alex@hostsharing.net", null);
final var givenPartner = givenSomeTemporaryPartnerBessler();
// when
final var result = jpaAttempt.transacted(() -> {
context("alex@hostsharing.net");
partnerRepo.deleteByUuid(givenPartner.getUuid());
});
// then
result.assertSuccessful();
assertThat(jpaAttempt.transacted(() -> {
context("fran@hostsharing.net", null);
return partnerRepo.findByUuid(givenPartner.getUuid());
}).assertSuccessful().returnedValue()).isEmpty();
}
@Test
public void nonGlobalAdmin_canNotDeleteTheirRelatedPartner() {
// given
context("alex@hostsharing.net", null);
final var givenPartner = givenSomeTemporaryPartnerBessler();
// when
final var result = jpaAttempt.transacted(() -> {
context("person-ErbengemeinschaftBesslerMelBessl@example.com");
assertThat(partnerRepo.findByUuid(givenPartner.getUuid())).isPresent();
partnerRepo.deleteByUuid(givenPartner.getUuid());
});
// then
result.assertExceptionWithRootCauseMessage(JpaSystemException.class,
"[403] User person-ErbengemeinschaftBesslerMelBessl@example.com not allowed to delete partner");
assertThat(jpaAttempt.transacted(() -> {
context("alex@hostsharing.net");
return partnerRepo.findByUuid(givenPartner.getUuid());
}).assertSuccessful().returnedValue()).isPresent(); // still there
}
@Test
public void deletingAPartnerAlsoDeletesRelatedRolesAndGrants() {
// given
context("alex@hostsharing.net");
final var initialRoleCount = roleRepo.findAll().size();
final var givenPartner = givenSomeTemporaryPartnerBessler();
assumeThat(roleRepo.findAll().size()).as("unexpected number of roles created")
.isEqualTo(initialRoleCount + 3);;
// when
final var result = jpaAttempt.transacted(() -> {
context("alex@hostsharing.net");
partnerRepo.deleteByUuid(givenPartner.getUuid());
}).assertSuccessful();
// then
final var roles = roleRepo.findAll();
assertThat(roleNamesOf(roles)).doesNotContainAnyElementsOf(List.of(
"hs_admin_partner#ErbengemeinschaftBesslerMelBessler-forthcontact.admin",
"hs_admin_partner#ErbengemeinschaftBesslerMelBessler-forthcontact.owner",
"hs_admin_partner#ErbengemeinschaftBesslerMelBessler-forthcontact.tenant"));
assertThat(roles.size()).as("invalid number of roles created")
.isEqualTo(initialRoleCount);
context("customer-admin@forthcontact.example.com");
assertThat(grantDisplaysOf(grantRepo.findAll())).doesNotContain(
"{ grant assumed role hs_admin_contact#forthcontact.owner to user customer-admin@forthcontact.example.com by role global#global.admin }");
context("person-ErbengemeinschaftBesslerMelBessl@example.com");
assertThat(grantDisplaysOf(grantRepo.findAll())).doesNotContain(
"{ grant assumed role hs_admin_person#ErbengemeinschaftBesslerMelBessler.owner to user person-ErbengemeinschaftBesslerMelBessl@example.com by role global#global.admin }");
}
}
private HsAdminPartnerEntity givenSomeTemporaryPartnerBessler() {
return jpaAttempt.transacted(() -> {
context("alex@hostsharing.net");
final var givenPerson = personRepo.findPersonByOptionalNameLike("Erbengemeinschaft Bessler").get(0);
final var givenContact = contactRepo.findContactByOptionalLabelLike("forth contact").get(0);
final var newPartner = HsAdminPartnerEntity.builder()
.uuid(UUID.randomUUID())
.person(givenPerson)
.contact(givenContact)
.build();
return partnerRepo.save(newPartner);
}).assertSuccessful().returnedValue();
}
void exactlyThesePartnersAreReturned(final List<HsAdminPartnerEntity> actualResult, final String... partnerTradeNames) {
assertThat(actualResult) assertThat(actualResult)
.hasSize(partnerTradeNames.length) .hasSize(partnerTradeNames.length)
.extracting(HsAdminPartnerEntity::getPerson) .extracting(HsAdminPartnerEntity::getPerson)

View File

@ -225,6 +225,8 @@ class HsAdminPersonRepositoryIntegrationTest extends ContextBasedTest {
}).assertSuccessful().returnedValue()).hasSize(0); }).assertSuccessful().returnedValue()).hasSize(0);
} }
// TODO.test: can NOT delete test is missing
@Test @Test
public void deletingAPersonAlsoDeletesRelatedRolesAndGrants() { public void deletingAPersonAlsoDeletesRelatedRolesAndGrants() {
// given // given

View File

@ -2,14 +2,15 @@
mkdir -p src/test/java/net/hostsharing/hsadminng/hs/admin/partner mkdir -p src/test/java/net/hostsharing/hsadminng/hs/admin/partner
#sed -e 's/hs-admin-contact/hs-admin-partner/g' \ sed -e 's/hs-admin-contact/hs-admin-partner/g' \
# -e 's/hs_admin_contact/hs_admin_partner/g' \ -e 's/hs_admin_contact/hs_admin_partner/g' \
# -e 's/HsAdminContact/HsAdminPartner/g' \ -e 's/HsAdminContact/HsAdminPartner/g' \
# -e 's/hsAdminContact/hsAdminPartner/g' \ -e 's/hsAdminContact/hsAdminPartner/g' \
# -e 's/contact/partner/g' \ -e 's/contact/partner/g' \
#<src/test/java/net/hostsharing/hsadminng/hs/admin/contact/HsAdminContactRepositoryIntegrationTest.java \ <src/test/java/net/hostsharing/hsadminng/hs/admin/contact/HsAdminContactRepositoryIntegrationTest.java \
#>src/test/java/net/hostsharing/hsadminng/hs/admin/partner/HsAdminPartnerRepositoryIntegrationTest.java >src/test/java/net/hostsharing/hsadminng/hs/admin/partner/HsAdminPartnerRepositoryIntegrationTest.java
exit
sed -e 's/hs-admin-contact/hs-admin-partner/g' \ sed -e 's/hs-admin-contact/hs-admin-partner/g' \
-e 's/hs_admin_contact/hs_admin_partner/g' \ -e 's/hs_admin_contact/hs_admin_partner/g' \