Implemented Validation of MessageForm in RestController and FormController. Closes #13

pull/21/head
Niclas Thobaben 2022-02-15 11:09:49 +01:00
parent 34e6e55ea4
commit 333ee23c42
9 changed files with 164 additions and 23 deletions

View File

@ -88,5 +88,4 @@ public class ForwardMessageFormTest {
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("http://myerrorsite.com"));
}
}

View File

@ -14,6 +14,7 @@ import org.springframework.test.web.servlet.MockMvc;
import java.time.Clock;
import java.time.LocalDateTime;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@ -53,4 +54,15 @@ public class ForwardMessageRestTest {
.andExpect(jsonPath("$.timestamp").value("2019-04-25T13:12:00"));
}
@Test
void forwardMessageWithInvalidFormReturns400StatusCode() throws Exception {
MessageForm form = MessageForm.of("", null, "", "sender @ company.com");
mockMvc.perform(post("/").contentType(APPLICATION_JSON)
.content(mapper.writeValueAsString(form)))
.andExpect(status().is4xxClientError())
.andExpect(content().contentType(APPLICATION_JSON))
.andExpect(jsonPath("$.[*].target").value(containsInAnyOrder("token", "subject", "content", "from")));
}
}

View File

@ -5,23 +5,19 @@ import de.nclazz.service.mailrelay.domain.Relay;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
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 org.springframework.web.server.ResponseStatusException;
import javax.validation.Valid;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@RestController
@RequestMapping("accounts")
@ -62,13 +58,4 @@ public class AccountRestController {
account.setReceivers(form.getReceivers());
return this.relay.saveAccount(account);
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public List<ValidationError> handleValidationExceptions(MethodArgumentNotValidException ex) {
return ex.getBindingResult()
.getAllErrors().stream()
.map(ValidationError::fromObjectError)
.collect(Collectors.toList());
}
}

View File

