ch.wisv.areafiftylan.users.service.UserServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for ch.wisv.areafiftylan.users.service.UserServiceImpl.java

Source

/*
 * Copyright (c) 2016  W.I.S.V. 'Christiaan Huygens'
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package ch.wisv.areafiftylan.users.service;

import ch.wisv.areafiftylan.security.token.PasswordResetToken;
import ch.wisv.areafiftylan.security.token.VerificationToken;
import ch.wisv.areafiftylan.security.token.repository.PasswordResetTokenRepository;
import ch.wisv.areafiftylan.security.token.repository.VerificationTokenRepository;
import ch.wisv.areafiftylan.users.model.Profile;
import ch.wisv.areafiftylan.users.model.ProfileDTO;
import ch.wisv.areafiftylan.users.model.User;
import ch.wisv.areafiftylan.users.model.UserDTO;
import ch.wisv.areafiftylan.utils.mail.MailService;
import com.google.common.base.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.domain.Sort;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.Optional;

@Service
public class UserServiceImpl implements UserService, UserDetailsService {

    private final UserRepository userRepository;
    private final VerificationTokenRepository verificationTokenRepository;
    private final PasswordResetTokenRepository passwordResetTokenRepository;
    private final MailService mailService;

    @Value("${a5l.mail.confirmUrl}")
    String requestUrl;
    @Value("${a5l.user.resetUrl}")
    String resetUrl;

    @Autowired
    public UserServiceImpl(UserRepository userRepository, VerificationTokenRepository verificationTokenRepository,
            PasswordResetTokenRepository passwordResetTokenRepository, MailService mailService) {
        this.userRepository = userRepository;
        this.verificationTokenRepository = verificationTokenRepository;
        this.mailService = mailService;
        this.passwordResetTokenRepository = passwordResetTokenRepository;
    }

    @Override
    public User getUserById(long id) {
        return userRepository.findOne(id);
    }

    @Override
    public Optional<User> getUserByEmail(String email) {
        return userRepository.findOneByEmailIgnoreCase(email);
    }

    @Override
    public Optional<User> getUserByUsername(String username) {
        return userRepository.findOneByUsernameIgnoreCase(username);
    }

    @Override
    public Collection<User> getAllUsers() {
        return userRepository.findAll(new Sort("email"));
    }

    @Override
    public User create(UserDTO userDTO, HttpServletRequest request) throws DataIntegrityViolationException {
        handleDuplicateUserFields(userDTO);

        // Hash the plain password coming from the DTO
        String passwordHash = getPasswordHash(userDTO.getPassword());
        User user = new User(userDTO.getUsername(), passwordHash, userDTO.getEmail());
        user.addRole(userDTO.getRole());
        // All users that register through the service have to be verified
        user.setEnabled(false);

        // Save the user so the verificationToken can be stored.
        user = userRepository.saveAndFlush(user);

        generateAndSendToken(request, user);

        return user;
    }

    private void handleDuplicateUserFields(UserDTO userDTO) throws DataIntegrityViolationException {
        // Check if the username already exists
        userRepository.findOneByUsernameIgnoreCase(userDTO.getUsername()).ifPresent(u -> {
            throw new DataIntegrityViolationException("username already in use");
        });

        // Check if the email is already in use
        userRepository.findOneByEmailIgnoreCase(userDTO.getEmail()).ifPresent(u -> {
            throw new DataIntegrityViolationException("email already in use");
        });
    }

    private void generateAndSendToken(HttpServletRequest request, User user) {
        // Create a new Verificationcode with this UUID, and link it to the user
        VerificationToken verificationToken = new VerificationToken(user);
        verificationTokenRepository.saveAndFlush(verificationToken);

        // Build the URL and send this to the mailservice for sending.
        String confirmUrl = requestUrl + "?token=" + verificationToken.getToken();
        mailService.sendVerificationmail(user, confirmUrl);
    }

    @Override
    public User replace(Long userId, UserDTO userDTO) {
        User user = userRepository.getOne(userId);

        user.setUsername(userDTO.getUsername());
        user.setEmail(userDTO.getEmail());
        user.setPasswordHash(getPasswordHash(userDTO.getPassword()));
        user.resetProfile();

        return userRepository.saveAndFlush(user);
    }

    @Override
    public void delete(Long userId) {
        // We don't delete users, we lock them
        throw new UnsupportedOperationException("Can't delete users, lock them instead");
    }

    @Override
    public User edit(Long userId, UserDTO userDTO) {
        User user = userRepository.findOne(userId);
        if (!Strings.isNullOrEmpty(userDTO.getUsername())) {
            user.setUsername(userDTO.getUsername());
        }
        if (!Strings.isNullOrEmpty(userDTO.getEmail())) {
            user.setEmail(userDTO.getEmail());
        }
        if (!Strings.isNullOrEmpty(userDTO.getPassword())) {
            user.setPasswordHash(getPasswordHash(userDTO.getPassword()));
        }
        return userRepository.saveAndFlush(user);

    }

    @Override
    public User addProfile(Long userId, ProfileDTO profileDTO) {
        User user = userRepository.findOne(userId);

        // Set all the profile fields at once
        user.getProfile().setAllFields(profileDTO.getFirstName(), profileDTO.getLastName(),
                profileDTO.getDisplayName(), profileDTO.getGender(), profileDTO.getAddress(),
                profileDTO.getZipcode(), profileDTO.getCity(), profileDTO.getPhoneNumber(), profileDTO.getNotes());
        return userRepository.saveAndFlush(user);

    }

    @Override
    public User changeProfile(Long userId, ProfileDTO profileDTO) {
        return addProfile(userId, profileDTO);
    }

    @Override
    public Profile resetProfile(Long userId) {
        Profile profile = userRepository.findOne(userId).getProfile();
        userRepository.findOne(userId).resetProfile();
        return profile;
    }

    @Override
    public void unlock(Long userId) {
        User user = userRepository.findOne(userId);
        user.setAccountNonLocked(true);
        userRepository.saveAndFlush(user);
    }

    @Override
    public void lock(Long userId) {
        User user = userRepository.findOne(userId);
        user.setAccountNonLocked(false);
        userRepository.saveAndFlush(user);
    }

    @Override
    public void verify(Long userId) {
        User user = userRepository.findOne(userId);
        user.setEnabled(true);
        userRepository.saveAndFlush(user);
    }

    @Override
    public void requestResetPassword(User user, HttpServletRequest request) {
        // Use the generated ID to create a passwordToken and link it to the user
        PasswordResetToken passwordResetToken = new PasswordResetToken(user);
        passwordResetTokenRepository.saveAndFlush(passwordResetToken);

        String passwordUrl = resetUrl + "?token=" + passwordResetToken.getToken();
        mailService.sendPasswordResetMail(user, passwordUrl);
    }

    @Override
    public void resetPassword(Long userId, String password) {
        User user = userRepository.findOne(userId);
        // The token is being checked in the authentication, so just set the password here
        user.setPasswordHash(new BCryptPasswordEncoder().encode(password));
        userRepository.saveAndFlush(user);
    }

    @Override
    public void changePassword(Long userId, String oldPassword, String newPassword) {
        User user = userRepository.findOne(userId);

        if (new BCryptPasswordEncoder().matches(oldPassword, user.getPassword())) {
            user.setPasswordHash(getPasswordHash(newPassword));
            userRepository.save(user);
        } else {
            throw new AccessDeniedException("Wrong password");
        }
    }

    @Override
    public Boolean checkEmailAvailable(String email) {
        return !userRepository.findOneByEmailIgnoreCase(email).isPresent();
    }

    @Override
    public Boolean checkUsernameAvailable(String username) {
        return !userRepository.findOneByUsernameIgnoreCase(username).isPresent();

    }

    /**
     * Encrypt the password using the BCryptPasswordEncoder with default settings
     *
     * @param plainTextPassword The password to be encoded
     *
     * @return The hashed password
     */
    private String getPasswordHash(String plainTextPassword) {
        return new BCryptPasswordEncoder().encode(plainTextPassword);
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return userRepository.findOneByUsernameIgnoreCase(username)
                .orElseThrow(() -> new UsernameNotFoundException(username));
    }
}