2018-03-29 17:59:47 +02:00
package com.sismics.docs.core.dao ;
2013-07-27 18:33:20 +02:00
import com.google.common.base.Joiner ;
2022-02-20 15:48:37 +01:00
import com.google.common.base.Strings ;
2021-01-05 18:59:18 +01:00
import at.favre.lib.crypto.bcrypt.BCrypt ;
import org.joda.time.DateTime ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
2015-05-17 22:20:34 +02:00
import com.sismics.docs.core.constant.AuditLogType ;
2021-01-05 18:59:18 +01:00
import com.sismics.docs.core.constant.Constants ;
2018-03-29 17:59:47 +02:00
import com.sismics.docs.core.dao.criteria.UserCriteria ;
import com.sismics.docs.core.dao.dto.UserDto ;
2013-07-27 18:33:20 +02:00
import com.sismics.docs.core.model.jpa.User ;
2015-05-17 22:20:34 +02:00
import com.sismics.docs.core.util.AuditLogUtil ;
2018-03-26 22:28:22 +02:00
import com.sismics.docs.core.util.EncryptionUtil ;
2013-07-27 18:33:20 +02:00
import com.sismics.docs.core.util.jpa.QueryParam ;
2016-03-19 19:41:28 +01:00
import com.sismics.docs.core.util.jpa.QueryUtil ;
2013-07-27 18:33:20 +02:00
import com.sismics.docs.core.util.jpa.SortCriteria ;
import com.sismics.util.context.ThreadLocalContext ;
2017-11-20 20:34:29 +01:00
2023-04-09 21:31:53 +02:00
import jakarta.persistence.EntityManager ;
import jakarta.persistence.NoResultException ;
import jakarta.persistence.Query ;
2017-11-20 20:34:29 +01:00
import java.sql.Timestamp ;
import java.util.* ;
2013-07-27 18:33:20 +02:00
/ * *
* User DAO .
*
* @author jtremeaux
* /
public class UserDao {
2021-01-05 18:59:18 +01:00
/ * *
* Logger .
* /
private static final Logger log = LoggerFactory . getLogger ( UserDao . class ) ;
2013-07-27 18:33:20 +02:00
/ * *
* Authenticates an user .
*
* @param username User login
* @param password User password
2016-03-22 23:08:49 +01:00
* @return The authenticated user or null
2013-07-27 18:33:20 +02:00
* /
2016-03-22 23:08:49 +01:00
public User authenticate ( String username , String password ) {
2013-07-27 18:33:20 +02:00
EntityManager em = ThreadLocalContext . get ( ) . getEntityManager ( ) ;
Query q = em . createQuery ( " select u from User u where u.username = :username and u.deleteDate is null " ) ;
q . setParameter ( " username " , username ) ;
try {
User user = ( User ) q . getSingleResult ( ) ;
2020-12-31 07:46:00 +01:00
BCrypt . Result result = BCrypt . verifyer ( ) . verify ( password . toCharArray ( ) , user . getPassword ( ) ) ;
if ( ! result . verified | | user . getDisableDate ( ) ! = null ) {
2013-07-27 18:33:20 +02:00
return null ;
}
2016-03-22 23:08:49 +01:00
return user ;
2013-07-27 18:33:20 +02:00
} catch ( NoResultException e ) {
return null ;
}
}
/ * *
* Creates a new user .
*
* @param user User to create
2016-02-15 22:28:13 +01:00
* @param userId User ID
2013-07-27 18:33:20 +02:00
* @return User ID
2017-11-20 20:34:29 +01:00
* @throws Exception e
2013-07-27 18:33:20 +02:00
* /
2016-02-15 22:28:13 +01:00
public String create ( User user , String userId ) throws Exception {
2013-07-27 18:33:20 +02:00
// Create the user UUID
user . setId ( UUID . randomUUID ( ) . toString ( ) ) ;
// Checks for user unicity
EntityManager em = ThreadLocalContext . get ( ) . getEntityManager ( ) ;
Query q = em . createQuery ( " select u from User u where u.username = :username and u.deleteDate is null " ) ;
q . setParameter ( " username " , user . getUsername ( ) ) ;
List < ? > l = q . getResultList ( ) ;
if ( l . size ( ) > 0 ) {
throw new Exception ( " AlreadyExistingUsername " ) ;
}
2015-05-17 22:20:34 +02:00
// Create the user
2013-07-27 18:33:20 +02:00
user . setCreateDate ( new Date ( ) ) ;
user . setPassword ( hashPassword ( user . getPassword ( ) ) ) ;
2018-03-26 22:28:22 +02:00
user . setPrivateKey ( EncryptionUtil . generatePrivateKey ( ) ) ;
user . setStorageCurrent ( 0L ) ;
2013-07-27 18:33:20 +02:00
em . persist ( user ) ;
2015-05-17 22:20:34 +02:00
// Create audit log
2016-02-15 22:28:13 +01:00
AuditLogUtil . create ( user , AuditLogType . CREATE , userId ) ;
2015-05-17 22:20:34 +02:00
2013-07-27 18:33:20 +02:00
return user . getId ( ) ;
}
/ * *
* Updates a user .
*
* @param user User to update
2016-02-15 22:28:13 +01:00
* @param userId User ID
2013-07-27 18:33:20 +02:00
* @return Updated user
* /
2016-02-15 22:28:13 +01:00
public User update ( User user , String userId ) {
2013-07-27 18:33:20 +02:00
EntityManager em = ThreadLocalContext . get ( ) . getEntityManager ( ) ;
// Get the user
Query q = em . createQuery ( " select u from User u where u.id = :id and u.deleteDate is null " ) ;
q . setParameter ( " id " , user . getId ( ) ) ;
2018-01-28 12:44:11 +01:00
User userDb = ( User ) q . getSingleResult ( ) ;
2013-07-27 18:33:20 +02:00
2016-02-15 22:28:13 +01:00
// Update the user (except password)
2018-01-28 12:44:11 +01:00
userDb . setEmail ( user . getEmail ( ) ) ;
userDb . setStorageQuota ( user . getStorageQuota ( ) ) ;
userDb . setStorageCurrent ( user . getStorageCurrent ( ) ) ;
userDb . setTotpKey ( user . getTotpKey ( ) ) ;
userDb . setDisableDate ( user . getDisableDate ( ) ) ;
2017-11-20 21:21:50 +01:00
2015-05-17 22:20:34 +02:00
// Create audit log
2018-01-28 12:44:11 +01:00
AuditLogUtil . create ( userDb , AuditLogType . UPDATE , userId ) ;
2015-05-17 22:20:34 +02:00
2013-07-27 18:33:20 +02:00
return user ;
}
2015-12-12 01:56:54 +01:00
/ * *
* Updates a user ' s quota .
*
* @param user User to update
* /
2017-11-20 20:34:29 +01:00
public void updateQuota ( User user ) {
2015-12-12 01:56:54 +01:00
EntityManager em = ThreadLocalContext . get ( ) . getEntityManager ( ) ;
// Get the user
Query q = em . createQuery ( " select u from User u where u.id = :id and u.deleteDate is null " ) ;
q . setParameter ( " id " , user . getId ( ) ) ;
2018-01-28 12:44:11 +01:00
User userDb = ( User ) q . getSingleResult ( ) ;
2015-12-12 01:56:54 +01:00
// Update the user
2018-02-01 18:01:11 +01:00
userDb . setStorageCurrent ( user . getStorageCurrent ( ) ) ;
2015-12-12 01:56:54 +01:00
}
2013-07-27 18:33:20 +02:00
/ * *
* Update the user password .
*
* @param user User to update
2016-02-15 22:28:13 +01:00
* @param userId User ID
2013-07-27 18:33:20 +02:00
* @return Updated user
* /
2016-02-15 22:28:13 +01:00
public User updatePassword ( User user , String userId ) {
2013-07-27 18:33:20 +02:00
EntityManager em = ThreadLocalContext . get ( ) . getEntityManager ( ) ;
// Get the user
Query q = em . createQuery ( " select u from User u where u.id = :id and u.deleteDate is null " ) ;
q . setParameter ( " id " , user . getId ( ) ) ;
2018-01-28 12:44:11 +01:00
User userDb = ( User ) q . getSingleResult ( ) ;
2013-07-27 18:33:20 +02:00
// Update the user
2018-01-28 12:44:11 +01:00
userDb . setPassword ( hashPassword ( user . getPassword ( ) ) ) ;
2013-07-27 18:33:20 +02:00
2015-05-17 22:20:34 +02:00
// Create audit log
2018-01-28 12:44:11 +01:00
AuditLogUtil . create ( userDb , AuditLogType . UPDATE , userId ) ;
2015-05-17 22:20:34 +02:00
2013-07-27 18:33:20 +02:00
return user ;
}
2018-01-01 17:14:12 +01:00
/ * *
* Update the hashed password silently .
*
* @param user User to update
* @return Updated user
* /
public User updateHashedPassword ( User user ) {
EntityManager em = ThreadLocalContext . get ( ) . getEntityManager ( ) ;
// Get the user
Query q = em . createQuery ( " select u from User u where u.id = :id and u.deleteDate is null " ) ;
q . setParameter ( " id " , user . getId ( ) ) ;
2018-01-28 12:44:11 +01:00
User userDb = ( User ) q . getSingleResult ( ) ;
2018-01-01 17:14:12 +01:00
// Update the user
2018-01-28 12:44:11 +01:00
userDb . setPassword ( user . getPassword ( ) ) ;
2018-01-01 17:14:12 +01:00
2019-05-06 18:12:44 +02:00
return user ;
}
/ * *
* Update the onboarding status .
*
* @param user User to update
* @return Updated user
* /
public User updateOnboarding ( User user ) {
EntityManager em = ThreadLocalContext . get ( ) . getEntityManager ( ) ;
// Get the user
Query q = em . createQuery ( " select u from User u where u.id = :id and u.deleteDate is null " ) ;
q . setParameter ( " id " , user . getId ( ) ) ;
User userDb = ( User ) q . getSingleResult ( ) ;
// Update the user
userDb . setOnboarding ( user . isOnboarding ( ) ) ;
2018-01-01 17:14:12 +01:00
return user ;
}
2013-07-27 18:33:20 +02:00
/ * *
* Gets a user by its ID .
*
* @param id User ID
* @return User
* /
public User getById ( String id ) {
EntityManager em = ThreadLocalContext . get ( ) . getEntityManager ( ) ;
try {
return em . find ( User . class , id ) ;
} catch ( NoResultException e ) {
return null ;
}
}
/ * *
* Gets an active user by its username .
*
* @param username User ' s username
* @return User
* /
public User getActiveByUsername ( String username ) {
EntityManager em = ThreadLocalContext . get ( ) . getEntityManager ( ) ;
try {
Query q = em . createQuery ( " select u from User u where u.username = :username and u.deleteDate is null " ) ;
q . setParameter ( " username " , username ) ;
return ( User ) q . getSingleResult ( ) ;
} catch ( NoResultException e ) {
return null ;
}
}
/ * *
* Deletes a user .
*
* @param username User ' s username
2016-02-15 22:28:13 +01:00
* @param userId User ID
2013-07-27 18:33:20 +02:00
* /
2016-02-15 22:28:13 +01:00
public void delete ( String username , String userId ) {
2013-07-27 18:33:20 +02:00
EntityManager em = ThreadLocalContext . get ( ) . getEntityManager ( ) ;
// Get the user
Query q = em . createQuery ( " select u from User u where u.username = :username and u.deleteDate is null " ) ;
q . setParameter ( " username " , username ) ;
2018-01-28 12:44:11 +01:00
User userDb = ( User ) q . getSingleResult ( ) ;
2013-07-27 18:33:20 +02:00
// Delete the user
Date dateNow = new Date ( ) ;
2018-01-28 12:44:11 +01:00
userDb . setDeleteDate ( dateNow ) ;
2013-07-27 18:33:20 +02:00
// Delete linked data
q = em . createQuery ( " delete from AuthenticationToken at where at.userId = :userId " ) ;
2018-01-28 12:44:11 +01:00
q . setParameter ( " userId " , userDb . getId ( ) ) ;
2013-07-27 18:33:20 +02:00
q . executeUpdate ( ) ;
2015-05-17 22:20:34 +02:00
2015-12-01 00:32:57 +01:00
q = em . createQuery ( " update Document d set d.deleteDate = :dateNow where d.userId = :userId and d.deleteDate is null " ) ;
2018-01-28 12:44:11 +01:00
q . setParameter ( " userId " , userDb . getId ( ) ) ;
2015-12-01 00:32:57 +01:00
q . setParameter ( " dateNow " , dateNow ) ;
q . executeUpdate ( ) ;
q = em . createQuery ( " update File f set f.deleteDate = :dateNow where f.userId = :userId and f.deleteDate is null " ) ;
2018-01-28 12:44:11 +01:00
q . setParameter ( " userId " , userDb . getId ( ) ) ;
2015-12-01 00:32:57 +01:00
q . setParameter ( " dateNow " , dateNow ) ;
q . executeUpdate ( ) ;
q = em . createQuery ( " update Acl a set a.deleteDate = :dateNow where a.targetId = :userId and a.deleteDate is null " ) ;
2018-01-28 12:44:11 +01:00
q . setParameter ( " userId " , userDb . getId ( ) ) ;
2015-12-01 00:32:57 +01:00
q . setParameter ( " dateNow " , dateNow ) ;
q . executeUpdate ( ) ;
q = em . createQuery ( " update Comment c set c.deleteDate = :dateNow where c.userId = :userId and c.deleteDate is null " ) ;
2018-01-28 12:44:11 +01:00
q . setParameter ( " userId " , userDb . getId ( ) ) ;
2015-12-01 00:32:57 +01:00
q . setParameter ( " dateNow " , dateNow ) ;
q . executeUpdate ( ) ;
2015-05-17 22:20:34 +02:00
// Create audit log
2018-01-28 12:44:11 +01:00
AuditLogUtil . create ( userDb , AuditLogType . DELETE , userId ) ;
2013-07-27 18:33:20 +02:00
}
/ * *
* Hash the user ' s password .
*
* @param password Clear password
* @return Hashed password
* /
2016-05-01 22:03:39 +02:00
private String hashPassword ( String password ) {
2021-01-05 18:59:18 +01:00
int bcryptWork = Constants . DEFAULT_BCRYPT_WORK ;
String envBcryptWork = System . getenv ( Constants . BCRYPT_WORK_ENV ) ;
2022-02-20 15:48:37 +01:00
if ( ! Strings . isNullOrEmpty ( envBcryptWork ) ) {
2021-01-05 18:59:18 +01:00
try {
int envBcryptWorkInt = Integer . parseInt ( envBcryptWork ) ;
if ( envBcryptWorkInt > = 4 & & envBcryptWorkInt < = 31 ) {
bcryptWork = envBcryptWorkInt ;
} else {
log . warn ( Constants . BCRYPT_WORK_ENV + " needs to be in range 4...31. Falling back to " + Constants . DEFAULT_BCRYPT_WORK + " . " ) ;
}
} catch ( NumberFormatException e ) {
log . warn ( Constants . BCRYPT_WORK_ENV + " needs to be a number in range 4...31. Falling back to " + Constants . DEFAULT_BCRYPT_WORK + " . " ) ;
}
}
return BCrypt . withDefaults ( ) . hashToString ( bcryptWork , password . toCharArray ( ) ) ;
2013-07-27 18:33:20 +02:00
}
/ * *
* Returns the list of all users .
*
2016-03-19 19:41:28 +01:00
* @param criteria Search criteria
2013-07-27 18:33:20 +02:00
* @param sortCriteria Sort criteria
2016-03-19 19:41:28 +01:00
* @return List of users
2013-07-27 18:33:20 +02:00
* /
2016-03-19 19:41:28 +01:00
public List < UserDto > findByCriteria ( UserCriteria criteria , SortCriteria sortCriteria ) {
2016-05-01 22:03:39 +02:00
Map < String , Object > parameterMap = new HashMap < > ( ) ;
List < String > criteriaList = new ArrayList < > ( ) ;
2015-05-09 14:44:19 +02:00
2017-11-20 21:21:50 +01:00
StringBuilder sb = new StringBuilder ( " select u.USE_ID_C as c0, u.USE_USERNAME_C as c1, u.USE_EMAIL_C as c2, u.USE_CREATEDATE_D as c3, u.USE_STORAGECURRENT_N as c4, u.USE_STORAGEQUOTA_N as c5, u.USE_TOTPKEY_C as c6, u.USE_DISABLEDATE_D as c7 " ) ;
2013-07-27 18:33:20 +02:00
sb . append ( " from T_USER u " ) ;
// Add search criterias
2015-05-09 14:44:19 +02:00
if ( criteria . getSearch ( ) ! = null ) {
criteriaList . add ( " lower(u.USE_USERNAME_C) like lower(:search) " ) ;
parameterMap . put ( " search " , " % " + criteria . getSearch ( ) + " % " ) ;
}
2018-02-02 17:18:34 +01:00
if ( criteria . getUserId ( ) ! = null ) {
criteriaList . add ( " u.USE_ID_C = :userId " ) ;
parameterMap . put ( " userId " , criteria . getUserId ( ) ) ;
}
if ( criteria . getUserName ( ) ! = null ) {
criteriaList . add ( " u.USE_USERNAME_C = :userName " ) ;
parameterMap . put ( " userName " , criteria . getUserName ( ) ) ;
}
2016-03-20 12:20:12 +01:00
if ( criteria . getGroupId ( ) ! = null ) {
sb . append ( " join T_USER_GROUP ug on ug.UGP_IDUSER_C = u.USE_ID_C and ug.UGP_IDGROUP_C = :groupId and ug.UGP_DELETEDATE_D is null " ) ;
parameterMap . put ( " groupId " , criteria . getGroupId ( ) ) ;
}
2013-07-27 18:33:20 +02:00
criteriaList . add ( " u.USE_DELETEDATE_D is null " ) ;
if ( ! criteriaList . isEmpty ( ) ) {
sb . append ( " where " ) ;
sb . append ( Joiner . on ( " and " ) . join ( criteriaList ) ) ;
}
// Perform the search
2016-03-19 19:41:28 +01:00
QueryParam queryParam = QueryUtil . getSortedQueryParam ( new QueryParam ( sb . toString ( ) , parameterMap ) , sortCriteria ) ;
@SuppressWarnings ( " unchecked " )
List < Object [ ] > l = QueryUtil . getNativeQuery ( queryParam ) . getResultList ( ) ;
2013-07-27 18:33:20 +02:00
// Assemble results
2016-05-01 22:03:39 +02:00
List < UserDto > userDtoList = new ArrayList < > ( ) ;
2013-07-27 18:33:20 +02:00
for ( Object [ ] o : l ) {
int i = 0 ;
UserDto userDto = new UserDto ( ) ;
userDto . setId ( ( String ) o [ i + + ] ) ;
userDto . setUsername ( ( String ) o [ i + + ] ) ;
userDto . setEmail ( ( String ) o [ i + + ] ) ;
userDto . setCreateTimestamp ( ( ( Timestamp ) o [ i + + ] ) . getTime ( ) ) ;
2015-11-29 19:42:49 +01:00
userDto . setStorageCurrent ( ( ( Number ) o [ i + + ] ) . longValue ( ) ) ;
2017-11-17 15:18:16 +01:00
userDto . setStorageQuota ( ( ( Number ) o [ i + + ] ) . longValue ( ) ) ;
2017-11-20 21:21:50 +01:00
userDto . setTotpKey ( ( String ) o [ i + + ] ) ;
if ( o [ i ] ! = null ) {
userDto . setDisableTimestamp ( ( ( Timestamp ) o [ i ] ) . getTime ( ) ) ;
}
2013-07-27 18:33:20 +02:00
userDtoList . add ( userDto ) ;
}
2016-03-19 19:41:28 +01:00
return userDtoList ;
2013-07-27 18:33:20 +02:00
}
2017-11-20 20:34:29 +01:00
/ * *
* Returns the global storage used by all users .
*
* @return Current global storage
* /
public long getGlobalStorageCurrent ( ) {
EntityManager em = ThreadLocalContext . get ( ) . getEntityManager ( ) ;
Query query = em . createNativeQuery ( " select sum(u.USE_STORAGECURRENT_N) from T_USER u where u.USE_DELETEDATE_D is null " ) ;
return ( ( Number ) query . getSingleResult ( ) ) . longValue ( ) ;
}
2017-11-20 21:21:50 +01:00
/ * *
* Returns the number of active users .
*
* @return Number of active users
* /
public long getActiveUserCount ( ) {
EntityManager em = ThreadLocalContext . get ( ) . getEntityManager ( ) ;
2017-11-21 19:37:29 +01:00
Query query = em . createNativeQuery ( " select count(u.USE_ID_C) from T_USER u where u.USE_DELETEDATE_D is null and (u.USE_DISABLEDATE_D is null or u.USE_DISABLEDATE_D >= :fromDate and u.USE_DISABLEDATE_D < :toDate) " ) ;
DateTime fromDate = DateTime . now ( ) . minusMonths ( 1 ) . dayOfMonth ( ) . withMinimumValue ( ) . withTimeAtStartOfDay ( ) ;
DateTime toDate = fromDate . plusMonths ( 1 ) ;
query . setParameter ( " fromDate " , fromDate . toDate ( ) ) ;
query . setParameter ( " toDate " , toDate . toDate ( ) ) ;
2017-11-20 21:21:50 +01:00
return ( ( Number ) query . getSingleResult ( ) ) . longValue ( ) ;
}
2013-07-27 18:33:20 +02:00
}