UserDetailsController.java
package sk.iway.iwcm.components.users.userdetail;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.codec.binary.Base64;
import org.apache.struts.util.ResponseUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import sk.iway.Password;
import sk.iway.iwcm.Constants;
import sk.iway.iwcm.Identity;
import sk.iway.iwcm.Tools;
import sk.iway.iwcm.common.CloudToolsForCore;
import sk.iway.iwcm.common.DocTools;
import sk.iway.iwcm.common.UserTools;
import sk.iway.iwcm.components.users.AuthorizeUserService;
import sk.iway.iwcm.components.users.groups_approve.GroupsApproveRepository;
import sk.iway.iwcm.i18n.Prop;
import sk.iway.iwcm.system.ModuleInfo;
import sk.iway.iwcm.system.Modules;
import sk.iway.iwcm.system.datatable.Datatable;
import sk.iway.iwcm.system.datatable.DatatablePageImpl;
import sk.iway.iwcm.system.datatable.DatatableRequest;
import sk.iway.iwcm.system.datatable.DatatableRestControllerV2;
import sk.iway.iwcm.system.datatable.NotifyBean;
import sk.iway.iwcm.system.datatable.NotifyButton;
import sk.iway.iwcm.system.datatable.NotifyBean.NotifyType;
import sk.iway.iwcm.system.datatable.ProcessItemAction;
import sk.iway.iwcm.system.datatable.SpecSearch;
import sk.iway.iwcm.users.PasswordSecurity;
import sk.iway.iwcm.users.PermissionGroupDB;
import sk.iway.iwcm.users.UserGroupDetails;
import sk.iway.iwcm.users.UserGroupsDB;
import sk.iway.iwcm.users.UsersDB;
@RestController
@Datatable
@RequestMapping(value = "/admin/rest/users")
@PreAuthorize(value = "@WebjetSecurityService.hasPermission('menuUsers')")
public class UserDetailsController extends DatatableRestControllerV2<UserDetailsEntity, Long> {
private final UserDetailsService userDetailsService;
private final UserDetailsRepository userDetailsRepository;
private final GroupsApproveRepository groupsApproveRepository;
private static final String PERM_EDIT_ADMINS = "users.edit_admins";
private static final String PERM_EDIT_PUBLIC_USERS = "users.edit_public_users";
@Autowired
public UserDetailsController(UserDetailsRepository userDetailsRepository, UserDetailsService userDetailsService, GroupsApproveRepository groupsApproveRepository) {
super(userDetailsRepository);
this.userDetailsRepository = userDetailsRepository;
this.userDetailsService = userDetailsService;
this.groupsApproveRepository = groupsApproveRepository;
}
@Override
public Page<UserDetailsEntity> getAllItems(Pageable pageable) {
DatatablePageImpl<UserDetailsEntity> page = new DatatablePageImpl<>(getAllItemsIncludeSpecSearch(new UserDetailsEntity(), pageable));
Prop prop = Prop.getInstance(Constants.getServletContext(), getRequest());
Modules modules = Modules.getInstance();
List<ModuleInfo> moduleItems = modules.getUserEditItems(prop);
getRequest().setAttribute("moduleItems",moduleItems);
page.addOptions("editorFields.emails", UserGroupsDB.getInstance().getUserGroupsByTypeId(UserGroupDetails.TYPE_EMAIL), "userGroupName", "userGroupId", false);
page.addOptions("editorFields.permisions", UserGroupsDB.getInstance().getUserGroupsByTypeId(UserGroupDetails.TYPE_PERMS), "userGroupName", "userGroupId", false);
page.addOptions("editorFields.enabledItems", moduleItems, "itemKey", "itemKey", false);
page.addOptions("editorFields.permGroups", (new PermissionGroupDB()).getAll(), "title", "id", false);
return page;
}
@Override
public UserDetailsEntity getOneItem(long id) {
UserDetailsEntity one = super.getOneItem(id);
if (id < 1) {
//novy zaznam, nastav defaultne hodnoty
//DTED 2.0.5 ma bug kedy padne, ak takyto option nema ziadnu hodnotu, museli sme nastavit
one.setSexMale(true);
one.setAuthorized(Boolean.TRUE);
} else {
if (UserDetailsService.isUsersSplitByDomain()) {
if (one.getDomainId()!=CloudToolsForCore.getDomainId()) return null;
}
}
return one;
}
@Override
public void beforeSave(UserDetailsEntity entity) {
Identity user = UsersDB.getCurrentUser(getRequest());
Boolean isCurrentUserAdmin = user.isEnabledItem(PERM_EDIT_ADMINS);
//If the user does not have admin permission but trying set admin permission throw error
if(!isCurrentUserAdmin.booleanValue() && entity.getAdmin().booleanValue()) {
throwError("components.file_archiv.file_rename.nemate_pravo_na_tuto_editaciu");
}
//Chceck if rating rank is set like null and set to 0
if(entity.getRatingRank() == null) {
entity.setRatingRank(0);
}
//Chceck if forum rank is set like null and set to 0
if(entity.getForumRank() == null) {
entity.setForumRank(0);
}
//Chceck if parent id is set like null and set to 0
if(entity.getParentId() == null) {
entity.setParentId(0);
}
if (entity.getRegDate() == null) entity.setRegDate(new Date(Tools.getNow()));
//Save into session last saved user group's
userDetailsService.setBeforeSaveUserGroups(entity);
}
@Override
public void afterSave(UserDetailsEntity entity, UserDetailsEntity saved) {
if ("*".equals(entity.getApiKey())) {
//vygeneruj access token
String apiKey = PasswordSecurity.generatePassword(32, true, true, true, true, false);
entity.setApiKey(apiKey);
String header = saved.getLogin()+":"+apiKey;
header = Constants.getString("logonTokenHeaderName") + ":" + Base64.encodeBase64String(header.getBytes());
addNotify(new NotifyBean(getProp().getText("components.user.apiKey.notifyTitle"), getProp().getText("components.user.apiKey.notifyText", ResponseUtils.filter(apiKey), header), NotifyType.SUCCESS));
}
boolean saveSuccess = userDetailsService.afterSave(entity, saved);
if (saveSuccess==false) throwError("editor.ajax.save.error");
//Save was successfull, send email's about adding to user groups (if user was added into new user group)
userDetailsService.sendUserGroupsEmails(saved, entity, getUser(), getRequest());
//update current user if editing self
if (userDetailsService.updateSelf(saved, getUser(), getRequest())) {
NotifyBean notify = new NotifyBean(getProp().getText("user.profile.save.title.js"), getProp().getText("user.profile.save.notifyText.js"), NotifyType.INFO, 10000);
notify.addButton(new NotifyButton(getProp().getText("menu.logout"), "btn btn-primary", "ti ti-logout", "window.location.href=$('.js-logout-toggler').attr('href')"));
addNotify(notify);
}
}
@Override
public void addSpecSearch(Map<String, String> params, List<Predicate> predicates, Root<UserDetailsEntity> root, CriteriaBuilder builder) {
Identity user = UsersDB.getCurrentUser(getRequest());
//Check user permissions and return for this user editable entities
Expression<Boolean> colAdmin = root.get("admin");
if(!user.isEnabledItem(PERM_EDIT_ADMINS) && user.isEnabledItem(PERM_EDIT_PUBLIC_USERS)) {
predicates.add(builder.isFalse(colAdmin));
} else if(user.isEnabledItem(PERM_EDIT_ADMINS) && !user.isEnabledItem(PERM_EDIT_PUBLIC_USERS)) {
predicates.add(builder.isTrue(colAdmin));
} else if(!user.isEnabledItem(PERM_EDIT_ADMINS) && !user.isEnabledItem(PERM_EDIT_PUBLIC_USERS)) {
//If user doesnt have admin and public perm in same time
predicates.add(builder.isFalse(colAdmin));
predicates.add(builder.isTrue(colAdmin));
}
SpecSearch<UserDetailsEntity> specSearch = new SpecSearch<>();
String permissions = params.get("searchEditorFields.permisions");
if (permissions != null) {
specSearch.addSpecSearchPasswordProtected(permissions, "userGroupsIds", predicates, root, builder);
}
String emails = params.get("searchEditorFields.emails");
if (emails != null) {
specSearch.addSpecSearchPasswordProtected(emails, "userGroupsIds", predicates, root, builder);
}
int userGroupId = Tools.getIntValue(params.get("userGroupId"), -1);
if (userGroupId > 0) {
specSearch.addSpecSearchPasswordProtected(userGroupId, "userGroupsIds", predicates, root, builder);
}
int permGroup = Tools.getIntValue(params.get("searchEditorFields.permGroups"), -1);
if(permGroup > 0) {
specSearch.addSpecSearchIdInForeignTableInteger(permGroup, "users_in_perm_groups", "user_id", "perm_group_id", "id", predicates, root, builder);
}
if (UserDetailsService.isUsersSplitByDomain()) {
predicates.add(builder.equal(root.get("domainId"), CloudToolsForCore.getDomainId()));
}
super.addSpecSearch(params, predicates, root, builder);
}
@SuppressWarnings("all")
@Override
public void validateEditor(HttpServletRequest request, DatatableRequest<Long, UserDetailsEntity> target, Identity user, Errors errors, Long id, UserDetailsEntity entity) {
if ("remove".equals(target.getAction())) return;
if ("random".equals(entity.getPassword()) || "*".equals(entity.getPassword()))
{
//vygeneruj heslo
entity.setPassword(Password.generateStringHash(5)+Password.generatePassword(5));
}
Prop prop = Prop.getInstance(request);
//Import setting
if(isImporting()) {
if(Tools.isEmpty(entity.getPassword())) entity.setPassword(UserTools.PASS_UNCHANGED);
if (entity.getEditorFields()==null) {
UserDetailsEditorFields udef = new UserDetailsEditorFields();
udef.fromUserDetailsEntity(entity, false, getRequest(), groupsApproveRepository);
}
//Generate default login
if(entity.getEditorFields()!=null && Tools.isEmpty(entity.getEditorFields().getLogin())) {
String autoLogin = Tools.isEmpty(entity.getUserGroupsIds()) == true ? "" : entity.getUserGroupsIds() + "-";
autoLogin += entity.get__rowNum__() + "-" + Password.generatePassword(4);
if( Tools.isNotEmpty(entity.getLastName()) ) autoLogin = DocTools.removeCharsDir( entity.getLastName() ).toLowerCase() + "-" + autoLogin;
entity.getEditorFields().setLogin(autoLogin);
}
//By default not admin
if(entity.getAdmin() == null) entity.setAdmin(false);
}
boolean allowWeakPassword = false;
if (entity.getEditorFields()!=null && Boolean.TRUE.equals(entity.getEditorFields().getAllowWeakPassword())) allowWeakPassword = true;
boolean admin = Boolean.TRUE.equals(entity.getAdmin());
userDetailsService.validatePassword(entity, allowWeakPassword, admin, prop, errors);
//not empty aby pri prazdnej hlasilo v editore, ze to je povinne pole
if (Tools.isNotEmpty(entity.getEmail()) && Tools.isEmail(entity.getEmail())==false) {
errors.rejectValue("errorField.email", null, prop.getText("javax.validation.constraints.Email.message"));
}
//validate login
if (entity.getEditorFields()==null || Tools.isEmpty(entity.getEditorFields().getLogin())) {
errors.rejectValue("errorField.editorFields.login", null, prop.getText("javax.validation.constraints.NotBlank.message"));
}
}
@Override
public UserDetailsEntity processFromEntity(UserDetailsEntity entity, ProcessItemAction action) {
boolean loadSubQueries = false;
if (ProcessItemAction.GETONE.equals(action)) {
loadSubQueries = true;
if (entity == null) entity = new UserDetailsEntity();
}
if(entity != null && entity.getEditorFields() == null) {
UserDetailsEditorFields udef = new UserDetailsEditorFields();
udef.fromUserDetailsEntity(entity, loadSubQueries, getRequest(), groupsApproveRepository);
}
//pri exporte nastav prazdne heslo
if (isExporting() && entity!=null) entity.setPassword("");
if (entity != null && loadSubQueries && entity.getId()!=null && entity.getId().longValue()>0) {
String apiKey = userDetailsRepository.getApiKeyByUserId(entity.getId());
if (Tools.isNotEmpty(apiKey)) {
entity.setApiKey(UserTools.PASS_UNCHANGED);
}
}
return entity;
}
@Override
public UserDetailsEntity processToEntity(UserDetailsEntity entity, ProcessItemAction action) {
if(entity != null) {
//Call toUserDetailsEntity to set new entity values from EditorFields
UserDetailsEditorFields udef = new UserDetailsEditorFields();
udef.toUserDetailsEntity(entity, getRequest());
}
return entity;
}
//Return list of user ids that belongs into selected groups
public static List<Integer> getUserIdsByUserGroupsIds(UserDetailsRepository repo, List<Integer> groupIds) {
List<Integer> userIds = new ArrayList<>();
for(Integer groupId : groupIds) {
List<Integer> tmp = repo.getUserIdsByUserGroupsIds(
"" + groupId,
"%," + groupId,
groupId + ",%",
"%," + groupId + ",%");
userIds.addAll(tmp);
}
return userIds;
}
//Return list od user emails that belongs into selected groups
public static List<String> getUserEmailsByUserGroupsIds(UserDetailsRepository repo, List<Integer> groupIds) {
List<String> userEmails = new ArrayList<>();
for(Integer groupId : groupIds) {
List<String> tmp = repo.getUserEmailsByUserGroupsIds(
"" + groupId,
"%," + groupId,
groupId + ",%",
"%," + groupId + ",%");
userEmails.addAll(tmp);
}
return userEmails;
}
@Override
public boolean processAction(UserDetailsEntity entity, String action) {
//Authorize user WITHOUT generation of new password
if("authUserNoGen".equals(action))
auth(entity.getId(), false);
//Authorize user WITH generation of new password
if("authUserWithGen".equals(action))
auth(entity.getId(), true);
return true;
}
/**
* Call user authorization and add notification about auth status
* @param userId
* @param generatePass
*/
public void auth(Long userId, boolean generatePass) {
String title = getProp().getText("components.users.auth_title");
//The ID must be > 0
if(userId == null || userId < 0) {
addNotify(new NotifyBean(title, getProp().getText("components.users.auth_failed.id_invalid"), NotifyType.ERROR));
return;
}
UserDetailsEntity userToApprove = userDetailsRepository.getById(userId);
boolean authorization = AuthorizeUserService.authUser(userToApprove, getUser(), generatePass, getRequest());
//Show notification about auth status
if(authorization) {
setForceReload(true);
addNotify(new NotifyBean(title, getProp().getText("components.users.auth_success", userToApprove.getFullName(), userToApprove.getLogin()), NotifyType.SUCCESS, 15000));
} else
addNotify(new NotifyBean(title, getProp().getText("components.users.auth_failed", userToApprove.getFullName(), userToApprove.getLogin()), NotifyType.ERROR));
}
@Override
public boolean beforeDelete(UserDetailsEntity entity) {
//Check that user is not trying delete user account, that is actually logged
if(entity.getId().intValue() == getUser().getUserId()) {
throwError("user.self_delete_error");
return false;
}
return true;
}
@Override
public void beforeDuplicate(UserDetailsEntity entity) {
//Force random password generation -> null value can cause problems
if(entity.getPassword() == null || entity.getPassword().equals(UserTools.PASS_UNCHANGED)) {
entity.setPassword("random");
super.beforeDuplicate(entity);
}
}
}