UserSettingsService.java
package fr.tiogars.inception.settings.user.services;
import java.time.Clock;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import fr.tiogars.inception.domains.auth.role.services.RoleService;
import fr.tiogars.inception.domains.auth.user.entities.UserEntity;
import fr.tiogars.inception.domains.auth.user.repositories.UserRepository;
import fr.tiogars.inception.settings.user.entities.UserSettings;
import fr.tiogars.inception.settings.user.entities.UserSettingsEntity;
import fr.tiogars.inception.settings.user.models.UpdateUserSettingsRequest;
import fr.tiogars.inception.settings.user.repositories.UserSettingsRepository;
/** Coordinates user settings, the ANONYMOUS role settings and their defaults. */
@Service
public class UserSettingsService {
public static final String DEFAULT_VIEW_MODE = "system";
private final Clock clock;
private final UserRepository userRepository;
private final UserSettingsRepository repository;
@Autowired
public UserSettingsService(UserSettingsRepository repository, UserRepository userRepository) {
this(repository, userRepository, Clock.systemUTC());
}
UserSettingsService(UserSettingsRepository repository, UserRepository userRepository, Clock clock) {
this.repository = repository;
this.userRepository = userRepository;
this.clock = clock;
}
/** Returns the settings of the authenticated account, or empty when the account does not exist. */
@Transactional(readOnly = true)
public Optional<UserSettings> findByUsername(String username) {
return userRepository.findByUsername(username).map(this::readUserSettings);
}
/** Updates the settings of the authenticated account, or returns empty when the account does not exist. */
@Transactional
public Optional<UserSettings> updateByUsername(String username, UpdateUserSettingsRequest request) {
return userRepository.findByUsername(username).map(user -> writeUserSettings(user, request));
}
/** Returns the settings of an account holding the USER role, or empty otherwise. */
@Transactional(readOnly = true)
public Optional<UserSettings> findByUserId(Long userId) {
return findManagedUser(userId).map(this::readUserSettings);
}
/** Updates the settings of an account holding the USER role, or returns empty otherwise. */
@Transactional
public Optional<UserSettings> updateByUserId(Long userId, UpdateUserSettingsRequest request) {
return findManagedUser(userId).map(user -> writeUserSettings(user, request));
}
@Transactional(readOnly = true)
public UserSettings findAnonymous() {
return repository.findByRoleCode(RoleService.ANONYMOUS)
.map(UserSettingsService::toRecord)
.orElseGet(() -> defaults(null, RoleService.ANONYMOUS));
}
@Transactional
public UserSettings updateAnonymous(UpdateUserSettingsRequest request) {
Instant timestamp = currentTimestamp();
UserSettingsEntity entity = repository.findByRoleCode(RoleService.ANONYMOUS)
.map(existing -> {
existing.update(request.viewMode(), timestamp);
return existing;
})
.orElseGet(() -> UserSettingsEntity.forRole(RoleService.ANONYMOUS, request.viewMode(), timestamp));
return toRecord(repository.save(entity));
}
private Optional<UserEntity> findManagedUser(Long userId) {
return userRepository.findById(userId)
.filter(user -> user.getRoles().stream().anyMatch(role -> RoleService.USER.equals(role.getCode())));
}
private UserSettings readUserSettings(UserEntity user) {
return repository.findByUserId(user.getId())
.map(UserSettingsService::toRecord)
.orElseGet(() -> defaults(user.getId(), null));
}
private UserSettings writeUserSettings(UserEntity user, UpdateUserSettingsRequest request) {
Instant timestamp = currentTimestamp();
UserSettingsEntity entity = repository.findByUserId(user.getId())
.map(existing -> {
existing.update(request.viewMode(), timestamp);
return existing;
})
.orElseGet(() -> UserSettingsEntity.forUser(user, request.viewMode(), timestamp));
return toRecord(repository.save(entity));
}
private Instant currentTimestamp() {
return Instant.now(clock).truncatedTo(ChronoUnit.MICROS);
}
private static UserSettings defaults(Long userId, String roleCode) {
return new UserSettings(userId, roleCode, DEFAULT_VIEW_MODE, null, null);
}
public static UserSettings toRecord(UserSettingsEntity entity) {
return new UserSettings(
entity.getUser() == null ? null : entity.getUser().getId(),
entity.getRoleCode(),
entity.getViewMode(),
entity.getCreatedDate(),
entity.getLastModifiedDate());
}
}