package pl.com.bottega.documentmanagement.api;
import com.google.common.base.Charsets;
import com.google.common.collect.Collections2;
import com.google.common.collect.Sets;
import com.google.common.hash.Hashing;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import pl.com.bottega.documentmanagement.domain.Employee;
import pl.com.bottega.documentmanagement.domain.EmployeeId;
import pl.com.bottega.documentmanagement.domain.Role;
import pl.com.bottega.documentmanagement.domain.repositories.EmployeeRepository;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Created by maciuch on 12.06.16.
*/
@Service
//@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class UserManager {
private EmployeeRepository employeeRepository;
private Employee currentEmployee;
private EmployeeFactory employeeFactory;
private PasswordHasher passwordHasher;
public UserManager(EmployeeRepository employeeRepository, EmployeeFactory employeeFactory, PasswordHasher passwordHasher) {
this.employeeRepository = employeeRepository;
this.employeeFactory = employeeFactory;
this.passwordHasher = passwordHasher;
}
@Transactional(isolation = Isolation.REPEATABLE_READ)
public SignupResultDto signup(String login, String password, EmployeeId employeeId) {
Employee employee = employeeRepository.findByEmployeeId(employeeId);
if (employee == null)
return setupNewAccount(login, password, employeeId);
if (employee.isRegistered())
return failed("employee registered");
if (employeeRepository.isLoginOccupied(login))
return failed("login occupied");
employee.setupAccount(login, password);
employeeRepository.save(employee);
return success();
}
private SignupResultDto setupNewAccount(String login, String password, EmployeeId employeeId) {
if (employeeRepository.isLoginOccupied(login))
return failed("login is occupied");
else {
Employee employee = employeeFactory.create(login, password, employeeId);
employeeRepository.save(employee);
return success();
}
}
private SignupResultDto failed(String reason) {
return new SignupResultDto(reason);
}
private SignupResultDto success() {
return new SignupResultDto();
}
public SignupResultDto login(String login, String password) {
this.currentEmployee = employeeRepository.findByLoginAndPassword(login, passwordHasher.hashedPassword(password));
if (this.currentEmployee == null)
return failed("login or password incorrect");
else
return success();
}
public Employee currentEmployee() {
return this.currentEmployee;
}
public boolean isAuthenticated(String... roles) {
return currentEmployee != null && currentEmployee.hasRoles(roles);
}
@Transactional
@RequiresAuth(roles = "ADMIN")
public void updateRoles(EmployeeId employeeId, Set<String> roleNames) {
Employee employee = employeeRepository.findByEmployeeId(employeeId);
employee.updateRoles(getRoles(roleNames));
}
@Transactional
public void createAdmin() {
Employee employee = new Employee("admin", passwordHasher.hashedPassword("admin"), new EmployeeId(0L));
employee.updateRoles(getRoles(Sets.newHashSet("ADMIN")));
employeeRepository.save(employee);
}
private Set<Role> getRoles(String... roleNames) {
return getRoles(Sets.newHashSet(roleNames));
}
private Set<Role> getRoles(Set<String> roleNames) {
Set<Role> rolesToUpdate = new HashSet<>();
Collection<Role> existingRoles = employeeRepository.getRoles(roleNames);
rolesToUpdate.addAll(existingRoles);
for (String roleName : roleNames) {
Role role = new Role(roleName);
if (!existingRoles.contains(role))
rolesToUpdate.add(role);
}
return rolesToUpdate;
}
}