From 4b005b914a8efd66899140d3a81c207debdb1581 Mon Sep 17 00:00:00 2001 From: Jan Klattenhoff Date: Wed, 23 Oct 2024 11:18:39 +0200 Subject: [PATCH 1/4] feat(employee): add action to remove employee from project --- .../RemoveEmployeeFromProjectAction.java | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/main/java/de/szut/lf8_starter/project/action/employee/RemoveEmployeeFromProjectAction.java diff --git a/src/main/java/de/szut/lf8_starter/project/action/employee/RemoveEmployeeFromProjectAction.java b/src/main/java/de/szut/lf8_starter/project/action/employee/RemoveEmployeeFromProjectAction.java new file mode 100644 index 0000000..4fec8e7 --- /dev/null +++ b/src/main/java/de/szut/lf8_starter/project/action/employee/RemoveEmployeeFromProjectAction.java @@ -0,0 +1,52 @@ +package de.szut.lf8_starter.project.action.employee; + +import de.szut.lf8_starter.employee.EmployeeService; +import de.szut.lf8_starter.project.ProjectEntity; +import de.szut.lf8_starter.project.ProjectService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.Optional; + +@RestController +public class RemoveEmployeeFromProjectAction { + private final ProjectService projectService; + private final EmployeeService employeeService; + + public RemoveEmployeeFromProjectAction(ProjectService projectService, EmployeeService employeeService) { + this.projectService = projectService; + this.employeeService = employeeService; + } + + @Operation(summary = "Remove an employee from a project") + @ApiResponses(value = { + @ApiResponse(responseCode = "204", description = "Employee removed from project"), + @ApiResponse(responseCode = "404", description = "Project or employee not found", content = @Content) + }) + @DeleteMapping("/projects/{projectId}/employees/{employeeId}") + public ResponseEntity remove( + @PathVariable Long projectId, + @PathVariable Long employeeId, + @RequestHeader("Authorization") String accessToken + ) { + Optional project = this.projectService.findById(projectId); + + if (project.isEmpty()) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + + if (!this.employeeService.employeeExists(accessToken, employeeId)) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + + project.get().getEmployees().remove(employeeId); + this.projectService.update(project.get()); + + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } +} -- 2.45.2 From 6c52670cb482dd5defda5110748eeb14af9d9976 Mon Sep 17 00:00:00 2001 From: Jan Klattenhoff Date: Wed, 23 Oct 2024 11:36:08 +0200 Subject: [PATCH 2/4] test: add integration test for removing employee from project --- ...oveEmployeeFromProjectIntegrationTest.java | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 src/test/java/de/szut/lf8_starter/integration/project/RemoveEmployeeFromProjectIntegrationTest.java diff --git a/src/test/java/de/szut/lf8_starter/integration/project/RemoveEmployeeFromProjectIntegrationTest.java b/src/test/java/de/szut/lf8_starter/integration/project/RemoveEmployeeFromProjectIntegrationTest.java new file mode 100644 index 0000000..978fd7c --- /dev/null +++ b/src/test/java/de/szut/lf8_starter/integration/project/RemoveEmployeeFromProjectIntegrationTest.java @@ -0,0 +1,78 @@ +package de.szut.lf8_starter.integration.project; + +import de.szut.lf8_starter.project.ProjectEntity; +import de.szut.lf8_starter.project.ProjectRepository; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.*; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; + +import java.time.LocalDate; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest +@AutoConfigureMockMvc(addFilters = false) +class RemoveEmployeeFromProjectIntegrationTest { + @Autowired + private MockMvc mockMvc; + + @Autowired + private RestTemplate restTemplate; + + @Autowired + private ProjectRepository projectRepository; + + @Test + void removeEmployeeFromProject() throws Exception { + ProjectEntity project = new ProjectEntity(); + project.setComment("comment"); + project.setContractor(1); + project.setContractorName("contractorName"); + project.setEndDate(LocalDate.of(2024, 1, 1)); + project.setLeadingEmployee(1); + project.setName("name"); + project.setStartDate(LocalDate.of(2021, 1, 1)); + project.setEmployees(List.of(1L, 2L, 3L, 312L)); + this.projectRepository.save(project); + + + mockMvc.perform(delete("/projects/{projectId}/employees/{employeeId}", 1, 312) + .header(HttpHeaders.AUTHORIZATION, getBearerToken()) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isNoContent()); + + ProjectEntity updatedProject = projectRepository.findById(1L).get(); + + assert !updatedProject.getEmployees().contains(312L); + } + + private String getBearerToken() { + String url = "https://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token"; + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + + MultiValueMap map = new LinkedMultiValueMap<>(); + map.add("grant_type", "password"); + map.add("client_id", "employee-management-service"); + map.add("username", "user"); + map.add("password", "test"); + + HttpEntity> request = new HttpEntity<>(map, headers); + + ResponseEntity response = this.restTemplate.exchange(url, HttpMethod.POST, request, Map.class); + + return Objects.requireNonNull(response.getBody()).get("access_token").toString(); + } +} -- 2.45.2 From 304a88ae0ec7b75e1aa2919349634a4d452bb968 Mon Sep 17 00:00:00 2001 From: Jan Klattenhoff Date: Wed, 23 Oct 2024 11:42:16 +0200 Subject: [PATCH 3/4] test(UpdateProjectActionTest): update test for not found response --- .../integration/project/UpdateProjectActionTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/de/szut/lf8_starter/integration/project/UpdateProjectActionTest.java b/src/test/java/de/szut/lf8_starter/integration/project/UpdateProjectActionTest.java index e03a680..a38e233 100644 --- a/src/test/java/de/szut/lf8_starter/integration/project/UpdateProjectActionTest.java +++ b/src/test/java/de/szut/lf8_starter/integration/project/UpdateProjectActionTest.java @@ -136,6 +136,6 @@ class UpdateProjectActionTest { @Test void updateProjectShouldReturnNotFoundResponseWhenProjectIsNotFound() throws Exception { - this.mockMvc.perform(put("/projects/2").content("{}").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isNotFound()); + this.mockMvc.perform(put("/projects/98723498798").content("{}").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isNotFound()); } } -- 2.45.2 From d702a867c74996e534441c5bdd6bdc08800f51cf Mon Sep 17 00:00:00 2001 From: Jan Klattenhoff Date: Wed, 23 Oct 2024 11:47:58 +0200 Subject: [PATCH 4/4] test: add 404 response test for non-existent project --- .../RemoveEmployeeFromProjectIntegrationTest.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/test/java/de/szut/lf8_starter/integration/project/RemoveEmployeeFromProjectIntegrationTest.java b/src/test/java/de/szut/lf8_starter/integration/project/RemoveEmployeeFromProjectIntegrationTest.java index 978fd7c..7e55dd8 100644 --- a/src/test/java/de/szut/lf8_starter/integration/project/RemoveEmployeeFromProjectIntegrationTest.java +++ b/src/test/java/de/szut/lf8_starter/integration/project/RemoveEmployeeFromProjectIntegrationTest.java @@ -17,8 +17,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @SpringBootTest @@ -75,4 +74,12 @@ class RemoveEmployeeFromProjectIntegrationTest { return Objects.requireNonNull(response.getBody()).get("access_token").toString(); } + + @Test + void removeEmployeeShouldReturn404IfProjectNotFound() throws Exception { + mockMvc.perform(delete("/projects/{projectId}/employees/{employeeId}", 1987234987, 312) + .header(HttpHeaders.AUTHORIZATION, getBearerToken()) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isNotFound()); + } } -- 2.45.2