Compare commits

...

6 commits

Author SHA1 Message Date
Rajbir Singh
b907501d8b PMT-4: Write Happy Path Test
All checks were successful
Quality Check / Validate OAS (push) Successful in 51s
Quality Check / Validate OAS (pull_request) Successful in 1m4s
Quality Check / Linting (push) Successful in 2m6s
Quality Check / Linting (pull_request) Successful in 2m10s
Quality Check / Testing (push) Successful in 2m20s
Quality Check / Static Analysis (push) Successful in 2m24s
Quality Check / Testing (pull_request) Successful in 2m16s
Quality Check / Static Analysis (pull_request) Successful in 2m20s
2024-10-21 13:09:31 +02:00
Rajbir Singh
96cb218e5c PMT-4: Implement Endpoint
Co-authored-by: Ole Kück <ole.kueck@hmmh.de>
2024-10-21 13:08:08 +02:00
Rajbir Singh
7e1ae9ed2c PMT-4: Implement Repository 2024-10-21 13:06:38 +02:00
81230367b5
PMT-4: Add Database Model for Allocations 2024-10-21 13:04:53 +02:00
Rajbir Singh
675e9a3449 PMT-4: Define Endpoint 2024-10-21 13:03:39 +02:00
a03a608d36
FIX Workflow badge
All checks were successful
Quality Check / Validate OAS (push) Successful in 33s
Quality Check / Linting (push) Successful in 1m8s
Quality Check / Testing (push) Successful in 1m14s
Quality Check / Static Analysis (push) Successful in 1m16s
2024-10-21 05:50:04 +00:00
8 changed files with 214 additions and 6 deletions

View file

