package de.flower.rmt.service;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import de.flower.common.service.security.IPasswordGenerator;
import de.flower.common.util.Check;
import de.flower.common.util.NameFinder;
import de.flower.rmt.model.db.entity.Player_;
import de.flower.rmt.model.db.entity.Role;
import de.flower.rmt.model.db.entity.Team;
import de.flower.rmt.model.db.entity.User;
import de.flower.rmt.model.db.entity.User_;
import de.flower.rmt.model.db.entity.event.Event;
import de.flower.rmt.model.dto.Password;
import de.flower.rmt.repository.IRoleRepo;
import de.flower.rmt.repository.IUserRepo;
import de.flower.rmt.repository.Specs;
import de.flower.rmt.service.mail.INotificationService;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.mail.internet.InternetAddress;
import javax.persistence.metamodel.Attribute;
import javax.validation.Validator;
import java.util.List;
import static de.flower.common.util.Check.*;
import static de.flower.rmt.repository.Specs.*;
import static org.springframework.data.jpa.domain.Specifications.where;
/**
* @author flowerrrr
*/
@Service
@Transactional(readOnly = true, propagation = Propagation.REQUIRED)
public class UserManager extends AbstractService implements IUserManager {
@Autowired
private IUserRepo userRepo;
@Autowired
private IRoleRepo roleRepo;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private IPasswordGenerator passwordGenerator;
@Autowired
private INotificationService notificationService;
@Autowired
private IRoleManager roleManager;
@Autowired
private IPlayerManager playerManager;
@Autowired
private Validator validator;
@Override
public User loadById(Long id, final Attribute... attributes) {
User entity = userRepo.findOne(where(eq(User_.id, id)).and(fetch(attributes)).and(fetch(User_.club)));
Check.notNull(entity);
assertClub(entity);
return entity;
}
@Override
public User findByUsername(String username, final Attribute... attributes) {
User entity = userRepo.findOne(where(eq(User_.email, username)).and(fetch(attributes)));
return entity;
}
@Override
@Transactional(readOnly = false)
public void save(User user) {
// check that a role is assigned
boolean isNew = user.isNew();
if (isNew) {
notEmpty(user.getRoles(), "user has no role(s) assigned");
}
userRepo.save(user);
if (isNew) {
for (Role role : user.getRoles()) {
roleRepo.save(role);
}
}
}
@Override
@Transactional(readOnly = false)
public void save(final User user, final boolean isManager) {
validate(user);
save(user);
if (isManager) {
roleManager.addRole(user.getId(), Role.Roles.MANAGER.getRoleName());
} else {
roleManager.removeRole(user.getId(), Role.Roles.MANAGER.getRoleName());
}
}
@Override
public List<User> findAll(final Attribute... attributes) {
List<User> list = userRepo.findAll(where(fetch(attributes)).and(asc(User_.fullname)));
return list;
}
@Override
public List<User> findAllFetchTeams(final Attribute... attributes) {
List<User> list = userRepo.findAllFetchTeams(getClub());
return list;
}
@Override
public List<User> findAllByTeam(final Team team) {
Check.notNull(team);
Specification spec = Specs.joinEq(User_.players, Player_.team, team);
return userRepo.findAll(where(spec).and(asc(User_.fullname)));
}
@Override
public List<User> findAllUnassignedPlayers(final Team team) {
return userRepo.findAllUnassignedPlayers(team, getClub());
}
@Override
public List<User> findAllUninvitedPlayers(final Event event) {
return userRepo.findAllUninvitedPlayers(event, getClub());
}
@Override
public List<User> findAllUninvitedPlayersByTeam(final Event event, final Team team) {
// get list of uninvited users and list of users of this team and intersect both sets.
List<User> uninvited = findAllUninvitedPlayers(event);
List<User> usersByTeam = findAllByTeam(team);
uninvited.retainAll(usersByTeam);
return uninvited;
}
@Override
@Transactional(readOnly = false)
public void delete(Long id) {
User entity = loadById(id);
// do not allow to delete currently logged in user
if (securityService.isCurrentUser(entity)) {
throw new IllegalArgumentException("Cannot delete currently logged in user.");
}
entity.setEmail(NameFinder.delete(entity.getEmail(), new Predicate<String>() {
@Override
public boolean apply(final String candidate) {
return userRepo.findByEmail(candidate) == null;
}
}));
entity.setFullname(NameFinder.delete(entity.getFullname(), new Predicate<String>() {
@Override
public boolean apply(final String candidate) {
return userRepo.findByFullname(candidate) == null;
}
}));
userRepo.softDelete(entity);
// delete user from all teams
playerManager.removeUserFromAllTeams(entity);
}
@Override
public User newInstance() {
User user = new User(getClub());
Role role = new Role(Role.Roles.PLAYER.getRoleName());
user.getRoles().add(role);
role.setUser(user);
initPassword(user);
// by default a new user is assumed to be fit.
user.setStatus(User.Status.FIT);
user.setEnabled(true);
return user;
}
@Override
@Transactional(readOnly = false)
public void resetPassword(final User user, final boolean sendMail) {
initPassword(user);
if (sendMail) {
notificationService.sendResetPasswordMail(user, securityService.getUser());
// even if user hasen't received invitation mail yet
user.setInvitationSent(true);
}
userRepo.save(user);
}
private void initPassword(User user) {
String initialPassword = passwordGenerator.generatePassword();
user.setInitialPassword(initialPassword);
user.setEncryptedPassword(encodePassword(initialPassword));
}
@Override
public void updatePassword(final Long userId, Password password) {
Check.notNull(userId);
User user = loadById(userId);
validate(password);
user.setInitialPassword(null);
user.setEncryptedPassword(encodePassword(password.getNewPassword()));
userRepo.save(user);
}
private String encodePassword(String password) {
return passwordEncoder.encodePassword(password, null);
}
@Override
@Transactional(readOnly = false)
public void sendInvitation(Long userId) {
User user = loadById(userId);
notificationService.sendInvitationNewUser(user, securityService.getUser());
user.setInvitationSent(true);
userRepo.save(user);
}
@Override
public List<InternetAddress> getAddressesForfAllUsers() {
List<User> users = findAll();
// convert to list of internet addresses
List<InternetAddress[]> internetAddresses = Lists.transform(users, new Function<User, InternetAddress[]>() {
@Override
public InternetAddress[] apply(final User user) {
return user.getInternetAddresses();
}
});
return de.flower.common.util.Collections.flattenArray(internetAddresses);
}
@Override
public void onLoginSuccess(final User userIn) {
User user = loadById(userIn.getId());
user.setLastLogin(new DateTime());
userRepo.save(user);
}
}