package com.aemreunal.service; /* * *********************** * * Copyright (c) 2015 * * * * This code belongs to: * * * * @author Ahmet Emre Ünal * * S001974 * * * * aemreunal@gmail.com * * emre.unal@ozu.edu.tr * * * * aemreunal.com * * *********************** * */ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.aemreunal.config.GlobalSettings; import com.aemreunal.domain.User; import com.aemreunal.exception.user.InvalidUsernameException; import com.aemreunal.exception.user.UserNotFoundException; import com.aemreunal.exception.user.UsernameClashException; import com.aemreunal.repository.user.UserRepo; import com.aemreunal.repository.user.UserSpecs; @Transactional @Service public class UserService { @Autowired private UserRepo userRepo; @Autowired private BCryptPasswordEncoder passwordEncoder; /** * Saves/updates the given user * * @param user * The user to save/update * * @return The saved/updated user */ public User save(User user) { // Encrypt the password if a new user is persisted. // TODO check possible password re-hashing bug when user is updated if (user.getUserId() == null) { user.setPassword(passwordEncoder.encode(user.getPassword())); } verifyUsernameCorrectness(user.getUsername()); verifyUsernameUniqueness(user.getUsername()); GlobalSettings.log("Saving user with ID = \'" + user.getUserId() + "\'"); return userRepo.save(user); } /** * Checks whether the specified username is correct (whether it already exists, * whether it contains spaces or not, etc.). * <p> * Usernames must: <li>Be less than {@value com.aemreunal.domain.User#USERNAME_MAX_LENGTH} * characters</li> <li>Start with a letter</li> <li>Not have any spaces</li> <li>Not * have any non-ASCII characters</li> <li>Not be the same as any existing * username</li> * * @param username * The username to check * * @throws InvalidUsernameException * When the username is invalid due to reasons stated above */ private void verifyUsernameCorrectness(String username) throws InvalidUsernameException { if (username.length() > User.USERNAME_MAX_LENGTH) { // The specified username contains more characters than allowed throw new InvalidUsernameException(username, "Username contains more than allowed number of characters!"); } else if (!Character.isLetter(username.charAt(0))) { // The specified username does not begin with a letter throw new InvalidUsernameException(username, "Username does not begin with a letter!"); } else if (username.indexOf(' ') != -1) { // The specified username contains spaces throw new InvalidUsernameException(username, "Username can not contain spaces!"); } else if (username.matches(GlobalSettings.NON_ASCII_REGEX)) { // The specified username contains non-ASCII characters throw new InvalidUsernameException(username, "Username can not contain non-ASCII characters!"); } else { for (char ch : username.toCharArray()) { if (!Character.isLetterOrDigit(ch)) { // The specified username contains a non-alphanumeric character throw new InvalidUsernameException(username, "Username contains an illegal (non-alphanumeric) character!"); } } } } /** * Check whether the given username is already taken or not * * @param username * The username of the user to check * * @throws UsernameClashException * When the username already exists */ @Transactional(readOnly = true) public void verifyUsernameUniqueness(String username) throws UsernameClashException { GlobalSettings.log("Checking whether username = \'" + username + "\' is taken"); if (userRepo.count(UserSpecs.usernameSpecification(username)) != 0) { // The specified username already exists throw new UsernameClashException(username); } } /** * Find the user with the given username * * @param username * The username of the user to search for * * @return The user with the given username */ @Transactional(readOnly = true) public User findByUsername(String username) { GlobalSettings.log("Finding user with username = \'" + username + "\'"); verifyUsernameCorrectness(username); User user = userRepo.findByUsername(username); if (user == null) { throw new UserNotFoundException(); } return user; } /** * Deletes the user with the given username and deletes everything (projects, etc.) * associated with the user * * @param username * The username of the user to delete * * @return Whether the user was deleted or not */ public User delete(String username) { GlobalSettings.log("Deleting user with username = \'" + username + "\'"); User userToDelete = findByUsername(username); userRepo.delete(userToDelete); return userToDelete; } }