package com.porterhead.user;
import com.porterhead.service.BaseService;
import com.porterhead.user.api.ApiUser;
import com.porterhead.user.api.CreateUserRequest;
import com.porterhead.user.api.UpdateUserRequest;
import com.porterhead.user.exception.AuthenticationException;
import com.porterhead.user.exception.DuplicateUserException;
import com.porterhead.user.exception.UserNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import javax.validation.Validator;
import static org.springframework.util.Assert.notNull;
@Service
public class UserServiceImpl extends BaseService implements UserService, UserDetailsService {
private Logger LOG = LoggerFactory.getLogger(UserService.class);
private UserRepository userRepository;
private PasswordEncoder passwordEncoder;
@Autowired
public UserServiceImpl(final UserRepository userRepository, Validator validator,
PasswordEncoder passwordEncoder) {
super(validator);
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return locateUser(username);
}
@Transactional
public ApiUser createUser(final CreateUserRequest createUserRequest) {
LOG.info("Validating user request.");
validate(createUserRequest);
final String emailAddress = createUserRequest.getUser().getEmailAddress().toLowerCase();
if (userRepository.findByEmailAddress(emailAddress) == null) {
LOG.info("User does not already exist in the data store - creating a new user [{}].",
emailAddress);
User newUser = insertNewUser(createUserRequest);
LOG.debug("Created new user [{}].", newUser.getEmailAddress());
return new ApiUser(newUser);
} else {
LOG.info("Duplicate user located, exception raised with appropriate HTTP response code.");
throw new DuplicateUserException();
}
}
@Override
public ApiUser authenticate(String username, String password) {
Assert.notNull(username);
Assert.notNull(password);
User user = locateUser(username);
if(!passwordEncoder.encode(password).equals(user.getHashedPassword())) {
throw new AuthenticationException();
}
return new ApiUser(user);
}
@Transactional
public ApiUser saveUser(String userId, UpdateUserRequest request) {
validate(request);
User user = userRepository.findById(userId);
if(user == null) {
throw new UserNotFoundException();
}
if(request.getFirstName() != null) {
user.setFirstName(request.getFirstName());
}
if(request.getLastName() != null) {
user.setLastName(request.getLastName());
}
if(request.getEmailAddress() != null) {
if(!request.getEmailAddress().equals(user.getEmailAddress())) {
user.setEmailAddress(request.getEmailAddress());
user.setVerified(false);
}
}
userRepository.save(user);
return new ApiUser(user);
}
@Override
public ApiUser getUser(String userId) {
Assert.notNull(userId);
User user = userRepository.findById(userId);
if(user == null) {
throw new UserNotFoundException();
}
return new ApiUser(user);
}
/**
* Locate the user and throw an exception if not found.
*
* @param username
* @return a User object is guaranteed.
* @throws AuthenticationException if user not located.
*/
private User locateUser(final String username) {
notNull(username, "Mandatory argument 'username' missing.");
User user = userRepository.findByEmailAddress(username.toLowerCase());
if (user == null) {
LOG.debug("Credentials [{}] failed to locate a user.", username.toLowerCase());
throw new UsernameNotFoundException("failed to locate a user");
}
return user;
}
private User insertNewUser(final CreateUserRequest createUserRequest) {
String hashedPassword = passwordEncoder.encode(createUserRequest.getPassword().getPassword());
User newUser = new User(createUserRequest.getUser(), hashedPassword, Role.ROLE_USER);
return userRepository.save(newUser);
}
}