Package org.projectforge.user

Source Code of org.projectforge.user.UserDao

/////////////////////////////////////////////////////////////////////////////
//
// Project ProjectForge Community Edition
//         www.projectforge.org
//
// Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de)
//
// ProjectForge is dual-licensed.
//
// This community edition is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation; version 3 of the License.
//
// This community edition is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, see http://www.gnu.org/licenses/.
//
/////////////////////////////////////////////////////////////////////////////

package org.projectforge.user;

import java.sql.Timestamp;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.hibernate.LockMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.projectforge.access.AccessChecker;
import org.projectforge.access.AccessException;
import org.projectforge.access.AccessType;
import org.projectforge.access.OperationType;
import org.projectforge.common.Crypt;
import org.projectforge.common.NumberHelper;
import org.projectforge.core.BaseDao;
import org.projectforge.core.BaseSearchFilter;
import org.projectforge.core.ConfigXml;
import org.projectforge.core.DisplayHistoryEntry;
import org.projectforge.core.ModificationStatus;
import org.projectforge.core.QueryFilter;
import org.projectforge.core.SecurityConfig;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
*
* @author Kai Reinhard (k.reinhard@micromata.de)
*
*/
public class UserDao extends BaseDao<PFUserDO>
{
  private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(UserDao.class);

  private static final String MESSAGE_KEY_OLD_PASSWORD_WRONG = "user.changePassword.error.oldPasswordWrong";

  private static final short AUTHENTICATION_TOKEN_LENGTH = 20;

  private static final short STAY_LOGGED_IN_KEY_LENGTH = 20;

  public static final String MESSAGE_KEY_PASSWORD_QUALITY_CHECK = "user.changePassword.error.passwordQualityCheck";

  public UserDao()
  {
    super(PFUserDO.class);
  }

  public UserGroupCache getUserGroupCache()
  {
    return userGroupCache;
  }

  public QueryFilter getDefaultFilter()
  {
    final QueryFilter queryFilter = new QueryFilter();
    queryFilter.add(Restrictions.eq("deleted", false));
    return queryFilter;
  }

  @Override
  public List<PFUserDO> getList(final BaseSearchFilter filter)
  {
    final PFUserFilter myFilter;
    if (filter instanceof PFUserFilter) {
      myFilter = (PFUserFilter) filter;
    } else {
      myFilter = new PFUserFilter(filter);
    }
    final QueryFilter queryFilter = new QueryFilter(myFilter);
    if (myFilter.getDeactivatedUser() != null) {
      queryFilter.add(Restrictions.eq("deactivated", myFilter.getDeactivatedUser()));
    }
    if (Login.getInstance().hasExternalUsermanagementSystem() == true) {
      // Check hasExternalUsermngmntSystem because otherwise the filter is may-be preset for an user and the user can't change the filter
      // (because the fields aren't visible).
      if (myFilter.getRestrictedUser() != null) {
        queryFilter.add(Restrictions.eq("restrictedUser", myFilter.getRestrictedUser()));
      }
      if (myFilter.getLocalUser() != null) {
        queryFilter.add(Restrictions.eq("localUser", myFilter.getLocalUser()));
      }
    }
    if (myFilter.getHrPlanning() != null) {
      queryFilter.add(Restrictions.eq("hrPlanning", myFilter.getHrPlanning()));
    }
    queryFilter.addOrder(Order.asc("username"));
    List<PFUserDO> list = getList(queryFilter);
    if (myFilter.getIsAdminUser() != null) {
      final List<PFUserDO> origList = list;
      list = new LinkedList<PFUserDO>();
      for (final PFUserDO user : origList) {
        if (myFilter.getIsAdminUser() == accessChecker.isUserMemberOfAdminGroup(user, false)) {
          list.add(user);
        }
      }
    }
    return list;
  }

  public String getGroupnames(final PFUserDO user)
  {
    if (user == null) {
      return "";
    }
    return userGroupCache.getGroupnames(user.getId());
  }

  public Collection<Integer> getAssignedGroups(final PFUserDO user)
  {
    return userGroupCache.getUserGroups(user);
  }

  public List<UserRightDO> getUserRights(final Integer userId)
  {
    return userGroupCache.getUserRights(userId);
  }

