/* vim: set ts=2 et sw=2 cindent fo=qroca: */
package com.globant.katari.user.application;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.Errors;
import com.globant.katari.core.application.Command;
import com.globant.katari.core.application.Initializable;
import com.globant.katari.core.application.Validatable;
import com.globant.katari.hibernate.coreuser.domain.Role;
import com.globant.katari.hibernate.coreuser.domain.RoleRepository;
import com.globant.katari.hibernate.coreuser.SecurityUtils;
import com.globant.katari.user.domain.User;
import com.globant.katari.user.domain.UserRepository;
/** Save user command.
*
* The execution of this command saves a user into the user repository.
*
* @author nicolas.frontini
*/
public class SaveUserCommand implements Command<Void>, Validatable,
Initializable {
/** The class logger.
*/
private static Logger log = LoggerFactory.getLogger(SaveUserCommand.class);
/** The user repository.
*/
private UserRepository userRepository;
/** The role repository.
*/
private RoleRepository roleRepository;
/** The id of the user.
*/
private long userId = 0;
/** The url to redirect back after editing the user.
*
* Goes back to the user list if not specified.
*/
private String backTo = null;
/**
* The list of all roles available in the system.
* It is null .
*/
private List<Role> availableRoles = null;
/** The user profile.
*
* It is null when changing the password of an existing user.
*/
private Profile profile;
/** The user password.
*
* It is null when changing the profile of an existing user.
*/
private Password password;
/** Constructor to dynamically proxy this type of command.
*/
protected SaveUserCommand() {
}
/** Constructor, builds a SaveUserCommand suitable for creating new users.
*
* @param theUserRepository The user repository. It cannot be null.
*
* @param theRoleRepository The role repository. It cannot be null.
*
* @param theProfile The user profile. It cannot be null.
*
* @param thePassword The password. It cannot be null.
*/
public SaveUserCommand(final UserRepository theUserRepository, final
RoleRepository theRoleRepository, final Profile theProfile, final
Password thePassword) {
Validate.notNull(theUserRepository, "The user repository cannot be null");
Validate.notNull(theRoleRepository, "The role repository cannot be null");
Validate.notNull(theProfile, "The user profile helper cannot be null");
Validate.notNull(thePassword, "The password helper cannot be null");
userRepository = theUserRepository;
roleRepository = theRoleRepository;
profile = theProfile;
password = thePassword;
}
/** Constructor, builds a SaveUserCommand suitable for modifying the user
* profile.
*
* @param theUserRepository The user repository. It cannot be null.
*
* @param theRoleRepository The role repository. It cannot be null.
*
* @param theProfile The user profile. It cannot be null.
*/
public SaveUserCommand(final UserRepository theUserRepository, final
RoleRepository theRoleRepository, final Profile theProfile) {
Validate.notNull(theUserRepository, "The user repository cannot be null");
Validate.notNull(theRoleRepository, "The role repository cannot be null");
Validate.notNull(theProfile, "The user profile helper cannot be null");
userRepository = theUserRepository;
roleRepository = theRoleRepository;
profile = theProfile;
}
/** Constructor, builds a SaveUserCommand suitable for changing the user
* password.
*
* @param theUserRepository The user repository. It cannot be null.
*
* @param theRoleRepository The role repository. It cannot be null.
*
* @param thePassword The password. It cannot be null.
*/
public SaveUserCommand(final UserRepository theUserRepository, final
RoleRepository theRoleRepository, final Password thePassword) {
Validate.notNull(theUserRepository, "The user repository cannot be null");
Validate.notNull(theRoleRepository, "The role repository cannot be null");
Validate.notNull(thePassword, "The password helper cannot be null");
userRepository = theUserRepository;
roleRepository = theRoleRepository;
password = thePassword;
}
/** Returns the id of the user.
*
* @return Returns the user id, 0 for a new user.
*/
public long getUserId() {
return userId;
}
/** Sets the id of the user.
*
* @param theUserId The id of the user. It cannot be 0.
*/
public void setUserId(final long theUserId) {
Validate.notNull(theUserId, "The user id cannot be 0.");
userId = theUserId;
}
/** Returns the profile.
*
* @return Returns the profile. It returns null only when modifying an
* existing user password.
*/
public Profile getProfile() {
return profile;
}
/** Returns the password.
*
* @return Returns the password. It returns null only when modifying the user
* profile.
*/
public Password getPassword() {
return password;
}
/** Returns the url to redirect to after saving the user information.
*
* @return Returns the url, as provided by the user.
*/
public String getBackTo() {
return backTo;
}
/** Sets the url to redirect to after saving the user information.
*
* @param theUrl the url to return to. If not specified, it returns to the
* list of users.
*/
public void setBackTo(final String theUrl) {
backTo = theUrl;
}
/** Returns all the available roles.
*
* @return Returns all the available roles, as a map of id to role name. It
* Never returns null.
*/
public Map<String, String> getAvailableRoles() {
// User Roles.
Map<String, String> rolesMap = new LinkedHashMap<String, String>();
for (Role role : availableRoles) {
rolesMap.put(String.valueOf(role.getId()), role.getName());
}
return rolesMap;
}
/**
* Returns the list of available roles.
* @return The list of roles, never null.
*/
public List<Role> getRoles() {
return Collections.unmodifiableList(availableRoles);
}
/** Returns the currently logged in user.
*
* @return The currently logged in user, never null.
*/
public User getMe() {
return (User) SecurityUtils.getCurrentUser();
}
/** Initializes this command form the specified userId.
*
* This loads the user specified in the user id. If it is not found, it throws
* an IllegalArgumentException.
*/
public void init() {
log.trace("Entering init");
availableRoles = roleRepository.getRoles();
if (userId != 0) {
User user = userRepository.findUser(userId);
if (user == null) {
throw new IllegalArgumentException("The user id was not found");
}
if (profile != null) {
profile.init(user);
}
}
log.trace("Leaving init");
}
/** Validates the user profile and the password data if it is a new user.
*
* Validates the user profile if it is a preexistent user being edited.
*
* Validates the password data if it is a change password action on a
* preexistent user.
*
* @param errors Contextual state about the validation process. It can not be
* null.
*/
public void validate(final Errors errors) {
log.trace("Entering validate");
if (profile != null) {
errors.pushNestedPath("profile");
profile.validate(userRepository, getUserId(), errors);
errors.popNestedPath();
}
if (password != null) {
User me = (User) SecurityUtils.getCurrentUser();
User user = userRepository.findUser(userId);
boolean editingMyself = (user != null && user.getId() == me.getId());
if (!editingMyself && me.isAdministrator()) {
// If an admin is editing somebody else, we skip the current password
// validation.
user = null;
}
errors.pushNestedPath("password");
password.validate(user, errors);
errors.popNestedPath();
}
log.trace("Leaving validate");
}
/** Modifies the user profile or password.
*
* Saves the user into the repository.
*
* The user must be logged in.
*
* The user is changing his own data or is an administrator.
*
* @return It returns nothing.
*/
public Void execute() {
log.trace("Entering execute");
User me = (User) SecurityUtils.getCurrentUser();
if (me == null) {
throw new RuntimeException("Not enough privileges");
}
User user = userRepository.findUser(userId);
boolean editingMyself = (user != null && user.getId() == me.getId());
if (!(editingMyself || me.isAdministrator())) {
// Non administrators can only edit theirselves.
throw new RuntimeException("Not enough privileges");
}
if (profile != null) {
user = profile.apply(roleRepository, user);
}
if (password != null) {
user = password.apply(user);
}
userRepository.save(user);
log.trace("Leaving execute");
return null;
}
}