From 52e4c84e367e1637879932d7573ba161f2e22a5c Mon Sep 17 00:00:00 2001 From: Hoai Viet Nguyen <viet.nguyen@th-koeln.de> Date: Fri, 13 Dec 2024 12:42:35 +0100 Subject: [PATCH] add inputvalidaiton an errors hints --- build.gradle | 1 + .../todolist/controllers/TasksController.kt | 30 ++++++++++++++----- .../controllers/TasksRestController.kt | 11 ++++--- .../todolist/controllers/UsersController.kt | 13 ++++++-- .../controllers/UsersRestController.kt | 11 ++++--- .../de/thk/gm/gdw/todolist/dtos/TaskDto.kt | 9 ++++++ .../de/thk/gm/gdw/todolist/dtos/UserDto.kt | 18 +++++++++++ .../de/thk/gm/gdw/todolist/models/User.kt | 3 ++ .../resources/templates/tasks/showTask.ftlh | 6 ++++ .../resources/templates/tasks/showTasks.ftlh | 3 ++ .../resources/templates/users/showUsers.ftlh | 11 ++++++- 11 files changed, 97 insertions(+), 19 deletions(-) create mode 100644 src/main/kotlin/de/thk/gm/gdw/todolist/dtos/TaskDto.kt create mode 100644 src/main/kotlin/de/thk/gm/gdw/todolist/dtos/UserDto.kt diff --git a/build.gradle b/build.gradle index ae87069..2f9b71e 100644 --- a/build.gradle +++ b/build.gradle @@ -31,6 +31,7 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.json:json:20231013' } diff --git a/src/main/kotlin/de/thk/gm/gdw/todolist/controllers/TasksController.kt b/src/main/kotlin/de/thk/gm/gdw/todolist/controllers/TasksController.kt index 19f8309..309e473 100644 --- a/src/main/kotlin/de/thk/gm/gdw/todolist/controllers/TasksController.kt +++ b/src/main/kotlin/de/thk/gm/gdw/todolist/controllers/TasksController.kt @@ -1,12 +1,16 @@ package de.thk.gm.gdw.todolist.controllers +import de.thk.gm.gdw.todolist.dtos.TaskDto import de.thk.gm.gdw.todolist.services.TasksService import de.thk.gm.gdw.todolist.services.UsersService +import jakarta.validation.Valid import org.springframework.http.HttpStatus import org.springframework.http.MediaType 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.servlet.mvc.support.RedirectAttributes import java.util.* @Controller @@ -22,8 +26,13 @@ class TasksController (private val tasksRestController: TasksRestController, pri } @PostMapping("/tasks") - fun saveTask(name: String, @PathVariable userId: UUID): String { - tasksRestController.saveTask(name, userId) + fun saveTask(@Valid taskDto: TaskDto, bindingResult: BindingResult, redirectAttributes: RedirectAttributes, @PathVariable userId: UUID): String { + if (bindingResult.hasErrors()) { + redirectAttributes.addFlashAttribute("errors", bindingResult) + } else { + tasksRestController.saveTask(taskDto, userId) + } + return "redirect:/users/$userId/tasks" } @@ -35,12 +44,17 @@ class TasksController (private val tasksRestController: TasksRestController, pri } @PutMapping("/tasks/{id}") - fun updateTask(@PathVariable userId: UUID, @PathVariable id: UUID, name: String, open: Boolean): String { - var task = tasksRestController.getTaskById(id, userId) - task.name = name - task.open = open - tasksService.save(task) - return "redirect:/users/$userId/tasks/${task.id}" + fun updateTask(@PathVariable userId: UUID, @PathVariable id: UUID,@Valid taskDto: TaskDto,bindingResult: BindingResult, redirectAttributes: RedirectAttributes): String { + if(bindingResult.hasErrors()) { + redirectAttributes.addFlashAttribute("errors", bindingResult) + } else { + var task = tasksRestController.getTaskById(id, userId) + task.name = taskDto.name + task.open = taskDto.open + tasksService.save(task) + } + + return "redirect:/users/$userId/tasks/${id}" } @DeleteMapping("/tasks/{id}") diff --git a/src/main/kotlin/de/thk/gm/gdw/todolist/controllers/TasksRestController.kt b/src/main/kotlin/de/thk/gm/gdw/todolist/controllers/TasksRestController.kt index 027a5ef..7ac541e 100644 --- a/src/main/kotlin/de/thk/gm/gdw/todolist/controllers/TasksRestController.kt +++ b/src/main/kotlin/de/thk/gm/gdw/todolist/controllers/TasksRestController.kt @@ -1,8 +1,10 @@ package de.thk.gm.gdw.todolist.controllers +import de.thk.gm.gdw.todolist.dtos.TaskDto import de.thk.gm.gdw.todolist.models.Task import de.thk.gm.gdw.todolist.services.TasksService import de.thk.gm.gdw.todolist.services.UsersService +import jakarta.validation.Valid import org.springframework.http.HttpStatus import org.springframework.http.MediaType import org.springframework.web.bind.annotation.* @@ -15,11 +17,11 @@ class TasksRestController (private val tasksService: TasksService, private val u @PostMapping("/tasks") @ResponseStatus(HttpStatus.CREATED) - fun saveTask(name : String, @PathVariable userId: UUID) { + fun saveTask(@Valid @RequestBody taskDto: TaskDto, @PathVariable userId: UUID) { val user = usersService.getUserById(userId) if(user != null) { var task = Task() - task.name = name + task.name = taskDto.name task.user = user tasksService.save(task) } else { @@ -59,12 +61,13 @@ class TasksRestController (private val tasksService: TasksService, private val u @PutMapping("/tasks/{id}") @ResponseStatus(HttpStatus.NO_CONTENT) - fun updateTask(@PathVariable("id") id : UUID, name : String, @PathVariable userId: UUID) { + fun updateTask(@PathVariable("id") id : UUID, @Valid @RequestBody taskDto: TaskDto, @PathVariable userId: UUID) { val user = usersService.getUserById(userId) if(user != null) { var task = tasksService.getByIdAndUser(id, user) if(task != null) { - task.name = name + task.name = taskDto.name + task.open = taskDto.open tasksService.save(task) } else { throw ResponseStatusException(HttpStatus.NOT_FOUND) diff --git a/src/main/kotlin/de/thk/gm/gdw/todolist/controllers/UsersController.kt b/src/main/kotlin/de/thk/gm/gdw/todolist/controllers/UsersController.kt index 160859f..de178b6 100644 --- a/src/main/kotlin/de/thk/gm/gdw/todolist/controllers/UsersController.kt +++ b/src/main/kotlin/de/thk/gm/gdw/todolist/controllers/UsersController.kt @@ -1,11 +1,15 @@ package de.thk.gm.gdw.todolist.controllers +import de.thk.gm.gdw.todolist.dtos.UserDto +import jakarta.validation.Valid import org.springframework.http.MediaType import org.springframework.stereotype.Controller import org.springframework.ui.Model +import org.springframework.validation.BindingResult import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.servlet.mvc.support.RedirectAttributes @Controller @RequestMapping(produces = [MediaType.TEXT_HTML_VALUE]) @@ -18,8 +22,13 @@ class UsersController (private val usersRestController: UsersRestController) { } @PostMapping("/users") - fun saveUsers(email: String): String { - usersRestController.saveUser(email) + fun saveUsers(@Valid userDto: UserDto, bindingResult: BindingResult, redirectAttributes: RedirectAttributes): String { + + if (bindingResult.hasErrors()) { + redirectAttributes.addFlashAttribute("errors", bindingResult) + } else { + usersRestController.saveUser(userDto) + } return "redirect:/" } } \ No newline at end of file diff --git a/src/main/kotlin/de/thk/gm/gdw/todolist/controllers/UsersRestController.kt b/src/main/kotlin/de/thk/gm/gdw/todolist/controllers/UsersRestController.kt index cd3a56b..f41d566 100644 --- a/src/main/kotlin/de/thk/gm/gdw/todolist/controllers/UsersRestController.kt +++ b/src/main/kotlin/de/thk/gm/gdw/todolist/controllers/UsersRestController.kt @@ -1,7 +1,9 @@ package de.thk.gm.gdw.todolist.controllers +import de.thk.gm.gdw.todolist.dtos.UserDto import de.thk.gm.gdw.todolist.models.User import de.thk.gm.gdw.todolist.services.UsersService +import jakarta.validation.Valid import org.springframework.http.HttpStatus import org.springframework.http.MediaType import org.springframework.web.bind.annotation.* @@ -14,9 +16,10 @@ class UsersRestController (private val usersService: UsersService) { @PostMapping("/users") @ResponseStatus(HttpStatus.CREATED) - fun saveUser(@RequestParam email : String): User { + fun saveUser(@Valid @RequestBody userDto: UserDto): User { var user = User() - user.email = email + user.email = userDto.email + user.birthday = userDto.birthday usersService.saveUser(user) return user } @@ -38,10 +41,10 @@ class UsersRestController (private val usersService: UsersService) { @PutMapping("/users/{id}") @ResponseStatus(HttpStatus.NO_CONTENT) - fun updateUser(email: String, @PathVariable id: UUID) { + fun updateUser(@Valid @RequestBody userDto: UserDto, @PathVariable id: UUID) { var user = usersService.getUserById(id) if (user != null) { - user.email = email + user.email = userDto.email usersService.saveUser(user) } else { throw ResponseStatusException(HttpStatus.NOT_FOUND) diff --git a/src/main/kotlin/de/thk/gm/gdw/todolist/dtos/TaskDto.kt b/src/main/kotlin/de/thk/gm/gdw/todolist/dtos/TaskDto.kt new file mode 100644 index 0000000..5a771c0 --- /dev/null +++ b/src/main/kotlin/de/thk/gm/gdw/todolist/dtos/TaskDto.kt @@ -0,0 +1,9 @@ +package de.thk.gm.gdw.todolist.dtos + +import jakarta.validation.constraints.Size + +class TaskDto { + @Size(min = 1, max = 50) + var name: String = "" + var open: Boolean = true +} \ No newline at end of file diff --git a/src/main/kotlin/de/thk/gm/gdw/todolist/dtos/UserDto.kt b/src/main/kotlin/de/thk/gm/gdw/todolist/dtos/UserDto.kt new file mode 100644 index 0000000..33477d6 --- /dev/null +++ b/src/main/kotlin/de/thk/gm/gdw/todolist/dtos/UserDto.kt @@ -0,0 +1,18 @@ +package de.thk.gm.gdw.todolist.dtos + +import jakarta.validation.constraints.Email +import jakarta.validation.constraints.Past +import jakarta.validation.constraints.PastOrPresent +import jakarta.validation.constraints.Size +import org.springframework.format.annotation.DateTimeFormat +import java.time.LocalDateTime +import java.util.* + +class UserDto { + @Email + @Size(min = 5, max = 50) + var email: String = "" + @DateTimeFormat(pattern = "yyyy-MM-dd") + @PastOrPresent + var birthday: Date? = null +} \ No newline at end of file diff --git a/src/main/kotlin/de/thk/gm/gdw/todolist/models/User.kt b/src/main/kotlin/de/thk/gm/gdw/todolist/models/User.kt index 4eeea08..8ad8589 100644 --- a/src/main/kotlin/de/thk/gm/gdw/todolist/models/User.kt +++ b/src/main/kotlin/de/thk/gm/gdw/todolist/models/User.kt @@ -3,6 +3,7 @@ package de.thk.gm.gdw.todolist.models import jakarta.persistence.Entity import jakarta.persistence.Id import jakarta.persistence.Table +import java.time.LocalDateTime import java.util.* @Entity @@ -11,4 +12,6 @@ class User { @Id val id : UUID = UUID.randomUUID() var email: String = "" + val createdAt: LocalDateTime = LocalDateTime.now() + var birthday: Date? = null } \ No newline at end of file diff --git a/src/main/resources/templates/tasks/showTask.ftlh b/src/main/resources/templates/tasks/showTask.ftlh index 2540fb1..f9978cc 100644 --- a/src/main/resources/templates/tasks/showTask.ftlh +++ b/src/main/resources/templates/tasks/showTask.ftlh @@ -4,8 +4,14 @@ <form action="/users/${task.user.id}/tasks/${task.id}" method="post"> <label>Task name</label><br> <input type="text" value="${task.name}" name="name"><br> + <#if errors?? && errors.getFieldError("name")??> + ${errors.getFieldError("name")["defaultMessage"]}<br> + </#if> <label>Open?</label> <input type="text" value="${task.open?string}" name="open"><br> + <#if errors?? && errors.getFieldError("open")??> + ${errors.getFieldError("open")["defaultMessage"]}<br> + </#if> <input type="hidden" name="_method" value="PUT"/> <button>Update</button> </form> diff --git a/src/main/resources/templates/tasks/showTasks.ftlh b/src/main/resources/templates/tasks/showTasks.ftlh index f4a452c..bf8da3c 100644 --- a/src/main/resources/templates/tasks/showTasks.ftlh +++ b/src/main/resources/templates/tasks/showTasks.ftlh @@ -9,6 +9,9 @@ </ul> <form action="/users/${user.id}/tasks" method="post"> <input name="name" type="text"> + <#if errors?? && errors.getFieldError("name")??> + ${errors.getFieldError("name")["defaultMessage"]} + </#if> <button>Create task</button> </form> <br> diff --git a/src/main/resources/templates/users/showUsers.ftlh b/src/main/resources/templates/users/showUsers.ftlh index c78c487..686028d 100644 --- a/src/main/resources/templates/users/showUsers.ftlh +++ b/src/main/resources/templates/users/showUsers.ftlh @@ -6,7 +6,16 @@ </#list> </ul> <form action="/users" method="post"> - <input placeholder="max.mustermann@example.org" name="email"> + <label for="email">Email</label> + <input placeholder="max.mustermann@example.org" name="email" minlength="5" maxlength="50" type="email" id="email"><br> + <#if errors?? && errors.getFieldError("email")??> + ${errors.getFieldError("email")["defaultMessage"]} + </#if> + <label for="birthday">Birthday</label> + <input name="birthday" type="date" id="birthday"> + <#if errors?? && errors.getFieldError("birthday")??> + ${errors.getFieldError("birthday")["defaultMessage"]} + </#if> <button>Create user</button> </form> </@base.layout> \ No newline at end of file -- GitLab