  public String[] getPersonalPhoneIdentifiers(final PFUserDO user)
  {
    final String[] tokens = StringUtils.split(user.getPersonalPhoneIdentifiers(), ", ;|");
    if (tokens == null) {
      return null;
    }
    int n = 0;
    for (final String token : tokens) {
      if (StringUtils.isNotBlank(token) == true) {
        n++;
      }
    }
    if (n == 0) {
      return null;
    }
    final String[] result = new String[n];
    n = 0;
    for (final String token : tokens) {
      if (StringUtils.isNotBlank(token) == true) {
        result[n] = token.trim();
        n++;
      }
    }
    return result;
  }

  public String getNormalizedPersonalPhoneIdentifiers(final PFUserDO user)
  {
    if (StringUtils.isNotBlank(user.getPersonalPhoneIdentifiers()) == true) {
      final String[] ids = getPersonalPhoneIdentifiers(user);
      if (ids != null) {
        final StringBuffer buf = new StringBuffer();
        boolean first = true;
        for (final String id : ids) {
          if (first == true) {
            first = false;
          } else {
            buf.append(",");
          }
          buf.append(id);
        }
        return buf.toString();
      }
    }
    return null;
  }

  /**
   * @see org.projectforge.core.BaseDao#afterSaveOrModify(org.projectforge.core.ExtendedBaseDO)
   */
  @Override
  protected void afterSaveOrModify(final PFUserDO obj)
  {
    if (obj.isMinorChange() == false) {
      userGroupCache.setExpired();
    }
  }

  /**
   * @see org.projectforge.core.BaseDao#hasAccess(Object, OperationType)
   */
  @Override
  public boolean hasAccess(final PFUserDO user, final PFUserDO obj, final PFUserDO oldObj, final OperationType operationType,
      final boolean throwException)
  {
    return accessChecker.isUserMemberOfAdminGroup(user, throwException);
  }

  /**
   * @return false, if no admin user and the context user is not at minimum in one groups assigned to the given user or false. Also deleted
   *         and deactivated users are only visible for admin users.
   * @see org.projectforge.core.BaseDao#hasSelectAccess(org.projectforge.core.BaseDO, boolean)
   * @see AccessChecker#areUsersInSameGroup(PFUserDO, PFUserDO)
   */
  @Override
  public boolean hasSelectAccess(final PFUserDO user, final PFUserDO obj, final boolean throwException)
  {
    boolean result = accessChecker.isUserMemberOfAdminGroup(user)
        || accessChecker.isUserMemberOfGroup(user, ProjectForgeGroup.FINANCE_GROUP, ProjectForgeGroup.CONTROLLING_GROUP);
    if (result == false && obj.hasSystemAccess() == true) {
      result = accessChecker.areUsersInSameGroup(user, obj);
    }
    if (throwException == true && result == false) {
      throw new AccessException(user, AccessType.GROUP, OperationType.SELECT);
    }
    return result;
  }

  @Override
  public boolean hasSelectAccess(final PFUserDO user, final boolean throwException)
  {
    return true;
  }

  /**
   * @see org.projectforge.core.BaseDao#hasInsertAccess(org.projectforge.user.PFUserDO)
   */
  @Override
  public boolean hasInsertAccess(final PFUserDO user)
  {
    return accessChecker.isUserMemberOfAdminGroup(user, false);
  }

  @Override
  protected void onSaveOrModify(final PFUserDO obj)
  {
    obj.checkAndFixPassword();
  }

  /**
   * Ohne Zugangsbegrenzung. Wird bei Anmeldung benötigt.
   * @param username
   * @param encryptedPassword
   * @return
   */
  @SuppressWarnings("unchecked")
  @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
  public PFUserDO authenticateUser(final String username, final String password)
  {
    Validate.notNull(username);
    Validate.notNull(password);

    PFUserDO user = getUser(username, password, true);
    if (user != null) {
      final int loginFailures = user.getLoginFailures();
      final Timestamp lastLogin = user.getLastLogin();
      user.setLastLogin(new Timestamp(new Date().getTime()));
      user.setLoginFailures(0);
      user.setMinorChange(true); // Avoid re-indexing of all dependent objects.
      internalUpdate(user, false);
      if (user.hasSystemAccess() == false) {
        log.warn("Deleted/deactivated user tried to login: " + user);
        return null;
      }
      final PFUserDO contextUser = new PFUserDO();
      contextUser.copyValuesFrom(user);
      contextUser.setLoginFailures(loginFailures); // Restore loginFailures for current user session.
      contextUser.setLastLogin(lastLogin); // Restore lastLogin for current user session.
      contextUser.setPassword(null);
      return contextUser;
    }
    final List<PFUserDO> list = getHibernateTemplate().find("from PFUserDO u where u.username = ?", username);
    if (list != null && list.isEmpty() == false && list.get(0) != null) {
      user = list.get(0);
      user.setLoginFailures(user.getLoginFailures() + 1);
      internalUpdate(user);
    }
    return null;
  }

