package ru.ulstu.user.service; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.domain.Page; import org.springframework.data.domain.Sort; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import ru.ulstu.configuration.ApplicationProperties; import ru.ulstu.core.error.EntityIdIsNullException; import ru.ulstu.core.jpa.OffsetablePageRequest; import ru.ulstu.core.model.BaseEntity; import ru.ulstu.core.model.response.PageableItems; import ru.ulstu.user.error.UserActivationError; import ru.ulstu.user.error.UserEmailExistsException; import ru.ulstu.user.error.UserIdExistsException; import ru.ulstu.user.error.UserIsUndeadException; import ru.ulstu.user.error.UserLoginExistsException; import ru.ulstu.user.error.UserNotActivatedException; import ru.ulstu.user.error.UserNotFoundException; import ru.ulstu.user.error.UserPasswordsNotValidOrNotMatchException; import ru.ulstu.user.error.UserResetKeyError; import ru.ulstu.user.model.User; import ru.ulstu.user.model.UserDto; import ru.ulstu.user.model.UserListDto; import ru.ulstu.user.model.UserResetPasswordDto; import ru.ulstu.user.model.UserRole; import ru.ulstu.user.model.UserRoleConstants; import ru.ulstu.user.model.UserRoleDto; import ru.ulstu.user.repository.UserRepository; import ru.ulstu.user.repository.UserRoleRepository; import ru.ulstu.user.util.UserUtils; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @Service @Transactional public class UserService implements UserDetailsService { private final Logger log = LoggerFactory.getLogger(UserService.class); private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; private final UserRoleRepository userRoleRepository; private final UserMapper userMapper; private final MailService mailService; private final ApplicationProperties applicationProperties; public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder, UserRoleRepository userRoleRepository, UserMapper userMapper, MailService mailService, ApplicationProperties applicationProperties) { this.userRepository = userRepository; this.passwordEncoder = passwordEncoder; this.userRoleRepository = userRoleRepository; this.userMapper = userMapper; this.mailService = mailService; this.applicationProperties = applicationProperties; } private User getUserByEmail(String email) { return userRepository.findOneByEmailIgnoreCase(email); } private User getUserByActivationKey(String activationKey) { return userRepository.findOneByActivationKey(activationKey); } public User getUserByLogin(String login) { return userRepository.findOneByLoginIgnoreCase(login); } @Transactional(readOnly = true) public UserDto getUserWithRolesById(Integer userId) { final User userEntity = userRepository.findOneWithRolesById(userId); if (userEntity == null) { throw new UserNotFoundException(userId.toString()); } return userMapper.userEntityToUserDto(userEntity); } @Transactional(readOnly = true) public PageableItems getAllUsers(int offset, int count) { final Page page = userRepository.findAll(new OffsetablePageRequest(offset, count, new Sort("id"))); return new PageableItems<>(page.getTotalElements(), userMapper.userEntitiesToUserListDtos(page.getContent())); } // TODO: read only active users public List findAll() { return userRepository.findAll(); } @Transactional(readOnly = true) public PageableItems getUserRoles() { final List roles = userRoleRepository.findAll().stream() .map(UserRoleDto::new) .sorted(Comparator.comparing(UserRoleDto::getViewValue)) .collect(Collectors.toList()); return new PageableItems<>(roles.size(), roles); } public UserDto createUser(UserDto userDto) { if (userDto.getId() != null) { throw new UserIdExistsException(); } if (getUserByLogin(userDto.getLogin()) != null) { throw new UserLoginExistsException(userDto.getLogin()); } if (getUserByEmail(userDto.getEmail()) != null) { throw new UserEmailExistsException(userDto.getEmail()); } if (!userDto.isPasswordsValid()) { throw new UserPasswordsNotValidOrNotMatchException(); } User user = userMapper.userDtoToUserEntity(userDto); user.setActivated(false); user.setActivationKey(UserUtils.generateActivationKey()); user.setRoles(Collections.singleton(new UserRole(UserRoleConstants.USER))); user.setPassword(passwordEncoder.encode(userDto.getPassword())); user = userRepository.save(user); mailService.sendActivationEmail(user); log.debug("Created Information for User: {}", user.getLogin()); return userMapper.userEntityToUserDto(user); } public UserDto activateUser(String activationKey) { final User user = getUserByActivationKey(activationKey); if (user == null) { throw new UserActivationError(activationKey); } user.setActivated(true); user.setActivationKey(null); user.setActivationDate(null); log.debug("Activated user: {}", user.getLogin()); return userMapper.userEntityToUserDto(userRepository.save(user)); } public UserDto updateUser(UserDto userDto) { if (userDto.getId() == null) { throw new EntityIdIsNullException(); } if (!Objects.equals( Optional.ofNullable(getUserByEmail(userDto.getEmail())) .map(BaseEntity::getId).orElse(userDto.getId()), userDto.getId())) { throw new UserEmailExistsException(userDto.getEmail()); } if (!Objects.equals( Optional.ofNullable(getUserByLogin(userDto.getLogin())) .map(BaseEntity::getId).orElse(userDto.getId()), userDto.getId())) { throw new UserLoginExistsException(userDto.getLogin()); } User user = userRepository.findOne(userDto.getId()); if (user == null) { throw new UserNotFoundException(userDto.getId().toString()); } if (applicationProperties.getUndeadUserLogin().equalsIgnoreCase(user.getLogin())) { userDto.setLogin(applicationProperties.getUndeadUserLogin()); userDto.setActivated(true); userDto.setRoles(Collections.singletonList(new UserRoleDto(UserRoleConstants.ADMIN))); } user.setLogin(userDto.getLogin()); user.setFirstName(userDto.getFirstName()); user.setLastName(userDto.getLastName()); user.setEmail(userDto.getEmail()); if (userDto.isActivated() != user.getActivated()) { if (userDto.isActivated()) { user.setActivationKey(null); user.setActivationDate(null); } else { user.setActivationKey(UserUtils.generateActivationKey()); user.setActivationDate(new Date()); } } user.setActivated(userDto.isActivated()); final Set roles = userMapper.rolesFromDto(userDto.getRoles()); user.setRoles(roles.isEmpty() ? Collections.singleton(new UserRole(UserRoleConstants.USER)) : roles); if (!StringUtils.isEmpty(userDto.getOldPassword())) { if (!userDto.isPasswordsValid() || !userDto.isOldPasswordValid()) { throw new UserPasswordsNotValidOrNotMatchException(); } if (!passwordEncoder.matches(userDto.getOldPassword(), user.getPassword())) { throw new UserPasswordsNotValidOrNotMatchException(); } user.setPassword(passwordEncoder.encode(userDto.getPassword())); log.debug("Changed password for User: {}", user.getLogin()); } user = userRepository.save(user); log.debug("Changed Information for User: {}", user.getLogin()); return userMapper.userEntityToUserDto(user); } public UserDto updateUserInformation(UserDto userDto) { if (userDto.getId() == null) { throw new EntityIdIsNullException(); } if (!Objects.equals( Optional.ofNullable(getUserByEmail(userDto.getEmail())) .map(BaseEntity::getId).orElse(userDto.getId()), userDto.getId())) { throw new UserEmailExistsException(userDto.getEmail()); } User user = userRepository.findOne(userDto.getId()); if (user == null) { throw new UserNotFoundException(userDto.getId().toString()); } user.setFirstName(userDto.getFirstName()); user.setLastName(userDto.getLastName()); user.setEmail(userDto.getEmail()); user = userRepository.save(user); log.debug("Updated Information for User: {}", user.getLogin()); return userMapper.userEntityToUserDto(user); } public UserDto changeUserPassword(UserDto userDto) { if (userDto.getId() == null) { throw new EntityIdIsNullException(); } if (!userDto.isPasswordsValid() || !userDto.isOldPasswordValid()) { throw new UserPasswordsNotValidOrNotMatchException(); } final String login = UserUtils.getCurrentUserLogin(); final User user = userRepository.findOneByLoginIgnoreCase(login); if (user == null) { throw new UserNotFoundException(login); } if (!passwordEncoder.matches(userDto.getOldPassword(), user.getPassword())) { throw new UserPasswordsNotValidOrNotMatchException(); } user.setPassword(passwordEncoder.encode(userDto.getPassword())); log.debug("Changed password for User: {}", user.getLogin()); return userMapper.userEntityToUserDto(userRepository.save(user)); } public boolean requestUserPasswordReset(String email) { User user = userRepository.findOneByEmailIgnoreCase(email); if (user == null) { throw new UserNotFoundException(email); } if (!user.getActivated()) { throw new UserNotActivatedException(); } user.setResetKey(UserUtils.generateResetKey()); user.setResetDate(new Date()); user = userRepository.save(user); mailService.sendPasswordResetMail(user); log.debug("Created Reset Password Request for User: {}", user.getLogin()); return true; } public boolean completeUserPasswordReset(String key, UserResetPasswordDto userResetPasswordDto) { if (!userResetPasswordDto.isPasswordsValid()) { throw new UserPasswordsNotValidOrNotMatchException(); } User user = userRepository.findOneByResetKey(key); if (user == null) { throw new UserResetKeyError(key); } user.setPassword(passwordEncoder.encode(userResetPasswordDto.getPassword())); user.setResetKey(null); user.setResetDate(null); user = userRepository.save(user); log.debug("Reset Password for User: {}", user.getLogin()); return true; } public UserDto deleteUser(Integer userId) { final User user = userRepository.findOne(userId); if (user == null) { throw new UserNotFoundException(userId.toString()); } if (applicationProperties.getUndeadUserLogin().equalsIgnoreCase(user.getLogin())) { throw new UserIsUndeadException(user.getLogin()); } userRepository.delete(user); log.debug("Deleted User: {}", user.getLogin()); return userMapper.userEntityToUserDto(user); } @Override public UserDetails loadUserByUsername(String username) { final User user = userRepository.findOneByLoginIgnoreCase(username); if (user == null) { throw new UserNotFoundException(username); } if (!user.getActivated()) { throw new UserNotActivatedException(); } return new org.springframework.security.core.userdetails.User(user.getLogin(), user.getPassword(), Optional.ofNullable(user.getRoles()).orElse(Collections.emptySet()).stream() .map(role -> new SimpleGrantedAuthority(role.getName())) .collect(Collectors.toList())); } public List findByIds(List ids) { return userRepository.findAll(ids); } public User findById(Integer id) { return userRepository.findOne(id); } public User getCurrentUser() { String login = UserUtils.getCurrentUserLogin(); User user = userRepository.findOneByLoginIgnoreCase(login); if (user == null) { throw new UserNotFoundException(login); } return user; } }