de.hska.ld.core.service.impl.UserServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for de.hska.ld.core.service.impl.UserServiceImpl.java

Source

/*
 *  Code contributed to the Learning Layers project
 *  http://www.learning-layers.eu
 *  Development is partly funded by the FP7 Programme of the European
 *  Commission under Grant Agreement FP7-ICT-318209.
 *  Copyright (c) 2015, Karlsruhe University of Applied Sciences.
 *  For a list of contributors see the AUTHORS file at the top-level directory
 *  of this distribution.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package de.hska.ld.core.service.impl;

import de.hska.ld.core.exception.*;
import de.hska.ld.core.persistence.domain.Role;
import de.hska.ld.core.persistence.domain.User;
import de.hska.ld.core.persistence.repository.UserRepository;
import de.hska.ld.core.service.MailService;
import de.hska.ld.core.service.RoleService;
import de.hska.ld.core.service.UserService;
import de.hska.ld.core.util.Core;
import org.apache.commons.validator.routines.EmailValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.env.Environment;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.Callable;

public class UserServiceImpl extends AbstractService<User> implements UserService {

    EmailValidator emailValidator = EmailValidator.getInstance();

    @Autowired
    private UserRepository repository;

    @Autowired(required = false)
    private PasswordEncoder passwordEncoder;

    @Autowired
    private RoleService roleService;

    @Autowired
    private MailService mailService;

    @Autowired
    private Environment env;

    @Override
    public User findByUsername(String username) {
        return repository.findByUsername(username);
    }

    @Override
    public User findByEmail(String email) {
        return repository.findByEmail(email);
    }

    @Override
    public List<User> findByRole(String roleName) {
        return repository.findByRole(roleName);
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return repository.findByUsernameOrEmail(username);
    }

    @Override
    public User save(User user) {
        User savedUser;
        User userFoundByUsername = findByUsername(user.getUsername());
        if (user.getId() == null) {
            User userFoundByEmail = findByEmail(user.getEmail());
            setNewUserFields(user, userFoundByUsername, userFoundByEmail);
            if (user.getLastupdatedAt() == null) {
                user.setLastupdatedAt(new Date());
            }
            savedUser = super.save(user);
        } else {
            // Check if the current user wants to update an account owned by somebody else
            User currentUser = Core.currentUser();
            boolean isAdmin = hasRole(currentUser, Core.ROLE_ADMIN);
            if (!isAdmin && currentUser != null && !currentUser.getId().equals(user.getId())) {
                throw new UserNotAuthorizedException();
            }
            if (userFoundByUsername != null && user.getUsername().equals(userFoundByUsername.getUsername())
                    && !user.getId().equals(userFoundByUsername.getId())) {
                throw new AlreadyExistsException("username");
            }
            User dbUser = repository.findOne(user.getId());
            dbUser.setFullName(user.getFullName());
            dbUser.setUsername(user.getUsername());
            if (dbUser.getEmail() == null) {
                dbUser.setEmail(user.getEmail());
            }
            savedUser = super.save(dbUser);

            User principal = Core.currentUser();
            if (principal != null) {
                if (principal.getId().equals(savedUser.getId())) {
                    principal.setFullName(savedUser.getFullName());
                    principal.setUsername(savedUser.getUsername());
                }
            }
        }

        return savedUser;
    }

    @Override
    public void delete(Long id) {
        User currentUser = Core.currentUser();
        if (!currentUser.getId().equals(id) && !hasRole(currentUser, Core.ROLE_ADMIN)) {
            throw new UserNotAuthorizedException();
        }
        User userToBeDeleted = findById(id);
        if (userToBeDeleted == null) {
            throw new NotFoundException("id");
        }
        super.save(userToBeDeleted);
    }

    @Override
    public User addRoles(String username, String... roleNames) {
        User user = findByUsername(username);
        if (user == null) {
            throw new ValidationException("username");
        }
        List<Role> filteredRoleList = filterRolesFromClient(roleNames);
        filteredRoleList.stream().filter(role -> !hasRole(user, role.getName()))
                .forEach(role -> user.getRoleList().add(role));
        return save(user);
    }

    @Override
    public void register(User user) {
        User userFoundByUsername = findByUsername(user.getUsername());
        User userFoundByEmail = findByEmail(user.getEmail());
        setNewUserFields(user, userFoundByUsername, userFoundByEmail);
        user.setRegistrationConfirmationKey(UUID.randomUUID().toString());
        user.setEnabled(false);
        user = super.save(user);

        ResourceBundle bundle = ResourceBundle.getBundle("messages", LocaleContextHolder.getLocale());
        String subject = bundle.getString("email.user.registration.subject");
        String text = bundle.getString("email.user.registration.text");
        String confirmationUrl = env.getProperty("module.core.auth.registrationConfirmUrl")
                + user.getForgotPasswordConfirmationKey();
        //sendConfirmationMail(user, subject, text, confirmationUrl);
    }

    @Override
    @Transactional
    public User confirmRegistration(String confirmationKey) {
        User user = repository.findByRegistrationConfirmationKey(confirmationKey);
        if (user == null) {
            throw new NotFoundException("confirmationKey");
        }
        user.setEnabled(true);
        user.setRegistrationConfirmationKey(null);
        user = super.save(user);
        return user;
    }

    @Override
    public String encodePassword(String password) {
        return passwordEncoder.encode(password);
    }

    @Override
    public Boolean hasRole(User user, String roleName) {
        if (user != null) {
            Collection<Role> roleList = user.getRoleList();
            for (Role role : roleList) {
                if (role.getName().equals(roleName)) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public void runAs(User user, Runnable runnable) {
        Authentication authenticationBefore = SecurityContextHolder.getContext().getAuthentication();
        SecurityContextHolder.getContext().setAuthentication(
                new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities()));
        try {
            runnable.run();
        } finally {
            SecurityContextHolder.getContext().setAuthentication(authenticationBefore);
        }
    }

    @Override
    public Callable callAs(User user, Callable callable) {
        return () -> {
            Authentication authenticationBefore = SecurityContextHolder.getContext().getAuthentication();
            SecurityContextHolder.getContext().setAuthentication(
                    new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities()));
            try {
                return callable.call();
            } finally {
                SecurityContextHolder.getContext().setAuthentication(authenticationBefore);
            }
        };
    }

    @Override
    public Page<User> getUsersPage(Integer pageNumber, Integer pageSize, String sortDirection,
            String sortProperty) {
        return getUsersPage(pageNumber, pageSize, sortDirection, sortProperty, null);
    }

    @Override
    public Page<User> getUsersPage(Integer pageNumber, Integer pageSize, String sortDirection, String sortProperty,
            String searchTerm) {
        Sort.Direction direction;
        if (Sort.Direction.ASC.toString().equals(sortDirection)) {
            direction = Sort.Direction.ASC;
        } else {
            direction = Sort.Direction.DESC;
        }
        Pageable pageable = new PageRequest(pageNumber, pageSize, direction, sortProperty);
        if (searchTerm == null) {
            return repository.findAll(pageable);
        } else {
            return repository.findMentionSuggestions("%" + searchTerm + "%", pageable);
        }
    }

    @Override
    public Page<User> getUsersDisabledPage(Integer pageNumber, Integer pageSize, String sortDirection,
            String sortProperty) {
        Sort.Direction direction;
        if (Sort.Direction.ASC.toString().equals(sortDirection)) {
            direction = Sort.Direction.ASC;
        } else {
            direction = Sort.Direction.DESC;
        }
        Pageable pageable = new PageRequest(pageNumber, pageSize, direction, sortProperty);
        return repository.findDisabledAll(pageable);
    }

    @Override
    @Transactional
    public User activateUser(Long userid) {
        User user = super.findById(userid);
        if (user != null) {
            user.setEnabled(true);
            super.save(user);
        }
        return user;
    }

    @Transactional
    public User deactivateUser(Long userid) {
        User user = super.findById(userid);
        if (user != null) {
            user.setEnabled(false);
            super.save(user);
        }
        return user;
    }

    @Override
    public List<User> getMentionSuggestions(String term) {
        return repository.findMentionSuggestions("%" + term + "%");
    }

    @Override
    @Transactional
    public User updatePassword(String password) {
        String hashedPwd = encodePassword(password);
        User currentUser = findById(Core.currentUser().getId());
        currentUser.setPassword(hashedPwd);
        return save(currentUser);
    }

    @Override
    public User updateProfile(User user) {
        User currentUser = Core.currentUser();
        User userToUpdate = findById(currentUser.getId());
        userToUpdate.setFullName(user.getFullName());
        userToUpdate.setDescription(user.getDescription());
        return save(userToUpdate);
    }

    @Override
    public List<byte[]> getAvatars(String userIdsString) {
        List<byte[]> avatarList = new ArrayList<>();
        if (userIdsString != null) {
            String[] userIds = userIdsString.split(";");
            for (String idString : userIds) {
                User user = findById(Long.parseLong(idString));
                if (user != null) {
                    avatarList.add(user.getAvatar());
                }
            }
        }
        return avatarList;
    }

    @Override
    public void uploadAvatar(MultipartFile file, String name) {
        try {
            //String avatar = name + ";" + new String(file.getBytes());
            User user = Core.currentUser();
            user.setAvatar(file.getBytes());
            super.save(user);
        } catch (IOException e) {
            throw new ApplicationException();
        }
    }

    @Override
    public void forgotPassword(String userUsernameOrEmail) {
        User user = repository.findByUsernameOrEmail(userUsernameOrEmail);
        if (user != null) {
            user.setForgotPasswordConfirmationKey(UUID.randomUUID().toString());
            user = super.save(user);

            ResourceBundle bundle = ResourceBundle.getBundle("messages", LocaleContextHolder.getLocale());
            String subject = bundle.getString("email.user.forgotPassword.subject");
            String text = bundle.getString("email.user.forgotPassword.text");
            String confirmationUrl = env.getProperty("module.core.auth.forgotPasswordConfirmUrl")
                    + user.getForgotPasswordConfirmationKey();

            sendConfirmationMail(user, subject, text, confirmationUrl);
        }
    }

    @Override
    public void forgotPasswordConfirm(String confirmationKey, String newPassword) {
        User user = repository.findByForgotPasswordConfirmationKey(confirmationKey);
        if (user != null) {
            user.setForgotPasswordConfirmationKey(null);
            user.setPassword(passwordEncoder.encode(newPassword));
            super.save(user);
        } else {
            throw new ApplicationException();
        }
    }

    @Override
    public void changeEmail(User user, String emailToBeConfirmed) {
        User userFoundByEmail = findByEmail(emailToBeConfirmed);
        if (userFoundByEmail == null) {
            user.setEmailToBeConfirmed(emailToBeConfirmed);
            user.setChangeEmailConfirmationKey(UUID.randomUUID().toString());
            user = super.save(user);

            ResourceBundle bundle = ResourceBundle.getBundle("messages", LocaleContextHolder.getLocale());
            String subject = bundle.getString("email.user.changeEmail.subject");
            String text = bundle.getString("email.user.changeEmail.text");
            String confirmationUrl = env.getProperty("module.core.auth.changeEmailConfirmUrl")
                    + user.getChangeEmailConfirmationKey();

            sendConfirmationMail(user.getFullName(), user.getEmailToBeConfirmed(), subject, text, confirmationUrl);
        } else {
            throw new AlreadyExistsException("email");
        }
    }

    @Override
    public void changeEmailConfirm(String confirmationKey) {
        User user = repository.findByChangeEmailConfirmationKey(confirmationKey);
        if (user != null) {
            User userFoundByEmail = findByEmail(user.getEmailToBeConfirmed());
            if (userFoundByEmail != null) {
                throw new AlreadyExistsException("email");
            }
            user.setEmail(user.getEmailToBeConfirmed());
            user.setChangeEmailConfirmationKey(null);
            user.setEmailToBeConfirmed(null);
            user = super.save(user);

            User principal = Core.currentUser();
            if (principal.getId().equals(user.getId())) {
                principal.setEmail(user.getEmail());
            }
        } else {
            throw new ApplicationException();
        }
    }

    @Override
    public User findBySubIdAndIssuer(String subId, String issuer) {
        return repository.findBySubIdAndIssuer(subId, issuer);
    }

    private void createRoleListForUser(User user) {
        Collection<Role> roleList;
        boolean adminAvailable = findByUsername(Core.BOOTSTRAP_ADMIN) != null;
        // Trust role list if the current user is a admin
        if (Core.isAdmin() || !adminAvailable) {
            roleList = user.getRoleList();
        } else {
            roleList = new ArrayList<>();
        }
        // Add user role if not exists
        if (!roleList.stream().anyMatch(r -> Core.ROLE_USER.equals(r.getName()))) {
            Role userRole = roleService.findByName(Core.ROLE_USER);
            roleList.add(userRole);
        }
        user.setRoleList(roleList);
    }

    private List<Role> filterRolesFromClient(String... roleNames) {
        List<Role> dbRoleList = new ArrayList<>();
        for (String roleName : roleNames) {
            Role dbRole = roleService.findByName(roleName);
            if (dbRole != null) {
                dbRoleList.add(dbRole);
            }
        }
        return dbRoleList;
    }

    private void setNewUserFields(User user, User userFoundByUsername, User userFoundByEmail) {
        // Check user input
        if (user.getPassword() == null) {
            throw new ValidationException("password");
        }
        if (userFoundByUsername != null) {
            throw new AlreadyExistsException("username=" + userFoundByUsername.getUsername());
        }
        if (userFoundByEmail != null) {
            throw new AlreadyExistsException("email" + userFoundByEmail.getEmail());
        }
        if (user.getEmail() != null && !emailValidator.isValid(user.getEmail())) {
            throw new ValidationException("email");
        }
        user.setId(null);
        user.setCreatedAt(new Date());
        user.setEnabled(true);
        String hashedPwd = encodePassword(user.getPassword());
        user.setPassword(hashedPwd);
        createRoleListForUser(user);
    }

    @SuppressWarnings("unchecked")
    private void sendConfirmationMail(String fullName, String email, String subject, String text,
            String confirmationUrl) {
        User user = new User();
        user.setFullName(fullName);
        user.setEmail(email);

        Map model = new HashMap<>();
        model.put("subject", subject);
        model.put("text", text);
        model.put("confirmationUrl", confirmationUrl);
        mailService.sendMail(user, model);
    }

    private void sendConfirmationMail(User user, String subject, String text, String confirmationUrl) {
        sendConfirmationMail(user.getFullName(), user.getEmail(), subject, text, confirmationUrl);
    }

    @Override
    public UserRepository getRepository() {
        return repository;
    }

    private static UserService instance;

    @PostConstruct
    public void afterPropertiesSet() throws Exception {
        instance = this;
    }

    public static UserService get() {
        return instance;
    }
}