From 76b0201cf2fec3d2b40feefe80a1f55339278fef Mon Sep 17 00:00:00 2001 From: Jan Klattenhoff Date: Wed, 23 Oct 2024 09:51:12 +0000 Subject: [PATCH] feat(employee): add action to remove employee from project (SCRUM-23) (!35) Reviewed-on: https://git.kjan.de/jank/LF8/pulls/35 Reviewed-by: Phan Huy Tran Co-authored-by: Jan Klattenhoff Co-committed-by: Jan Klattenhoff --- .../RemoveEmployeeFromProjectAction.java | 52 ++++++++++++ ...oveEmployeeFromProjectIntegrationTest.java | 85 +++++++++++++++++++ .../project/UpdateProjectActionTest.java | 2 +- 3 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 src/main/java/de/szut/lf8_starter/project/action/employee/RemoveEmployeeFromProjectAction.java create mode 100644 src/test/java/de/szut/lf8_starter/integration/project/RemoveEmployeeFromProjectIntegrationTest.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); + } +} 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..7e55dd8 --- /dev/null +++ b/src/test/java/de/szut/lf8_starter/integration/project/RemoveEmployeeFromProjectIntegrationTest.java @@ -0,0 +1,85 @@ +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.*; +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(); + } + + @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()); + } +} 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()); } }