  @SuppressWarnings("unchecked")
  private PFUserDO getUser(final String username, final String password, final boolean updateSaltAndPepperIfNeeded)
  {
    final List<PFUserDO> list = getHibernateTemplate().find("from PFUserDO u where u.username = ?", username);
    if (list == null || list.isEmpty() == true || list.get(0) == null) {
      return null;
    }
    final PFUserDO user = list.get(0);
    final PasswordCheckResult passwordCheckResult = checkPassword(user, password);
    if (passwordCheckResult.isOK() == false) {
      return null;
    }
    if (updateSaltAndPepperIfNeeded == true && passwordCheckResult.isPasswordUpdateNeeded() == true) {
      log.info("Giving salt and/or pepper to the password of the user " + user.getId() + ".");
      createEncryptedPassword(user, password);
    }
    return user;
  }

  @SuppressWarnings("unchecked")
  public PFUserDO getUserByStayLoggedInKey(final String username, final String stayLoggedInKey)
  {
    final List<PFUserDO> list = getHibernateTemplate().find("from PFUserDO u where u.username = ? and u.stayLoggedInKey = ?",
        new Object[] { username, stayLoggedInKey});
    PFUserDO user = null;
    if (list != null && list.isEmpty() == false && list.get(0) != null) {
      user = list.get(0);
    }
    if (user != null && user.hasSystemAccess() == false) {
      log.warn("Deleted/deactivated user tried to login (via stay-logged-in): " + user);
      return null;
    }
    return user;
  }

  /**
   * Does an user with the given username already exists? Works also for existing users (if username was modified).
   * @param user
   * @return
   */
  @SuppressWarnings("unchecked")
  public boolean doesUsernameAlreadyExist(final PFUserDO user)
  {
    Validate.notNull(user);
    List<PFUserDO> list = null;
    if (user.getId() == null) {
      // New user
      list = getHibernateTemplate().find("from PFUserDO u where u.username = ?", user.getUsername());
    } else {
      // user already exists. Check maybe changed username:
      list = getHibernateTemplate().find("from PFUserDO u where u.username = ? and pk <> ?",
          new Object[] { user.getUsername(), user.getId()});
    }
    if (CollectionUtils.isNotEmpty(list) == true) {
      return true;
    }
    return false;
  }

  /**
   * Encrypts the password with a new generated salt string and the pepper string if configured any.
   * @param user The user to user.
   * @param password as clear text.
   * @see Crypt#digest(String)
   */
  public void createEncryptedPassword(final PFUserDO user, final String password)
  {
    final String saltString = createSaltString();
    user.setPasswordSalt(saltString);
    final String encryptedPassword = Crypt.digest(getPepperString() + saltString + password);
    user.setPassword(encryptedPassword);
  }

  /**
   * Checks the given password by comparing it with the stored user password. For backward compatibility the password is encrypted with and
   * without pepper (if configured). The salt string of the given user is used.
   * @param user
   * @param password as clear text.
   * @return true if the password matches the user's password.
   */
  public PasswordCheckResult checkPassword(final PFUserDO user, final String password)
  {
    if (user == null) {
      log.warn("User not given in checkPassword(PFUserDO, String) method.");
      return PasswordCheckResult.FAILED;
    }
    final String userPassword = user.getPassword();
    if (StringUtils.isBlank(userPassword) == true) {
      log.warn("User's password is blank, can't checkPassword(PFUserDO, String) for user with id " + user.getId());
      return PasswordCheckResult.FAILED;
    }
    String saltString = user.getPasswordSalt();
    if (saltString == null) {
      saltString = "";
    }
    final String pepperString = getPepperString();
    String encryptedPassword = Crypt.digest(pepperString + saltString + password);
    if (userPassword.equals(encryptedPassword) == true) {
      // Passwords match!
      if (StringUtils.isEmpty(saltString) == true) {
        log.info("Password of user " + user.getId() + " with username '" + user.getUsername() + "' is not yet salted!");
        return PasswordCheckResult.OK_WITHOUT_SALT;
      }
      return PasswordCheckResult.OK;
    }
    if (StringUtils.isNotBlank(pepperString) == true) {
      // Check password without pepper:
      encryptedPassword = Crypt.digest(saltString + password);
      if (userPassword.equals(encryptedPassword) == true) {
        // Passwords match!
        if (StringUtils.isEmpty(saltString) == true) {
          log.info("Password of user " + user.getId() + " with username '" + user.getUsername() + "' is not yet salted and has no pepper!");
          return PasswordCheckResult.OK_WITHOUT_SALT_AND_PEPPER;
        }
        log.info("Password of user " + user.getId() + " with username '" + user.getUsername() + "' has no pepper!");
        return PasswordCheckResult.OK_WITHOUT_PEPPER;
      }
    }
    return PasswordCheckResult.FAILED;
  }

