Skip to content

Commit

Permalink
fix(FE): validation message and form submission (#425)
Browse files Browse the repository at this point in the history
* fix: fixing validation on the backend

* fix(FE): validation message parsing

adding a failsafe mechanism to avoid parsing wrong returned data.

* feat(FE): adding form submission and validation

- added form submission using composition api
- changed the name of the fields on the validation to match the name of the property on the object
- created a ContactComponent to aggregate the contact information
- added submission check example code
  • Loading branch information
Paulo Gomes da Cruz Junior authored Mar 30, 2023
1 parent 01a226a commit 5ac42f7
Show file tree
Hide file tree
Showing 19 changed files with 345 additions and 244 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

Expand Down Expand Up @@ -73,6 +76,7 @@ public ClientSubmissionController(
)
}
)
@ResponseStatus(HttpStatus.CREATED)
public Mono<Void> submit(
@RequestBody ClientSubmissionDto request,
ServerHttpResponse serverResponse) {
Expand All @@ -82,18 +86,19 @@ public Mono<Void> submit(
)
.doOnNext(this::validate)
.flatMap(clientService::submit)
.doOnNext(submissionId -> {
serverResponse
.setStatusCode(HttpStatus.CREATED);

HttpHeaders headers = serverResponse.getHeaders();
headers
.add(
"Location",
String.format("/api/clients/submissions/%d", submissionId));
headers.add(
"x-sub-id", String.valueOf(submissionId));
}
.doOnNext(submissionId ->
serverResponse
.getHeaders()
.addAll(
CollectionUtils
.toMultiValueMap(
Map.of(
"Location",
List.of(String.format("/api/clients/submissions/%d", submissionId)),
"x-sub-id", List.of(String.valueOf(submissionId))
)
)
)
)
.then();
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ca.bc.gov.app.dto.bcregistry;

import ca.bc.gov.app.dto.client.ClientAddressDto;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import lombok.With;
Expand Down Expand Up @@ -28,7 +29,14 @@
"province": {"value": "QC", text": "Quebec"},
"city": "Montreal",
"postalCode": "H3B1A7",
"index": 1
"index": 1,
"contacts":{
"type": "person",
"firstName": "JAMES",
"lastName": "BAXTER",
"phoneNumber": "123456789"
"email": "[email protected]",
}
}
]
}"""
Expand Down Expand Up @@ -63,6 +71,6 @@ public record ClientDetailsDto(
"index": 1
}
]""")
List<ClientAddressDataDto> addresses
List<ClientAddressDto> addresses
) {
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,67 @@
package ca.bc.gov.app.dto.client;

import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import lombok.With;

@Schema(
description = "An address information",
title = "ClientAddressData",
example = """
{
"streetAddress": "123 Main St",
"country": {
"value": "CA",
"text": "Canada"
},
"province": {
"value": "ON",
"text": "Ontario"
},
"city": "Toronto",
"postalCode": "M5V2L7",
"index": 1,
"contacts":{
"type": "person",
"firstName": "JAMES",
"lastName": "BAXTER",
"phoneNumber": "123456789"
"email": "[email protected]",
}
}"""
)
@With
public record ClientAddressDto(
@Schema(description = "The street address", example = "123 Main St")
String streetAddress,
@Schema(description = "The country for this address", example = """
{
"value": "CA",
"text": "Canada"
}""")
ClientValueTextDto country,
@Schema(description = "The province or state for this address", example = """
{
"value": "ON",
"text": "Ontario"
}""")
ClientValueTextDto province,
@Schema(description = "The city for this address", example = "Toronto")
String city,
@Schema(description = "The postal code or zip code for this address", example = "M5V2L7")
String postalCode,
@Schema(description = "The index for this address. It is used to order the addresses",
example = "3")
int index,

@Schema(description = "A list of contacts for this address",example = """
{
"type": "person",
"firstName": "JAMES",
"lastName": "BAXTER",
"phoneNumber": "123456789"
"email": "[email protected]",
}""")
List<ClientContactDto> contacts
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
title = "ClientContact",
example = """
{
"type": "person",
"contactType": {
"value": "person",
"text": "Person"
},
"firstName": "JAMES",
"lastName": "BAXTER",
"phoneNumber": "123456789"
Expand All @@ -17,7 +20,7 @@
public record ClientContactDto(
@Schema(description = "The type of contact",
example = "person")
String type,
ClientValueTextDto contactType,

@Schema(description = "The first name of the contact",
example = "JAMES")
Expand All @@ -34,6 +37,8 @@ public record ClientContactDto(
example = "[email protected]")
String email,

@Schema(description = "The index for this address. It is used to order the addresses",
example = "3")
int index
) {
}
2 changes: 2 additions & 0 deletions backend/src/main/java/ca/bc/gov/app/filter/CorsWebFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ public Mono<Void> filter(ServerWebExchange ctx, WebFilterChain chain) {

headers.add("Access-Control-Allow-Headers",
String.join(",", corsSettings.getHeaders()));
headers.add("Access-Control-Expose-Headers",
String.join(",", corsSettings.getHeaders()));

if (CorsUtils.isPreFlightRequest(request)) {
response.setStatusCode(HttpStatus.NO_CONTENT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import ca.bc.gov.app.dto.bcregistry.BcRegistryBusinessAdressesDto;
import ca.bc.gov.app.dto.bcregistry.BcRegistryBusinessDto;
import ca.bc.gov.app.dto.bcregistry.BcRegistryFacetSearchResultEntryDto;
import ca.bc.gov.app.dto.bcregistry.ClientAddressDataDto;
import ca.bc.gov.app.dto.bcregistry.ClientDetailsDto;
import ca.bc.gov.app.dto.client.ClientAddressDto;
import ca.bc.gov.app.dto.client.ClientLocationDto;
Expand Down Expand Up @@ -216,7 +215,7 @@ public Flux<ClientLookUpDto> findByClientNameOrIncorporation(String value) {
));
}

private Function<List<ClientAddressDataDto>, ClientDetailsDto> buildDetails(
private Function<List<ClientAddressDto>, ClientDetailsDto> buildDetails(
BcRegistryBusinessDto details) {
return addresses -> new ClientDetailsDto(
details.legalName(),
Expand All @@ -226,17 +225,18 @@ private Function<List<ClientAddressDataDto>, ClientDetailsDto> buildDetails(
);
}

private Function<Tuple2<Long, BcRegistryAddressDto>, Mono<ClientAddressDataDto>> buildAddress() {
private Function<Tuple2<Long, BcRegistryAddressDto>, Mono<ClientAddressDto>> buildAddress() {
return addressTuple ->
Mono
.just(
new ClientAddressDataDto(
new ClientAddressDto(
addressTuple.getT2().streetAddress(),
null,
null,
addressTuple.getT2().addressCity(),
addressTuple.getT2().postalCode(),
addressTuple.getT1().intValue()
addressTuple.getT1().intValue(),
List.of()
)
)
.flatMap(address ->
Expand Down
11 changes: 9 additions & 2 deletions backend/src/main/java/ca/bc/gov/app/util/ClientMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.time.LocalDate;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ClientMapper {
Expand Down Expand Up @@ -59,7 +60,7 @@ public static SubmissionDetailEntity mapToSubmissionDetailEntity(
.withFirstName(clientBusinessInformationDto.firstName())
.withLastName(clientBusinessInformationDto.lastName())
.withClientTypeCode(clientSubmissionDto.businessType().clientType().value())
.withDateOfBirth(LocalDate.parse(clientBusinessInformationDto.birthdate()))
.withDateOfBirth(parseBirthdate(clientBusinessInformationDto))
.withDoingBusinessAsName(clientBusinessInformationDto.doingBusinessAsName());
}

Expand Down Expand Up @@ -97,10 +98,16 @@ public static SubmissionLocationContactEntity mapToSubmissionLocationContactEnti
) {
return new SubmissionLocationContactEntity()
.withSubmissionLocationId(submissionLocationId)
.withContactTypeCode(clientContactDto.type())
.withContactTypeCode(clientContactDto.contactType().value())
.withFirstName(clientContactDto.firstName())
.withLastName(clientContactDto.lastName())
.withBusinessPhoneNumber(clientContactDto.phoneNumber())
.withEmailAddress(clientContactDto.email());
}

private static LocalDate parseBirthdate(ClientBusinessInformationDto clientBusinessInformationDto) {
if(clientBusinessInformationDto == null || StringUtils.isBlank(clientBusinessInformationDto.birthdate()))
return null;
return LocalDate.parse(clientBusinessInformationDto.birthdate());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,24 @@
import static ca.bc.gov.app.util.ValidationUtil.validatePhoneNumber;

import ca.bc.gov.app.dto.client.ClientContactDto;
import ca.bc.gov.app.entity.client.ClientTypeCodeEntity;
import ca.bc.gov.app.entity.client.ContactTypeCodeEntity;
import ca.bc.gov.app.repository.client.ClientTypeCodeRepository;
import ca.bc.gov.app.repository.client.ContactTypeCodeRepository;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

@Component
@RequiredArgsConstructor
public class ClientContactDtoValidator implements Validator {

private final ContactTypeCodeRepository typeCodeRepository;

@Override
public boolean supports(Class<?> clazz) {
return ClientContactDto.class.equals(clazz);
Expand All @@ -20,9 +31,6 @@ public boolean supports(Class<?> clazz) {
@Override
public void validate(Object target, Errors errors) {

ValidationUtils.rejectIfEmptyOrWhitespace(errors, "type",
fieldIsMissingErrorMessage("type"));

ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName",
fieldIsMissingErrorMessage("firstName"));

Expand All @@ -31,9 +39,28 @@ public void validate(Object target, Errors errors) {

ClientContactDto contact = (ClientContactDto) target;

validateContactType(contact, errors);

validatePhoneNumber(
contact.phoneNumber(), "phoneNumber", errors);

validateEmail(contact.email(), "email", errors);
}

@SneakyThrows
private void validateContactType(ClientContactDto contact, Errors errors) {
if (contact.contactType() == null || StringUtils.isBlank(contact.contactType().value())) {
errors.rejectValue("contactType", fieldIsMissingErrorMessage("contactType"));
return;
}

ContactTypeCodeEntity contactTypeCode = typeCodeRepository
.findById(contact.contactType().value()).toFuture().get();

if (contactTypeCode == null) {
errors.rejectValue("contactType", "Contact Type "+contact.contactType().text()+" is invalid");
}

}

}
3 changes: 3 additions & 0 deletions backend/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ ca:
- Content-Type,
- Content-Range,
- Range
- Location
- location
- x-sub-id
methods:
- OPTIONS
- GET
Expand Down
Loading

0 comments on commit 5ac42f7

Please sign in to comment.