From 0119b1cfa0af722c4add84181fb7cce33e33b03b Mon Sep 17 00:00:00 2001 From: Denis Natusch Date: Tue, 28 Nov 2023 09:48:06 +0100 Subject: [PATCH] Add staff form and bind it to model Closes #51 --- .../asciidoc/developer_documentation.adoc | 1 + src/main/asciidoc/models/design/staff.puml | 21 ++++- src/main/asciidoc/models/design/staff.svg | 4 +- .../java/catering/staff/StaffController.java | 47 ++++++++--- src/main/java/catering/staff/StaffForm.java | 38 +++++++++ src/main/resources/templates/edit-staff.html | 11 +-- src/main/resources/templates/staff.html | 8 +- .../StaffControllerIntegrationTests.java | 77 +++++++++++++++---- 8 files changed, 169 insertions(+), 38 deletions(-) create mode 100644 src/main/java/catering/staff/StaffForm.java diff --git a/src/main/asciidoc/developer_documentation.adoc b/src/main/asciidoc/developer_documentation.adoc index e5bc32f..f8506c4 100644 --- a/src/main/asciidoc/developer_documentation.adoc +++ b/src/main/asciidoc/developer_documentation.adoc @@ -300,6 +300,7 @@ image:models/design/staff.svg[class design diagram - Staff] |StaffController |A Spring MVC Controller for handling staff-related operations such as adding, removing, and updating staff data. It interacts with StaffManagement. |StaffManagement |A class that manages interactions and logic with StaffRepository. It provides methods to find, save/add, list, and delete staff members. |StaffRepository |An extension of 'CrudRepository' that provides standard methods to perform CRUD operations on staff objects. +|StaffForm |A Form to cache a user input that was made during registration or updating an Employee. |=== === Link between analysis and design diff --git a/src/main/asciidoc/models/design/staff.puml b/src/main/asciidoc/models/design/staff.puml index a9683c8..131e32f 100644 --- a/src/main/asciidoc/models/design/staff.puml +++ b/src/main/asciidoc/models/design/staff.puml @@ -6,6 +6,8 @@ skinparam groupInheritance 2 package Spring { class CrudRepository class Streamable + class Errors + class Model } package catering.staff { @@ -32,13 +34,18 @@ package catering.staff { class StaffController { + StaffController(staffRepository: StaffRepository) + getStaff(model: Model): String + + getStaff(model: Model, form: StaffForm): String + removeEmployee(employee: Employee, model: Model): String - + addEmployee(name: String, job: JobType): String + + addEmployee(form:StaffForm, result:Errors, model: Model): String + editEmployee(employee: Employee, model Model): String - + updateEmployee(employee: Employee, name: String, job: JobType): String + + editEmployee(model Model, form:StaffForm): String + + updateEmployee(employee: Employee, form:StaffForm): String } StaffController --> StaffManagement : -staffManagement StaffController ..> Employee + StaffController ..> StaffForm + StaffController ..> Model + StaffController ..> Errors class StaffManagement { + StaffManagement(staffRepository: StaffRepository) @@ -56,6 +63,16 @@ package catering.staff { StaffRepository ..|> Streamable StaffRepository o-- Employee + class StaffForm { + - name: String + + StaffForm(): void + + getName(): String + + getJob(): JobType + + setName(name:String): void + + setJob(job:JobType): void + + validate(e:Errors): void + } + StaffForm ..> JobType : -job } @enduml diff --git a/src/main/asciidoc/models/design/staff.svg b/src/main/asciidoc/models/design/staff.svg index 018cce9..646af03 100644 --- a/src/main/asciidoc/models/design/staff.svg +++ b/src/main/asciidoc/models/design/staff.svg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:faedcb3bb6b731e3c46d8edc7da5b0b6e8ab2875f42099053fa27bc3f5389d99 -size 25860 +oid sha256:6e21a55b26fdb047ad17f31b1811043524c82d78b8a1c6181168630b606c5d0d +size 28806 diff --git a/src/main/java/catering/staff/StaffController.java b/src/main/java/catering/staff/StaffController.java index 8a478b6..79c9696 100644 --- a/src/main/java/catering/staff/StaffController.java +++ b/src/main/java/catering/staff/StaffController.java @@ -3,11 +3,15 @@ package catering.staff; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; +import jakarta.validation.Valid; + import org.springframework.ui.Model; +import org.springframework.validation.Errors; @Controller public class StaffController { @@ -21,10 +25,26 @@ public class StaffController { @GetMapping("/staff") @PreAuthorize("hasRole('ADMIN')") public String getStaff(Model model) { + return getStaff(model, new StaffForm()); + } + + public String getStaff(Model model, @Valid StaffForm form) { model.addAttribute("staff", staffManagement.findAll()); + model.addAttribute("form", form); return "staff"; } + @PostMapping("/staff/add") + @PreAuthorize("hasRole('ADMIN')") + public String addEmployee(@Valid @ModelAttribute("form") StaffForm form, Errors result, Model model) { + form.validate(result); + if (result.hasErrors()) { + return getStaff(model, form); + } + staffManagement.save(new Employee(form.getName(), form.getJob())); + return "redirect:/staff"; + } + @PostMapping("/staff/remove") @PreAuthorize("hasRole('ADMIN')") public String removeEmployee(@RequestParam("id") Employee employee, Model model) { @@ -32,25 +52,30 @@ public class StaffController { return "redirect:/staff"; } - @PostMapping("/staff/add") - @PreAuthorize("hasRole('ADMIN')") - public String addEmployee(@RequestParam String name, @RequestParam JobType job) { - staffManagement.save(new Employee(name, job)); - return "redirect:/staff"; - } - @GetMapping("/staff/edit/{id}") @PreAuthorize("hasRole('ADMIN')") public String editEmployee(@PathVariable("id") Employee employee, Model model) { - model.addAttribute("employee", employee); + StaffForm form = new StaffForm(); + form.setJob(employee.getJob()); + form.setName(employee.getName()); + return editEmployee(model, form); + } + + public String editEmployee(Model model, @Valid StaffForm form) { + model.addAttribute("form", form); return "edit-staff"; } @PostMapping("/staff/edit/{id}") @PreAuthorize("hasRole('ADMIN')") - public String updateEmployee(@PathVariable("id") Employee employee, @RequestParam String name, @RequestParam JobType job) { - employee.setJob(job); - employee.setName(name); + public String updateEmployee(@PathVariable("id") Employee employee, @Valid @ModelAttribute("form") StaffForm form, + Errors result, Model model) { + form.validate(result); + if (result.hasErrors()) { + return editEmployee(model, form); + } + employee.setJob(form.getJob()); + employee.setName(form.getName()); staffManagement.save(employee); return "redirect:/staff"; } diff --git a/src/main/java/catering/staff/StaffForm.java b/src/main/java/catering/staff/StaffForm.java new file mode 100644 index 0000000..cbd8961 --- /dev/null +++ b/src/main/java/catering/staff/StaffForm.java @@ -0,0 +1,38 @@ +package catering.staff; + +import org.springframework.validation.Errors; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; + +public class StaffForm { + + private @NotEmpty String name; + private @NotNull JobType job; + + public StaffForm() { + } + + public String getName() { + return name; + } + + public JobType getJob() { + return job; + } + + public void setName(String name) { + this.name = name; + } + + public void setJob(JobType job) { + this.job = job; + } + + public void validate(Errors e) { + if (job == null) { + e.rejectValue("job", "job is not a job type"); + } + } + +} diff --git a/src/main/resources/templates/edit-staff.html b/src/main/resources/templates/edit-staff.html index 38249b7..2f52476 100644 --- a/src/main/resources/templates/edit-staff.html +++ b/src/main/resources/templates/edit-staff.html @@ -7,17 +7,18 @@
-
- +
- + +
Ungültiger Name
- + +
Ungültiger Job
diff --git a/src/main/resources/templates/staff.html b/src/main/resources/templates/staff.html index 3634dac..b6ae0ca 100644 --- a/src/main/resources/templates/staff.html +++ b/src/main/resources/templates/staff.html @@ -37,16 +37,18 @@