  private String createSaltString()
  {
    return NumberHelper.getSecureRandomBase64String(10);
  }

  private String getPepperString()
  {
    final SecurityConfig securityConfig = ConfigXml.getInstance().getSecurityConfig();
    if (securityConfig != null) {
      return securityConfig.getPasswordPepper();
    }
    return "";
  }

  /**
   * Changes the user's password. Checks the password quality and the correct authentication for the old password before. Also the
   * stay-logged-in-key will be renewed, so any existing stay-logged-in cookie will be invalid.
   * @param user
   * @param oldPassword
   * @param newPassword
   * @return Error message key if any check failed or null, if successfully changed.
   */
  @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
  public String changePassword(PFUserDO user, final String oldPassword, final String newPassword)
  {
    Validate.notNull(user);
    Validate.notNull(oldPassword);
    Validate.notNull(newPassword);
    final String errorMsgKey = checkPasswordQuality(newPassword);
    if (errorMsgKey != null) {
      return errorMsgKey;
    }
    accessChecker.checkRestrictedOrDemoUser();
    user = getUser(user.getUsername(), oldPassword, false);
    if (user == null) {
      return MESSAGE_KEY_OLD_PASSWORD_WRONG;
    }
    createEncryptedPassword(user, newPassword);
    onPasswordChange(user);
    Login.getInstance().passwordChanged(user, newPassword);
    log.info("Password changed and stay-logged-key renewed for user: " + user.getId() + " - " + user.getUsername());
    return null;
  }

  public void onPasswordChange(final PFUserDO user)
  {
    user.checkAndFixPassword();
    if (user.getPassword() != null) {
      user.setStayLoggedInKey(createStayLoggedInKey());
      user.setLastPasswordChange(new Date());
    } else {
      throw new IllegalArgumentException(
          "Given password seems to be not encrypted! Aborting due to security reasons (for avoiding storage of clear password in the database).");
    }
  }

  /**
   * Returns the user's stay-logged-in key if exists (must be not blank with a size >= 10). If not, a new stay-logged-in key will be
   * generated.
   * @param userId
   * @return
   */
  @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
  public String getStayLoggedInKey(final Integer userId)
  {
    final PFUserDO user = internalGetById(userId);
    if (StringUtils.isBlank(user.getStayLoggedInKey()) || user.getStayLoggedInKey().trim().length() < 10) {
      user.setStayLoggedInKey(createStayLoggedInKey());
      log.info("Stay-logged-key renewed for user: " + userId + " - " + user.getUsername());
    }
    return user.getStayLoggedInKey();
  }

  /**
   * Renews the user's stay-logged-in key (random string sequence).
   */
  @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
  public void renewStayLoggedInKey(final Integer userId)
  {
    if (PFUserContext.getUserId().equals(userId) == false) {
      // Only admin users are able to renew authentication token of other users:
      accessChecker.checkIsLoggedInUserMemberOfAdminGroup();
    }
    accessChecker.checkRestrictedOrDemoUser(); // Demo users are also not allowed to do this.
    final PFUserDO user = internalGetById(userId);
    user.setStayLoggedInKey(createStayLoggedInKey());
    log.info("Stay-logged-key renewed for user: " + userId + " - " + user.getUsername());
  }

  private String createStayLoggedInKey()
  {
    return NumberHelper.getSecureRandomUrlSaveString(STAY_LOGGED_IN_KEY_LENGTH);
  }

