package org.datasurvey.service; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.stream.Collectors; import org.datasurvey.config.Constants; import org.datasurvey.domain.Authority; import org.datasurvey.domain.User; import org.datasurvey.domain.UsuarioExtra; import org.datasurvey.domain.enumeration.EstadoUsuario; import org.datasurvey.repository.AuthorityRepository; import org.datasurvey.repository.UserRepository; import org.datasurvey.repository.UsuarioExtraRepository; import org.datasurvey.security.AuthoritiesConstants; import org.datasurvey.security.SecurityUtils; import org.datasurvey.service.dto.AdminUserDTO; import org.datasurvey.service.dto.UserDTO; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cache.CacheManager; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import tech.jhipster.security.RandomUtil; /** * Service class for managing users. */ @Service @Transactional public class UserService { private final Logger log = LoggerFactory.getLogger(UserService.class); private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; private final AuthorityRepository authorityRepository; private final CacheManager cacheManager; private final UsuarioExtraRepository usuarioExtraRepository; public UserService( UserRepository userRepository, PasswordEncoder passwordEncoder, AuthorityRepository authorityRepository, CacheManager cacheManager, UsuarioExtraRepository usuarioExtraRepository ) { this.userRepository = userRepository; this.passwordEncoder = passwordEncoder; this.authorityRepository = authorityRepository; this.cacheManager = cacheManager; this.usuarioExtraRepository = usuarioExtraRepository; } public Optional activateRegistration(String key) { log.debug("Activating user for activation key {}", key); return userRepository .findOneByActivationKey(key) .map( user -> { // activate given user for the registration key. user.setActivated(true); user.setActivationKey(null); this.clearUserCaches(user); log.debug("Activated user: {}", user); return user; } ); } public Optional completePasswordReset(String newPassword, String key) { log.debug("Reset user password for reset key {}", key); return userRepository .findOneByResetKey(key) .filter(user -> user.getResetDate().isAfter(Instant.now().minusSeconds(86400))) .map( user -> { user.setPassword(passwordEncoder.encode(newPassword)); user.setResetKey(null); user.setResetDate(null); this.clearUserCaches(user); return user; } ); } public Optional requestPasswordReset(String mail) { return userRepository .findOneByEmailIgnoreCase(mail) .filter(User::isActivated) .map( user -> { user.setResetKey(RandomUtil.generateResetKey()); user.setResetDate(Instant.now()); this.clearUserCaches(user); return user; } ); } public User registerUser(AdminUserDTO userDTO, String password) { userRepository .findOneByLogin(userDTO.getLogin().toLowerCase()) .ifPresent( existingUser -> { boolean removed = removeNonActivatedUser(existingUser); if (!removed) { throw new UsernameAlreadyUsedException(); } } ); userRepository .findOneByEmailIgnoreCase(userDTO.getEmail()) .ifPresent( existingUser -> { boolean removed = removeNonActivatedUser(existingUser); if (!removed) { throw new EmailAlreadyUsedException(); } } ); User newUser = new User(); String encryptedPassword = passwordEncoder.encode(password); newUser.setLogin(userDTO.getLogin().toLowerCase()); // new user gets initially a generated password newUser.setPassword(encryptedPassword); newUser.setFirstName(userDTO.getFirstName()); newUser.setLastName(userDTO.getLastName()); if (userDTO.getEmail() != null) { newUser.setEmail(userDTO.getEmail().toLowerCase()); } newUser.setImageUrl(userDTO.getImageUrl()); newUser.setLangKey(userDTO.getLangKey()); // new user is not active newUser.setActivated(false); // new user gets registration key newUser.setActivationKey(RandomUtil.generateActivationKey()); Set authorities = new HashSet<>(); authorityRepository.findById(AuthoritiesConstants.USER).ifPresent(authorities::add); newUser.setAuthorities(authorities); userRepository.save(newUser); this.clearUserCaches(newUser); log.debug("Created Information for User: {}", newUser); return newUser; } /* * Modified to register extra user data * name, iconoPerfil, fechaNacimiento, estado, pais */ public User registerUser(AdminUserDTO userDTO, String password, String name, Integer profileIcon, Integer isAdmin, Integer isGoogle) { userRepository .findOneByLogin(userDTO.getLogin().toLowerCase()) .ifPresent( existingUser -> { boolean removed = removeNonActivatedUser(existingUser); if (!removed) { throw new UsernameAlreadyUsedException(); } } ); userRepository .findOneByEmailIgnoreCase(userDTO.getEmail()) .ifPresent( existingUser -> { boolean removed = removeNonActivatedUser(existingUser); if (!removed) { throw new EmailAlreadyUsedException(); } } ); User newUser = new User(); String encryptedPassword = passwordEncoder.encode(password); newUser.setLogin(userDTO.getLogin().toLowerCase()); // new user gets initially a generated password newUser.setPassword(encryptedPassword); newUser.setFirstName(userDTO.getFirstName()); newUser.setLastName(userDTO.getLastName()); if (userDTO.getEmail() != null) { newUser.setEmail(userDTO.getEmail().toLowerCase()); } newUser.setImageUrl(userDTO.getImageUrl()); newUser.setLangKey(userDTO.getLangKey()); // new user is not active if (isGoogle == 1) { newUser.setActivated(true); } else { newUser.setActivated(false); } // new user gets registration key newUser.setActivationKey(RandomUtil.generateActivationKey()); Set authorities = new HashSet<>(); // Check whether it's an ADMIN or USER and apply authorities if (isAdmin == 1) { authorityRepository.findById(AuthoritiesConstants.ADMIN).ifPresent(authorities::add); } authorityRepository.findById(AuthoritiesConstants.USER).ifPresent(authorities::add); newUser.setAuthorities(authorities); userRepository.save(newUser); this.clearUserCaches(newUser); log.debug("Created Information for User: {}", newUser); // Create and save the UsuarioExtra entity // nombre, iconoPerfil 1-28, fechaNacimiento, estado ACTIVE UsuarioExtra usuarioExtra = new UsuarioExtra(); usuarioExtra.setId(newUser.getId()); usuarioExtra.setUser(newUser); usuarioExtra.setNombre(name); usuarioExtra.setEstado(EstadoUsuario.ACTIVE); usuarioExtra.setIconoPerfil(profileIcon.toString()); usuarioExtraRepository.save(usuarioExtra); return newUser; } private boolean removeNonActivatedUser(User existingUser) { if (existingUser.isActivated()) { return false; } userRepository.delete(existingUser); userRepository.flush(); this.clearUserCaches(existingUser); return true; } public User createUser(AdminUserDTO userDTO) { User user = new User(); user.setLogin(userDTO.getLogin().toLowerCase()); user.setFirstName(userDTO.getFirstName()); user.setLastName(userDTO.getLastName()); if (userDTO.getEmail() != null) { user.setEmail(userDTO.getEmail().toLowerCase()); } user.setImageUrl(userDTO.getImageUrl()); if (userDTO.getLangKey() == null) { user.setLangKey(Constants.DEFAULT_LANGUAGE); // default language } else { user.setLangKey(userDTO.getLangKey()); } String encryptedPassword = passwordEncoder.encode(RandomUtil.generatePassword()); user.setPassword(encryptedPassword); user.setResetKey(RandomUtil.generateResetKey()); user.setResetDate(Instant.now()); user.setActivated(true); if (userDTO.getAuthorities() != null) { Set authorities = userDTO .getAuthorities() .stream() .map(authorityRepository::findById) .filter(Optional::isPresent) .map(Optional::get) .collect(Collectors.toSet()); user.setAuthorities(authorities); } userRepository.save(user); this.clearUserCaches(user); log.debug("Created Information for User: {}", user); return user; } /** * Update all information for a specific user, and return the modified user. * * @param userDTO user to update. * @return updated user. */ public Optional updateUser(AdminUserDTO userDTO) { return Optional .of(userRepository.findById(userDTO.getId())) .filter(Optional::isPresent) .map(Optional::get) .map( user -> { this.clearUserCaches(user); user.setLogin(userDTO.getLogin().toLowerCase()); user.setFirstName(userDTO.getFirstName()); user.setLastName(userDTO.getLastName()); if (userDTO.getEmail() != null) { user.setEmail(userDTO.getEmail().toLowerCase()); } user.setImageUrl(userDTO.getImageUrl()); user.setActivated(userDTO.isActivated()); user.setLangKey(userDTO.getLangKey()); Set managedAuthorities = user.getAuthorities(); managedAuthorities.clear(); userDTO .getAuthorities() .stream() .map(authorityRepository::findById) .filter(Optional::isPresent) .map(Optional::get) .forEach(managedAuthorities::add); this.clearUserCaches(user); log.debug("Changed Information for User: {}", user); return user; } ) .map(AdminUserDTO::new); } public void deleteUser(String login) { userRepository .findOneByLogin(login) .ifPresent( user -> { userRepository.delete(user); this.clearUserCaches(user); log.debug("Deleted User: {}", user); } ); } /** * Update basic information (first name, last name, email, language) for the current user. * * @param firstName first name of user. * @param lastName last name of user. * @param email email id of user. * @param langKey language key. * @param imageUrl image URL of user. */ public void updateUser(String firstName, String lastName, String email, String langKey, String imageUrl) { SecurityUtils .getCurrentUserLogin() .flatMap(userRepository::findOneByLogin) .ifPresent( user -> { user.setFirstName(firstName); user.setLastName(lastName); if (email != null) { user.setEmail(email.toLowerCase()); } user.setLangKey(langKey); user.setImageUrl(imageUrl); this.clearUserCaches(user); log.debug("Changed Information for User: {}", user); } ); } @Transactional public void changePassword(String currentClearTextPassword, String newPassword) { SecurityUtils .getCurrentUserLogin() .flatMap(userRepository::findOneByLogin) .ifPresent( user -> { String currentEncryptedPassword = user.getPassword(); if (!passwordEncoder.matches(currentClearTextPassword, currentEncryptedPassword)) { throw new InvalidPasswordException(); } String encryptedPassword = passwordEncoder.encode(newPassword); user.setPassword(encryptedPassword); this.clearUserCaches(user); log.debug("Changed password for User: {}", user); } ); } @Transactional(readOnly = true) public Page getAllManagedUsers(Pageable pageable) { return userRepository.findAll(pageable).map(AdminUserDTO::new); } @Transactional(readOnly = true) public Page getAllPublicUsers(Pageable pageable) { return userRepository.findAllByIdNotNullAndActivatedIsTrue(pageable).map(UserDTO::new); } @Transactional(readOnly = true) public Optional getUserWithAuthoritiesByLogin(String login) { return userRepository.findOneWithAuthoritiesByLogin(login); } @Transactional(readOnly = true) public Optional getUserWithAuthorities() { return SecurityUtils.getCurrentUserLogin().flatMap(userRepository::findOneWithAuthoritiesByLogin); } /** * Not activated users should be automatically deleted after 3 days. *

* This is scheduled to get fired everyday, at 01:00 (am). */ @Scheduled(cron = "0 0 1 * * ?") public void removeNotActivatedUsers() { userRepository .findAllByActivatedIsFalseAndActivationKeyIsNotNullAndCreatedDateBefore(Instant.now().minus(3, ChronoUnit.DAYS)) .forEach( user -> { log.debug("Deleting not activated user {}", user.getLogin()); userRepository.delete(user); this.clearUserCaches(user); } ); } /** * Gets a list of all the authorities. * @return a list of all the authorities. */ @Transactional(readOnly = true) public List getAuthorities() { return authorityRepository.findAll().stream().map(Authority::getName).collect(Collectors.toList()); } private void clearUserCaches(User user) { Objects.requireNonNull(cacheManager.getCache(UserRepository.USERS_BY_LOGIN_CACHE)).evict(user.getLogin()); if (user.getEmail() != null) { Objects.requireNonNull(cacheManager.getCache(UserRepository.USERS_BY_EMAIL_CACHE)).evict(user.getEmail()); } } }