package ee.esutoniagodesu.service;
import ee.esutoniagodesu.domain.ac.table.EAuthority;
import ee.esutoniagodesu.domain.ac.table.User;
import ee.esutoniagodesu.domain.ac.table.UserAccountExternal;
import ee.esutoniagodesu.repository.domain.ac.UserRepository;
import ee.esutoniagodesu.security.AuthoritiesConstants;
import ee.esutoniagodesu.security.SecurityUtils;
import ee.esutoniagodesu.util.JCRandom;
import ee.esutoniagodesu.util.RandomUtil;
import ee.esutoniagodesu.util.iso.ISO6391;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.inject.Inject;
import java.time.ZonedDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
/**
* Service class for managing users.
*/
@Service
@Transactional
public class UserService {
private static final Logger log = LoggerFactory.getLogger(UserService.class);
@Inject
private PasswordEncoder passwordEncoder;
@Inject
private UserRepository userRepository;
public Optional<User> activateRegistration(String key) {
log.debug("Activating user for activation key {}", key);
return userRepository.findOneByActivationKey(key)
.map(user -> {
// activate given user for the registration key.
user.setActivated(true);
user.setActivationKey(null);
userRepository.save(user);
log.debug("Activated user: {}", user);
return user;
});
}
public Optional<User> completePasswordReset(String newPassword, String key) {
log.debug("Reset user password for reset key {}", key);
return userRepository.findOneByResetKey(key)
.filter(user -> {
ZonedDateTime oneDayAgo = ZonedDateTime.now().minusHours(24);
return user.getAccountForm().getResetDate().isAfter(oneDayAgo);
})
.map(user -> {
user.getAccountForm().setPassword(passwordEncoder.encode(newPassword));
user.getAccountForm().setResetKey(null);
user.getAccountForm().setResetDate(null);
userRepository.save(user);
return user;
});
}
public Optional<User> requestPasswordReset(String mail) {
return userRepository.findOneByEmail(mail)
.filter(User::isActivated)
.map(user -> {
user.getAccountForm().setResetKey(RandomUtil.generateResetKey());
user.getAccountForm().setResetDate(ZonedDateTime.now());
userRepository.save(user);
return user;
});
}
public static User newUser(User newUser) {
newUser.setUuid(JCRandom.random13B());
Set<EAuthority> authorities = new HashSet<>();
authorities.add(EAuthority.ROLE_USER);
newUser.setAuthorities(authorities);
return newUser;
}
public User addExternalToUser(User user, UserAccountExternal external) {
external.setUser(user);
user.getAccountExternals().add(external);
userRepository.save(user);
log.debug("Created External Information {} for Social User: {}", external, user);
return user;
}
public User createUserWithExternal(User newUser) {
return createUserWithExternal(newUser, userRepository);
}
public static User createUserWithExternal(User newUser, UserRepository userRepository) {
newUser = newUser(newUser);
newUser.setActivated(true);
UserAccountExternal external = newUser.getAccountExternals().iterator().next();
external.setUser(newUser);
userRepository.save(newUser);
log.debug("Created External Information {} for Social User: {}", external, newUser);
return newUser;
}
public User createUserWithAccountForm(User newUser) {
newUser = newUser(newUser);
// new user is not active
newUser.setActivated(false);
// new user gets registration key
newUser.setActivationKey(RandomUtil.generateActivationKey());
// new user gets initially a generated password
String encryptedPassword = passwordEncoder.encode(newUser.getAccountForm().getPassword());
newUser.getAccountForm().setPassword(encryptedPassword);
newUser.getAccountForm().setUser(newUser);
userRepository.save(newUser);
log.debug("Created Information for User: {}", newUser);
return newUser;
}
public void updateUserInformation(String firstName, String lastName, String email, ISO6391 langKey) {
securityUser().ifPresent(u -> {
u.setFirstName(firstName);
u.setLastName(lastName);
u.setEmail(email);
u.setLangKey(langKey);
userRepository.save(u);
log.debug("Changed Information for User: {}", u);
});
}
public void changePassword(String password) {
securityUser().ifPresent(u -> {
String encryptedPassword = passwordEncoder.encode(password);
u.getAccountForm().setPassword(encryptedPassword);
userRepository.save(u);
log.debug("Changed password for User: {}", u);
});
}
@Transactional(readOnly = true)
public User getUserWithAuthorities() {
User currentUser = securityUser().get();
currentUser.getAuthorities().size(); // eagerly load the association
return currentUser;
}
private Optional<User> securityUser() {
return userRepository.findOneByUuid(SecurityUtils.getUserUuid());
}
public void deleteAccount() {
if (!SecurityUtils.isAuthenticated()) {
throw new IllegalStateException("not authenticated");
}
if (SecurityUtils.isUserInRole(AuthoritiesConstants.ADMIN)) {
throw new IllegalStateException("delete admin account not allowed");
}
securityUser().ifPresent(user -> {
userRepository.delete(user);
log.debug("Deleted account for User: {}", user);
});
}
/**
* Not activated users should be automatically deleted after 3 days.
* <p/>
* <p>
* This is scheduled to get fired everyday, at 01:00 (am).
* </p>
*/
@Scheduled(cron = "0 0 1 * * ?")
public void removeNotActivatedUsers() {
ZonedDateTime now = ZonedDateTime.now();
List<User> users = userRepository.findAllByActivatedIsFalseAndCreatedDateBefore(now.minusDays(3));
for (User user : users) {
log.debug("Deleting not activated user {}", user.toString());
userRepository.delete(user);
}
}
}