feat: Implement feature to acknowledge project time frames when assigning employees to projects (SCRUM-7 SCRUM-2) (!38)
All checks were successful
Build / Build and analyze (push) Successful in 1m34s
Quality Check / Tests (push) Successful in 1m0s
Quality Check / Checkstyle Main (push) Successful in 25s
Release / Release (push) Successful in 43s

Co-authored-by: Phan Huy Tran <p.tran@neusta.de>
Reviewed-on: #38
Co-authored-by: Phan Huy Tran <ptran@noreply.localhost>
Co-committed-by: Phan Huy Tran <ptran@noreply.localhost>
This commit is contained in:
Phan Huy Tran 2024-10-25 05:01:10 +00:00 committed by Jan Gleytenhoover
commit 5f6caa7fc2
16 changed files with 334 additions and 54 deletions

View file

@ -1,5 +1,6 @@
package de.szut.lf8_starter.project;
import de.szut.lf8_starter.project.dto.project.GetProjectDto;
import org.springframework.stereotype.Service;
import java.util.List;
@ -32,4 +33,18 @@ public class ProjectService {
public void delete(Long id) {
this.projectRepository.deleteById(id);
}
public boolean isOverlapping(GetProjectDto getProjectDto, ProjectEntity existingProjectEntity) {
return isDateRangeOverlapping(getProjectDto, existingProjectEntity) || isDateEqual(getProjectDto, existingProjectEntity);
}
private boolean isDateRangeOverlapping(GetProjectDto getProjectDto, ProjectEntity existingProjectEntity) {
return getProjectDto.getStartDate().isBefore(existingProjectEntity.getPlannedEndDate())
&& getProjectDto.getPlannedEndDate().isAfter(existingProjectEntity.getStartDate());
}
private boolean isDateEqual(GetProjectDto getProjectDto, ProjectEntity existingProjectEntity) {
return getProjectDto.getStartDate().isEqual(existingProjectEntity.getStartDate())
|| getProjectDto.getPlannedEndDate().isEqual(existingProjectEntity.getPlannedEndDate());
}
}

View file

@ -1,5 +1,6 @@
package de.szut.lf8_starter.project.action.crud;
import de.szut.lf8_starter.employee.EmployeeService;
import de.szut.lf8_starter.project.ProjectEntity;
import de.szut.lf8_starter.project.ProjectService;
import de.szut.lf8_starter.project.dto.project.CreateProjectDto;
@ -12,15 +13,18 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping(value = "/projects")
public class CreateProjectAction {
private final EmployeeService employeeService;
private final ProjectService projectService;
private final ProjectMapper projectMapper;
public CreateProjectAction(ProjectService projectService, ProjectMapper mappingService) {
public CreateProjectAction(EmployeeService employeeService, ProjectService projectService, ProjectMapper mappingService) {
this.employeeService = employeeService;
this.projectService = projectService;
this.projectMapper = mappingService;
}
@ -29,14 +33,31 @@ public class CreateProjectAction {
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "created project", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = GetProjectDto.class))}),
@ApiResponse(responseCode = "400", description = "invalid JSON posted", content = @Content),
@ApiResponse(responseCode = "401", description = "not authorized", content = @Content)})
@ApiResponse(responseCode = "401", description = "not authorized", content = @Content),
@ApiResponse(responseCode = "409", description = "Project dates conflict", content = @Content)
})
@PostMapping
@ResponseStatus(code = HttpStatus.CREATED)
public GetProjectDto create(@RequestBody @Valid CreateProjectDto createProjectDto) {
ProjectEntity projectEntity = this.projectMapper.mapCreateDtoToEntity(createProjectDto);
public ResponseEntity<Object> create(
@RequestBody @Valid CreateProjectDto createProjectDto,
@RequestHeader("Authorization") String accessToken
) {
ProjectEntity project = this.projectMapper.mapCreateDtoToEntity(createProjectDto);
projectEntity = this.projectService.create(projectEntity);
for (Long employeeId : createProjectDto.getEmployees()) {
if (!this.employeeService.employeeExists(accessToken, employeeId)) {
return new ResponseEntity<>("Employee with ID: " + employeeId + " not found", HttpStatus.NOT_FOUND);
}
return this.projectMapper.mapToGetDto(projectEntity);
for (GetProjectDto getProjectDto : this.employeeService.getProjects(employeeId)) {
if (projectService.isOverlapping(getProjectDto, project)) {
return new ResponseEntity<>("Project dates conflict with an existing project for Employee with ID: " + employeeId, HttpStatus.CONFLICT);
}
}
}
this.projectService.create(project);
return new ResponseEntity<>(this.projectMapper.mapToGetDto(project), HttpStatus.CREATED);
}
}

View file

@ -1,4 +1,4 @@
package de.szut.lf8_starter.project.action;
package de.szut.lf8_starter.project.action.crud;
import de.szut.lf8_starter.project.ProjectEntity;
import de.szut.lf8_starter.project.ProjectService;

View file

@ -3,6 +3,7 @@ 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 de.szut.lf8_starter.project.dto.project.GetProjectDto;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
@ -29,7 +30,8 @@ public class AddEmployeeToProjectAction {
@Operation(summary = "Add an employee to a project")
@ApiResponses(value = {
@ApiResponse(responseCode = "204", description = "Employee added to project"),
@ApiResponse(responseCode = "404", description = "Project or employee not found", content = @Content)
@ApiResponse(responseCode = "404", description = "Project or employee not found", content = @Content),
@ApiResponse(responseCode = "409", description = "Project dates conflict", content = @Content)
})
@PostMapping("/projects/{projectId}/employees/{employeeId}")
public ResponseEntity<Object> create(
@ -37,18 +39,26 @@ public class AddEmployeeToProjectAction {
@PathVariable Long employeeId,
@RequestHeader("Authorization") String accessToken
) {
Optional<ProjectEntity> project = this.projectService.findById(projectId);
Optional<ProjectEntity> optionalProject = this.projectService.findById(projectId);
if (project.isEmpty()) {
if (optionalProject.isEmpty()) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
ProjectEntity projectEntity = optionalProject.get();
if (!this.employeeService.employeeExists(accessToken, employeeId)) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
project.get().getEmployees().add(employeeId);
this.projectService.update(project.get());
for (GetProjectDto getProjectDto : this.employeeService.getProjects(employeeId)) {
if (this.projectService.isOverlapping(getProjectDto, projectEntity)) {
return new ResponseEntity<>("Project dates conflict with an existing project for Employee with ID: " + employeeId, HttpStatus.CONFLICT);
}
}
projectEntity.getEmployees().add(employeeId);
this.projectService.update(projectEntity);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}