1 package fr.tiogars.domaintemplate.domains.auth.role.services;
2
3 import java.time.Clock;
4 import java.time.Instant;
5 import java.time.temporal.ChronoUnit;
6 import java.util.List;
7 import java.util.Optional;
8 import java.util.Set;
9
10 import org.springframework.beans.factory.annotation.Autowired;
11 import org.springframework.stereotype.Service;
12 import org.springframework.transaction.annotation.Transactional;
13
14 import fr.tiogars.domaintemplate.domains.auth.role.entities.Role;
15 import fr.tiogars.domaintemplate.domains.auth.role.entities.RoleEntity;
16 import fr.tiogars.domaintemplate.domains.auth.role.models.CreateRoleRequest;
17 import fr.tiogars.domaintemplate.domains.auth.role.models.UpdateRoleRequest;
18 import fr.tiogars.domaintemplate.domains.auth.role.repositories.RoleRepository;
19
20
21 @Service
22 public class RoleService {
23
24 public static final String ADMIN = "ADMIN";
25 public static final String USER = "USER";
26
27 private static final Set<String> SYSTEM_ROLES = Set.of(ADMIN, USER);
28
29 private final Clock clock;
30 private final RoleRepository repository;
31
32 @Autowired
33 public RoleService(RoleRepository repository) {
34 this(repository, Clock.systemUTC());
35 }
36
37 RoleService(RoleRepository repository, Clock clock) {
38 this.repository = repository;
39 this.clock = clock;
40 }
41
42 @Transactional
43 public Optional<Role> create(CreateRoleRequest request) {
44 if (repository.findByCode(request.code()).isPresent()) {
45 return Optional.empty();
46 }
47 Instant timestamp = currentTimestamp();
48 return Optional.of(toRecord(repository.save(new RoleEntity(request.code(), request.label(), timestamp, timestamp))));
49 }
50
51 @Transactional
52 public Optional<Role> update(Long id, UpdateRoleRequest request) {
53 return repository.findById(id)
54 .map(existing -> {
55 existing.update(request.label(), currentTimestamp());
56 return toRecord(repository.save(existing));
57 });
58 }
59
60 @Transactional
61 public boolean delete(Long id) {
62 return repository.findById(id)
63 .filter(existing -> !SYSTEM_ROLES.contains(existing.getCode()))
64 .map(existing -> {
65 repository.delete(existing);
66 return true;
67 })
68 .orElse(false);
69 }
70
71 public List<Role> findAll() {
72 return repository.findAllByOrderByCodeAsc().stream()
73 .map(RoleService::toRecord)
74 .toList();
75 }
76
77 public Optional<Role> findById(Long id) {
78 return repository.findById(id).map(RoleService::toRecord);
79 }
80
81 public Optional<RoleEntity> findEntityByCode(String code) {
82 return repository.findByCode(code);
83 }
84
85 @Transactional
86 public List<Role> seedDefaultRoles() {
87 return List.of(
88 seedSystemRole(ADMIN, "Administrator"),
89 seedSystemRole(USER, "User"));
90 }
91
92 private Role seedSystemRole(String code, String label) {
93 Instant timestamp = currentTimestamp();
94 RoleEntity entity = repository.findByCode(code)
95 .map(existing -> {
96 existing.update(label, timestamp);
97 return existing;
98 })
99 .orElseGet(() -> new RoleEntity(code, label, timestamp, timestamp));
100 return toRecord(repository.save(entity));
101 }
102
103 private Instant currentTimestamp() {
104 return Instant.now(clock).truncatedTo(ChronoUnit.MICROS);
105 }
106
107 public static Role toRecord(RoleEntity entity) {
108 return new Role(entity.getId(), entity.getCode(), entity.getLabel(), entity.getCreatedDate(), entity.getLastModifiedDate());
109 }
110 }