feat: UserCreateRequest model & validation

This commit is contained in:
Piotr Dec 2024-05-22 01:04:26 +02:00
parent 6fb6ca275c
commit edf770b8ed
Signed by: stawros
GPG key ID: F89F27AD8F881A91
5 changed files with 141 additions and 0 deletions

View file

@ -41,6 +41,10 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId> <artifactId>spring-boot-starter-data-jpa</artifactId>

View file

@ -0,0 +1,24 @@
package eu.ztsh.wymiana.validation;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Target({ FIELD, PARAMETER })
@Retention(RUNTIME)
@Constraint(validatedBy = AdultValidator.class)
@Documented
public @interface Adult {
String message() default "{jakarta.validation.constraints.Adult.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}

View file

@ -0,0 +1,42 @@
package eu.ztsh.wymiana.validation;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Arrays;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class AdultValidator implements ConstraintValidator<Adult, String> {
private final Pattern pattern = Pattern.compile("\\d{11}");
private final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (!pattern.matcher(value).matches()) {
return false;
}
var datePart = Arrays.stream(value.substring(0, 6).split("")).map(Integer::parseInt).toArray(Integer[]::new);
final String prefix;
if (datePart[2] > 1) {
datePart[2] = (datePart[2] - 2);
prefix = "20";
} else {
prefix = "19";
}
var dateStamp = prefix.concat(Arrays.stream(datePart).map(Objects::toString).collect(Collectors.joining()));
try {
return LocalDate.parse(dateStamp, dtf)
.plusYears(18)
.isBefore(LocalDate.now(context.getClockProvider().getClock()));
} catch (DateTimeParseException exception) {
return false;
}
}
}

View file

@ -0,0 +1,13 @@
package eu.ztsh.wymiana.web.model;
import eu.ztsh.wymiana.validation.Adult;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
public record UserCreateRequest(
@NotNull String name,
@NotNull String surname,
@Adult String pesel,
@Min(0) int pln) {
}

View file

@ -0,0 +1,58 @@
package eu.ztsh.wymiana.validation;
import jakarta.validation.ConstraintValidatorContext;
import org.hibernate.validator.internal.engine.DefaultClockProvider;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static org.assertj.core.api.Assertions.assertThat;
class AdultValidatorTest {
private static AdultValidator validator;
private static ConstraintValidatorContext validatorContext;
@BeforeAll
static void prepare() {
validator = new AdultValidator();
validatorContext = Mockito.mock(ConstraintValidatorContext.class);
Mockito.when(validatorContext.getClockProvider()).thenReturn(DefaultClockProvider.INSTANCE);
}
@Test
@DisplayName("No digits in PESEL")
void invalidPatternTest() {
assertThat(call("notAPesel")).isFalse();
}
@Test
@DisplayName("Not an adult")
void notAnAdultTest() {
assertThat(call("24242400000")).isFalse();
}
@Test
@DisplayName("Adult")
void adultTest() {
assertThat(call("88010100000")).isTrue();
}
@Test
@DisplayName("Elderly person")
void seniorTest() {
assertThat(call("00010100000")).isTrue();
}
@Test
@DisplayName("Invalid date")
void notAValidDateTest() {
assertThat(call("00919100000")).isFalse();
}
private boolean call(String value) {
return validator.isValid(value, validatorContext);
}
}