added configurable password validator and fixed mapstruct bugs
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
<description>Adapter to call validate addresses in external systems</description>
|
||||
<properties>
|
||||
<java.version>14</java.version>
|
||||
<org.mapstruct.version>1.3.1.Final</org.mapstruct.version>
|
||||
<org.mapstruct.version>1.4.1.Final</org.mapstruct.version>
|
||||
<org.lombok.version>1.18.12</org.lombok.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<packaging>jar</packaging>
|
||||
<properties>
|
||||
<java.version>14</java.version>
|
||||
<org.mapstruct.version>1.3.1.Final</org.mapstruct.version>
|
||||
<org.mapstruct.version>1.4.1.Final</org.mapstruct.version>
|
||||
<org.lombok.version>1.18.12</org.lombok.version>
|
||||
<testcontainers.version>1.15.0</testcontainers.version>
|
||||
</properties>
|
||||
|
||||
@@ -43,7 +43,8 @@ public interface CustomerMapper {
|
||||
getAddressAttribute(customer, Address.AddressType.BILLING, Address::getStreet),
|
||||
getAddressAttribute(customer, Address.AddressType.BILLING, Address::getHouseNumber),
|
||||
getAddressAttribute(customer, Address.AddressType.BILLING, Address::getZipCode),
|
||||
getAddressAttribute(customer, Address.AddressType.BILLING, Address::getCountry));
|
||||
getAddressAttribute(customer, Address.AddressType.BILLING, Address::getCountry),
|
||||
null);
|
||||
}
|
||||
|
||||
private <T> T getAddressAttribute(
|
||||
|
||||
@@ -3,37 +3,39 @@ package de.strasser.peter.hexagonal.persistence.model;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Document
|
||||
public class CustomerEntity {
|
||||
@Id
|
||||
private BigInteger id;
|
||||
private String name;
|
||||
private String hashedPassword;
|
||||
private LocalDate birthday;
|
||||
private boolean active;
|
||||
@Id private BigInteger id;
|
||||
private String name;
|
||||
private String hashedPassword;
|
||||
private LocalDate birthday;
|
||||
private boolean active;
|
||||
|
||||
private String street;
|
||||
private Integer houseNumber;
|
||||
private Integer zipCode;
|
||||
private String country;
|
||||
private String street;
|
||||
private Integer houseNumber;
|
||||
private Integer zipCode;
|
||||
private String country;
|
||||
|
||||
private String shippingStreet;
|
||||
private Integer shippingHouseNumber;
|
||||
private Integer shippingZipCode;
|
||||
private String shippingCountry;
|
||||
private String shippingStreet;
|
||||
private Integer shippingHouseNumber;
|
||||
private Integer shippingZipCode;
|
||||
private String shippingCountry;
|
||||
|
||||
private String billingStreet;
|
||||
private Integer billingHouseNumber;
|
||||
private Integer billingZipCode;
|
||||
private String billingCountry;
|
||||
private String billingStreet;
|
||||
private Integer billingHouseNumber;
|
||||
private Integer billingZipCode;
|
||||
private String billingCountry;
|
||||
|
||||
@CreatedDate private LocalDateTime createdAt;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<description>Web adapter</description>
|
||||
<properties>
|
||||
<java.version>14</java.version>
|
||||
<org.mapstruct.version>1.3.1.Final</org.mapstruct.version>
|
||||
<org.mapstruct.version>1.4.1.Final</org.mapstruct.version>
|
||||
<org.lombok.version>1.18.12</org.lombok.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
|
||||
@@ -2,7 +2,7 @@ package de.strasser.peter.hexagonal.web;
|
||||
|
||||
import de.strasser.peter.hexagonal.application.customer.port.in.AddAddressUseCase;
|
||||
import de.strasser.peter.hexagonal.application.customer.port.in.commands.AddAddressCommand;
|
||||
import de.strasser.peter.hexagonal.common.validators.TestUtils;
|
||||
import de.strasser.peter.hexagonal.common.validators.ReadStringResources;
|
||||
import de.strasser.peter.hexagonal.web.mapper.AddAddressWebMapperImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -31,7 +31,7 @@ class AddAddressControllerTest {
|
||||
|
||||
@Test
|
||||
public void should_AddAddress() throws Exception {
|
||||
final String body = TestUtils.readStringFromResource("valid_add_address.json");
|
||||
final String body = ReadStringResources.readStringFromResource("valid_add_address.json");
|
||||
final int customerId = 1231231;
|
||||
|
||||
mockMvc
|
||||
|
||||
@@ -2,7 +2,7 @@ package de.strasser.peter.hexagonal.web;
|
||||
|
||||
import de.strasser.peter.hexagonal.application.customer.port.in.RegisterCustomerUseCase;
|
||||
import de.strasser.peter.hexagonal.application.customer.port.in.commands.RegisterCustomerCommand;
|
||||
import de.strasser.peter.hexagonal.common.validators.TestUtils;
|
||||
import de.strasser.peter.hexagonal.common.validators.ReadStringResources;
|
||||
import de.strasser.peter.hexagonal.web.mapper.RegisterCustomerWebMapperImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -30,7 +30,7 @@ class RegisterCustomerControllerTest {
|
||||
|
||||
@Test
|
||||
public void should_RegisterUser_When_SendingValidRequest() throws Exception {
|
||||
final String body = TestUtils.readStringFromResource("valid_register_customer.json");
|
||||
final String body = ReadStringResources.readStringFromResource("valid_register_customer.json");
|
||||
mockMvc
|
||||
.perform(post("/v1/register").contentType(MediaType.APPLICATION_JSON).content(body))
|
||||
.andExpect(status().isOk())
|
||||
@@ -43,7 +43,7 @@ class RegisterCustomerControllerTest {
|
||||
|
||||
@Test
|
||||
public void should_DenyRequest_When_SendingInvalidDateFormat() throws Exception {
|
||||
final String body = TestUtils.readStringFromResource("invalid_date_register_customer.json");
|
||||
final String body = ReadStringResources.readStringFromResource("invalid_date_register_customer.json");
|
||||
|
||||
mockMvc
|
||||
.perform(post("/v1/register").contentType(MediaType.APPLICATION_JSON).content(body))
|
||||
|
||||
@@ -16,8 +16,9 @@
|
||||
<description>Business logic for demo project</description>
|
||||
<properties>
|
||||
<java.version>14</java.version>
|
||||
<org.mapstruct.version>1.3.1.Final</org.mapstruct.version>
|
||||
<org.lombok.version>1.18.12</org.lombok.version>
|
||||
<org.mapstruct.version>1.4.2.Final</org.mapstruct.version>
|
||||
<org.lombok.version>1.18.16</org.lombok.version>
|
||||
<lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -49,7 +50,11 @@
|
||||
<artifactId>mapstruct</artifactId>
|
||||
<version>${org.mapstruct.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok-mapstruct-binding</artifactId>
|
||||
<version>${lombok-mapstruct-binding.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
@@ -72,6 +77,11 @@
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${org.lombok.version}</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok-mapstruct-binding</artifactId>
|
||||
<version>${lombok-mapstruct-binding.version}</version>
|
||||
</path>
|
||||
<!-- other annotation processors -->
|
||||
</annotationProcessorPaths>
|
||||
<compilerArgs>
|
||||
|
||||
@@ -18,10 +18,10 @@ import java.util.Map;
|
||||
public class Customer {
|
||||
private final BigInteger id;
|
||||
private String name;
|
||||
private String hashedPassword;
|
||||
private LocalDate birthday;
|
||||
private int age;
|
||||
private Map<Address.AddressType, Address> addresses;
|
||||
private final String hashedPassword;
|
||||
private final LocalDate birthday;
|
||||
private final int age;
|
||||
private final Map<Address.AddressType, Address> addresses;
|
||||
private boolean active;
|
||||
|
||||
private Customer(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package de.strasser.peter.hexagonal.application.customer.port.in.commands;
|
||||
|
||||
|
||||
import de.strasser.peter.hexagonal.common.validators.SecurePassword;
|
||||
import de.strasser.peter.hexagonal.application.customer.validator.SecurePassword;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
package de.strasser.peter.hexagonal.common.validators;
|
||||
package de.strasser.peter.hexagonal.application.customer.validator;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.ConstraintValidator;
|
||||
@@ -29,13 +32,17 @@ public @interface SecurePassword {
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
|
||||
@Component
|
||||
class PasswordValidator implements ConstraintValidator<SecurePassword, String> {
|
||||
private static final String DEFAULT_PASSWORD_REQUIREMENTS =
|
||||
"^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*(),.?\":{}|<>])(?=\\S+$).{8,}$";
|
||||
|
||||
@Value("${password.format:" + DEFAULT_PASSWORD_REQUIREMENTS + "}")
|
||||
private String pwFormat;
|
||||
|
||||
@Override
|
||||
public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
|
||||
return s != null
|
||||
&& s.matches(
|
||||
"^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*(),.?\":{}|<>])(?=\\S+$).{8,}$");
|
||||
return s != null && s.matches(pwFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
package de.strasser.peter.hexagonal.application;
|
||||
|
||||
|
||||
import de.strasser.peter.hexagonal.application.customer.mapper.AddAddressMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.test.mock.mockito.SpyBean;
|
||||
|
||||
@Slf4j
|
||||
@SpringBootApplication
|
||||
public class TestConfiguration {
|
||||
|
||||
|
||||
@SpyBean public AddAddressMapper addAddressMapperMock;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ package de.strasser.peter.hexagonal.application.customer.domain;
|
||||
|
||||
import de.strasser.peter.hexagonal.application.customer.exception.TooOldToDeactivateExc;
|
||||
import de.strasser.peter.hexagonal.application.customer.exception.TooYoungExc;
|
||||
import de.strasser.peter.hexagonal.application.customer.mapper.AddAddressMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Collections;
|
||||
@@ -11,6 +13,7 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class CustomerTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void should_CreateNewCustomer() {
|
||||
final var customer = Customer.newCustomer("name", "pw", LocalDate.of(1980, 1, 1));
|
||||
@@ -58,4 +61,6 @@ class CustomerTest {
|
||||
final Customer customer = Customer.newCustomer("name", "pw", LocalDate.of(1950, 1, 1));
|
||||
assertThrows(TooOldToDeactivateExc.class, customer::deactivate);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ class AddressServiceTest {
|
||||
@MockBean private SaveCustomerPort saveCustomerAdapterMock;
|
||||
@MockBean private AddressValidatorPort addressValidatorAdapterMock;
|
||||
@MockBean private LoadCustomerPort loadCustomerAdapterMock;
|
||||
@SpyBean private AddAddressMapper addAddressMapperMock;
|
||||
|
||||
@Test
|
||||
public void should_AddAddress() {
|
||||
|
||||
@@ -30,8 +30,7 @@ class RegisterCustomerServiceTest {
|
||||
private AddressValidatorPort addressValidatorAdapterMock;
|
||||
@MockBean
|
||||
private LoadCustomerPort loadCustomerAdapterMock;
|
||||
@MockBean
|
||||
private AddAddressMapper addAddressMapperMock;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
|
||||
1
application/src/test/resources/application.yml
Normal file
1
application/src/test/resources/application.yml
Normal file
@@ -0,0 +1 @@
|
||||
# password.format: ^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*(),.?":{}|<>])(?=\S+$).{8,}$
|
||||
@@ -6,7 +6,7 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
||||
public class TestUtils {
|
||||
public class ReadStringResources {
|
||||
|
||||
public static String readStringFromResource(String filename) throws IOException {
|
||||
final File file = ResourceUtils.getFile("classpath:" + filename);
|
||||
@@ -1,2 +0,0 @@
|
||||
spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false
|
||||
logging.level.org.springframework.data.mongodb.core.MongoTemplate=DEBUG
|
||||
3
config/src/main/resources/application.yml
Normal file
3
config/src/main/resources/application.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS: false
|
||||
|
||||
password.format: ^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*(),.?":{}|<>])(?=\S+$).{8,}$
|
||||
Reference in New Issue
Block a user