diff --git a/.github/workflows/jacoco_report.yml b/.github/workflows/jacoco_report.yml
new file mode 100644
index 0000000..3cd3280
--- /dev/null
+++ b/.github/workflows/jacoco_report.yml
@@ -0,0 +1,31 @@
+# A Github action that publishes the JaCoCo report as a comment
+
+name: Measure coverage
+
+on:
+ pull_request:
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ permissions:
+ pull-requests: write
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up JDK 17
+ uses: actions/setup-java@v1
+ with:
+ java-version: '17'
+ - name: Build with Maven
+ run: mvn --batch-mode --update-snapshots test
+
+ - name: Jacoco Report to PR
+ id: jacoco
+ uses: madrapps/jacoco-report@v1.6.1
+ with:
+ paths: ${{ github.workspace }}/build/site/jacoco/jacoco.xml
+ token: ${{ secrets.GITHUB_TOKEN }}
+ min-coverage-overall: 40
+ min-coverage-changed-files: 60
+ title: Code Coverage
+ update-comment: true
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index be5acb5..5cc290c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -41,6 +41,15 @@
spring-security-test
test
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+ javax.validation
+ validation-api
+ 2.0.1.Final
+
org.postgresql
postgresql
diff --git a/src/main/java/ru/job4j/cars/controller/PostController.java b/src/main/java/ru/job4j/cars/controller/PostController.java
index 2292e3a..0d9a61e 100644
--- a/src/main/java/ru/job4j/cars/controller/PostController.java
+++ b/src/main/java/ru/job4j/cars/controller/PostController.java
@@ -5,6 +5,7 @@
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
+import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import ru.job4j.cars.dto.ImageDto;
@@ -13,6 +14,7 @@
import ru.job4j.cars.model.CarModel;
import ru.job4j.cars.model.Post;
import ru.job4j.cars.service.*;
+import ru.job4j.cars.utilities.SearchValidator;
@Controller
@RequestMapping("/posts")
@@ -29,14 +31,13 @@ public class PostController {
private final FuelTypeService fuelTypeService;
private final TransmissionService transmissionService;
+ private final SearchValidator searchValidator;
+
@GetMapping("/all")
- public String getAllPosts(Model model, @ModelAttribute PostSearchDto searchDto) {
+ public String getAllPosts(Model model, @ModelAttribute PostSearchDto searchDto, BindingResult br) {
addFormAttributesToModel(model);
- boolean searchActive = searchDto.getCar() != null
- || searchDto.getHighestPrice() > 0
- || searchDto.getLowestPrice() > 0
- || searchDto.getPostCreatedBeforeDays() > 0
- || searchDto.isImageExists();
+ searchValidator.validate(searchDto, br);
+ boolean searchActive = searchIsActiveCheck(br);
if (!searchActive) {
model.addAttribute("posts", postService.findAllNotSold());
} else {
@@ -75,32 +76,24 @@ public String getEditPage(Model model, @PathVariable int id) {
}
@PostMapping("/create")
- public String createPost(@ModelAttribute Post post, @RequestParam MultipartFile file, Model model) {
- try {
- Optional savedPost = postService.save(post,
- new ImageDto(file.getOriginalFilename(), file.getBytes()));
- if (savedPost.isEmpty()) {
- model.addAttribute("message", "Произошла ошибка при создании объявления.");
- return "errors/404";
- }
- } catch (IOException e) {
- model.addAttribute("message", "Ошибка при создании объявления!");
+ public String createPost(@ModelAttribute Post post, @RequestParam MultipartFile file, Model model)
+ throws IOException {
+ Optional savedPost = postService.save(post,
+ new ImageDto(file.getOriginalFilename(), file.getBytes()));
+ if (savedPost.isEmpty()) {
+ model.addAttribute("message", "Произошла ошибка при создании объявления.");
return "errors/404";
}
return "redirect:/posts/all";
}
@PostMapping("/edit")
- public String editPost(@ModelAttribute Post post, @RequestParam MultipartFile file, Model model) {
- try {
- boolean isUpdated = postService.update(post,
- new ImageDto(file.getOriginalFilename(), file.getBytes()));
- if (!isUpdated) {
- model.addAttribute("message", "Произошла ошибка при обновлении объявления.");
- return "errors/404";
- }
- } catch (IOException e) {
- model.addAttribute("message", "Ошибка при обновлении объявления!");
+ public String editPost(@ModelAttribute Post post, @RequestParam MultipartFile file, Model model)
+ throws IOException {
+ boolean isUpdated = postService.update(post,
+ new ImageDto(file.getOriginalFilename(), file.getBytes()));
+ if (!isUpdated) {
+ model.addAttribute("message", "Произошла ошибка при обновлении объявления.");
return "errors/404";
}
return "redirect:/users/posts";
@@ -123,4 +116,8 @@ private Model addFormAttributesToModel(Model model) {
return model;
}
+ private boolean searchIsActiveCheck(BindingResult bindingResult) {
+ return bindingResult.getErrorCount() < PostSearchDto.class.getDeclaredFields().length;
+ }
+
}
\ No newline at end of file
diff --git a/src/main/java/ru/job4j/cars/handler/MultipartFileGlobalExceptionHandler.java b/src/main/java/ru/job4j/cars/handler/MultipartFileGlobalExceptionHandler.java
new file mode 100644
index 0000000..a146459
--- /dev/null
+++ b/src/main/java/ru/job4j/cars/handler/MultipartFileGlobalExceptionHandler.java
@@ -0,0 +1,20 @@
+package ru.job4j.cars.handler;
+
+import java.io.IOException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+
+@ControllerAdvice
+@Slf4j
+public class MultipartFileGlobalExceptionHandler {
+
+ @ExceptionHandler (value = {IOException.class})
+ public String ioExceptionHandle(Exception e, Model model) {
+ log.error(e.getMessage(), e);
+ model.addAttribute("message", "Ошибка при работе с объявлением!");
+ return "errors/404";
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/ru/job4j/cars/utilities/SearchValidator.java b/src/main/java/ru/job4j/cars/utilities/SearchValidator.java
new file mode 100644
index 0000000..9febc65
--- /dev/null
+++ b/src/main/java/ru/job4j/cars/utilities/SearchValidator.java
@@ -0,0 +1,36 @@
+package ru.job4j.cars.utilities;
+
+import org.springframework.stereotype.Component;
+import org.springframework.validation.Errors;
+import org.springframework.validation.Validator;
+import ru.job4j.cars.dto.PostSearchDto;
+
+@Component
+public class SearchValidator implements Validator {
+
+ @Override
+ public boolean supports(Class> clazz) {
+ return PostSearchDto.class.equals(clazz);
+ }
+
+ @Override
+ public void validate(Object target, Errors errors) {
+ PostSearchDto dto = (PostSearchDto) target;
+ if (dto.getCar() == null) {
+ errors.rejectValue("car", "Car is null");
+ }
+ if (dto.getHighestPrice() <= 0) {
+ errors.rejectValue("highestPrice", "highest price is less than 1");
+ }
+ if (dto.getLowestPrice() <= 0) {
+ errors.rejectValue("lowestPrice", "lowest price is less than 1");
+ }
+ if (dto.getPostCreatedBeforeDays() <= 0) {
+ errors.rejectValue("postCreatedBeforeDays", "created before is less than 1");
+ }
+ if (!dto.isImageExists()) {
+ errors.rejectValue("imageExists", " only image exists is false");
+ }
+ }
+
+}
\ No newline at end of file