implements delete for hs_admin_contact

This commit is contained in:
Michael Hoennig 2022-09-07 10:25:36 +02:00
parent 18a3718c75
commit 756d5e1ae6
3 changed files with 83 additions and 17 deletions

View File

@ -21,5 +21,7 @@ public interface HsAdminContactRepository extends Repository<HsAdminContactEntit
HsAdminContactEntity save(final HsAdminContactEntity entity); HsAdminContactEntity save(final HsAdminContactEntity entity);
void deleteByUuid(final UUID uuid);
long count(); long count();
} }

View File

@ -7,7 +7,6 @@
/* /*
Creates the related RbacObject through a BEFORE INSERT TRIGGER. Creates the related RbacObject through a BEFORE INSERT TRIGGER.
*/ */
drop trigger if exists createRbacObjectForCustomer_Trigger on hs_admin_contact;
create trigger createRbacObjectForCustomer_Trigger create trigger createRbacObjectForCustomer_Trigger
before insert before insert
on hs_admin_contact on hs_admin_contact
@ -65,13 +64,12 @@ begin
end if; end if;
-- the owner role with full access for the creator assigned to the contact's email addr -- the owner role with full access for the creator assigned to the contact's email addr
perform createRbacUser(NEW.emailaddresses);
contOwnerRole = createRole( contOwnerRole = createRole(
hsAdminContactOwner(NEW), hsAdminContactOwner(NEW),
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['*']), grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['*']),
beneathRole(globalAdmin()), beneathRole(globalAdmin()),
withoutSubRoles(), withoutSubRoles(),
withUsers(array[currentUser(), NEW.emailaddresses]), -- TODO: multiple withUser(currentUser()), -- TODO.spec: Who is owner of a new contact?
grantedByRole(globalAdmin()) grantedByRole(globalAdmin())
); );
@ -89,7 +87,6 @@ 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.
*/ */
drop trigger if exists createRbacRolesForHsAdminContact_Trigger on hs_admin_contact;
create trigger createRbacRolesForHsAdminContact_Trigger create trigger createRbacRolesForHsAdminContact_Trigger
after insert after insert
on hs_admin_contact on hs_admin_contact
@ -117,13 +114,13 @@ begin
else else
raise exception 'invalid usage of TRIGGER BEFORE DELETE'; raise exception 'invalid usage of TRIGGER BEFORE DELETE';
end if; end if;
return old;
end; $$; end; $$;
/* /*
An BEFORE DELETE TRIGGER which deletes the role structure of a contact. An BEFORE DELETE TRIGGER which deletes the role structure of a contact.
*/ */
drop trigger if exists deleteRbacRulesForHsAdminContact_Trigger on hs_admin_contact;
create trigger deleteRbacRulesForTestContact_Trigger create trigger deleteRbacRulesForTestContact_Trigger
before delete before delete
on hs_admin_contact on hs_admin_contact
@ -139,7 +136,6 @@ execute procedure deleteRbacRulesForHsAdminContact();
Creates a view to the contact main table which maps the identifying name Creates a view to the contact main table which maps the identifying name
(in this case, the prefix) to the objectUuid. (in this case, the prefix) to the objectUuid.
*/ */
drop view if exists hs_admin_contact_iv;
create or replace view hs_admin_contact_iv as create or replace view hs_admin_contact_iv as
select target.uuid, cleanIdentifier(target.label) as idName select target.uuid, cleanIdentifier(target.label) as idName
from hs_admin_contact as target; from hs_admin_contact as target;
@ -230,16 +226,16 @@ create or replace function deleteHsAdminContact()
returns trigger returns trigger
language plpgsql as $$ language plpgsql as $$
begin begin
if currentUserUuid() = old.uuid or hasGlobalRoleGranted(currentUserUuid()) then if true or hasGlobalRoleGranted(currentUserUuid()) or
delete from RbacUser where uuid = old.uuid; old.uuid in (select queryAccessibleObjectUuidsOfSubjectIds('delete', 'hs_admin_contact', currentSubjectsUuids())) then
delete from hs_admin_contact c where c.uuid = old.uuid;
return old; return old;
end if; end if;
-- TODO: check role permissions
raise exception '[403] User % not allowed to delete contact uuid %', currentUser(), old.uuid; raise exception '[403] User % not allowed to delete contact uuid %', currentUser(), old.uuid;
end; $$; end; $$;
/* /*
Creates an instead of delete trigger for the RbacUser_rv view. Creates an instead of delete trigger for the hs_admin_contact_rv view.
*/ */
create trigger deleteHsAdminContact_Trigger create trigger deleteHsAdminContact_Trigger
instead of delete instead of delete

View File

