From ee90ff7a5ece7c2f0fa24de518a42161237f5c69 Mon Sep 17 00:00:00 2001 From: Jan Klattenhoff Date: Wed, 25 Sep 2024 12:05:12 +0200 Subject: [PATCH 1/3] feat(project): add ProjectController, Service, Mapper, and DTO --- .../project/ProjectController.java | 38 +++++++++++++++++++ .../lf8_starter/project/ProjectMapper.java | 21 ++++++++++ .../lf8_starter/project/ProjectService.java | 21 ++++++++++ .../project/dto/ProjectGetDto.java | 29 ++++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 src/main/java/de/szut/lf8_starter/project/ProjectController.java create mode 100644 src/main/java/de/szut/lf8_starter/project/ProjectMapper.java create mode 100644 src/main/java/de/szut/lf8_starter/project/ProjectService.java create mode 100644 src/main/java/de/szut/lf8_starter/project/dto/ProjectGetDto.java diff --git a/src/main/java/de/szut/lf8_starter/project/ProjectController.java b/src/main/java/de/szut/lf8_starter/project/ProjectController.java new file mode 100644 index 0000000..259efff --- /dev/null +++ b/src/main/java/de/szut/lf8_starter/project/ProjectController.java @@ -0,0 +1,38 @@ +package de.szut.lf8_starter.project; + +import de.szut.lf8_starter.project.dto.ProjectGetDto; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping(value = "projects") +public class ProjectController { + private final ProjectService service; + private final ProjectMapper projectMapper; + public ProjectController(ProjectService service, ProjectMapper projectMapper) { + this.service = service; + this.projectMapper = projectMapper; + } + + @Operation(summary = "returns all projects") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "all projects", + content = {@Content(mediaType = "application/json", + schema = @Schema(implementation = ProjectGetDto.class))}), + @ApiResponse(responseCode = "401", description = "not authorized", + content = @Content)}) + @GetMapping + public List findAll() { + return this.service + .readAll() + .stream() + .map(this.projectMapper::mapToGetDto) + .toList(); + } +} \ No newline at end of file diff --git a/src/main/java/de/szut/lf8_starter/project/ProjectMapper.java b/src/main/java/de/szut/lf8_starter/project/ProjectMapper.java new file mode 100644 index 0000000..1846038 --- /dev/null +++ b/src/main/java/de/szut/lf8_starter/project/ProjectMapper.java @@ -0,0 +1,21 @@ +package de.szut.lf8_starter.project; + +import de.szut.lf8_starter.project.dto.ProjectGetDto; +import org.springframework.stereotype.Service; + +@Service +public class ProjectMapper { + public ProjectGetDto mapToGetDto(ProjectEntity entity) { + return new ProjectGetDto( + entity.getId(), + entity.getName(), + entity.getLeadingEmployee(), + entity.getEmployees(), + entity.getContractor(), + entity.getContractorName(), + entity.getComment(), + entity.getStartDate(), + entity.getEndDate() + ); + } +} diff --git a/src/main/java/de/szut/lf8_starter/project/ProjectService.java b/src/main/java/de/szut/lf8_starter/project/ProjectService.java new file mode 100644 index 0000000..8aeedfa --- /dev/null +++ b/src/main/java/de/szut/lf8_starter/project/ProjectService.java @@ -0,0 +1,21 @@ +package de.szut.lf8_starter.project; + +import de.szut.lf8_starter.hello.HelloEntity; +import de.szut.lf8_starter.hello.HelloRepository; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +public class ProjectService { + private final ProjectRepository repository; + + public ProjectService(ProjectRepository repository) { + this.repository = repository; + } + + public List readAll() { + return this.repository.findAll(); + } +} diff --git a/src/main/java/de/szut/lf8_starter/project/dto/ProjectGetDto.java b/src/main/java/de/szut/lf8_starter/project/dto/ProjectGetDto.java new file mode 100644 index 0000000..4d53212 --- /dev/null +++ b/src/main/java/de/szut/lf8_starter/project/dto/ProjectGetDto.java @@ -0,0 +1,29 @@ +package de.szut.lf8_starter.project.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.time.LocalDate; +import java.util.List; + +@Data +@AllArgsConstructor +public class ProjectGetDto { + private long id; + + private String name; + + private long leadingEmployee; + + private List employees; + + private long contractor; + + private String contractorName; + + private String comment; + + private LocalDate startDate; + + private LocalDate endDate; +} From f33721f16d425b042e99662d1cfbe17a1179eb51 Mon Sep 17 00:00:00 2001 From: Jan Klattenhoff Date: Wed, 25 Sep 2024 12:07:18 +0200 Subject: [PATCH 2/3] style(ProjectController): fix missing newline at end of file --- .../java/de/szut/lf8_starter/project/ProjectController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/szut/lf8_starter/project/ProjectController.java b/src/main/java/de/szut/lf8_starter/project/ProjectController.java index 259efff..e39c274 100644 --- a/src/main/java/de/szut/lf8_starter/project/ProjectController.java +++ b/src/main/java/de/szut/lf8_starter/project/ProjectController.java @@ -35,4 +35,4 @@ public class ProjectController { .map(this.projectMapper::mapToGetDto) .toList(); } -} \ No newline at end of file +} From 6d5f67f7ca2f0d955bfd713f50050a48d1265ee3 Mon Sep 17 00:00:00 2001 From: Jan Klattenhoff Date: Wed, 25 Sep 2024 13:01:54 +0200 Subject: [PATCH 3/3] feat: add authentication helper and project findAll test --- .../project/ProjectRepository.java | 2 + .../project/utils/AuthenticationHelper.java | 35 +++++++++++ .../integration/project/ProjectFindAll.java | 61 +++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 src/main/java/de/szut/lf8_starter/project/utils/AuthenticationHelper.java create mode 100644 src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAll.java diff --git a/src/main/java/de/szut/lf8_starter/project/ProjectRepository.java b/src/main/java/de/szut/lf8_starter/project/ProjectRepository.java index 9798fc8..6f7e33f 100644 --- a/src/main/java/de/szut/lf8_starter/project/ProjectRepository.java +++ b/src/main/java/de/szut/lf8_starter/project/ProjectRepository.java @@ -1,6 +1,8 @@ package de.szut.lf8_starter.project; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +@Repository public interface ProjectRepository extends JpaRepository { } diff --git a/src/main/java/de/szut/lf8_starter/project/utils/AuthenticationHelper.java b/src/main/java/de/szut/lf8_starter/project/utils/AuthenticationHelper.java new file mode 100644 index 0000000..2a9d397 --- /dev/null +++ b/src/main/java/de/szut/lf8_starter/project/utils/AuthenticationHelper.java @@ -0,0 +1,35 @@ +package de.szut.lf8_starter.project.utils; + +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +public interface AuthenticationHelper { + + default String getAuthenticationToken(TestRestTemplate restTemplate) { + MultiValueMap authParams = new LinkedMultiValueMap<>(); + authParams.add("grant_type", "password"); + authParams.add("client_id", "employee-management-service"); + authParams.add("username", "user"); + authParams.add("password", "test"); + + HttpHeaders headers = new HttpHeaders(); + headers.set("Content-Type", "application/x-www-form-urlencoded"); + + HttpEntity> request = new HttpEntity<>(authParams, headers); + ResponseEntity authResponse = restTemplate.postForEntity("https://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token", request, String.class); + + // Extract the token from the response + String responseBody = authResponse.getBody(); + assert responseBody != null; + + return "Bearer " + extractToken(responseBody); + } + + private String extractToken(String responseBody) { + return responseBody.substring(responseBody.indexOf("access_token\":\"") + 15, responseBody.indexOf("\"", responseBody.indexOf("access_token\":\"") + 15)); + } +} \ No newline at end of file diff --git a/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAll.java b/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAll.java new file mode 100644 index 0000000..ab87527 --- /dev/null +++ b/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAll.java @@ -0,0 +1,61 @@ +package de.szut.lf8_starter.integration.project; + +import de.szut.lf8_starter.project.ProjectEntity; +import de.szut.lf8_starter.project.ProjectRepository; +import de.szut.lf8_starter.project.utils.AuthenticationHelper; +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.boot.test.web.client.TestRestTemplate; +import org.springframework.test.web.servlet.MockMvc; + +import java.time.LocalDate; +import java.util.List; + +import static org.hamcrest.collection.IsCollectionWithSize.hasSize; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@AutoConfigureMockMvc +public class ProjectFindAll implements AuthenticationHelper { + @Autowired + private ProjectRepository projectRepository; + + @Autowired + private MockMvc mockMvc; + + @Autowired + private TestRestTemplate restTemplate; + + @Test + void findAllProjects() throws Exception { + var project = new ProjectEntity(); + project.setId(1); + 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)); + this.projectRepository.save(project); + + this.mockMvc.perform(get("/projects").header("Authorization", getAuthenticationToken(restTemplate))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(1))) + .andExpect(jsonPath("$[0].id").value(1)) + .andExpect(jsonPath("$[0].comment").value("comment")) + .andExpect(jsonPath("$[0].contractor").value(1)) + .andExpect(jsonPath("$[0].contractorName").value("contractorName")) + .andExpect(jsonPath("$[0].endDate").value("2024-01-01")) + .andExpect(jsonPath("$[0].leadingEmployee").value(1)) + .andExpect(jsonPath("$[0].name").value("name")) + .andExpect(jsonPath("$[0].startDate").value("2021-01-01")) + .andExpect(jsonPath("$[0].employees").isArray()) + .andExpect(jsonPath("$[0].employees", hasSize(3))); + } +}