package com.sungardas.enhancedsnapshots.service.impl;
import java.util.List;
import com.sungardas.enhancedsnapshots.aws.dynamodb.Roles;
import com.sungardas.enhancedsnapshots.aws.dynamodb.model.User;
import com.sungardas.enhancedsnapshots.aws.dynamodb.repository.UserRepository;
import com.sungardas.enhancedsnapshots.dto.UserDto;
import com.sungardas.enhancedsnapshots.dto.converter.UserDtoConverter;
import com.sungardas.enhancedsnapshots.exception.DataAccessException;
import com.sungardas.enhancedsnapshots.exception.OperationNotAllowedException;
import com.sungardas.enhancedsnapshots.exception.UniqueConstraintViolationException;
import com.sungardas.enhancedsnapshots.service.UserService;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;
@Service
@DependsOn("ConfigurationMediator")
public class UserServiceImpl implements UserService {
private static final Logger LOG = LogManager.getLogger(UserServiceImpl.class);
@Autowired
private UserRepository userRepository;
@Override
public List<UserDto> getAllUsers() {
try {
return UserDtoConverter.convert(userRepository.findAll());
} catch (RuntimeException e) {
LOG.error(e);
throw new DataAccessException(e);
}
}
@Override
public void createUser(UserDto userInfo, String password) throws DataAccessException, UniqueConstraintViolationException {
// check whether user with the same email already exists
if (!userRepository.findByEmail(userInfo.getEmail().toLowerCase()).isEmpty()) {
UniqueConstraintViolationException e = new UniqueConstraintViolationException("User with such email already exists: " + userInfo.getEmail());
LOG.info("Failed to register user.", e);
throw e;
}
try {
User newUser = UserDtoConverter.convert(userInfo);
newUser.setPassword(DigestUtils.sha512Hex(password));
// convert user email to lowercase
newUser.setEmail(newUser.getEmail().toLowerCase());
if (newUser.getRole().isEmpty()) {
newUser.setRole(Roles.USER.getName());
}
userRepository.save(newUser);
} catch (RuntimeException e) {
LOG.error("Failed to register user.", e);
throw e;
}
}
@Override
public void createSamlUser(UserDto userInfo) throws DataAccessException, UniqueConstraintViolationException {
createUser(userInfo, "");
}
@Override
public void updateUser(UserDto userInfo, String newPassword, String currentUserEmail) {
// check user exists
List<User> users = userRepository.findByEmail(userInfo.getEmail().toLowerCase());
if (users.isEmpty()) {
DataAccessException e = new DataAccessException("User with such email does not exist: " + userInfo.getEmail());
LOG.info("Failed to update user.", e);
throw e;
}
try {
// currentUser - user who performs update
User currentUser = userRepository.findByEmail(currentUserEmail.toLowerCase()).get(0);
// check whether current user has permission to modify existing user
if (isAdmin(currentUser) || userInfo.getEmail().toLowerCase().equals(currentUserEmail)) {
User userToBeUpdated = users.get(0);
User updatedUser = UserDtoConverter.convert(userInfo);
updatedUser.setId(userToBeUpdated.getId());
// new password setting
if (newPassword != null && !newPassword.isEmpty()) {
updatedUser.setPassword(DigestUtils.sha512Hex(newPassword));
} else {
// in case password is empty we use old password
updatedUser.setPassword(userToBeUpdated.getPassword());
}
// in case it's last admin in system, ADMIN role can not be changed
if (isAdmin(userToBeUpdated) && updatedUser.getRole().equals(Roles.USER.getName()) && isLastAdmin()) {
OperationNotAllowedException e = new OperationNotAllowedException("At least one user with admin role must be in system.");
LOG.error("Admin role can not be changed in case it's last admin in system.", e);
throw e;
}
// not admin user can not change its role to admin
if (!isAdmin(currentUser) && updatedUser.getRole().equals(Roles.ADMIN.getName())) {
OperationNotAllowedException e = new OperationNotAllowedException("Only admin users can create other users with admin roles");
LOG.error("Only admin users can create other users with admin roles", e);
throw e;
}
// convert user email to lowercase
updatedUser.setEmail(updatedUser.getEmail().toLowerCase());
userRepository.save(updatedUser);
} else {
OperationNotAllowedException e = new OperationNotAllowedException("Only users with admin role can update users.");
LOG.error("Failed to update user.", e);
throw e;
}
} catch (RuntimeException e) {
LOG.error("Failed to update user.", e);
throw e;
}
}
@Override
public void removeUser(String userEmail) {
// check user exists
if (userRepository.findByEmail(userEmail.toLowerCase()).isEmpty()) {
DataAccessException e = new DataAccessException("User with such email does not exist: " + userEmail);
LOG.info("Failed to remove user.", e);
throw e;
}
try {
// in case it's last admin in system, it can not be removed
if (isAdmin(userEmail) && isLastAdmin()) {
OperationNotAllowedException e = new OperationNotAllowedException("Admin user can not be removed in case it is the last admin in system.");
LOG.debug("Admin user can not be removed in case it's last admin in system.", e);
throw e;
} else {
userRepository.delete(userRepository.findByEmail(userEmail));
}
} catch (RuntimeException e) {
LOG.error("Failed to remove user.", e);
throw e;
}
}
@Override
public User getUser(String user) {
// there should not be several users with one email
if(userRepository.findByEmail(user.toLowerCase()).isEmpty()){
return null;
}
return userRepository.findByEmail(user.toLowerCase()).get(0);
}
public boolean isAdmin(String userEmail) {
User user = userRepository.findByEmail(userEmail.toLowerCase()).get(0);
return user.getRole() != null && user.getRole().equals(Roles.ADMIN.getName());
}
private boolean isAdmin(User user) {
return user.getRole() != null &&
user.getRole().equals(Roles.ADMIN.getName());
}
private boolean isLastAdmin() {
return userRepository.findByRole(Roles.ADMIN.getName()).size() == 1;
}
}