avoid select before insert and map sub-entities in mapper
This commit is contained in:
@@ -9,6 +9,7 @@ import org.springframework.core.MethodParameter;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.orm.jpa.JpaObjectRetrievalFailureException;
|
||||
import org.springframework.orm.jpa.JpaSystemException;
|
||||
import org.springframework.validation.BindingResult;
|
||||
@@ -43,6 +44,25 @@ class RestResponseEntityExceptionHandlerUnitTest {
|
||||
assertThat(errorResponse.getBody().getMessage()).isEqualTo("First Line");
|
||||
}
|
||||
|
||||
@Test
|
||||
void handleForeignKeyViolation() {
|
||||
// given
|
||||
final var givenException = new DataIntegrityViolationException("""
|
||||
... violates foreign key constraint ...
|
||||
Detail: Second Line
|
||||
Third Line
|
||||
""");
|
||||
final var givenWebRequest = mock(WebRequest.class);
|
||||
|
||||
// when
|
||||
final var errorResponse = exceptionHandler.handleConflict(givenException, givenWebRequest);
|
||||
|
||||
// then
|
||||
assertThat(errorResponse.getStatusCodeValue()).isEqualTo(400);
|
||||
assertThat(errorResponse.getBody()).isNotNull()
|
||||
.extracting(CustomErrorResponse::getMessage).isEqualTo("Second Line");
|
||||
}
|
||||
|
||||
@Test
|
||||
void jpaExceptionWithKnownErrorCode() {
|
||||
// given
|
||||
|
||||
@@ -9,7 +9,6 @@ public class TestHsOfficeBankAccount {
|
||||
|
||||
static public HsOfficeBankAccountEntity hsOfficeBankAccount(final String holder, final String iban, final String bic) {
|
||||
return HsOfficeBankAccountEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.holder(holder)
|
||||
.iban(iban)
|
||||
.bic(bic)
|
||||
|
||||
@@ -17,8 +17,7 @@ import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.persistence.EntityManager;
|
||||
import java.util.UUID;
|
||||
|
||||
import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid;
|
||||
@@ -49,7 +48,8 @@ class HsOfficeContactControllerAcceptanceTest {
|
||||
@Autowired
|
||||
JpaAttempt jpaAttempt;
|
||||
|
||||
Set<UUID> tempContactUuids = new HashSet<>();
|
||||
@Autowired
|
||||
EntityManager em;
|
||||
|
||||
@Nested
|
||||
@Accepts({ "Contact:F(Find)" })
|
||||
@@ -103,7 +103,7 @@ class HsOfficeContactControllerAcceptanceTest {
|
||||
.contentType(ContentType.JSON)
|
||||
.body("""
|
||||
{
|
||||
"label": "Test Contact",
|
||||
"label": "Temp Contact",
|
||||
"emailAddresses": "test@example.org"
|
||||
}
|
||||
""")
|
||||
@@ -114,14 +114,14 @@ class HsOfficeContactControllerAcceptanceTest {
|
||||
.statusCode(201)
|
||||
.contentType(ContentType.JSON)
|
||||
.body("uuid", isUuidValid())
|
||||
.body("label", is("Test Contact"))
|
||||
.body("label", is("Temp Contact"))
|
||||
.body("emailAddresses", is("test@example.org"))
|
||||
.header("Location", startsWith("http://localhost"))
|
||||
.extract().header("Location"); // @formatter:on
|
||||
|
||||
// finally, the new contact can be accessed under the generated UUID
|
||||
final var newUserUuid = toCleanup(UUID.fromString(
|
||||
location.substring(location.lastIndexOf('/') + 1)));
|
||||
final var newUserUuid = UUID.fromString(
|
||||
location.substring(location.lastIndexOf('/') + 1));
|
||||
assertThat(newUserUuid).isNotNull();
|
||||
}
|
||||
}
|
||||
@@ -208,7 +208,7 @@ class HsOfficeContactControllerAcceptanceTest {
|
||||
.contentType(ContentType.JSON)
|
||||
.body("""
|
||||
{
|
||||
"label": "patched contact",
|
||||
"label": "Temp patched contact",
|
||||
"emailAddresses": "patched@example.org",
|
||||
"postalAddress": "Patched Address",
|
||||
"phoneNumbers": "+01 100 123456"
|
||||
@@ -221,7 +221,7 @@ class HsOfficeContactControllerAcceptanceTest {
|
||||
.statusCode(200)
|
||||
.contentType(ContentType.JSON)
|
||||
.body("uuid", isUuidValid())
|
||||
.body("label", is("patched contact"))
|
||||
.body("label", is("Temp patched contact"))
|
||||
.body("emailAddresses", is("patched@example.org"))
|
||||
.body("postalAddress", is("Patched Address"))
|
||||
.body("phoneNumbers", is("+01 100 123456"));
|
||||
@@ -231,7 +231,7 @@ class HsOfficeContactControllerAcceptanceTest {
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
assertThat(contactRepo.findByUuid(givenContact.getUuid())).isPresent().get()
|
||||
.matches(person -> {
|
||||
assertThat(person.getLabel()).isEqualTo("patched contact");
|
||||
assertThat(person.getLabel()).isEqualTo("Temp patched contact");
|
||||
assertThat(person.getEmailAddresses()).isEqualTo("patched@example.org");
|
||||
assertThat(person.getPostalAddress()).isEqualTo("Patched Address");
|
||||
assertThat(person.getPhoneNumbers()).isEqualTo("+01 100 123456");
|
||||
@@ -353,28 +353,16 @@ class HsOfficeContactControllerAcceptanceTest {
|
||||
.phoneNumbers("+01 200 " + RandomStringUtils.randomNumeric(8))
|
||||
.build();
|
||||
|
||||
toCleanup(newContact.getUuid());
|
||||
|
||||
return contactRepo.save(newContact);
|
||||
}).assertSuccessful().returnedValue();
|
||||
}
|
||||
|
||||
private UUID toCleanup(final UUID tempContactUuid) {
|
||||
tempContactUuids.add(tempContactUuid);
|
||||
return tempContactUuid;
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
@AfterEach
|
||||
void cleanup() {
|
||||
tempContactUuids.forEach(uuid -> {
|
||||
jpaAttempt.transacted(() -> {
|
||||
context.define("superuser-alex@hostsharing.net", null);
|
||||
System.out.println("DELETING temporary contact: " + uuid);
|
||||
final var count = contactRepo.deleteByUuid(uuid);
|
||||
System.out.println("DELETED temporary contact: " + uuid + (count > 0 ? " successful" : " failed"));
|
||||
}).assertSuccessful();
|
||||
});
|
||||
jpaAttempt.transacted(() -> {
|
||||
context.define("superuser-alex@hostsharing.net", null);
|
||||
em.createQuery("DELETE FROM HsOfficeContactEntity c WHERE c.label LIKE 'Temp %'").executeUpdate();
|
||||
}).assertSuccessful();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -54,9 +54,6 @@ class HsOfficeContactRepositoryIntegrationTest extends ContextBasedTest {
|
||||
@MockBean
|
||||
HttpServletRequest request;
|
||||
|
||||
@Container
|
||||
Container postgres;
|
||||
|
||||
@Nested
|
||||
class CreateContact {
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ public class TestHsOfficeContact {
|
||||
|
||||
static public HsOfficeContactEntity hsOfficeContact(final String label, final String emailAddr) {
|
||||
return HsOfficeContactEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.label(label)
|
||||
.postalAddress("address of " + label)
|
||||
.emailAddresses(emailAddr)
|
||||
|
||||
@@ -71,7 +71,6 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase
|
||||
// when
|
||||
final var result = attempt(em, () -> {
|
||||
final var newCoopAssetsTransaction = HsOfficeCoopAssetsTransactionEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.membership(givenMembership)
|
||||
.transactionType(HsOfficeCoopAssetsTransactionType.DEPOSIT)
|
||||
.assetValue(new BigDecimal("128.00"))
|
||||
@@ -104,7 +103,6 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase
|
||||
null,
|
||||
10001).get(0);
|
||||
final var newCoopAssetsTransaction = HsOfficeCoopAssetsTransactionEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.membership(givenMembership)
|
||||
.transactionType(HsOfficeCoopAssetsTransactionType.DEPOSIT)
|
||||
.assetValue(new BigDecimal("128.00"))
|
||||
|
||||
@@ -69,7 +69,6 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase
|
||||
// when
|
||||
final var result = attempt(em, () -> {
|
||||
final var newCoopSharesTransaction = HsOfficeCoopSharesTransactionEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.membership(givenMembership)
|
||||
.transactionType(HsOfficeCoopSharesTransactionType.SUBSCRIPTION)
|
||||
.shareCount(4)
|
||||
@@ -102,7 +101,6 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase
|
||||
null,
|
||||
10001).get(0);
|
||||
final var newCoopSharesTransaction = HsOfficeCoopSharesTransactionEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.membership(givenMembership)
|
||||
.transactionType(HsOfficeCoopSharesTransactionType.SUBSCRIPTION)
|
||||
.shareCount(4)
|
||||
|
||||
@@ -2,15 +2,16 @@ package net.hostsharing.hsadminng.hs.office.debitor;
|
||||
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.http.ContentType;
|
||||
import net.hostsharing.test.Accepts;
|
||||
import net.hostsharing.hsadminng.HsadminNgApplication;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository;
|
||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRepository;
|
||||
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRepository;
|
||||
import net.hostsharing.test.Accepts;
|
||||
import net.hostsharing.test.JpaAttempt;
|
||||
import org.json.JSONException;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -18,8 +19,7 @@ import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.persistence.EntityManager;
|
||||
import java.util.UUID;
|
||||
|
||||
import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid;
|
||||
@@ -35,7 +35,8 @@ import static org.hamcrest.Matchers.*;
|
||||
@Transactional
|
||||
class HsOfficeDebitorControllerAcceptanceTest {
|
||||
|
||||
private static int nextDebitorNumber = 20001;
|
||||
private static final int LOWEST_TEMP_DEBITOR_NUMBER = 20000;
|
||||
private static int nextDebitorNumber = LOWEST_TEMP_DEBITOR_NUMBER;
|
||||
|
||||
@LocalServerPort
|
||||
private Integer port;
|
||||
@@ -58,7 +59,8 @@ class HsOfficeDebitorControllerAcceptanceTest {
|
||||
@Autowired
|
||||
JpaAttempt jpaAttempt;
|
||||
|
||||
Set<UUID> tempDebitorUuids = new HashSet<>();
|
||||
@Autowired
|
||||
EntityManager em;
|
||||
|
||||
@Nested
|
||||
@Accepts({ "Debitor:F(Find)" })
|
||||
@@ -164,7 +166,7 @@ class HsOfficeDebitorControllerAcceptanceTest {
|
||||
"vatBusiness": true,
|
||||
"refundBankAccountUuid": "%s"
|
||||
}
|
||||
""".formatted( givenPartner.getUuid(), givenContact.getUuid(), nextDebitorNumber++, givenBankAccount.getUuid()))
|
||||
""".formatted( givenPartner.getUuid(), givenContact.getUuid(), ++nextDebitorNumber, givenBankAccount.getUuid()))
|
||||
.port(port)
|
||||
.when()
|
||||
.post("http://localhost/api/hs/office/debitors")
|
||||
@@ -180,8 +182,8 @@ class HsOfficeDebitorControllerAcceptanceTest {
|
||||
.extract().header("Location"); // @formatter:on
|
||||
|
||||
// finally, the new debitor can be accessed under the generated UUID
|
||||
final var newUserUuid = toCleanup(UUID.fromString(
|
||||
location.substring(location.lastIndexOf('/') + 1)));
|
||||
final var newUserUuid = UUID.fromString(
|
||||
location.substring(location.lastIndexOf('/') + 1));
|
||||
assertThat(newUserUuid).isNotNull();
|
||||
}
|
||||
|
||||
@@ -202,7 +204,7 @@ class HsOfficeDebitorControllerAcceptanceTest {
|
||||
"billingContactUuid": "%s",
|
||||
"debitorNumber": "%s"
|
||||
}
|
||||
""".formatted( givenPartner.getUuid(), givenContact.getUuid(), nextDebitorNumber++))
|
||||
""".formatted( givenPartner.getUuid(), givenContact.getUuid(), ++nextDebitorNumber))
|
||||
.port(port)
|
||||
.when()
|
||||
.post("http://localhost/api/hs/office/debitors")
|
||||
@@ -220,8 +222,8 @@ class HsOfficeDebitorControllerAcceptanceTest {
|
||||
.extract().header("Location"); // @formatter:on
|
||||
|
||||
// finally, the new debitor can be accessed under the generated UUID
|
||||
final var newUserUuid = toCleanup(UUID.fromString(
|
||||
location.substring(location.lastIndexOf('/') + 1)));
|
||||
final var newUserUuid = UUID.fromString(
|
||||
location.substring(location.lastIndexOf('/') + 1));
|
||||
assertThat(newUserUuid).isNotNull();
|
||||
}
|
||||
|
||||
@@ -245,7 +247,7 @@ class HsOfficeDebitorControllerAcceptanceTest {
|
||||
"vatCountryCode": "DE",
|
||||
"vatBusiness": true
|
||||
}
|
||||
""".formatted( givenPartner.getUuid(), givenContactUuid, nextDebitorNumber++))
|
||||
""".formatted( givenPartner.getUuid(), givenContactUuid, ++nextDebitorNumber))
|
||||
.port(port)
|
||||
.when()
|
||||
.post("http://localhost/api/hs/office/debitors")
|
||||
@@ -275,7 +277,7 @@ class HsOfficeDebitorControllerAcceptanceTest {
|
||||
"vatCountryCode": "DE",
|
||||
"vatBusiness": true
|
||||
}
|
||||
""".formatted( givenPartnerUuid, givenContact.getUuid(), nextDebitorNumber++))
|
||||
""".formatted( givenPartnerUuid, givenContact.getUuid(), ++nextDebitorNumber))
|
||||
.port(port)
|
||||
.when()
|
||||
.post("http://localhost/api/hs/office/debitors")
|
||||
@@ -520,33 +522,24 @@ class HsOfficeDebitorControllerAcceptanceTest {
|
||||
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("Fourth").get(0);
|
||||
final var givenContact = contactRepo.findContactByOptionalLabelLike("forth contact").get(0);
|
||||
final var newDebitor = HsOfficeDebitorEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.debitorNumber(nextDebitorNumber++)
|
||||
.debitorNumber(++nextDebitorNumber)
|
||||
.partner(givenPartner)
|
||||
.billingContact(givenContact)
|
||||
.build();
|
||||
|
||||
toCleanup(newDebitor.getUuid());
|
||||
|
||||
return debitorRepo.save(newDebitor);
|
||||
}).assertSuccessful().returnedValue();
|
||||
}
|
||||
|
||||
private UUID toCleanup(final UUID tempDebitorUuid) {
|
||||
tempDebitorUuids.add(tempDebitorUuid);
|
||||
return tempDebitorUuid;
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
@AfterEach
|
||||
void cleanup() {
|
||||
tempDebitorUuids.forEach(uuid -> {
|
||||
jpaAttempt.transacted(() -> {
|
||||
context.define("superuser-alex@hostsharing.net", null);
|
||||
System.out.println("DELETING temporary debitor: " + uuid);
|
||||
final var count = debitorRepo.deleteByUuid(uuid);
|
||||
System.out.println("DELETED temporary debitor: " + uuid + (count > 0 ? " successful" : " failed"));
|
||||
});
|
||||
jpaAttempt.transacted(() -> {
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
final var count = em.createQuery(
|
||||
"DELETE FROM HsOfficeDebitorEntity d WHERE d.debitorNumber > " + LOWEST_TEMP_DEBITOR_NUMBER)
|
||||
.executeUpdate();
|
||||
System.out.printf("deleted %d entities%n", count);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -79,7 +79,6 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest {
|
||||
// when
|
||||
final var result = attempt(em, () -> {
|
||||
final var newDebitor = HsOfficeDebitorEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.debitorNumber(20001)
|
||||
.partner(givenPartner)
|
||||
.billingContact(givenContact)
|
||||
@@ -112,7 +111,6 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest {
|
||||
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("Fourth").get(0);
|
||||
final var givenContact = contactRepo.findContactByOptionalLabelLike("forth contact").get(0);
|
||||
final var newDebitor = HsOfficeDebitorEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.debitorNumber(20002)
|
||||
.partner(givenPartner)
|
||||
.billingContact(givenContact)
|
||||
@@ -544,7 +542,6 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest {
|
||||
final var givenBankAccount =
|
||||
bankAccount != null ? bankAccountRepo.findByOptionalHolderLike(bankAccount).get(0) : null;
|
||||
final var newDebitor = HsOfficeDebitorEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.debitorNumber(20000)
|
||||
.partner(givenPartner)
|
||||
.billingContact(givenContact)
|
||||
|
||||
@@ -11,7 +11,6 @@ import static net.hostsharing.hsadminng.hs.office.partner.TestHsOfficePartner.TE
|
||||
public class TestHsOfficeDebitor {
|
||||
|
||||
public static final HsOfficeDebitorEntity TEST_DEBITOR = HsOfficeDebitorEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.debitorNumber(10001)
|
||||
.partner(TEST_PARTNER)
|
||||
.billingContact(TEST_CONTACT)
|
||||
|
||||
@@ -2,26 +2,25 @@ package net.hostsharing.hsadminng.hs.office.membership;
|
||||
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
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.mapper.Mapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.boot.test.mock.mockito.SpyBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.orm.jpa.JpaObjectRetrievalFailureException;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityNotFoundException;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
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.status;
|
||||
@@ -97,14 +96,13 @@ public class HsOfficeMembershipControllerRestTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void respondBadRequest_ifAnyGivenUuidCannotBeResolved() throws Exception {
|
||||
void respondBadRequest_ifAnyGivenPartnerUuidCannotBeFound() throws Exception {
|
||||
|
||||
// given
|
||||
when(membershipRepo.save(any())).thenThrow(
|
||||
new JpaObjectRetrievalFailureException(
|
||||
new EntityNotFoundException(
|
||||
// same would happen with HsOfficePartnerEntity which could not be resolved
|
||||
"Unable to find net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity with id ...")));
|
||||
final var givenPartnerUuid = UUID.randomUUID();
|
||||
final var givenMainDebitorUuid = UUID.randomUUID();
|
||||
when(em.find(HsOfficePartnerEntity.class, givenPartnerUuid)).thenReturn(null);
|
||||
when(em.find(HsOfficeDebitorEntity.class, givenMainDebitorUuid)).thenReturn(mock(HsOfficeDebitorEntity.class));
|
||||
|
||||
// when
|
||||
mockMvc.perform(MockMvcRequestBuilders
|
||||
@@ -118,13 +116,44 @@ public class HsOfficeMembershipControllerRestTest {
|
||||
"memberNumber": 20001,
|
||||
"validFrom": "2022-10-13"
|
||||
}
|
||||
""".formatted(UUID.randomUUID(), UUID.randomUUID()))
|
||||
""".formatted(givenPartnerUuid, givenMainDebitorUuid))
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
|
||||
// then
|
||||
.andExpect(status().is4xxClientError())
|
||||
.andExpect(jsonPath("status", is(400)))
|
||||
.andExpect(jsonPath("error", is("Bad Request")))
|
||||
.andExpect(jsonPath("message", is("Unable to find Debitor with uuid ...")));
|
||||
.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",
|
||||
"memberNumber": 20001,
|
||||
"validFrom": "2022-10-13"
|
||||
}
|
||||
""".formatted(givenPartnerUuid, givenMainDebitorUuid))
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
|
||||
// then
|
||||
.andExpect(status().is4xxClientError())
|
||||
.andExpect(jsonPath("status", is(400)))
|
||||
.andExpect(jsonPath("error", is("Bad Request")))
|
||||
.andExpect(jsonPath("message", is("Unable to find Debitor with uuid " + givenMainDebitorUuid)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,6 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTest {
|
||||
// when
|
||||
final var result = attempt(em, () -> {
|
||||
final var newMembership = toCleanup(HsOfficeMembershipEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.memberNumber(20001)
|
||||
.partner(givenPartner)
|
||||
.mainDebitor(givenDebitor)
|
||||
@@ -107,7 +106,6 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTest {
|
||||
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("First").get(0);
|
||||
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike("First").get(0);
|
||||
final var newMembership = toCleanup(HsOfficeMembershipEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.memberNumber(20002)
|
||||
.partner(givenPartner)
|
||||
.mainDebitor(givenDebitor)
|
||||
@@ -409,7 +407,6 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTest {
|
||||
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike(partnerTradeName).get(0);
|
||||
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike(debitorName).get(0);
|
||||
final var newMembership = HsOfficeMembershipEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.memberNumber(20002)
|
||||
.partner(givenPartner)
|
||||
.mainDebitor(givenDebitor)
|
||||
|
||||
@@ -11,7 +11,6 @@ public class TestHsMembership {
|
||||
|
||||
public static final HsOfficeMembershipEntity TEST_MEMBERSHIP =
|
||||
HsOfficeMembershipEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.partner(TEST_PARTNER)
|
||||
.memberNumber(300001)
|
||||
.validity(Range.closedInfinite(LocalDate.parse("2020-01-01")))
|
||||
|
||||
@@ -17,8 +17,7 @@ import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.persistence.EntityManager;
|
||||
import java.util.UUID;
|
||||
|
||||
import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid;
|
||||
@@ -32,7 +31,6 @@ import static org.hamcrest.Matchers.startsWith;
|
||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
classes = { HsadminNgApplication.class, JpaAttempt.class }
|
||||
)
|
||||
@Transactional
|
||||
class HsOfficePartnerControllerAcceptanceTest {
|
||||
|
||||
@LocalServerPort
|
||||
@@ -56,10 +54,12 @@ class HsOfficePartnerControllerAcceptanceTest {
|
||||
@Autowired
|
||||
JpaAttempt jpaAttempt;
|
||||
|
||||
Set<UUID> tempPartnerUuids = new HashSet<>();
|
||||
@Autowired
|
||||
EntityManager em;
|
||||
|
||||
@Nested
|
||||
@Accepts({ "Partner:F(Find)" })
|
||||
@Transactional
|
||||
class ListPartners {
|
||||
|
||||
@Test
|
||||
@@ -109,6 +109,7 @@ class HsOfficePartnerControllerAcceptanceTest {
|
||||
|
||||
@Nested
|
||||
@Accepts({ "Partner:C(Create)" })
|
||||
@Transactional
|
||||
class AddPartner {
|
||||
|
||||
@Test
|
||||
@@ -127,8 +128,8 @@ class HsOfficePartnerControllerAcceptanceTest {
|
||||
"contactUuid": "%s",
|
||||
"personUuid": "%s",
|
||||
"details": {
|
||||
"registrationOffice": "Registergericht Aurich",
|
||||
"registrationNumber": "123456"
|
||||
"registrationOffice": "Temp Registergericht Aurich",
|
||||
"registrationNumber": "111111"
|
||||
}
|
||||
}
|
||||
""".formatted(givenContact.getUuid(), givenPerson.getUuid()))
|
||||
@@ -139,16 +140,16 @@ class HsOfficePartnerControllerAcceptanceTest {
|
||||
.statusCode(201)
|
||||
.contentType(ContentType.JSON)
|
||||
.body("uuid", isUuidValid())
|
||||
.body("details.registrationOffice", is("Registergericht Aurich"))
|
||||
.body("details.registrationNumber", is("123456"))
|
||||
.body("details.registrationOffice", is("Temp Registergericht Aurich"))
|
||||
.body("details.registrationNumber", is("111111"))
|
||||
.body("contact.label", is(givenContact.getLabel()))
|
||||
.body("person.tradeName", is(givenPerson.getTradeName()))
|
||||
.header("Location", startsWith("http://localhost"))
|
||||
.extract().header("Location"); // @formatter:on
|
||||
|
||||
// finally, the new partner can be accessed under the generated UUID
|
||||
final var newUserUuid = toCleanup(UUID.fromString(
|
||||
location.substring(location.lastIndexOf('/') + 1)));
|
||||
final var newUserUuid = UUID.fromString(
|
||||
location.substring(location.lastIndexOf('/') + 1));
|
||||
assertThat(newUserUuid).isNotNull();
|
||||
}
|
||||
|
||||
@@ -209,6 +210,7 @@ class HsOfficePartnerControllerAcceptanceTest {
|
||||
|
||||
@Nested
|
||||
@Accepts({ "Partner:R(Read)" })
|
||||
@Transactional
|
||||
class GetPartner {
|
||||
|
||||
@Test
|
||||
@@ -275,6 +277,7 @@ class HsOfficePartnerControllerAcceptanceTest {
|
||||
|
||||
@Nested
|
||||
@Accepts({ "Partner:U(Update)" })
|
||||
@Transactional
|
||||
class PatchPartner {
|
||||
|
||||
@Test
|
||||
@@ -294,7 +297,7 @@ class HsOfficePartnerControllerAcceptanceTest {
|
||||
"contactUuid": "%s",
|
||||
"personUuid": "%s",
|
||||
"details": {
|
||||
"registrationOffice": "Registergericht Hamburg",
|
||||
"registrationOffice": "Temp Registergericht Aurich",
|
||||
"registrationNumber": "222222",
|
||||
"birthName": "Maja Schmidt",
|
||||
"birthday": "1938-04-08",
|
||||
@@ -320,7 +323,7 @@ class HsOfficePartnerControllerAcceptanceTest {
|
||||
.matches(person -> {
|
||||
assertThat(person.getPerson().getTradeName()).isEqualTo("Third OHG");
|
||||
assertThat(person.getContact().getLabel()).isEqualTo("forth contact");
|
||||
assertThat(person.getDetails().getRegistrationOffice()).isEqualTo("Registergericht Hamburg");
|
||||
assertThat(person.getDetails().getRegistrationOffice()).isEqualTo("Temp Registergericht Aurich");
|
||||
assertThat(person.getDetails().getRegistrationNumber()).isEqualTo("222222");
|
||||
assertThat(person.getDetails().getBirthName()).isEqualTo("Maja Schmidt");
|
||||
assertThat(person.getDetails().getBirthday()).isEqualTo("1938-04-08");
|
||||
@@ -365,8 +368,8 @@ class HsOfficePartnerControllerAcceptanceTest {
|
||||
.matches(person -> {
|
||||
assertThat(person.getPerson().getTradeName()).isEqualTo(givenPartner.getPerson().getTradeName());
|
||||
assertThat(person.getContact().getLabel()).isEqualTo(givenPartner.getContact().getLabel());
|
||||
assertThat(person.getDetails().getRegistrationOffice()).isEqualTo(null);
|
||||
assertThat(person.getDetails().getRegistrationNumber()).isEqualTo(null);
|
||||
assertThat(person.getDetails().getRegistrationOffice()).isEqualTo("Temp Registergericht Leer");
|
||||
assertThat(person.getDetails().getRegistrationNumber()).isEqualTo("333333");
|
||||
assertThat(person.getDetails().getBirthName()).isEqualTo("Maja Schmidt");
|
||||
assertThat(person.getDetails().getBirthday()).isEqualTo("1938-04-08");
|
||||
assertThat(person.getDetails().getDateOfDeath()).isEqualTo("2022-01-12");
|
||||
@@ -378,6 +381,7 @@ class HsOfficePartnerControllerAcceptanceTest {
|
||||
|
||||
@Nested
|
||||
@Accepts({ "Partner:D(Delete)" })
|
||||
@Transactional
|
||||
class DeletePartner {
|
||||
|
||||
@Test
|
||||
@@ -445,35 +449,41 @@ class HsOfficePartnerControllerAcceptanceTest {
|
||||
final var givenPerson = personRepo.findPersonByOptionalNameLike("Erben Bessler").get(0);
|
||||
final var givenContact = contactRepo.findContactByOptionalLabelLike("forth contact").get(0);
|
||||
final var newPartner = HsOfficePartnerEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.person(givenPerson)
|
||||
.contact(givenContact)
|
||||
.details(HsOfficePartnerDetailsEntity.builder()
|
||||
.uuid((UUID.randomUUID()))
|
||||
.registrationOffice("Temp Registergericht Leer")
|
||||
.registrationNumber("333333")
|
||||
.build())
|
||||
.build();
|
||||
|
||||
toCleanup(newPartner.getUuid());
|
||||
|
||||
return partnerRepo.save(newPartner);
|
||||
}).assertSuccessful().returnedValue();
|
||||
}
|
||||
|
||||
private UUID toCleanup(final UUID tempPartnerUuid) {
|
||||
tempPartnerUuids.add(tempPartnerUuid);
|
||||
return tempPartnerUuid;
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void cleanup() {
|
||||
tempPartnerUuids.forEach(uuid -> {
|
||||
jpaAttempt.transacted(() -> {
|
||||
context.define("superuser-alex@hostsharing.net", null);
|
||||
System.out.println("DELETING temporary partner: " + uuid);
|
||||
final var count = partnerRepo.deleteByUuid(uuid);
|
||||
System.out.println("DELETED temporary partner: " + uuid + (count > 0 ? " successful" : " failed"));
|
||||
});
|
||||
});
|
||||
final var deleted = jpaAttempt.transacted(() -> {
|
||||
context.define("superuser-alex@hostsharing.net", null);
|
||||
em.createNativeQuery("""
|
||||
delete from hs_office_partner p
|
||||
where p.detailsuuid in (
|
||||
select d.uuid from hs_office_partner_details d
|
||||
where d.registrationoffice like 'Temp %')
|
||||
""")
|
||||
.executeUpdate();
|
||||
}).assertSuccessful().returnedValue();
|
||||
|
||||
final var remaining = jpaAttempt.transacted(() -> {
|
||||
em.createNativeQuery("""
|
||||
select count(p) from hs_office_partner p
|
||||
where p.detailsuuid in (
|
||||
select d.uuid from hs_office_partner_details d
|
||||
where d.registrationoffice like 'Temp %')
|
||||
""")
|
||||
.getSingleResult();
|
||||
}).assertSuccessful().returnedValue();
|
||||
System.err.println("@AfterEach" + ": " + deleted + " records deleted, " + remaining + " remaining");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -73,11 +73,9 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest {
|
||||
// when
|
||||
final var result = attempt(em, () -> {
|
||||
final var newPartner = toCleanup(HsOfficePartnerEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.person(givenPerson)
|
||||
.contact(givenContact)
|
||||
.details(HsOfficePartnerDetailsEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.build())
|
||||
.build());
|
||||
return partnerRepo.save(newPartner);
|
||||
@@ -106,10 +104,9 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest {
|
||||
final var givenPerson = personRepo.findPersonByOptionalNameLike("Erben Bessler").get(0);
|
||||
final var givenContact = contactRepo.findContactByOptionalLabelLike("forth contact").get(0);
|
||||
final var newPartner = toCleanup(HsOfficePartnerEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.person(givenPerson)
|
||||
.contact(givenContact)
|
||||
.details(HsOfficePartnerDetailsEntity.builder().uuid(UUID.randomUUID()).build())
|
||||
.details(HsOfficePartnerDetailsEntity.builder().build())
|
||||
.build());
|
||||
return partnerRepo.save(newPartner);
|
||||
});
|
||||
@@ -406,12 +403,9 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest {
|
||||
final var givenPerson = personRepo.findPersonByOptionalNameLike("Erben Bessler").get(0);
|
||||
final var givenContact = contactRepo.findContactByOptionalLabelLike(contact).get(0);
|
||||
final var newPartner = HsOfficePartnerEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.person(givenPerson)
|
||||
.contact(givenContact)
|
||||
.details(HsOfficePartnerDetailsEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.build())
|
||||
.details(HsOfficePartnerDetailsEntity.builder().build())
|
||||
.build();
|
||||
|
||||
toCleanup(newPartner);
|
||||
|
||||
@@ -13,7 +13,6 @@ public class TestHsOfficePartner {
|
||||
|
||||
static public HsOfficePartnerEntity HsOfficePartnerWithLegalPerson(final String tradeName) {
|
||||
return HsOfficePartnerEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.person(HsOfficePersonEntity.builder()
|
||||
.personType(LEGAL)
|
||||
.tradeName(tradeName)
|
||||
|
||||
@@ -2,14 +2,13 @@ package net.hostsharing.hsadminng.hs.office.person;
|
||||
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.http.ContentType;
|
||||
import net.hostsharing.test.Accepts;
|
||||
import net.hostsharing.hsadminng.HsadminNgApplication;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.test.Accepts;
|
||||
import net.hostsharing.test.JpaAttempt;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.json.JSONException;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -17,8 +16,7 @@ import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.persistence.EntityManager;
|
||||
import java.util.UUID;
|
||||
|
||||
import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid;
|
||||
@@ -31,7 +29,6 @@ import static org.hamcrest.Matchers.startsWith;
|
||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
classes = { HsadminNgApplication.class, JpaAttempt.class }
|
||||
)
|
||||
@Transactional
|
||||
class HsOfficePersonControllerAcceptanceTest {
|
||||
|
||||
@LocalServerPort
|
||||
@@ -49,7 +46,8 @@ class HsOfficePersonControllerAcceptanceTest {
|
||||
@Autowired
|
||||
JpaAttempt jpaAttempt;
|
||||
|
||||
Set<UUID> tempPersonUuids = new HashSet<>();
|
||||
@Autowired
|
||||
EntityManager em;
|
||||
|
||||
@Nested
|
||||
@Accepts({ "Person:F(Find)" })
|
||||
@@ -129,9 +127,7 @@ class HsOfficePersonControllerAcceptanceTest {
|
||||
class AddPerson {
|
||||
|
||||
@Test
|
||||
void globalAdmin_withoutAssumedRole_canAddPerson() {
|
||||
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
void globalAdmin_canAddPerson() {
|
||||
|
||||
final var location = RestAssured // @formatter:off
|
||||
.given()
|
||||
@@ -141,7 +137,7 @@ class HsOfficePersonControllerAcceptanceTest {
|
||||
{
|
||||
"personType": "NATURAL",
|
||||
"familyName": "Tester",
|
||||
"givenName": "Testi"
|
||||
"givenName": "Temp Testi"
|
||||
}
|
||||
""")
|
||||
.port(port)
|
||||
@@ -153,23 +149,24 @@ class HsOfficePersonControllerAcceptanceTest {
|
||||
.body("uuid", isUuidValid())
|
||||
.body("personType", is("NATURAL"))
|
||||
.body("familyName", is("Tester"))
|
||||
.body("givenName", is("Testi"))
|
||||
.body("givenName", is("Temp Testi"))
|
||||
.header("Location", startsWith("http://localhost"))
|
||||
.extract().header("Location"); // @formatter:on
|
||||
|
||||
// finally, the new person can be accessed under the generated UUID
|
||||
final var newUserUuid = toCleanup(UUID.fromString(
|
||||
location.substring(location.lastIndexOf('/') + 1)));
|
||||
final var newUserUuid = UUID.fromString(
|
||||
location.substring(location.lastIndexOf('/') + 1));
|
||||
assertThat(newUserUuid).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@Accepts({ "Person:R(Read)" })
|
||||
@Transactional
|
||||
class GetPerson {
|
||||
|
||||
@Test
|
||||
void globalAdmin_withoutAssumedRole_canGetArbitraryPerson() {
|
||||
void globalAdmin_canGetArbitraryPerson() {
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
final var givenPersonUuid = personRepo.findPersonByOptionalNameLike("Erben").get(0).getUuid();
|
||||
|
||||
@@ -192,8 +189,10 @@ class HsOfficePersonControllerAcceptanceTest {
|
||||
@Test
|
||||
@Accepts({ "Person:X(Access Control)" })
|
||||
void normalUser_canNotGetUnrelatedPerson() {
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
final var givenPersonUuid = personRepo.findPersonByOptionalNameLike("Erben").get(0).getUuid();
|
||||
final var givenPersonUuid = jpaAttempt.transacted(() -> {
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
return personRepo.findPersonByOptionalNameLike("Erben").get(0).getUuid();
|
||||
}).returnedValue();
|
||||
|
||||
RestAssured // @formatter:off
|
||||
.given()
|
||||
@@ -208,8 +207,10 @@ class HsOfficePersonControllerAcceptanceTest {
|
||||
@Test
|
||||
@Accepts({ "Person:X(Access Control)" })
|
||||
void personOwnerUser_canGetRelatedPerson() {
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
final var givenPersonUuid = personRepo.findPersonByOptionalNameLike("Erben").get(0).getUuid();
|
||||
final var givenPersonUuid = jpaAttempt.transacted(() -> {
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
return personRepo.findPersonByOptionalNameLike("Erben").get(0).getUuid();
|
||||
}).returnedValue();
|
||||
|
||||
RestAssured // @formatter:off
|
||||
.given()
|
||||
@@ -233,12 +234,12 @@ class HsOfficePersonControllerAcceptanceTest {
|
||||
|
||||
@Nested
|
||||
@Accepts({ "Person:U(Update)" })
|
||||
@Transactional
|
||||
class PatchPerson {
|
||||
|
||||
@Test
|
||||
void globalAdmin_withoutAssumedRole_canPatchAllPropertiesOfArbitraryPerson() {
|
||||
void globalAdmin_canPatchAllPropertiesOfArbitraryPerson() {
|
||||
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
final var givenPerson = givenSomeTemporaryPersonCreatedBy("selfregistered-test-user@hostsharing.org");
|
||||
|
||||
final var location = RestAssured // @formatter:off
|
||||
@@ -248,9 +249,9 @@ class HsOfficePersonControllerAcceptanceTest {
|
||||
.body("""
|
||||
{
|
||||
"personType": "JOINT_REPRESENTATION",
|
||||
"tradeName": "Patched Trade Name",
|
||||
"familyName": "Patched Family Name",
|
||||
"givenName": "Patched Given Name"
|
||||
"tradeName": "Temp Trade Name - patched",
|
||||
"familyName": "Temp Family Name - patched",
|
||||
"givenName": "Temp Given Name - patched"
|
||||
}
|
||||
""")
|
||||
.port(port)
|
||||
@@ -261,9 +262,9 @@ class HsOfficePersonControllerAcceptanceTest {
|
||||
.contentType(ContentType.JSON)
|
||||
.body("uuid", isUuidValid())
|
||||
.body("personType", is("JOINT_REPRESENTATION"))
|
||||
.body("tradeName", is("Patched Trade Name"))
|
||||
.body("familyName", is("Patched Family Name"))
|
||||
.body("givenName", is("Patched Given Name"));
|
||||
.body("tradeName", is("Temp Trade Name - patched"))
|
||||
.body("familyName", is("Temp Family Name - patched"))
|
||||
.body("givenName", is("Temp Given Name - patched"));
|
||||
// @formatter:on
|
||||
|
||||
// finally, the person is actually updated
|
||||
@@ -271,17 +272,16 @@ class HsOfficePersonControllerAcceptanceTest {
|
||||
assertThat(personRepo.findByUuid(givenPerson.getUuid())).isPresent().get()
|
||||
.matches(person -> {
|
||||
assertThat(person.getPersonType()).isEqualTo(HsOfficePersonType.JOINT_REPRESENTATION);
|
||||
assertThat(person.getTradeName()).isEqualTo("Patched Trade Name");
|
||||
assertThat(person.getFamilyName()).isEqualTo("Patched Family Name");
|
||||
assertThat(person.getGivenName()).isEqualTo("Patched Given Name");
|
||||
assertThat(person.getTradeName()).isEqualTo("Temp Trade Name - patched");
|
||||
assertThat(person.getFamilyName()).isEqualTo("Temp Family Name - patched");
|
||||
assertThat(person.getGivenName()).isEqualTo("Temp Given Name - patched");
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void globalAdmin_withoutAssumedRole_canPatchPartialPropertiesOfArbitraryPerson() {
|
||||
void globalAdmin_canPatchPartialPropertiesOfArbitraryPerson() {
|
||||
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
final var givenPerson = givenSomeTemporaryPersonCreatedBy("selfregistered-test-user@hostsharing.org");
|
||||
|
||||
final var location = RestAssured // @formatter:off
|
||||
@@ -290,8 +290,8 @@ class HsOfficePersonControllerAcceptanceTest {
|
||||
.contentType(ContentType.JSON)
|
||||
.body("""
|
||||
{
|
||||
"familyName": "Patched Family Name",
|
||||
"givenName": "Patched Given Name"
|
||||
"familyName": "Temp Family Name - patched",
|
||||
"givenName": "Temp Given Name - patched"
|
||||
}
|
||||
""")
|
||||
.port(port)
|
||||
@@ -303,17 +303,18 @@ class HsOfficePersonControllerAcceptanceTest {
|
||||
.body("uuid", isUuidValid())
|
||||
.body("personType", is(givenPerson.getPersonType().toString()))
|
||||
.body("tradeName", is(givenPerson.getTradeName()))
|
||||
.body("familyName", is("Patched Family Name"))
|
||||
.body("givenName", is("Patched Given Name"));
|
||||
.body("familyName", is("Temp Family Name - patched"))
|
||||
.body("givenName", is("Temp Given Name - patched"));
|
||||
// @formatter:on
|
||||
|
||||
// finally, the person is actually updated
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
assertThat(personRepo.findByUuid(givenPerson.getUuid())).isPresent().get()
|
||||
.matches(person -> {
|
||||
assertThat(person.getPersonType()).isEqualTo(givenPerson.getPersonType());
|
||||
assertThat(person.getTradeName()).isEqualTo(givenPerson.getTradeName());
|
||||
assertThat(person.getFamilyName()).isEqualTo("Patched Family Name");
|
||||
assertThat(person.getGivenName()).isEqualTo("Patched Given Name");
|
||||
assertThat(person.getFamilyName()).isEqualTo("Temp Family Name - patched");
|
||||
assertThat(person.getGivenName()).isEqualTo("Temp Given Name - patched");
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@@ -321,11 +322,11 @@ class HsOfficePersonControllerAcceptanceTest {
|
||||
|
||||
@Nested
|
||||
@Accepts({ "Person:D(Delete)" })
|
||||
@Transactional
|
||||
class DeletePerson {
|
||||
|
||||
@Test
|
||||
void globalAdmin_withoutAssumedRole_canDeleteArbitraryPerson() {
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
void globalAdmin_canDeleteArbitraryPerson() {
|
||||
final var givenPerson = givenSomeTemporaryPersonCreatedBy("selfregistered-test-user@hostsharing.org");
|
||||
|
||||
RestAssured // @formatter:off
|
||||
@@ -338,6 +339,8 @@ class HsOfficePersonControllerAcceptanceTest {
|
||||
.statusCode(204); // @formatter:on
|
||||
|
||||
// then the given person is gone
|
||||
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
assertThat(personRepo.findByUuid(givenPerson.getUuid())).isEmpty();
|
||||
}
|
||||
|
||||
@@ -362,7 +365,6 @@ class HsOfficePersonControllerAcceptanceTest {
|
||||
@Test
|
||||
@Accepts({ "Person:X(Access Control)" })
|
||||
void normalUser_canNotDeleteUnrelatedPerson() {
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
final var givenPerson = givenSomeTemporaryPersonCreatedBy("selfregistered-test-user@hostsharing.org");
|
||||
|
||||
RestAssured // @formatter:off
|
||||
@@ -376,6 +378,7 @@ class HsOfficePersonControllerAcceptanceTest {
|
||||
// @formatter:on
|
||||
|
||||
// then the given person is still there
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
assertThat(personRepo.findByUuid(givenPerson.getUuid())).isNotEmpty();
|
||||
}
|
||||
}
|
||||
@@ -388,32 +391,21 @@ class HsOfficePersonControllerAcceptanceTest {
|
||||
.personType(HsOfficePersonType.LEGAL)
|
||||
.tradeName("Temp " + Context.getCallerMethodNameFromStackFrame(2))
|
||||
.familyName(RandomStringUtils.randomAlphabetic(10) + "@example.org")
|
||||
.givenName("Given Name " + RandomStringUtils.randomAlphabetic(10))
|
||||
.givenName("Temp Given Name " + RandomStringUtils.randomAlphabetic(10))
|
||||
.build();
|
||||
|
||||
toCleanup(newPerson.getUuid());
|
||||
|
||||
return personRepo.save(newPerson);
|
||||
}).assertSuccessful().returnedValue();
|
||||
}
|
||||
|
||||
private UUID toCleanup(final UUID tempPersonUuid) {
|
||||
tempPersonUuids.add(tempPersonUuid);
|
||||
return tempPersonUuid;
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
@AfterEach
|
||||
void cleanup() {
|
||||
tempPersonUuids.forEach(uuid -> {
|
||||
jpaAttempt.transacted(() -> {
|
||||
context.define("superuser-alex@hostsharing.net", null);
|
||||
System.out.println("DELETING temporary person: " + uuid);
|
||||
final var entity = personRepo.findByUuid(uuid);
|
||||
final var count = personRepo.deleteByUuid(uuid);
|
||||
System.out.println("DELETED temporary person: " + uuid + (count > 0 ? " successful" : " failed") +
|
||||
(" (" + entity.map(hsOfficePersonEntity -> hsOfficePersonEntity.toShortString()).orElse("null") + ")"));
|
||||
}).assertSuccessful();
|
||||
});
|
||||
jpaAttempt.transacted(() -> {
|
||||
context.define("superuser-alex@hostsharing.net", null);
|
||||
em.createQuery("""
|
||||
DELETE FROM HsOfficePersonEntity p
|
||||
WHERE p.tradeName LIKE 'Temp %' OR p.givenName LIKE 'Temp %'
|
||||
""").executeUpdate();
|
||||
}).assertSuccessful();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ public class TestHsOfficePerson {
|
||||
|
||||
static public HsOfficePersonEntity hsOfficePerson(final String tradeName) {
|
||||
return HsOfficePersonEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.personType(HsOfficePersonType.NATURAL)
|
||||
.tradeName(tradeName)
|
||||
.build();
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package net.hostsharing.hsadminng.hs.office.relationship;
|
||||
|
||||
import net.hostsharing.hsadminng.HsadminNgApplication;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.context.ContextBasedTest;
|
||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRepository;
|
||||
@@ -15,10 +14,8 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.orm.jpa.JpaSystemException;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -74,7 +71,6 @@ class HsOfficeRelationshipRepositoryIntegrationTest extends ContextBasedTest {
|
||||
// when
|
||||
final var result = attempt(em, () -> {
|
||||
final var newRelationship = toCleanup(HsOfficeRelationshipEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.relAnchor(givenAnchorPerson)
|
||||
.relHolder(givenHolderPerson)
|
||||
.relType(HsOfficeRelationshipType.JOINT_AGENT)
|
||||
@@ -103,7 +99,6 @@ class HsOfficeRelationshipRepositoryIntegrationTest extends ContextBasedTest {
|
||||
final var givenHolderPerson = personRepo.findPersonByOptionalNameLike("Anita").get(0);
|
||||
final var givenContact = contactRepo.findContactByOptionalLabelLike("forth contact").get(0);
|
||||
final var newRelationship = toCleanup(HsOfficeRelationshipEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.relAnchor(givenAnchorPerson)
|
||||
.relHolder(givenHolderPerson)
|
||||
.relType(HsOfficeRelationshipType.JOINT_AGENT)
|
||||
@@ -393,7 +388,6 @@ class HsOfficeRelationshipRepositoryIntegrationTest extends ContextBasedTest {
|
||||
final var givenHolderPerson = personRepo.findPersonByOptionalNameLike(holderPerson).get(0);
|
||||
final var givenContact = contactRepo.findContactByOptionalLabelLike(contact).get(0);
|
||||
final var newRelationship = HsOfficeRelationshipEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.relType(HsOfficeRelationshipType.JOINT_AGENT)
|
||||
.relAnchor(givenAnchorPerson)
|
||||
.relHolder(givenHolderPerson)
|
||||
|
||||
@@ -3,14 +3,15 @@ package net.hostsharing.hsadminng.hs.office.sepamandate;
|
||||
import com.vladmihalcea.hibernate.type.range.Range;
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.http.ContentType;
|
||||
import net.hostsharing.test.Accepts;
|
||||
import net.hostsharing.hsadminng.HsadminNgApplication;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository;
|
||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository;
|
||||
import net.hostsharing.test.Accepts;
|
||||
import net.hostsharing.test.JpaAttempt;
|
||||
import org.json.JSONException;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -18,9 +19,8 @@ import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import java.time.LocalDate;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid;
|
||||
@@ -56,7 +56,8 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
|
||||
@Autowired
|
||||
JpaAttempt jpaAttempt;
|
||||
|
||||
Set<UUID> tempSepaMandateUuids = new HashSet<>();
|
||||
@Autowired
|
||||
EntityManager em;
|
||||
|
||||
@Nested
|
||||
@Accepts({ "SepaMandate:F(Find)" })
|
||||
@@ -131,7 +132,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
|
||||
{
|
||||
"debitorUuid": "%s",
|
||||
"bankAccountUuid": "%s",
|
||||
"reference": "temp ref A",
|
||||
"reference": "temp ref CAT A",
|
||||
"validFrom": "2022-10-13"
|
||||
}
|
||||
""".formatted(givenDebitor.getUuid(), givenBankAccount.getUuid()))
|
||||
@@ -144,15 +145,15 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
|
||||
.body("uuid", isUuidValid())
|
||||
.body("debitor.partner.person.tradeName", is("Third OHG"))
|
||||
.body("bankAccount.iban", is("DE02200505501015871393"))
|
||||
.body("reference", is("temp ref A"))
|
||||
.body("reference", is("temp ref CAT A"))
|
||||
.body("validFrom", is("2022-10-13"))
|
||||
.body("validTo", equalTo(null))
|
||||
.header("Location", startsWith("http://localhost"))
|
||||
.extract().header("Location"); // @formatter:on
|
||||
|
||||
// finally, the new sepaMandate can be accessed under the generated UUID
|
||||
final var newUserUuid = toCleanup(UUID.fromString(
|
||||
location.substring(location.lastIndexOf('/') + 1)));
|
||||
final var newUserUuid = UUID.fromString(
|
||||
location.substring(location.lastIndexOf('/') + 1));
|
||||
assertThat(newUserUuid).isNotNull();
|
||||
}
|
||||
|
||||
@@ -171,7 +172,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
|
||||
.body("""
|
||||
{
|
||||
"bankAccountUuid": "%s",
|
||||
"reference": "temp ref A",
|
||||
"reference": "temp ref CAT B",
|
||||
"validFrom": "2022-10-13"
|
||||
}
|
||||
""".formatted(givenBankAccount.getUuid()))
|
||||
@@ -197,7 +198,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
|
||||
{
|
||||
"debitorUuid": "%s",
|
||||
"bankAccountUuid": "%s",
|
||||
"reference": "temp ref A",
|
||||
"reference": "temp ref CAT C",
|
||||
"validFrom": "2022-10-13",
|
||||
"validTo": "2024-12-31"
|
||||
}
|
||||
@@ -226,7 +227,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
|
||||
{
|
||||
"debitorUuid": "%s",
|
||||
"bankAccountUuid": "%s",
|
||||
"reference": "temp ref A",
|
||||
"reference": "temp refCAT D",
|
||||
"validFrom": "2022-10-13",
|
||||
"validTo": "2024-12-31"
|
||||
}
|
||||
@@ -267,7 +268,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
|
||||
"debitorNumber": 10001,
|
||||
"billingContact": { "label": "first contact" }
|
||||
},
|
||||
"bankAccount": {
|
||||
"bankAccount": {
|
||||
"holder": "First GmbH",
|
||||
"iban": "DE02120300000000202051"
|
||||
},
|
||||
@@ -319,7 +320,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
|
||||
"debitorNumber": 10001,
|
||||
"billingContact": { "label": "first contact" }
|
||||
},
|
||||
"bankAccount": {
|
||||
"bankAccount": {
|
||||
"holder": "First GmbH",
|
||||
"iban": "DE02120300000000202051"
|
||||
},
|
||||
@@ -359,7 +360,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
|
||||
.body("uuid", isUuidValid())
|
||||
.body("debitor.partner.person.tradeName", is("First GmbH"))
|
||||
.body("bankAccount.iban", is("DE02120300000000202051"))
|
||||
.body("reference", is("temp ref X"))
|
||||
.body("reference", is("temp ref CAT Z"))
|
||||
.body("validFrom", is("2022-11-01"))
|
||||
.body("validTo", is("2022-12-31"));
|
||||
// @formatter:on
|
||||
@@ -369,7 +370,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
|
||||
.matches(mandate -> {
|
||||
assertThat(mandate.getDebitor().toString()).isEqualTo("debitor(10001: First GmbH)");
|
||||
assertThat(mandate.getBankAccount().toShortString()).isEqualTo("First GmbH");
|
||||
assertThat(mandate.getReference()).isEqualTo("temp ref X");
|
||||
assertThat(mandate.getReference()).isEqualTo("temp ref CAT Z");
|
||||
assertThat(mandate.getValidity().asString()).isEqualTo("[2022-11-01,2023-01-01)");
|
||||
return true;
|
||||
});
|
||||
@@ -387,7 +388,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
|
||||
.contentType(ContentType.JSON)
|
||||
.body("""
|
||||
{
|
||||
"reference": "new ref"
|
||||
"reference": "temp ref CAT new"
|
||||
}
|
||||
""")
|
||||
.port(port)
|
||||
@@ -405,7 +406,6 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nested
|
||||
@@ -435,7 +435,6 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
|
||||
void bankAccountAdminUser_canNotDeleteRelatedSepaMandate() {
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
final var givenSepaMandate = givenSomeTemporarySepaMandate();
|
||||
assertThat(givenSepaMandate.getReference()).isEqualTo("temp ref X");
|
||||
|
||||
RestAssured // @formatter:off
|
||||
.given()
|
||||
@@ -455,7 +454,6 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
|
||||
void normalUser_canNotDeleteUnrelatedSepaMandate() {
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
final var givenSepaMandate = givenSomeTemporarySepaMandate();
|
||||
assertThat(givenSepaMandate.getReference()).isEqualTo("temp ref X");
|
||||
|
||||
RestAssured // @formatter:off
|
||||
.given()
|
||||
@@ -480,32 +478,25 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
|
||||
.uuid(UUID.randomUUID())
|
||||
.debitor(givenDebitor)
|
||||
.bankAccount(givenBankAccount)
|
||||
.reference("temp ref X")
|
||||
.reference("temp ref CAT Z")
|
||||
.validity(Range.closedOpen(
|
||||
LocalDate.parse("2022-11-01"), LocalDate.parse("2023-03-31")))
|
||||
.build();
|
||||
|
||||
toCleanup(newSepaMandate.getUuid());
|
||||
|
||||
return sepaMandateRepo.save(newSepaMandate);
|
||||
}).assertSuccessful().returnedValue();
|
||||
}
|
||||
|
||||
private UUID toCleanup(final UUID tempSepaMandateUuid) {
|
||||
tempSepaMandateUuids.add(tempSepaMandateUuid);
|
||||
return tempSepaMandateUuid;
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
@AfterEach
|
||||
void cleanup() {
|
||||
tempSepaMandateUuids.forEach(uuid -> {
|
||||
jpaAttempt.transacted(() -> {
|
||||
context.define("superuser-alex@hostsharing.net", null);
|
||||
System.out.println("DELETING temporary sepaMandate: " + uuid);
|
||||
final var count = sepaMandateRepo.deleteByUuid(uuid);
|
||||
System.out.println("DELETED temporary sepaMandate: " + uuid + (count > 0 ? " successful" : " failed"));
|
||||
});
|
||||
});
|
||||
jpaAttempt.transacted(() -> {
|
||||
context.define("superuser-alex@hostsharing.net", null);
|
||||
final var count = em.createQuery("DELETE FROM HsOfficeSepaMandateEntity s WHERE s.reference like 'temp %'")
|
||||
.executeUpdate();
|
||||
if (count == 0) {
|
||||
System.out.println("nothing deleted");
|
||||
}
|
||||
}).assertSuccessful();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,15 +16,15 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.orm.jpa.JpaSystemException;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.time.LocalDate;
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.grantDisplaysOf;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.roleNamesOf;
|
||||
@@ -33,7 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assumptions.assumeThat;
|
||||
|
||||
@DataJpaTest
|
||||
@Import( { Context.class, JpaAttempt.class })
|
||||
@Import({ Context.class, JpaAttempt.class })
|
||||
class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTest {
|
||||
|
||||
@Autowired
|
||||
@@ -52,16 +52,14 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTest {
|
||||
RawRbacGrantRepository rawGrantRepo;
|
||||
|
||||
@Autowired
|
||||
EntityManager em;
|
||||
JpaAttempt jpaAttempt;
|
||||
|
||||
@Autowired
|
||||
JpaAttempt jpaAttempt;
|
||||
EntityManager em;
|
||||
|
||||
@MockBean
|
||||
HttpServletRequest request;
|
||||
|
||||
Set<HsOfficeSepaMandateEntity> tempEntities = new HashSet<>();
|
||||
|
||||
@Nested
|
||||
class CreateSepaMandate {
|
||||
|
||||
@@ -75,14 +73,13 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTest {
|
||||
|
||||
// when
|
||||
final var result = attempt(em, () -> {
|
||||
final var newSepaMandate = toCleanup(HsOfficeSepaMandateEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
final var newSepaMandate = HsOfficeSepaMandateEntity.builder()
|
||||
.debitor(givenDebitor)
|
||||
.bankAccount(givenBankAccount)
|
||||
.reference("temp ref A")
|
||||
.validity(Range.closedOpen(
|
||||
LocalDate.parse("2020-01-01"), LocalDate.parse("2023-01-01")))
|
||||
.build());
|
||||
.build();
|
||||
return sepaMandateRepo.save(newSepaMandate);
|
||||
});
|
||||
|
||||
@@ -108,14 +105,13 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTest {
|
||||
attempt(em, () -> {
|
||||
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike("First").get(0);
|
||||
final var givenBankAccount = bankAccountRepo.findByOptionalHolderLike("Paul Winkler").get(0);
|
||||
final var newSepaMandate = toCleanup(HsOfficeSepaMandateEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
final var newSepaMandate = HsOfficeSepaMandateEntity.builder()
|
||||
.debitor(givenDebitor)
|
||||
.bankAccount(givenBankAccount)
|
||||
.reference("temp ref B")
|
||||
.validity(Range.closedOpen(
|
||||
LocalDate.parse("2020-01-01"), LocalDate.parse("2023-01-01")))
|
||||
.build());
|
||||
.build();
|
||||
return sepaMandateRepo.save(newSepaMandate);
|
||||
});
|
||||
|
||||
@@ -255,7 +251,7 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTest {
|
||||
context("superuser-alex@hostsharing.net");
|
||||
givenSepaMandate.setValidity(Range.closedOpen(
|
||||
givenSepaMandate.getValidity().lower(), newValidityEnd));
|
||||
return toCleanup(sepaMandateRepo.save(givenSepaMandate));
|
||||
return sepaMandateRepo.save(givenSepaMandate);
|
||||
});
|
||||
|
||||
// then
|
||||
@@ -408,18 +404,10 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTest {
|
||||
|
||||
@BeforeEach
|
||||
@AfterEach
|
||||
@Transactional
|
||||
void cleanup() {
|
||||
tempEntities.forEach(tempSepaMandate -> {
|
||||
jpaAttempt.transacted(() -> {
|
||||
context("superuser-alex@hostsharing.net", null);
|
||||
System.out.println("DELETING temporary sepaMandate: " + tempSepaMandate.toString());
|
||||
sepaMandateRepo.deleteByUuid(tempSepaMandate.getUuid());
|
||||
});
|
||||
});
|
||||
jpaAttempt.transacted(() -> {
|
||||
context("superuser-alex@hostsharing.net", null);
|
||||
em.createQuery("DELETE FROM HsOfficeSepaMandateEntity WHERE reference like 'temp ref%'");
|
||||
});
|
||||
context("superuser-alex@hostsharing.net", null);
|
||||
em.createQuery("DELETE FROM HsOfficeSepaMandateEntity WHERE reference like 'temp ref%'").executeUpdate();
|
||||
}
|
||||
|
||||
private HsOfficeSepaMandateEntity givenSomeTemporarySepaMandateBessler(final String bankAccountHolder) {
|
||||
@@ -428,7 +416,6 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTest {
|
||||
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike("First").get(0);
|
||||
final var givenBankAccount = bankAccountRepo.findByOptionalHolderLike(bankAccountHolder).get(0);
|
||||
final var newSepaMandate = HsOfficeSepaMandateEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.debitor(givenDebitor)
|
||||
.bankAccount(givenBankAccount)
|
||||
.reference("temp ref X")
|
||||
@@ -436,17 +423,10 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTest {
|
||||
LocalDate.parse("2020-01-01"), LocalDate.parse("2023-01-01")))
|
||||
.build();
|
||||
|
||||
toCleanup(newSepaMandate);
|
||||
|
||||
return sepaMandateRepo.save(newSepaMandate);
|
||||
}).assertSuccessful().returnedValue();
|
||||
}
|
||||
|
||||
private HsOfficeSepaMandateEntity toCleanup(final HsOfficeSepaMandateEntity tempEntity) {
|
||||
tempEntities.add(tempEntity);
|
||||
return tempEntity;
|
||||
}
|
||||
|
||||
void exactlyTheseSepaMandatesAreReturned(
|
||||
final List<HsOfficeSepaMandateEntity> actualResult,
|
||||
final String... sepaMandateNames) {
|
||||
|
||||
@@ -13,6 +13,8 @@ import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacrole.TestRbacRole.*;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
@@ -35,6 +37,9 @@ class RbacRoleControllerRestTest {
|
||||
@MockBean
|
||||
RbacRoleRepository rbacRoleRepository;
|
||||
|
||||
@MockBean
|
||||
EntityManager em;
|
||||
|
||||
@Test
|
||||
void apiCustomersWillReturnCustomersFromRepository() throws Exception {
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import java.util.UUID;
|
||||
|
||||
import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid;
|
||||
@@ -36,6 +37,9 @@ class RbacUserControllerRestTest {
|
||||
@MockBean
|
||||
RbacUserRepository rbacUserRepository;
|
||||
|
||||
@MockBean
|
||||
EntityManager em;
|
||||
|
||||
@Test
|
||||
void createUserUsesGivenUuid() throws Exception {
|
||||
// given
|
||||
|
||||
@@ -8,6 +8,6 @@ public class TestCustomer {
|
||||
static final TestCustomerEntity yyy = hsCustomer("yyy", 10002, "yyy@example.com");
|
||||
|
||||
static public TestCustomerEntity hsCustomer(final String prefix, final int reference, final String adminName) {
|
||||
return new TestCustomerEntity(randomUUID(), prefix, reference, adminName);
|
||||
return new TestCustomerEntity(null, prefix, reference, adminName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import net.hostsharing.hsadminng.HsadminNgApplication;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.test.JpaAttempt;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -13,8 +14,7 @@ import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.persistence.EntityManager;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -43,7 +43,8 @@ class TestCustomerControllerAcceptanceTest {
|
||||
@Autowired
|
||||
JpaAttempt jpaAttempt;
|
||||
|
||||
Set<UUID> tempPartnerUuids = new HashSet<>();
|
||||
@Autowired
|
||||
EntityManager em;
|
||||
|
||||
@Nested
|
||||
class ListCustomers {
|
||||
@@ -144,51 +145,13 @@ class TestCustomerControllerAcceptanceTest {
|
||||
.extract().header("Location"); // @formatter:on
|
||||
|
||||
// finally, the new customer can be viewed by its own admin
|
||||
final var newUserUuid = toCleanup(UUID.fromString(
|
||||
location.substring(location.lastIndexOf('/') + 1)));
|
||||
final var newUserUuid = UUID.fromString(
|
||||
location.substring(location.lastIndexOf('/') + 1));
|
||||
context.define("customer-admin@uuu.example.com");
|
||||
assertThat(testCustomerRepository.findByUuid(newUserUuid))
|
||||
.hasValueSatisfying(c -> assertThat(c.getPrefix()).isEqualTo("uuu"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void globalAdmin_withoutAssumedRole_canAddCustomerWithGivenUuid() {
|
||||
|
||||
final var givenUuid = toCleanup(UUID.randomUUID());
|
||||
|
||||
final var location = RestAssured // @formatter:off
|
||||
.given()
|
||||
.header("current-user", "superuser-alex@hostsharing.net")
|
||||
.contentType(ContentType.JSON)
|
||||
.body("""
|
||||
{
|
||||
"uuid": "%s",
|
||||
"reference": 90010,
|
||||
"prefix": "vvv",
|
||||
"adminUserName": "customer-admin@vvv.example.com"
|
||||
}
|
||||
""".formatted(givenUuid))
|
||||
.port(port)
|
||||
.when()
|
||||
.post("http://localhost/api/test/customers")
|
||||
.then().assertThat()
|
||||
.statusCode(201)
|
||||
.contentType(ContentType.JSON)
|
||||
.body("prefix", is("vvv"))
|
||||
.header("Location", startsWith("http://localhost"))
|
||||
.extract().header("Location"); // @formatter:on
|
||||
|
||||
// finally, the new customer can be viewed by its own admin
|
||||
final var newUserUuid = UUID.fromString(
|
||||
location.substring(location.lastIndexOf('/') + 1));
|
||||
context.define("customer-admin@vvv.example.com");
|
||||
assertThat(testCustomerRepository.findByUuid(newUserUuid))
|
||||
.hasValueSatisfying(c -> {
|
||||
assertThat(c.getPrefix()).isEqualTo("vvv");
|
||||
assertThat(c.getUuid()).isEqualTo(givenUuid);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void globalAdmin_withAssumedCustomerAdminRole_canNotAddCustomer() {
|
||||
|
||||
@@ -266,26 +229,14 @@ class TestCustomerControllerAcceptanceTest {
|
||||
.body("message", containsString("line: 1, column: 1"));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private UUID toCleanup(final UUID tempPartnerUuid) {
|
||||
tempPartnerUuids.add(tempPartnerUuid);
|
||||
return tempPartnerUuid;
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
@AfterEach
|
||||
void cleanup() {
|
||||
tempPartnerUuids.forEach(uuid -> {
|
||||
jpaAttempt.transacted(() -> {
|
||||
context.define("superuser-alex@hostsharing.net", null);
|
||||
System.out.println("DELETING temporary partner: " + uuid);
|
||||
final var entity = testCustomerRepository.findByUuid(uuid);
|
||||
final var count = testCustomerRepository.deleteByUuid(uuid);
|
||||
System.out.println(
|
||||
"DELETED temporary partner: " + uuid + (count > 0 ? " successful" : " failed") + " (" + entity.map(
|
||||
TestCustomerEntity::getPrefix).orElse("???") + ")");
|
||||
}).assertSuccessful();
|
||||
});
|
||||
jpaAttempt.transacted(() -> {
|
||||
context.define("superuser-alex@hostsharing.net", null);
|
||||
em.createQuery("DELETE FROM TestCustomerEntity c WHERE c.reference < 99900").executeUpdate();
|
||||
}).assertSuccessful();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.hostsharing.test;
|
||||
|
||||
import org.assertj.core.api.ObjectAssert;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.NestedExceptionUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -105,6 +106,11 @@ public class JpaAttempt {
|
||||
return result;
|
||||
}
|
||||
|
||||
public ObjectAssert<T> assertThatResult() {
|
||||
assertSuccessful();
|
||||
return assertThat(returnedValue());
|
||||
}
|
||||
|
||||
public RuntimeException caughtException() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
@@ -1,41 +1,35 @@
|
||||
package net.hostsharing.test;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.*;
|
||||
import net.hostsharing.hsadminng.errors.DisplayName;
|
||||
import net.hostsharing.hsadminng.mapper.Mapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.validation.ValidationException;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.catchThrowable;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class MapperUnitTest {
|
||||
|
||||
private Mapper mapper = new Mapper();
|
||||
@Mock
|
||||
EntityManager em;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class SourceBean {
|
||||
@InjectMocks
|
||||
Mapper mapper;
|
||||
|
||||
private String a;
|
||||
private String b;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class TargetBean {
|
||||
|
||||
private String a;
|
||||
private String b;
|
||||
private String c;
|
||||
}
|
||||
final UUID GIVEN_UUID = UUID.randomUUID();
|
||||
|
||||
@Test
|
||||
void mapsNullBeanToNull() {
|
||||
@@ -46,48 +40,198 @@ class MapperUnitTest {
|
||||
|
||||
@Test
|
||||
void mapsBean() {
|
||||
final SourceBean givenSource = new SourceBean("1234", "Text");
|
||||
final SourceBean givenSource = SourceBean.builder().a("1234").b("Text").build();
|
||||
final var result = mapper.map(givenSource, TargetBean.class);
|
||||
assertThat(result).usingRecursiveComparison().isEqualTo(
|
||||
new TargetBean("1234", "Text", null)
|
||||
TargetBean.builder().a("1234").b("Text").build()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void mapsBeanWithExistingSubEntity() {
|
||||
final SourceBean givenSource = SourceBean.builder().a("1234").b("Text").s1(new SubSourceBean1(GIVEN_UUID)).build();
|
||||
when(em.find(SubTargetBean1.class, GIVEN_UUID)).thenReturn(new SubTargetBean1(GIVEN_UUID, "xxx"));
|
||||
|
||||
final var result = mapper.map(givenSource, TargetBean.class);
|
||||
assertThat(result).usingRecursiveComparison().isEqualTo(
|
||||
TargetBean.builder().a("1234").b("Text").s1(new SubTargetBean1(GIVEN_UUID, "xxx")).build()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void mapsBeanWithSubEntityWithNullUuid() {
|
||||
final SourceBean givenSource = SourceBean.builder().a("1234").b("Text").s1(new SubSourceBean1(null)).build();
|
||||
|
||||
final var result = mapper.map(givenSource, TargetBean.class);
|
||||
assertThat(result).usingRecursiveComparison().isEqualTo(
|
||||
TargetBean.builder().a("1234").b("Text").s1(new SubTargetBean1(null, null)).build()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void mapsBeanWithSubEntityWithoutUuidField() {
|
||||
final SourceBean givenSource = SourceBean.builder().a("1234").b("Text").s3(new SubSourceBean3("xxx")).build();
|
||||
|
||||
final var result = mapper.map(givenSource, TargetBean.class);
|
||||
assertThat(result).usingRecursiveComparison().isEqualTo(
|
||||
TargetBean.builder().a("1234").b("Text").s3(new SubTargetBean3("xxx")).build()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void mapsBeanWithSubEntityNotFound() {
|
||||
final SourceBean givenSource = SourceBean.builder().a("1234").b("Text").s1(new SubSourceBean1(GIVEN_UUID)).build();
|
||||
when(em.find(SubTargetBean1.class, GIVEN_UUID)).thenReturn(null);
|
||||
|
||||
final var exception = catchThrowable(() ->
|
||||
mapper.map(givenSource, TargetBean.class)
|
||||
);
|
||||
|
||||
assertThat(exception).isInstanceOf(ValidationException.class)
|
||||
.hasMessage("Unable to find SubTargetBean1 with uuid " + GIVEN_UUID);
|
||||
}
|
||||
|
||||
@Test
|
||||
void mapsBeanWithSubEntityNotFoundAndDisplayName() {
|
||||
final SourceBean givenSource = SourceBean.builder().a("1234").b("Text").s2(new SubSourceBean2(GIVEN_UUID)).build();
|
||||
when(em.find(SubTargetBean2.class, GIVEN_UUID)).thenReturn(null);
|
||||
|
||||
final var exception = catchThrowable(() ->
|
||||
mapper.map(givenSource, TargetBean.class)
|
||||
);
|
||||
|
||||
assertThat(exception).isInstanceOf(ValidationException.class)
|
||||
.hasMessage("Unable to find SomeDisplayName with uuid " + GIVEN_UUID);
|
||||
}
|
||||
|
||||
@Test
|
||||
void mapsBeanWithPostmapper() {
|
||||
final SourceBean givenSource = new SourceBean("1234", "Text");
|
||||
final SourceBean givenSource = SourceBean.builder().a("1234").b("Text").build();
|
||||
final var result = mapper.map(givenSource, TargetBean.class, (s, t) -> {t.setC("Extra");});
|
||||
assertThat(result).usingRecursiveComparison().isEqualTo(
|
||||
new TargetBean("1234", "Text", "Extra")
|
||||
TargetBean.builder().a("1234").b("Text").c("Extra").build()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void mapsList() {
|
||||
final var givenSource = List.of(
|
||||
new SourceBean("111", "Text A"),
|
||||
new SourceBean("222", "Text B"),
|
||||
new SourceBean("333", "Text C"));
|
||||
SourceBean.builder().a("111").b("Text A").build(),
|
||||
SourceBean.builder().a("222").b("Text B").build(),
|
||||
SourceBean.builder().a("333").b("Text C").build());
|
||||
final var result = mapper.mapList(givenSource, TargetBean.class);
|
||||
assertThat(result).usingRecursiveComparison().isEqualTo(
|
||||
List.of(
|
||||
new TargetBean("111", "Text A", null),
|
||||
new TargetBean("222", "Text B", null),
|
||||
new TargetBean("333", "Text C", null)));
|
||||
TargetBean.builder().a("111").b("Text A").build(),
|
||||
TargetBean.builder().a("222").b("Text B").build(),
|
||||
TargetBean.builder().a("333").b("Text C").build()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void mapsListWithPostMapper() {
|
||||
final var givenSource = List.of(
|
||||
new SourceBean("111", "Text A"),
|
||||
new SourceBean("222", "Text B"),
|
||||
new SourceBean("333", "Text C"));
|
||||
SourceBean.builder().a("111").b("Text A").build(),
|
||||
SourceBean.builder().a("222").b("Text B").build(),
|
||||
SourceBean.builder().a("333").b("Text C").build());
|
||||
final var result = mapper.mapList(givenSource, TargetBean.class, (s, t) -> {t.setC("Extra");});
|
||||
assertThat(result).usingRecursiveComparison().isEqualTo(
|
||||
List.of(
|
||||
new TargetBean("111", "Text A", "Extra"),
|
||||
new TargetBean("222", "Text B", "Extra"),
|
||||
new TargetBean("333", "Text C", "Extra")));
|
||||
TargetBean.builder().a("111").b("Text A").c("Extra").build(),
|
||||
TargetBean.builder().a("222").b("Text B").c("Extra").build(),
|
||||
TargetBean.builder().a("333").b("Text C").c("Extra").build()));
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class SourceBean {
|
||||
|
||||
private String a;
|
||||
private String b;
|
||||
private SubSourceBean1 s1;
|
||||
private SubSourceBean2 s2;
|
||||
private SubSourceBean3 s3;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class SubSourceBean1 {
|
||||
|
||||
private UUID uuid;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class SubSourceBean2 {
|
||||
|
||||
private UUID uuid;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class SubSourceBean3 {
|
||||
|
||||
private String x;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class TargetBean {
|
||||
|
||||
private String a;
|
||||
private String b;
|
||||
private String c;
|
||||
|
||||
@ManyToOne
|
||||
private SubTargetBean1 s1;
|
||||
|
||||
@ManyToOne
|
||||
private SubTargetBean2 s2;
|
||||
|
||||
@ManyToOne
|
||||
private SubTargetBean3 s3;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class SubTargetBean1 {
|
||||
|
||||
private UUID uuid;
|
||||
private String x;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@DisplayName("SomeDisplayName")
|
||||
public static class SubTargetBean2 {
|
||||
|
||||
private UUID uuid;
|
||||
private String x;
|
||||
}
|
||||
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class SubTargetBean3 {
|
||||
|
||||
private String x;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user