  /**
   * Get authentication key by user. ; )
   *
   * @param userName
   * @param authKey
   * @return
   */
  @SuppressWarnings("unchecked")
  public PFUserDO getUserByAuthenticationToken(final Integer userId, final String authKey)
  {
    final List<PFUserDO> list = getHibernateTemplate().find("from PFUserDO u where u.id = ? and u.authenticationToken = ?",
        new Object[] { userId, authKey});
    PFUserDO user = null;
    if (list != null && list.isEmpty() == false && list.get(0) != null) {
      user = list.get(0);
    }
    if (user != null && user.hasSystemAccess() == false) {
      log.warn("Deleted user tried to login (via authentication token): " + user);
      return null;
    }
    return user;
  }

  /**
   * Returns the user's authentication token if exists (must be not blank with a size >= 10). If not, a new token key will be generated.
   * @param userId
   * @return
   */
  @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
  public String getAuthenticationToken(final Integer userId)
  {
    final PFUserDO user = internalGetById(userId);
    if (StringUtils.isBlank(user.getAuthenticationToken()) || user.getAuthenticationToken().trim().length() < 10) {
      user.setAuthenticationToken(createAuthenticationToken());
      log.info("Authentication token renewed for user: " + userId + " - " + user.getUsername());
    }
    return user.getAuthenticationToken();
  }

  /**
   * Renews the user's authentication token (random string sequence).
   */
  @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
  public void renewAuthenticationToken(final Integer userId)
  {
    if (PFUserContext.getUserId().equals(userId) == false) {
      // Only admin users are able to renew authentication token of other users:
      accessChecker.checkIsLoggedInUserMemberOfAdminGroup();
    }
    accessChecker.checkRestrictedOrDemoUser(); // Demo users are also not allowed to do this.
    final PFUserDO user = internalGetById(userId);
    user.setAuthenticationToken(createAuthenticationToken());
    log.info("Authentication token renewed for user: " + userId + " - " + user.getUsername());
  }

  private String createAuthenticationToken()
  {
    return NumberHelper.getSecureRandomUrlSaveString(AUTHENTICATION_TOKEN_LENGTH);
  }

  /**
   * Uses the context user.
   * @param data
   * @return
   * @see #encrypt(Integer, String)
   */
  public String encrypt(final String data)
  {
    return encrypt(PFUserContext.getUserId(), data);
  }

  /**
   * Encrypts the given str with AES. The key is the current authenticationToken of the given user (by id) (first 16 bytes of it).
   * @param userId
   * @param data
   * @return The base64 encoded result (url safe).
   * @see Crypt#encrypt(String, String)
   */
  public String encrypt(final Integer userId, final String data)
  {
    final String authenticationToken = StringUtils.rightPad(getCachedAuthenticationToken(userId), 32, "x");
    return Crypt.encrypt(authenticationToken, data);
  }

  /**
   * for faster access (due to permanent usage e. g. by subscription of calendars
   * @param userId
   * @return
   */
  public String getCachedAuthenticationToken(final Integer userId)
  {
    final PFUserDO user = userGroupCache.getUser(userId);
    final String authenticationToken = user.getAuthenticationToken();
    if (StringUtils.isBlank(authenticationToken) == false && authenticationToken.trim().length() >= 10) {
      return authenticationToken;
    }
    return getAuthenticationToken(userId);
  }

  /**
   * @param userId
   * @param encryptedString
   * @return The decrypted string.
   * @see Crypt#decrypt(String, String)
   */
  public String decrypt(final Integer userId, final String encryptedString)
  {
    // final PFUserDO user = userGroupCache.getUser(userId); // for faster access (due to permanent usage e. g. by subscription of calendars
    // (ics).
    final String authenticationToken = StringUtils.rightPad(getCachedAuthenticationToken(userId), 32, "x");
    return Crypt.decrypt(authenticationToken, encryptedString);
  }

  /**
   * Checks the password quality of a new password. Password must have at least 6 characters and at minimum one letter and one non-letter
   * character.
   * @param newPassword
   * @return null if password quality is OK, otherwise the i18n message key of the password check failure.
   */
  public String checkPasswordQuality(final String newPassword)
  {
    boolean letter = false;
    boolean nonLetter = false;
    if (newPassword == null || newPassword.length() < 6) {
      return MESSAGE_KEY_PASSWORD_QUALITY_CHECK;
    }
    for (int i = 0; i < newPassword.length(); i++) {
      final char ch = newPassword.charAt(i);
      if (letter == false && Character.isLetter(ch) == true) {
        letter = true;
      } else if (nonLetter == false && Character.isLetter(ch) == false) {
        nonLetter = true;
      }
    }
    if (letter == true && nonLetter == true) {
      return null;
    }
    return MESSAGE_KEY_PASSWORD_QUALITY_CHECK;
  }

