Skip to content

Commit 92bcf57

Browse files
lcanobbionevio18324schiltpuzzle
authored
feat: Add /role endpoint #34
* feat: add role entity class #34 * feat: add role dto #34 * feat: add role mapper and rename dto class #34 * feat: add role repository #34 * feat: add validation business and persitience service #34 * feat: add role migration #34 * refactor: add attribute isManagement to role #34 * feat: add role controller and add isManagement to migration #34 * feat: add all enpoints and modified migration #34 * fix: review improvements #34 * fix: change datatype from varchar to text #34 * fix: change from @where to @sqlrestriction because where is obsoltetd #34 * fix: rename file like okr and change id assigment #34 * fix: internal server error when searching for a not existing role #34 * fix: internal server error when searching for a not existing role #34 * fix: change namo of test-data-migration to avoid version problems #34 * test: add all tests about role #34 * chore: change sonar warnings #34 * fix: naming and delete service returns void #34 * fix: review improvements #34 * chore: format one test and set default value to isManagement --------- Co-authored-by: Nevio Di Gennaro <digennaro@puzzle.ch> Co-authored-by: schiltpzzle <schilt@puzzle.ch>
1 parent e67fefe commit 92bcf57

17 files changed

Lines changed: 927 additions & 12 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.role.RoleDto;
4+
import ch.puzzle.pcts.mapper.RoleMapper;
5+
import ch.puzzle.pcts.model.role.Role;
6+
import ch.puzzle.pcts.service.business.RoleBusinessService;
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/roles")
21+
public class RoleController {
22+
private final RoleMapper mapper;
23+
private final RoleBusinessService service;
24+
25+
@Autowired
26+
public RoleController(RoleMapper mapper, RoleBusinessService service) {
27+
this.mapper = mapper;
28+
this.service = service;
29+
}
30+
31+
@Operation(summary = "List all roles")
32+
@ApiResponse(responseCode = "200", description = "A list of roles", content = {
33+
@Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = RoleDto.class))) })
34+
@GetMapping
35+
public ResponseEntity<List<RoleDto>> getRole() {
36+
return ResponseEntity.ok(mapper.toDto(service.getAll()));
37+
}
38+
39+
@Operation(summary = "Get a role by ID")
40+
@ApiResponses(value = {
41+
@ApiResponse(responseCode = "200", description = "A single role", content = {
42+
@Content(mediaType = "application/json", schema = @Schema(implementation = RoleDto.class)) }),
43+
@ApiResponse(responseCode = "404", description = "Role not found", content = @Content) })
44+
@GetMapping("{id}")
45+
public ResponseEntity<RoleDto> getRoleById(@PathVariable long id) {
46+
Role role = service.getById(id);
47+
return ResponseEntity.ok(mapper.toDto(role));
48+
}
49+
50+
@Operation(summary = "Create a new role")
51+
@ApiResponse(responseCode = "201", description = "Role created successfully", content = {
52+
@Content(mediaType = "application/json", schema = @Schema(implementation = RoleDto.class)) })
53+
@PostMapping
54+
public ResponseEntity<RoleDto> createNew(@Valid @RequestBody RoleDto dto) {
55+
Role newRole = service.create(mapper.fromDto(dto));
56+
return ResponseEntity.status(201).body(mapper.toDto(newRole));
57+
}
58+
59+
@Operation(summary = "Update a role")
60+
@ApiResponses(value = {
61+
@ApiResponse(responseCode = "200", description = "Role updated successfully", content = {
62+
@Content(mediaType = "application/json", schema = @Schema(implementation = RoleDto.class)) }),
63+
@ApiResponse(responseCode = "404", description = "Role not found", content = @Content) })
64+
@PutMapping("{id}")
65+
public ResponseEntity<RoleDto> updateRole(@PathVariable Long id, @RequestBody RoleDto dto) {
66+
Role updatedRole = service.update(id, mapper.fromDto(dto));
67+
return ResponseEntity.ok(mapper.toDto(updatedRole));
68+
}
69+
70+
@Operation(summary = "Delete a role")
71+
@ApiResponses(value = {
72+
@ApiResponse(responseCode = "204", description = "Role deleted successfully", content = @Content),
73+
@ApiResponse(responseCode = "404", description = "Role not found", content = @Content) })
74+
@DeleteMapping("{id}")
75+
public ResponseEntity<Void> deleteRole(@PathVariable Long id) {
76+
service.delete(id);
77+
return ResponseEntity.status(204).build();
78+
}
79+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package ch.puzzle.pcts.dto.role;
2+
3+
public record RoleDto(Long id, String name, boolean isManagement) {
4+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package ch.puzzle.pcts.mapper;
2+
3+
import ch.puzzle.pcts.dto.role.RoleDto;
4+
import ch.puzzle.pcts.model.role.Role;
5+
import java.util.List;
6+
import org.springframework.stereotype.Component;
7+
8+
@Component
9+
public class RoleMapper {
10+
11+
public List<RoleDto> toDto(List<Role> models) {
12+
return models.stream().map(this::toDto).toList();
13+
}
14+
15+
public List<Role> fromDto(List<RoleDto> dtos) {
16+
return dtos.stream().map(this::fromDto).toList();
17+
}
18+
19+
public RoleDto toDto(Role model) {
20+
return new RoleDto(model.getId(), model.getName(), model.getIsManagement());
21+
}
22+
23+
public Role fromDto(RoleDto dto) {
24+
return new Role(dto.id(), dto.name(), dto.isManagement());
25+
}
26+
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,8 @@ public enum ErrorKey {
44
VALIDATION,
55
VALIDATION_DOES_NOT_INCLUDE,
66
INTERNAL,
7-
ID_IS_NOT_NULL
7+
ID_IS_NOT_NULL,
8+
NOT_FOUND,
9+
ROLE_NAME_IS_NULL,
10+
ROLE_NAME_IS_EMPTY,
811
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package ch.puzzle.pcts.model.role;
2+
3+
import jakarta.persistence.*;
4+
import org.hibernate.annotations.SQLDelete;
5+
import org.hibernate.annotations.SQLRestriction;
6+
7+
@Entity
8+
@SQLDelete(sql = "UPDATE role SET deleted_at = CURRENT_TIMESTAMP WHERE id = ?")
9+
@SQLRestriction("deleted_at IS NULL")
10+
public class Role {
11+
@Id
12+
@GeneratedValue(strategy = GenerationType.IDENTITY)
13+
private Long id;
14+
15+
private String name;
16+
17+
private boolean isManagement;
18+
19+
public Role(Long id, String name, boolean isManagement) {
20+
this.id = id;
21+
this.name = name;
22+
this.isManagement = isManagement;
23+
}
24+
25+
public Role() {
26+
}
27+
28+
public Long getId() {
29+
return id;
30+
}
31+
32+
public void setId(Long id) {
33+
this.id = id;
34+
}
35+
36+
public String getName() {
37+
return name;
38+
}
39+
40+
public void setName(String name) {
41+
this.name = name;
42+
}
43+
44+
public boolean getIsManagement() {
45+
return this.isManagement;
46+
}
47+
48+
public void setIsManagement(boolean isManagement) {
49+
this.isManagement = isManagement;
50+
}
51+
}
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.role.Role;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
import org.springframework.stereotype.Repository;
6+
7+
@Repository
8+
public interface RoleRepository extends JpaRepository<Role, Long> {
9+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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.role.Role;
6+
import ch.puzzle.pcts.service.persistence.RolePersistenceService;
7+
import ch.puzzle.pcts.service.validation.RoleValidationService;
8+
import java.util.List;
9+
import org.springframework.http.HttpStatus;
10+
import org.springframework.stereotype.Service;
11+
12+
@Service
13+
public class RoleBusinessService {
14+
private final RoleValidationService validationService;
15+
private final RolePersistenceService persistenceService;
16+
17+
public RoleBusinessService(RoleValidationService validationService, RolePersistenceService persistenceService) {
18+
this.validationService = validationService;
19+
this.persistenceService = persistenceService;
20+
}
21+
22+
public List<Role> getAll() {
23+
return persistenceService.getAll();
24+
}
25+
26+
public Role getById(long id) {
27+
validationService.validateOnGetById(id);
28+
return persistenceService
29+
.getById(id)
30+
.orElseThrow(() -> new PCTSException(HttpStatus.NOT_FOUND,
31+
"Role with id: " + id + " does not exist.",
32+
ErrorKey.NOT_FOUND));
33+
}
34+
35+
public Role create(Role role) {
36+
validationService.validateOnCreate(role);
37+
return persistenceService.create(role);
38+
}
39+
40+
public Role update(Long id, Role role) {
41+
validationService.validateOnUpdate(id, role);
42+
return persistenceService.update(id, role);
43+
}
44+
45+
public void delete(Long id) {
46+
validationService.validateOnDelete(id);
47+
persistenceService.delete(id);
48+
}
49+
}
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.role.Role;
4+
import ch.puzzle.pcts.repository.RoleRepository;
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 RolePersistenceService {
12+
private final RoleRepository repository;
13+
14+
@Autowired
15+
public RolePersistenceService(RoleRepository repository) {
16+
this.repository = repository;
17+
}
18+
19+
public Role create(Role role) {
20+
return repository.save(role);
21+
}
22+
23+
public Optional<Role> getById(long id) {
24+
return repository.findById(id);
25+
}
26+
27+
public List<Role> getAll() {
28+
return repository.findAll();
29+
}
30+
31+
public Role update(Long id, Role role) {
32+
role.setId(id);
33+
return repository.save(role);
34+
}
35+
36+
public void delete(Long id) {
37+
repository.deleteById(id);
38+
}
39+
}

backend/src/main/java/ch/puzzle/pcts/service/validation/ExampleValidationService.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
import ch.puzzle.pcts.exception.PCTSException;
44
import ch.puzzle.pcts.model.error.ErrorKey;
55
import ch.puzzle.pcts.model.example.Example;
6-
import ch.puzzle.pcts.service.persistence.ExamplePersistenceService;
7-
import org.springframework.beans.factory.annotation.Autowired;
86
import org.springframework.http.HttpStatus;
97
import org.springframework.stereotype.Component;
108

@@ -14,13 +12,6 @@
1412
*/
1513
@Component
1614
public class ExampleValidationService {
17-
private final ExamplePersistenceService persistenceService;
18-
19-
@Autowired
20-
public ExampleValidationService(ExamplePersistenceService persistenceService) {
21-
this.persistenceService = persistenceService;
22-
}
23-
2415
public void validateOnCreate(Example example) {
2516

2617
if (!example.getText().contains("Example")) {
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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.role.Role;
6+
import ch.puzzle.pcts.service.persistence.RolePersistenceService;
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 RoleValidationService {
13+
private final RolePersistenceService persistenceService;
14+
15+
@Autowired
16+
public RoleValidationService(RolePersistenceService persistenceService) {
17+
this.persistenceService = persistenceService;
18+
}
19+
20+
public void validateOnGetById(Long id) {
21+
validateIfExists(id);
22+
}
23+
24+
public void validateOnCreate(Role role) {
25+
validateIfIdIsNull(role.getId());
26+
validateName(role.getName());
27+
}
28+
29+
public void validateOnDelete(Long id) {
30+
validateIfExists(id);
31+
}
32+
33+
public void validateOnUpdate(Long id, Role role) {
34+
validateIfExists(id);
35+
validateIfIdIsNull(role.getId());
36+
validateName(role.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, "Name must not be null", ErrorKey.ROLE_NAME_IS_NULL);
48+
}
49+
50+
if (name.isBlank()) {
51+
throw new PCTSException(HttpStatus.BAD_REQUEST, "Name must not be empty", ErrorKey.ROLE_NAME_IS_EMPTY);
52+
}
53+
}
54+
55+
private void validateIfExists(long id) {
56+
persistenceService
57+
.getById(id)
58+
.orElseThrow(() -> new PCTSException(HttpStatus.NOT_FOUND,
59+
"Role with id: " + id + " does not exist.",
60+
ErrorKey.NOT_FOUND));
61+
}
62+
}

0 commit comments

Comments
 (0)