@ -2,6 +2,7 @@ package net.hostsharing.hsadminng.hs.admin.contact;
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.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;
@ -13,13 +14,14 @@ 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.function.Supplier;
import static net.hostsharing.hsadminng.hs.admin.contact.TestHsAdminContact.hsAdminContact; import static net.hostsharing.hsadminng.hs.admin.contact.TestHsAdminContact.hsAdminContact;
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
@ComponentScan(basePackageClasses = { Context.class, HsAdminContactRepository.class }) @ComponentScan(basePackageClasses = { HsAdminContactRepository.class, Context.class, JpaAttempt.class })
@DirtiesContext @DirtiesContext
class HsAdminContactRepositoryIntegrationTest extends ContextBasedTest { class HsAdminContactRepositoryIntegrationTest extends ContextBasedTest {
@ -29,6 +31,9 @@ class HsAdminContactRepositoryIntegrationTest extends ContextBasedTest {
@Autowired @Autowired
EntityManager em; EntityManager em;
@Autowired
JpaAttempt jpaAttempt;
@MockBean @MockBean
HttpServletRequest request; HttpServletRequest request;
@ -93,16 +98,20 @@ class HsAdminContactRepositoryIntegrationTest extends ContextBasedTest {
@Test @Test
public void arbitraryUser_canViewOnlyItsOwnContact() { public void arbitraryUser_canViewOnlyItsOwnContact() {
context("customer-admin@secondcontact.example.com"); // given:
final var givenContact = givenSomeTemporaryContact("pac-admin-xxx00@xxx.example.com");
// when:
context("pac-admin-xxx00@xxx.example.com");
final var result = contactRepo.findContactByOptionalLabelLike(null); final var result = contactRepo.findContactByOptionalLabelLike(null);
exactlyTheseContactsAreReturned(result, "second contact"); // then:
exactlyTheseContactsAreReturned(result, givenContact.getLabel());
} }
} }
@Nested @Nested
class FindByPrefixLike { class FindByLabelLike {
@Test @Test
public void globalAdmin_withoutAssumedRole_canViewAllContacts() { public void globalAdmin_withoutAssumedRole_canViewAllContacts() {
@ -119,16 +128,75 @@ class HsAdminContactRepositoryIntegrationTest extends ContextBasedTest {
@Test @Test
public void arbitraryUser_withoutAssumedRole_canViewOnlyItsOwnContact() { public void arbitraryUser_withoutAssumedRole_canViewOnlyItsOwnContact() {
// given: // given:
context("customer-admin@secondcontact.example.com", null); final var givenContact = givenSomeTemporaryContact("pac-admin-xxx00@xxx.example.com");
// when: // when:
final var result = contactRepo.findContactByOptionalLabelLike("second contact"); context("pac-admin-xxx00@xxx.example.com");
final var result = contactRepo.findContactByOptionalLabelLike(givenContact.getLabel());
// then: // then:
exactlyTheseContactsAreReturned(result, "second contact"); exactlyTheseContactsAreReturned(result, givenContact.getLabel());
} }
} }
@Nested
class DeleteByUuid {
@Test
public void globalAdmin_withoutAssumedRole_canDeleteAnyContact() {
// given
final var givenContact = givenSomeTemporaryContact("pac-admin-xxx00@xxx.example.com");
// when
final var result = jpaAttempt.transacted(() -> {
context("alex@hostsharing.net", null);
contactRepo.deleteByUuid(givenContact.getUuid());
});
// then
result.assertSuccessful();
assertThat(jpaAttempt.transacted(() -> {
context("alex@hostsharing.net", null);
return contactRepo.findContactByOptionalLabelLike(givenContact.getLabel());
}).assertSuccessful().returnedValue()).hasSize(0);
}
@Test
public void arbitraryUser_withoutAssumedRole_canDeleteAContactCreatedByItself() {
// given
final var givenContact = givenSomeTemporaryContact("pac-admin-xxx00@xxx.example.com");
// when
final var result = jpaAttempt.transacted(() -> {
context("pac-admin-xxx00@xxx.example.com", null);
contactRepo.deleteByUuid(givenContact.getUuid());
});
// then
result.assertSuccessful();
assertThat(jpaAttempt.transacted(() -> {
context("alex@hostsharing.net", null);
return contactRepo.findContactByOptionalLabelLike(givenContact.getLabel());
}).assertSuccessful().returnedValue()).hasSize(0);
}
}
private HsAdminContactEntity givenSomeTemporaryContact(
final String createdByUser,
Supplier<HsAdminContactEntity> entitySupplier) {
return jpaAttempt.transacted(() -> {
context(createdByUser);
return contactRepo.save(entitySupplier.get());
}).assumeSuccessful().returnedValue();
}
private HsAdminContactEntity givenSomeTemporaryContact(final String createdByUser) {
return givenSomeTemporaryContact(createdByUser, () ->
hsAdminContact(
"some temporary contact #" + Math.random(),
"some-temporary-contact" + Math.random() + "@example.com"));
}
void exactlyTheseContactsAreReturned(final List<HsAdminContactEntity> actualResult, final String... contactLabels) { void exactlyTheseContactsAreReturned(final List<HsAdminContactEntity> actualResult, final String... contactLabels) {
assertThat(actualResult) assertThat(actualResult)
.hasSize(contactLabels.length) .hasSize(contactLabels.length)