Skip to content

Commit eb54dfa

Browse files
committed
feat: implement experience type endpoint #35
1 parent 393eb0e commit eb54dfa

10 files changed

Lines changed: 376 additions & 0 deletions

File tree

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package ch.puzzle.pcts.controller;
2+
3+
import ch.puzzle.pcts.dto.experienceType.ExperienceTypeDto;
4+
import ch.puzzle.pcts.mapper.ExperienceTypeMapper;
5+
import ch.puzzle.pcts.model.experienceType.ExperienceType;
6+
import ch.puzzle.pcts.service.business.ExperienceTypeBusinessService;
7+
import io.swagger.v3.oas.annotations.Operation;
8+
import io.swagger.v3.oas.annotations.media.ArraySchema;
9+
import io.swagger.v3.oas.annotations.media.Content;
10+
import io.swagger.v3.oas.annotations.media.Schema;
11+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
12+
import io.swagger.v3.oas.annotations.responses.ApiResponses;
13+
import jakarta.validation.Valid;
14+
import java.util.List;
15+
import org.springframework.beans.factory.annotation.Autowired;
16+
import org.springframework.http.ResponseEntity;
17+
import org.springframework.web.bind.annotation.*;
18+
19+
@RestController
20+
@RequestMapping("/api/v1/experience-types")
21+
public class ExperienceTypeController {
22+
private final ExperienceTypeMapper mapper;
23+
private final ExperienceTypeBusinessService service;
24+
25+
@Autowired
26+
public ExperienceTypeController(ExperienceTypeMapper mapper, ExperienceTypeBusinessService service) {
27+
this.mapper = mapper;
28+
this.service = service;
29+
}
30+
31+
@Operation(summary = "List all experience-types")
32+
@ApiResponse(responseCode = "200", description = "A list of experience-types", content = {
33+
@Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = ExperienceTypeDto.class))) })
34+
@GetMapping
35+
public ResponseEntity<List<ExperienceTypeDto>> getExperienceType() {
36+
return ResponseEntity.ok(mapper.toDto(service.getAll()));
37+
}
38+
39+
@Operation(summary = "Get a experience-type by ID")
40+
@ApiResponses(value = { @ApiResponse(responseCode = "200", description = "A single experience-type", content = {
41+
@Content(mediaType = "application/json", schema = @Schema(implementation = ExperienceTypeDto.class)) }),
42+
@ApiResponse(responseCode = "404", description = "Experience-type not found", content = @Content) })
43+
@GetMapping("{id}")
44+
public ResponseEntity<ExperienceTypeDto> getExperienceTypeById(@PathVariable long id) {
45+
ExperienceType experienceType = service.getById(id);
46+
return ResponseEntity.ok(mapper.toDto(experienceType));
47+
}
48+
49+
@Operation(summary = "Create a new experience-type")
50+
@ApiResponse(responseCode = "201", description = "ExperienceType created successfully", content = {
51+
@Content(mediaType = "application/json", schema = @Schema(implementation = ExperienceTypeDto.class)) })
52+
@PostMapping
53+
public ResponseEntity<ExperienceTypeDto> createNew(@Valid @RequestBody ExperienceTypeDto dto) {
54+
ExperienceType newExperienceType = service.create(mapper.fromDto(dto));
55+
return ResponseEntity.status(201).body(mapper.toDto(newExperienceType));
56+
}
57+
58+
@Operation(summary = "Update a experience-type")
59+
@ApiResponses(value = {
60+
@ApiResponse(responseCode = "200", description = "ExperienceType updated successfully", content = {
61+
@Content(mediaType = "application/json", schema = @Schema(implementation = ExperienceTypeDto.class)) }),
62+
@ApiResponse(responseCode = "404", description = "ExperienceType not found", content = @Content) })
63+
@PutMapping("{id}")
64+
public ResponseEntity<ExperienceTypeDto> updateExperienceType(@PathVariable Long id,
65+
@RequestBody ExperienceTypeDto dto) {
66+
ExperienceType updatedExperienceType = service.update(id, mapper.fromDto(dto));
67+
return ResponseEntity.ok(mapper.toDto(updatedExperienceType));
68+
}
69+
70+
@Operation(summary = "Delete a experience-type")
71+
@ApiResponses(value = {
72+
@ApiResponse(responseCode = "204", description = "ExperienceType deleted successfully", content = @Content),
73+
@ApiResponse(responseCode = "404", description = "ExperienceType not found", content = @Content) })
74+
@DeleteMapping("{id}")
75+
public ResponseEntity<Void> deleteExperienceType(@PathVariable Long id) {
76+
service.delete(id);
77+
return ResponseEntity.status(204).build();
78+
}
79+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package ch.puzzle.pcts.dto.experienceType;
2+
3+
import java.math.BigDecimal;
4+
5+
public record ExperienceTypeDto(Long id, String name, BigDecimal highlyRelevantPoints, BigDecimal limitedRelevantPoints,
6+
BigDecimal littleRelevantPoints) {
7+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package ch.puzzle.pcts.mapper;
2+
3+
import ch.puzzle.pcts.dto.experienceType.ExperienceTypeDto;
4+
import ch.puzzle.pcts.model.experienceType.ExperienceType;
5+
import java.util.List;
6+
import org.springframework.stereotype.Component;
7+
8+
@Component
9+
public class ExperienceTypeMapper {
10+
11+
public List<ExperienceTypeDto> toDto(List<ExperienceType> models) {
12+
return models.stream().map(this::toDto).toList();
13+
}
14+
15+
public List<ExperienceType> fromDto(List<ExperienceTypeDto> dtos) {
16+
return dtos.stream().map(this::fromDto).toList();
17+
}
18+
19+
public ExperienceTypeDto toDto(ExperienceType model) {
20+
return new ExperienceTypeDto(model.getId(),
21+
model.getName(),
22+
model.getHighlyRelevantPoints(),
23+
model.getLimitedRelevantPoints(),
24+
model.getLittleRelevantPoints());
25+
}
26+
27+
public ExperienceType fromDto(ExperienceTypeDto dto) {
28+
return new ExperienceType(dto
29+
.id(), dto.name(), dto.highlyRelevantPoints(), dto.limitedRelevantPoints(), dto.littleRelevantPoints());
30+
}
31+
}

backend/src/main/java/ch/puzzle/pcts/model/error/ErrorKey.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ public enum ErrorKey {
88
NOT_FOUND,
99
ROLE_NAME_IS_NULL,
1010
ROLE_NAME_IS_EMPTY,
11+
EXPERIENCE_TYPE_NAME_IS_NULL,
12+
EXPERIENCE_TYPE_NAME_IS_EMPTY,
1113
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package ch.puzzle.pcts.model.experienceType;
2+
3+
import jakarta.persistence.Entity;
4+
import jakarta.persistence.GeneratedValue;
5+
import jakarta.persistence.GenerationType;
6+
import jakarta.persistence.Id;
7+
import java.math.BigDecimal;
8+
9+
@Entity
10+
public class ExperienceType {
11+
@Id
12+
@GeneratedValue(strategy = GenerationType.IDENTITY)
13+
private Long id;
14+
15+
private String name;
16+
17+
private BigDecimal highlyRelevantPoints;
18+
19+
private BigDecimal limitedRelevantPoints;
20+
21+
private BigDecimal littleRelevantPoints;
22+
23+
public ExperienceType(Long id, String name, BigDecimal highlyRelevantPoints, BigDecimal limitedRelevantPoints,
24+
BigDecimal littleRelevantPoints) {
25+
this.id = id;
26+
this.name = name;
27+
this.highlyRelevantPoints = highlyRelevantPoints;
28+
this.limitedRelevantPoints = limitedRelevantPoints;
29+
this.littleRelevantPoints = littleRelevantPoints;
30+
}
31+
32+
public ExperienceType() {
33+
}
34+
35+
public Long getId() {
36+
return id;
37+
}
38+
39+
public void setId(Long id) {
40+
this.id = id;
41+
}
42+
43+
public String getName() {
44+
return name;
45+
}
46+
47+
public void setName(String name) {
48+
this.name = name;
49+
}
50+
51+
public BigDecimal getHighlyRelevantPoints() {
52+
return highlyRelevantPoints;
53+
}
54+
55+
public void setHighlyRelevantPoints(BigDecimal highlyRelevantPoints) {
56+
this.highlyRelevantPoints = highlyRelevantPoints;
57+
}
58+
59+
public BigDecimal getLimitedRelevantPoints() {
60+
return limitedRelevantPoints;
61+
}
62+
63+
public void setLimitedRelevantPoints(BigDecimal limitedRelevantPoints) {
64+
this.limitedRelevantPoints = limitedRelevantPoints;
65+
}
66+
67+
public BigDecimal getLittleRelevantPoints() {
68+
return littleRelevantPoints;
69+
}
70+
71+
public void setLittleRelevantPoints(BigDecimal littleRelevantPoints) {
72+
this.littleRelevantPoints = littleRelevantPoints;
73+
}
74+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package ch.puzzle.pcts.repository;
2+
3+
import ch.puzzle.pcts.model.experienceType.ExperienceType;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
import org.springframework.stereotype.Repository;
6+
7+
@Repository
8+
public interface ExperienceTypeRepository extends JpaRepository<ExperienceType, Long> {
9+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package ch.puzzle.pcts.service.business;
2+
3+
import ch.puzzle.pcts.exception.PCTSException;
4+
import ch.puzzle.pcts.model.error.ErrorKey;
5+
import ch.puzzle.pcts.model.experienceType.ExperienceType;
6+
import ch.puzzle.pcts.service.persistence.ExperienceTypePersistenceService;
7+
import ch.puzzle.pcts.service.validation.ExperienceTypeValidationService;
8+
import java.util.List;
9+
import org.springframework.http.HttpStatus;
10+
import org.springframework.stereotype.Service;
11+
12+
@Service
13+
public class ExperienceTypeBusinessService {
14+
private final ExperienceTypeValidationService validationService;
15+
private final ExperienceTypePersistenceService persistenceService;
16+
17+
public ExperienceTypeBusinessService(ExperienceTypeValidationService validationService,
18+
ExperienceTypePersistenceService persistenceService) {
19+
this.validationService = validationService;
20+
this.persistenceService = persistenceService;
21+
}
22+
23+
public List<ExperienceType> getAll() {
24+
return persistenceService.getAll();
25+
}
26+
27+
public ExperienceType getById(long id) {
28+
validationService.validateOnGetById(id);
29+
return persistenceService
30+
.getById(id)
31+
.orElseThrow(() -> new PCTSException(HttpStatus.NOT_FOUND,
32+
"ExperienceType with id: " + id + " does not exist.",
33+
ErrorKey.NOT_FOUND));
34+
}
35+
36+
public ExperienceType create(ExperienceType experienceType) {
37+
validationService.validateOnCreate(experienceType);
38+
return persistenceService.create(experienceType);
39+
}
40+
41+
public ExperienceType update(Long id, ExperienceType experienceType) {
42+
validationService.validateOnUpdate(id, experienceType);
43+
return persistenceService.update(id, experienceType);
44+
}
45+
46+
public void delete(Long id) {
47+
validationService.validateOnDelete(id);
48+
persistenceService.delete(id);
49+
}
50+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package ch.puzzle.pcts.service.persistence;
2+
3+
import ch.puzzle.pcts.model.experienceType.ExperienceType;
4+
import ch.puzzle.pcts.repository.ExperienceTypeRepository;
5+
import java.util.List;
6+
import java.util.Optional;
7+
import org.springframework.beans.factory.annotation.Autowired;
8+
import org.springframework.stereotype.Component;
9+
10+
@Component
11+
public class ExperienceTypePersistenceService {
12+
private final ExperienceTypeRepository repository;
13+
14+
@Autowired
15+
public ExperienceTypePersistenceService(ExperienceTypeRepository repository) {
16+
this.repository = repository;
17+
}
18+
19+
public ExperienceType create(ExperienceType role) {
20+
return repository.save(role);
21+
}
22+
23+
public Optional<ExperienceType> getById(long id) {
24+
return repository.findById(id);
25+
}
26+
27+
public List<ExperienceType> getAll() {
28+
return repository.findAll();
29+
}
30+
31+
public ExperienceType update(Long id, ExperienceType experience) {
32+
experience.setId(id);
33+
return repository.save(experience);
34+
}
35+
36+
public void delete(Long id) {
37+
repository.deleteById(id);
38+
}
39+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package ch.puzzle.pcts.service.validation;
2+
3+
import ch.puzzle.pcts.exception.PCTSException;
4+
import ch.puzzle.pcts.model.error.ErrorKey;
5+
import ch.puzzle.pcts.model.experienceType.ExperienceType;
6+
import ch.puzzle.pcts.service.persistence.ExperienceTypePersistenceService;
7+
import org.springframework.beans.factory.annotation.Autowired;
8+
import org.springframework.http.HttpStatus;
9+
import org.springframework.stereotype.Component;
10+
11+
@Component
12+
public class ExperienceTypeValidationService {
13+
private final ExperienceTypePersistenceService persistenceService;
14+
15+
@Autowired
16+
public ExperienceTypeValidationService(ExperienceTypePersistenceService persistenceService) {
17+
this.persistenceService = persistenceService;
18+
}
19+
20+
public void validateOnGetById(Long id) {
21+
validateIfExists(id);
22+
}
23+
24+
public void validateOnCreate(ExperienceType experienceType) {
25+
validateIfIdIsNull(experienceType.getId());
26+
validateName(experienceType.getName());
27+
}
28+
29+
public void validateOnDelete(Long id) {
30+
validateIfExists(id);
31+
}
32+
33+
public void validateOnUpdate(Long id, ExperienceType experienceType) {
34+
validateIfExists(id);
35+
validateIfIdIsNull(experienceType.getId());
36+
validateName(experienceType.getName());
37+
}
38+
39+
private void validateIfIdIsNull(Long id) {
40+
if (id != null) {
41+
throw new PCTSException(HttpStatus.BAD_REQUEST, "Id needs to be undefined", ErrorKey.ID_IS_NOT_NULL);
42+
}
43+
}
44+
45+
private void validateName(String name) {
46+
if (name == null) {
47+
throw new PCTSException(HttpStatus.BAD_REQUEST,
48+
"Name must not be null",
49+
ErrorKey.EXPERIENCE_TYPE_NAME_IS_NULL);
50+
}
51+
52+
if (name.isBlank()) {
53+
throw new PCTSException(HttpStatus.BAD_REQUEST,
54+
"Name must not be empty",
55+
ErrorKey.EXPERIENCE_TYPE_NAME_IS_EMPTY);
56+
}
57+
}
58+
59+
private void validateIfExists(long id) {
60+
persistenceService
61+
.getById(id)
62+
.orElseThrow(() -> new PCTSException(HttpStatus.NOT_FOUND,
63+
"ExperienceType with id: " + id + " does not exist.",
64+
ErrorKey.NOT_FOUND));
65+
}
66+
67+
// private void validateIfPointsArePositive(BigDecimal highlyRelevantPoints,
68+
// BigDecimal limitedRelevantPoints,
69+
// BigDecimal littleRelevantPoints) {
70+
// if (highlyRelevantPoints.signum() < 0|| limitedRelevantPoints.signum() < 0||
71+
// littleRelevantPoints.signum() < 0){
72+
//
73+
//
74+
// }
75+
//
76+
// }
77+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CREATE TABLE IF NOT EXISTS experience_type
2+
(
3+
id BIGINT NOT NUll PRIMARY KEY,
4+
name TEXT NOT NULL,
5+
highly_relevant_points DECIMAL NOT NULL,
6+
limited_relevant_points DECIMAL NOT NULL,
7+
little_relevant_points DECIMAL NOT NULL
8+
);

0 commit comments

Comments
 (0)