diff --git a/src/main/java/com/bravo/user/dao/model/User.java b/src/main/java/com/bravo/user/dao/model/User.java index 4419501..2b4dee1 100644 --- a/src/main/java/com/bravo/user/dao/model/User.java +++ b/src/main/java/com/bravo/user/dao/model/User.java @@ -18,6 +18,26 @@ public class User { @Column(name = "id") private String id; + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public void setMiddleName(String middleName) { + this.middleName = middleName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public void setPhoneNumber(Integer phoneNumber) { + this.phoneNumber = phoneNumber; + } + + public void setUpdated(LocalDateTime updated) { + this.updated = updated; + } + @Column(name = "first_name", nullable = false) private String firstName; @@ -27,9 +47,37 @@ public class User { @Column(name = "last_name", nullable = false) private String lastName; + public String getId() { + return id; + } + + public String getFirstName() { + return firstName; + } + + public String getMiddleName() { + return middleName; + } + + public String getLastName() { + return lastName; + } + + public Integer getPhoneNumber() { + return phoneNumber; + } + + public LocalDateTime getUpdated() { + return updated; + } + + @Column(name = "phone_number", nullable = false) + private Integer phoneNumber; + @Column(name = "updated", nullable = false) private LocalDateTime updated; + public User(){ super(); this.id = UUID.randomUUID().toString(); @@ -41,5 +89,6 @@ public User(final UserSaveDto user){ this.firstName = user.getFirstName(); this.middleName = user.getMiddleName(); this.lastName = user.getLastName(); + this.phoneNumber = user.getPhoneNumber(); } } diff --git a/src/main/java/com/bravo/user/dao/model/mapper/ResourceMapper.java b/src/main/java/com/bravo/user/dao/model/mapper/ResourceMapper.java index 069435f..0660ea9 100644 --- a/src/main/java/com/bravo/user/dao/model/mapper/ResourceMapper.java +++ b/src/main/java/com/bravo/user/dao/model/mapper/ResourceMapper.java @@ -2,6 +2,8 @@ import com.bravo.user.dao.model.User; import com.bravo.user.model.dto.UserReadDto; + +import java.time.LocalDateTime; import java.util.Collection; import java.util.List; import java.util.stream.Collectors; @@ -31,6 +33,9 @@ public UserReadDto convertUser(final User user){ name = String.format("%s %s", user.getFirstName(), user.getLastName()); } dto.setName(name); + dto.setPhoneNumber(user.getPhoneNumber()); + dto.setUpdated(LocalDateTime.now()); + return dto; } } diff --git a/src/main/java/com/bravo/user/dao/specification/AbstractSpecification.java b/src/main/java/com/bravo/user/dao/specification/AbstractSpecification.java index ecb3a7e..17a11d4 100644 --- a/src/main/java/com/bravo/user/dao/specification/AbstractSpecification.java +++ b/src/main/java/com/bravo/user/dao/specification/AbstractSpecification.java @@ -68,6 +68,17 @@ protected > void applyInFilter( predicates.add(path.in(values)); } + protected > void applyInLengthFilter( + final Expression path, + final Y values, + final Integer length + ){ + if(ValidatorUtil.isInvalidLength(values, length)){ + return; + } + predicates.add(path.in(values)); + } + protected > void applyStringFilter( final Expression path, final X values @@ -103,4 +114,5 @@ protected > void applyStringFilter( applyInFilter(targetPath, inClause); } } + } diff --git a/src/main/java/com/bravo/user/dao/specification/UserSpecification.java b/src/main/java/com/bravo/user/dao/specification/UserSpecification.java index fc18129..8ffd665 100644 --- a/src/main/java/com/bravo/user/dao/specification/UserSpecification.java +++ b/src/main/java/com/bravo/user/dao/specification/UserSpecification.java @@ -4,7 +4,9 @@ import com.bravo.user.model.filter.UserFilter; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Path; import javax.persistence.criteria.Root; +import java.util.Set; public class UserSpecification extends AbstractSpecification { @@ -27,5 +29,14 @@ public void doFilter( applyStringFilter(root.get("firstName"), filter.getFirstNames()); applyStringFilter(root.get("lastName"), filter.getLastNames()); applyStringFilter(root.get("middleName"), filter.getMiddleNames()); + + // Validates whether phone number contains only digits + applyInFilter(root.get("phoneNumber"), filter.getPhoneNumbers()); + + // Validates whether phone number complies with correct length + applyInLengthFilter(root.get("phoneNumber"), filter.getPhoneNumbers(), filter.getPhoneNumberLength()); + } + + } diff --git a/src/main/java/com/bravo/user/model/dto/UserReadDto.java b/src/main/java/com/bravo/user/model/dto/UserReadDto.java index 599d301..6e15bc5 100644 --- a/src/main/java/com/bravo/user/model/dto/UserReadDto.java +++ b/src/main/java/com/bravo/user/model/dto/UserReadDto.java @@ -8,5 +8,19 @@ public class UserReadDto { private String id; private String name; + private Integer phoneNumber; private LocalDateTime updated; + + public void setName(String name) { + this.name = name; + } + + public void setPhoneNumber(Integer phoneNumber) { + this.phoneNumber = phoneNumber; + } + + public void setUpdated(LocalDateTime updated) { + this.updated = updated; + } + } diff --git a/src/main/java/com/bravo/user/model/dto/UserSaveDto.java b/src/main/java/com/bravo/user/model/dto/UserSaveDto.java index 988569a..b23ce4d 100644 --- a/src/main/java/com/bravo/user/model/dto/UserSaveDto.java +++ b/src/main/java/com/bravo/user/model/dto/UserSaveDto.java @@ -8,4 +8,23 @@ public class UserSaveDto { private String firstName; private String middleName; private String lastName; + private Integer phoneNumber; + + public String getFirstName() { + return firstName; + } + + public String getMiddleName() { + return middleName; + } + + public String getLastName() { + return lastName; + } + + public Integer getPhoneNumber() { + return phoneNumber; + } + + } diff --git a/src/main/java/com/bravo/user/model/filter/UserFilter.java b/src/main/java/com/bravo/user/model/filter/UserFilter.java index 480c7bf..855f26b 100644 --- a/src/main/java/com/bravo/user/model/filter/UserFilter.java +++ b/src/main/java/com/bravo/user/model/filter/UserFilter.java @@ -7,9 +7,40 @@ @Data public class UserFilter { + public Set getIds() { + return ids; + } + private Set ids; private Set firstNames; private Set lastNames; private Set middleNames; + private Set phoneNumbers; + + public Set getFirstNames() { + return firstNames; + } + + public Set getLastNames() { + return lastNames; + } + + public Set getMiddleNames() { + return middleNames; + } + + public Set getPhoneNumbers() { + return phoneNumbers; + } + + public Integer getPhoneNumberLength() { + return phoneNumberLength; + } + + public DateFilter getDateFilter() { + return dateFilter; + } + + private final Integer phoneNumberLength = 10; private DateFilter dateFilter; } diff --git a/src/main/java/com/bravo/user/service/UserService.java b/src/main/java/com/bravo/user/service/UserService.java index 1628f47..c014833 100644 --- a/src/main/java/com/bravo/user/service/UserService.java +++ b/src/main/java/com/bravo/user/service/UserService.java @@ -75,6 +75,9 @@ public UserReadDto update(final String id, final UserSaveDto request){ if(ValidatorUtil.isValid(request.getLastName())){ user.setFirstName(request.getLastName()); } + if(ValidatorUtil.isValid(request.getPhoneNumber())){ + user.setPhoneNumber(request.getPhoneNumber()); + } final User updated = userRepository.save(user); diff --git a/src/main/java/com/bravo/user/utility/ValidatorUtil.java b/src/main/java/com/bravo/user/utility/ValidatorUtil.java index 4feeca8..cffa75d 100644 --- a/src/main/java/com/bravo/user/utility/ValidatorUtil.java +++ b/src/main/java/com/bravo/user/utility/ValidatorUtil.java @@ -41,12 +41,27 @@ else if(value instanceof DateFilter){ else if(value instanceof String){ isValid = isStringValid((String)value); } + else if(value instanceof Integer) { + isValid = isIntegerValid((Integer)value); + } else { isValid = value != null; } return isValid; } + public static boolean isInvalidLength(T value, T length){ + return !isValidLength(value, length); + } + + public static boolean isValidLength(T value, T length){ + boolean isValid = false; + if(value instanceof Integer){ + isValid = isIntegerLengthValid((Integer) value, (Integer) length); + } + return isValid; + } + private static boolean isCollectionValid(final Collection collection){ return !collection.isEmpty() && !collection.stream() @@ -62,4 +77,16 @@ private static boolean isDateFilterValid(final DateFilter date){ private static boolean isStringValid(final String string){ return string != null && !string.trim().isEmpty(); } + + private static boolean isIntegerValid(final Integer integer) { + if(integer == null || integer == 0) + return false; + String onlyDigits = "\\d+"; + String inString = integer.toString(); + return inString.matches(onlyDigits); + } + + private static boolean isIntegerLengthValid(final Integer integer, final Integer length) { + return String.valueOf(integer).length() == length; + } } diff --git a/src/main/java/com/bravo/user/validator/UserValidator.java b/src/main/java/com/bravo/user/validator/UserValidator.java index c8eff9b..604f775 100644 --- a/src/main/java/com/bravo/user/validator/UserValidator.java +++ b/src/main/java/com/bravo/user/validator/UserValidator.java @@ -5,6 +5,7 @@ import com.bravo.user.utility.ValidatorUtil; import org.springframework.stereotype.Component; import org.springframework.validation.Errors; +import com.bravo.user.model.filter.UserFilter; @Component public class UserValidator extends CrudValidator { @@ -20,6 +21,11 @@ protected void validateCreate(Object o, Errors errors) { UserSaveDto instance = (UserSaveDto) o; + /* Admittedly, this is a bit of a hack storing the phone number length in + * the UserFilter class and having to new up an instance here :( + */ + UserFilter userFilter = new UserFilter(); + // required fields if(ValidatorUtil.isInvalid(instance.getFirstName())){ errors.reject("'firstName' is required"); @@ -27,6 +33,13 @@ protected void validateCreate(Object o, Errors errors) { if(ValidatorUtil.isInvalid(instance.getLastName())){ errors.reject("'lastName' is required"); } + if(ValidatorUtil.isInvalid(instance.getPhoneNumber())){ + errors.reject("'phoneNumber' is required and must contain only digits"); + } + if(ValidatorUtil.isInvalidLength(instance.getPhoneNumber(), userFilter.getPhoneNumberLength())){ + errors.reject("'phoneNumber' must be 10 digits in length"); + } + } @Override @@ -37,5 +50,9 @@ protected void validateUpdate(Object o, Errors errors) { if(ValidatorUtil.isEmpty(instance, "id", "updated")){ errors.reject("'request' modifiable field(s) are required"); } + + if(String.valueOf(instance.getPhoneNumber()).length() > 0 && ValidatorUtil.isInvalid(instance.getPhoneNumber())){ + errors.reject("'phoneNumber' is must contain only digits"); + } } } diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 6edbe05..453ace2 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -5,12 +5,13 @@ create table user ( first_name varchar(100) not null, middle_name varchar(100) null, last_name varchar(100) not null, + phone_number integer not null, updated timestamp not null default current_timestamp() ); insert into user (id, first_name, middle_name, last_name) values - ('097e1c2e-8ba3-463e-96d2-7a08f32944a6','Justin','Marquis','Wheeler'), - ('b1f6c877-c4a2-4e00-a986-2cbed56e257f','James',null,'Wagon'), - ('d7d77a1b-d0e4-49bb-804d-895db58027cb','John','Smith','Doe'), - ('5f99aae9-7426-4e5b-932a-4f7066785e63','Jack',null,'Pool'), - ('d54cbbb5-96f7-496e-8142-ce4966061940','Joan','Marie','River'); + ('097e1c2e-8ba3-463e-96d2-7a08f32944a6','Justin','Marquis','Wheeler', 6161112222), + ('b1f6c877-c4a2-4e00-a986-2cbed56e257f','James',null,'Wagon', 6162223333), + ('d7d77a1b-d0e4-49bb-804d-895db58027cb','John','Smith','Doe', 6163334444), + ('5f99aae9-7426-4e5b-932a-4f7066785e63','Jack',null,'Pool', 6164445555), + ('d54cbbb5-96f7-496e-8142-ce4966061940','Joan','Marie','River', 6165556666);