@ -1,11 +1,14 @@
package de.nclazz.service.mailrelay.adapter.web;
import de.nclazz.service.mailrelay.domain.Message;
import de.nclazz.service.mailrelay.domain.StringUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import java.time.LocalDateTime;
@Data
@ -13,12 +16,20 @@ import java.time.LocalDateTime;
@NoArgsConstructor
public class MessageForm {
@NotBlank
private String token;
@NotBlank
private String subject;
@NotBlank
private String content;
@Pattern(regexp = StringUtils.EMAIL_RFC_5322_REGEX)
@NotBlank
private String from;
private String onSuccess;
private String onError;

View File

@ -5,10 +5,12 @@ import de.nclazz.service.mailrelay.domain.Relay;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.validation.Valid;
import java.time.Clock;
import java.time.LocalDateTime;
@ -23,16 +25,17 @@ public class MessageFormController {
@PostMapping
public String forwardMessage(@RequestHeader(name = "Referer", required = false)String referer,
MessageForm form) {
@Valid MessageForm form,
BindingResult bindingResult) {
if(bindingResult.hasErrors()) {
return "redirect:" + form.getOnError();
}
String token = form.getToken();
Message message = form.toMessage(LocalDateTime.now(this.clock));
try {
this.relay.forwardMessage(token, message);
}catch(Exception e) {
log.error("An error occurred", e);
return "redirect:" + form.getOnError();
}
this.relay.forwardMessage(token, message);
String redirect = referer;

View File

@ -7,6 +7,7 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import java.time.Clock;
import java.time.LocalDateTime;
@ -18,7 +19,7 @@ public class MessageRestController {
private final Clock clock;
@PostMapping
public Message forwardMessage(@RequestBody MessageForm form) {
public Message forwardMessage(@RequestBody @Valid MessageForm form) {
String token = form.getToken();
Message message = form.toMessage(LocalDateTime.now(this.clock));

View File

@ -0,0 +1,32 @@
package de.nclazz.service.mailrelay.adapter.web;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import java.util.List;
import java.util.stream.Collectors;
@ControllerAdvice
public class NotValidExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
return ResponseEntity
.badRequest()
.body(mapBindingResultToValidationErrors(ex));
}
private List<ValidationError> mapBindingResultToValidationErrors(MethodArgumentNotValidException ex) {
return ex.getBindingResult()
.getAllErrors().stream()
.map(ValidationError::fromObjectError)
.collect(Collectors.toList());
}
}

View File

@ -5,6 +5,7 @@ import de.nclazz.service.mailrelay.domain.Account;
import de.nclazz.service.mailrelay.domain.Relay;
import de.nclazz.service.mailrelay.domain.TestRelayBuilder;
import org.junit.jupiter.api.Test;
import org.springframework.validation.BindingResult;
import java.time.Clock;
import java.time.LocalDateTime;
@ -12,6 +13,7 @@ import java.util.List;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
class MessageFormControllerTest {
@ -34,7 +36,7 @@ class MessageFormControllerTest {
MessageForm form = MessageForm.of(token, "Subject", "Message", "sender@company.com");
MessageFormController controller = new MessageFormController(relay, fakeClock);
controller.forwardMessage("http://mysite.org", form);
controller.forwardMessage("http://mysite.org", form, mock(BindingResult.class));
assertThat(account.getSentMessages())
.hasSize(1)

View File

@ -0,0 +1,94 @@
package de.nclazz.service.mailrelay.adapter.web;
import org.hibernate.validator.HibernateValidator;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import static org.assertj.core.api.Assertions.assertThat;
class MessageFormValidationTest {
private LocalValidatorFactoryBean localValidatorFactory;
@BeforeEach
public void setup() {
localValidatorFactory = new LocalValidatorFactoryBean();
localValidatorFactory.setProviderClass(HibernateValidator.class);
localValidatorFactory.afterPropertiesSet();
}
@Test
void tokenAsNullStringShouldBeNotValid() {
MessageForm form = MessageForm.of(null, "My Subject", "My Content", "mail@me.com");
assertThat(localValidatorFactory.validate(form))
.hasSize(1);
}
@Test
void tokenAsEmptyStringShouldBeNotValid() {
MessageForm form = MessageForm.of("", "My Subject", "My Content", "mail@me.com");
assertThat(localValidatorFactory.validate(form))
.hasSize(1);
}
@Test
void subjectAsNullStringShouldBeNotValid() {
MessageForm form = MessageForm.of("mytoken", null, "My Content", "mail@me.com");
assertThat(localValidatorFactory.validate(form))
.hasSize(1);
}
@Test
void subjectAsEmptyStringShouldBeNotValid() {
MessageForm form = MessageForm.of("mytoken", "", "My Content", "mail@me.com");
assertThat(localValidatorFactory.validate(form))
.hasSize(1);
}
@Test
void contentAsNullStringShouldBeNotValid() {
MessageForm form = MessageForm.of("mytoken", "Subject", null, "mail@me.com");
assertThat(localValidatorFactory.validate(form))
.hasSize(1);
}
@Test
void contentAsEmptyStringShouldBeNotValid() {
MessageForm form = MessageForm.of("mytoken", "Subject", "", "mail@me.com");
assertThat(localValidatorFactory.validate(form))
.hasSize(1);
}
@Test
void fromAsNullStringShouldBeNotValid() {
MessageForm form = MessageForm.of("mytoken", "Subject", "My Content", null);
assertThat(localValidatorFactory.validate(form))
.hasSize(1);
}
@Test
void fromAsEmptyStringShouldBeNotValid() {
MessageForm form = MessageForm.of("mytoken", "Subject", "My Content", "");
assertThat(localValidatorFactory.validate(form))
.isNotEmpty();
}
@Test
void fromAsInvalidMailAddressShouldBeNotValid() {
MessageForm form = MessageForm.of("mytoken", "Subject", "My Content", "invalid @ mail+address.com");
assertThat(localValidatorFactory.validate(form))
.hasSize(1);
}
}