Personal Hinzufügen

- +
- + +
Ungültiger Name
- +
Ungültiger Job
diff --git a/src/test/java/catering/staff/StaffControllerIntegrationTests.java b/src/test/java/catering/staff/StaffControllerIntegrationTests.java index f6d5265..d1df07e 100644 --- a/src/test/java/catering/staff/StaffControllerIntegrationTests.java +++ b/src/test/java/catering/staff/StaffControllerIntegrationTests.java @@ -29,8 +29,8 @@ class StaffControllerIntegrationTests { MockMvc mvc; MockHttpServletRequestBuilder createStaff = post("/staff/add") - .param("name", "Karl Baum") - .param("job", "COOK"); + .param("name", "Karl Baum") + .param("job", "COOK"); @Autowired private StaffManagement staffManagement; @@ -55,16 +55,16 @@ class StaffControllerIntegrationTests { @WithMockUser(username = "admin", password = "admin", roles = "ADMIN") void viewStaff() throws Exception { mvc.perform(get("/staff")) - .andExpect(status().isOk()) - .andExpect(content().string(containsString(defaultEmployee.getName()))); + .andExpect(status().isOk()) + .andExpect(content().string(containsString(defaultEmployee.getName()))); } @Test @WithMockUser(username = "admin", password = "admin", roles = "ADMIN") void viewStaffEditPage() throws Exception { mvc.perform(get("/staff/edit/" + defaultEmployeeId.toString())) - .andExpect(status().isOk()) - .andExpect(content().string(containsString(defaultEmployee.getName()))); + .andExpect(status().isOk()) + .andExpect(content().string(containsString(defaultEmployee.getName()))); } @Test @@ -83,12 +83,12 @@ class StaffControllerIntegrationTests { @WithMockUser(username = "admin", password = "admin", roles = "ADMIN") void modifyStaff() throws Exception { mvc.perform(post("/staff/edit/" + defaultEmployeeId.toString()) - .param("name", "Dieter Bäume") - .param("job", "SERVICE")).andExpect(redirectedUrl("/staff")) - .andExpect(redirectedUrl("/staff")); + .param("name", "Dieter Bäume") + .param("job", "SERVICE")).andExpect(redirectedUrl("/staff")) + .andExpect(redirectedUrl("/staff")); assertThat(staffManagement.findById(defaultEmployeeId).get()) - .extracting("name", "job") - .containsExactly("Dieter Bäume", JobType.SERVICE); + .extracting("name", "job") + .containsExactly("Dieter Bäume", JobType.SERVICE); } @Test @@ -103,6 +103,53 @@ class StaffControllerIntegrationTests { .doesNotContain("Dieter Baum"); } + @Test + @WithMockUser(username = "admin", password = "admin", roles = "ADMIN") + void addStaffWrong() throws Exception { + mvc.perform(post("/staff/add")) + .andExpect(content().string(containsString("Ungültiger Name"))) + .andExpect(content().string(containsString("Ungültiger Job"))); + } + + @Test + @WithMockUser(username = "admin", password = "admin", roles = "ADMIN") + void editStaffWrong() throws Exception { + mvc.perform(post("/staff/edit/" + defaultEmployeeId.toString())) + .andExpect(content().string(containsString("Ungültiger Name"))) + .andExpect(content().string(containsString("Ungültiger Job"))); + assertThat(staffManagement.findById(defaultEmployeeId).get()) + .extracting("name", "job") + .containsExactly("Dieter Baum", JobType.COOK); + } + + @Test + @WithMockUser(username = "admin", password = "admin", roles = "ADMIN") + void addStaffWithWrongJobType() throws Exception { + assertThat(staffManagement.findAll().stream()) + .extracting("name") + .doesNotContain("Paul Kunst"); + mvc.perform(post("/staff/add") + .param("name", "Paul Kunst") + .param("job", "notAJob")) + .andExpect(content().string(containsString("Ungültiger Job"))); + assertThat(staffManagement.findAll().stream()) + .extracting("name") + .doesNotContain("Paul Kunst"); + } + + @Test + @WithMockUser(username = "admin", password = "admin", roles = "ADMIN") + void editStaffWithWrongJobType() throws Exception { + mvc.perform( + post("/staff/edit/" + defaultEmployeeId.toString()) + .param("name", defaultEmployee.getName()) + .param("job", "notAJob")) + .andExpect(content().string(containsString("Ungültiger Job"))); + assertThat(staffManagement.findById(defaultEmployeeId).get()) + .extracting("name", "job") + .containsExactly("Dieter Baum", JobType.COOK); + } + @Test @WithMockUser(username = "dieter", password = "123", roles = "CUSTOMER") void refuseCustomer() throws Exception { @@ -114,10 +161,10 @@ class StaffControllerIntegrationTests { @WithAnonymousUser void refuseAnonymous() throws Exception { mvc.perform(get("/staff")) - .andExpect(status().is3xxRedirection()) - .andExpect(header().string(HttpHeaders.LOCATION, endsWith("/login"))); + .andExpect(status().is3xxRedirection()) + .andExpect(header().string(HttpHeaders.LOCATION, endsWith("/login"))); mvc.perform(get("/staff/edit/" + defaultEmployeeId)) - .andExpect(status().is3xxRedirection()) - .andExpect(header().string(HttpHeaders.LOCATION, endsWith("/login"))); + .andExpect(status().is3xxRedirection()) + .andExpect(header().string(HttpHeaders.LOCATION, endsWith("/login"))); } }