  @SuppressWarnings("unchecked")
  @Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
  public PFUserDO getInternalByName(final String username)
  {
    final List<PFUserDO> list = getHibernateTemplate().find("from PFUserDO u where u.username = ?", username);
    if (list != null && list.size() > 0) {
      return list.get(0);
    }
    return null;
  }

  /**
   * User can modify own setting, this method ensures that only such properties will be updated, the user's are allowed to.
   * @param user
   */
  @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW, isolation = Isolation.REPEATABLE_READ)
  public void updateMyAccount(final PFUserDO user)
  {
    accessChecker.checkRestrictedOrDemoUser();
    final PFUserDO contextUser = PFUserContext.getUser();
    Validate.isTrue(user.getId().equals(contextUser.getId()) == true);
    final PFUserDO dbUser = getHibernateTemplate().load(clazz, user.getId(), LockMode.PESSIMISTIC_WRITE);
    if (copyValues(user, dbUser, "deleted", "password", "lastLogin", "loginFailures", "username", "stayLoggedInKey", "authenticationToken",
        "rights") != ModificationStatus.NONE) {
      dbUser.setLastUpdate();
      log.info("Object updated: " + dbUser.toString());
      copyValues(user, contextUser, "deleted", "password", "lastLogin", "loginFailures", "username", "stayLoggedInKey",
          "authenticationToken", "rights");
    } else {
      log.info("No modifications detected (no update needed): " + dbUser.toString());
    }
    userGroupCache.updateUser(user);
  }

  /**
   * Gets history entries of super and adds all history entries of the AuftragsPositionDO childs.
   * @see org.projectforge.core.BaseDao#getDisplayHistoryEntries(org.projectforge.core.ExtendedBaseDO)
   */
  @Override
  public List<DisplayHistoryEntry> getDisplayHistoryEntries(final PFUserDO obj)
  {
    final List<DisplayHistoryEntry> list = super.getDisplayHistoryEntries(obj);
    if (hasLoggedInUserHistoryAccess(obj, false) == false) {
      return list;
    }
    if (CollectionUtils.isNotEmpty(obj.getRights()) == true) {
      for (final UserRightDO right : obj.getRights()) {
        final List<DisplayHistoryEntry> entries = internalGetDisplayHistoryEntries(right);
        for (final DisplayHistoryEntry entry : entries) {
          final String propertyName = entry.getPropertyName();
          if (propertyName != null) {
            entry.setPropertyName(right.getRightId() + ":" + entry.getPropertyName()); // Prepend number of positon.
          } else {
            entry.setPropertyName(String.valueOf(right.getRightId()));
          }
        }
        list.addAll(entries);
      }
    }
    Collections.sort(list, new Comparator<DisplayHistoryEntry>() {
      public int compare(final DisplayHistoryEntry o1, final DisplayHistoryEntry o2)
      {
        return (o2.getTimestamp().compareTo(o1.getTimestamp()));
      }
    });
    return list;
  }

  @Override
  public boolean hasHistoryAccess(final PFUserDO user, final boolean throwException)
  {
    return accessChecker.isUserMemberOfAdminGroup(user, throwException);
  }

  /**
   * Re-index all dependent objects only if the username, first or last name was changed.
   * @see org.projectforge.core.BaseDao#wantsReindexAllDependentObjects(org.projectforge.core.ExtendedBaseDO,
   *      org.projectforge.core.ExtendedBaseDO)
   */
  @Override
  protected boolean wantsReindexAllDependentObjects(final PFUserDO obj, final PFUserDO dbObj)
  {
    if (super.wantsReindexAllDependentObjects(obj, dbObj) == false) {
      return false;
    }
    return StringUtils.equals(obj.getUsername(), dbObj.getUsername()) == false
        || StringUtils.equals(obj.getFirstname(), dbObj.getFirstname()) == false
        || StringUtils.equals(obj.getLastname(), dbObj.getLastname()) == false;
  }

  @Override
  public PFUserDO newInstance()
  {
    return new PFUserDO();
  }
}
TOP

Related Classes of org.projectforge.user.UserDao

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.