@ -1,4 +1,4 @@
![QS Badge](https://git.euph.dev//SZUT/ProjectManagmentTool//actions/workflows/qs.yml/badge.svg)
![QS Badge](https://git.euph.dev//SZUT/ProjectManagmentTool//actions/workflows/qs.yml/badge.svg?branch=trunk)
# ProjectManagmentTool
Schulprojekt zum Erstellen eines Projektverwaltungstools

View file

@ -68,6 +68,15 @@ components:
plannedEnd:
type: string
format: date-time
AddEmployeeDTO:
type: object
properties:
employeeId:
type: integer
format: int64
qualificationId:
type: integer
format: int64
responses:
Unauthorized:
description: "Unauthorized"
@ -147,6 +156,37 @@ paths:
/project/{id}:
post:
operationId: "addEmployee"
description: "Adds an employee to a specific Project"
parameters:
- in: path
name: id
schema:
type: integer
format: int64
required: true
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/AddEmployeeDTO"
responses:
204:
description: "Employee successfully added to the specific Project"
401:
$ref: "#/components/responses/Unauthorized"
404:
$ref: "#/components/responses/NotFound"
409:
$ref: "#/components/responses/Conflict"
422:
$ref: "#/components/responses/UnprocessableContent"
500:
$ref: "#/components/responses/InternalError"
503:
$ref: "#/components/responses/ServiceUnavailable"
delete:
operationId: "deleteProject"
description: "Delete a specific Project"
@ -170,4 +210,3 @@ paths:
type: string
500:
$ref: "#/components/responses/InternalError"

View file

@ -1,13 +1,13 @@
package de.hmmh.pmt;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.hmmh.pmt.db.Allocation;
import de.hmmh.pmt.db.AllocationRepository;
import de.hmmh.pmt.db.Project;
import de.hmmh.pmt.db.ProjectRepository;
import de.hmmh.pmt.dtos.CreateProjectDTO;
import de.hmmh.pmt.dtos.CreatedProjectDTO;
import de.hmmh.pmt.dtos.GetAllProjectsDTO;
import de.hmmh.pmt.dtos.ProjectInfo;
import de.hmmh.pmt.dtos.*;
import de.hmmh.pmt.employee.ApiClientFactory;
import de.hmmh.pmt.employee.dtos.EmployeeResponseDTO;
import de.hmmh.pmt.oas.DefaultApi;
import de.hmmh.pmt.util.Mapper;
import jakarta.servlet.http.HttpServletRequest;
@ -19,6 +19,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestClientException;
import java.time.ZoneOffset;
import java.util.List;
import java.util.Optional;
@Controller
@ -30,6 +32,8 @@ public class ApiController implements DefaultApi {
private ApiClientFactory apiClientFactory;
@Autowired
private ProjectRepository projectRepository;
@Autowired
AllocationRepository allocationRepository;
@Override
public Optional<ObjectMapper> getObjectMapper() {
@ -92,4 +96,51 @@ public class ApiController implements DefaultApi {
CreatedProjectDTO response = mapper.map(project);
return new ResponseEntity<>(response, HttpStatus.CREATED);
}
@Override
public ResponseEntity<Void> addEmployee(Long id, AddEmployeeDTO body) {
Optional<Project> optionalProject = projectRepository.findById(id);
if (optionalProject.isEmpty()) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
Project project = optionalProject.get();
EmployeeResponseDTO employee;
try {
employee = apiClientFactory.getEmployeeApi().findById(body.getEmployeeId());
} catch (HttpClientErrorException exception) {
return new ResponseEntity<>(exception.getStatusCode().equals(HttpStatus.NOT_FOUND)
? HttpStatus.NOT_FOUND
: HttpStatus.SERVICE_UNAVAILABLE);
} catch (RestClientException exception) {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
if (employee.getSkillSet()
.stream()
.noneMatch(qualification -> qualification.getId().equals(body.getQualificationId()))) {
return new ResponseEntity<>(HttpStatus.UNPROCESSABLE_ENTITY);
}
long start = project.getStart().toEpochSecond(ZoneOffset.UTC);
long plannedEnd = project.getPlannedEnd().toEpochSecond(ZoneOffset.UTC);
List<Allocation> allocations = allocationRepository.findAllocationsByEmployeeId(body.getEmployeeId());
if (allocations.stream()
.map(Allocation::getProject)
.anyMatch(allocatedProject -> {
long allocatedStart = allocatedProject.getStart().toEpochSecond(null);
long allocatedPlannedEnd = allocatedProject.getPlannedEnd().toEpochSecond(null);
return Math.max(start, allocatedStart) <= Math.min(plannedEnd, allocatedPlannedEnd);
})) {
return new ResponseEntity<>(HttpStatus.UNPROCESSABLE_ENTITY);
}
Allocation allocation = new Allocation();
allocation.setEmployeeId(employee.getId());
allocation.setRole(body.getQualificationId());
allocation.setProject(project);
allocationRepository.save(allocation);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
}

View file

@ -0,0 +1,34 @@
package de.hmmh.pmt.db;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import lombok.*;
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Entity
@IdClass(AllocationId.class)
@Table(name = "allocation")
public class Allocation {
@Id
@Setter(AccessLevel.NONE)
private Long projectId;
@ManyToOne
@JoinColumn(name = "allocation_project", referencedColumnName = "id", insertable = false, updatable = false)
private Project project;
@Id
private Long employeeId;
@NotNull
private Long role; // This is a QualificationId
public void setProject(Project project) {
this.project = project;
this.projectId = project.getId();
}
}

View file

@ -0,0 +1,18 @@
package de.hmmh.pmt.db;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class AllocationId implements Serializable {
private static final long serialVersionUID = 1L;
private Long projectId;
private Long employeeId;
}

View file

@ -0,0 +1,10 @@
package de.hmmh.pmt.db;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
public interface AllocationRepository extends CrudRepository<Allocation, AllocationId> {
List<Allocation> findAllocationsByEmployeeId(Long employeeId);
}

View file

@ -4,6 +4,10 @@
<Class name="de.hmmh.pmt.employee.ApiClientFactory"/>
<Bug code="M,V,EI"/>
</Match>
<Match>
<Class name="de.hmmh.pmt.db.Allocation"/>
<Bug code="M,V,EI,EI2"/>
</Match>
<Match>
<!--Ignore Auto Generated Code -->
<Source name="~.*build/.*"/>

View file

@ -0,0 +1,52 @@
package de.hmmh.pmt.project;
import de.hmmh.pmt.IntegrationTest;
import de.hmmh.pmt.db.Project;
import de.hmmh.pmt.dtos.AddEmployeeDTO;
import de.hmmh.pmt.employee.dtos.EmployeeResponseDTO;
import de.hmmh.pmt.employee.dtos.QualificationGetDTO;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.List;
import java.util.Map;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.when;
public class AddEmployeeTest extends IntegrationTest {
@Test
void addValidEmployee() throws Exception {
EmployeeResponseDTO employee= new EmployeeResponseDTO();
employee.setId(2L);
employee.setSkillSet(List.of(newQualification(1L)));
when(mockEmployeeApi.findById(anyLong()))
.thenReturn(employee);
Map<String, Project> allProjects = createTestProjectData();
AddEmployeeDTO addEmployeeDTO = new AddEmployeeDTO();
addEmployeeDTO.setEmployeeId(1L);
addEmployeeDTO.setQualificationId(1L);
RequestBuilder request = MockMvcRequestBuilders
.post(baseUri + "/project/" + allProjects.get("research-lab").getId())
.contentType(MediaType.APPLICATION_JSON)
.content(this.objectMapper.writeValueAsString(addEmployeeDTO));
this.mvc
.perform(request)
.andExpect(status().isNoContent());
}
private static QualificationGetDTO newQualification(Long id){
QualificationGetDTO qualificationGetDTO = new QualificationGetDTO();
qualificationGetDTO.setId(id);
return qualificationGetDTO;
}
}