2023-11-17 18:01:44 +01:00
package eu.eudat.query ;
import eu.eudat.authorization.AuthorizationFlags ;
import eu.eudat.authorization.Permission ;
import eu.eudat.commons.enums.IsActive ;
import eu.eudat.commons.scope.user.UserScope ;
2023-12-01 12:18:20 +01:00
import eu.eudat.data.* ;
2024-01-05 10:05:40 +01:00
import eu.eudat.model.Language ;
2023-11-17 18:01:44 +01:00
import eu.eudat.model.User ;
import eu.eudat.model.PublicUser ;
2023-11-20 16:09:24 +01:00
import eu.eudat.query.utils.BuildSubQueryInput ;
2023-11-17 18:01:44 +01:00
import eu.eudat.query.utils.QueryUtilsService ;
import gr.cite.commons.web.authz.service.AuthorizationService ;
import gr.cite.tools.data.query.FieldResolver ;
import gr.cite.tools.data.query.QueryBase ;
import gr.cite.tools.data.query.QueryContext ;
2024-01-05 10:05:40 +01:00
import gr.cite.tools.exception.MyNotFoundException ;
2023-11-17 18:01:44 +01:00
import jakarta.persistence.Tuple ;
import jakarta.persistence.criteria.CriteriaBuilder ;
import jakarta.persistence.criteria.Predicate ;
import jakarta.persistence.criteria.Subquery ;
import org.springframework.beans.factory.config.ConfigurableBeanFactory ;
import org.springframework.context.annotation.Scope ;
2024-01-05 10:05:40 +01:00
import org.springframework.context.i18n.LocaleContextHolder ;
2023-11-17 18:01:44 +01:00
import org.springframework.stereotype.Component ;
import java.time.Instant ;
import java.util.* ;
@Component
@Scope ( value = ConfigurableBeanFactory . SCOPE_PROTOTYPE )
public class UserQuery extends QueryBase < UserEntity > {
private String like ;
2024-01-05 10:05:40 +01:00
private Boolean dmpAssociated ;
2023-11-17 18:01:44 +01:00
private Collection < UUID > ids ;
2023-11-20 16:09:24 +01:00
private Collection < String > emails ;
2023-11-17 18:01:44 +01:00
private Collection < UUID > excludedIds ;
private Collection < IsActive > isActives ;
2023-12-01 12:18:20 +01:00
private UserRoleQuery userRoleQuery ;
2023-11-17 18:01:44 +01:00
private EnumSet < AuthorizationFlags > authorize = EnumSet . of ( AuthorizationFlags . None ) ;
private final UserScope userScope ;
private final AuthorizationService authService ;
2023-11-20 16:09:24 +01:00
private final QueryUtilsService queryUtilsService ;
public UserQuery ( UserScope userScope , AuthorizationService authService , QueryUtilsService queryUtilsService ) {
2023-11-17 18:01:44 +01:00
this . userScope = userScope ;
this . authService = authService ;
2023-11-20 16:09:24 +01:00
this . queryUtilsService = queryUtilsService ;
2023-11-17 18:01:44 +01:00
}
public UserQuery like ( String value ) {
this . like = value ;
return this ;
}
public UserQuery ids ( UUID value ) {
this . ids = List . of ( value ) ;
return this ;
}
public UserQuery ids ( UUID . . . value ) {
this . ids = Arrays . asList ( value ) ;
return this ;
}
public UserQuery ids ( Collection < UUID > values ) {
this . ids = values ;
return this ;
}
2023-11-20 16:09:24 +01:00
public UserQuery emails ( String value ) {
this . emails = List . of ( value ) ;
return this ;
}
public UserQuery emails ( String . . . value ) {
this . emails = Arrays . asList ( value ) ;
return this ;
}
public UserQuery emails ( Collection < String > values ) {
this . emails = values ;
return this ;
}
2023-11-17 18:01:44 +01:00
public UserQuery excludedIds ( Collection < UUID > values ) {
this . excludedIds = values ;
return this ;
}
public UserQuery excludedIds ( UUID value ) {
this . excludedIds = List . of ( value ) ;
return this ;
}
public UserQuery excludedIds ( UUID . . . value ) {
this . excludedIds = Arrays . asList ( value ) ;
return this ;
}
public UserQuery isActive ( IsActive value ) {
this . isActives = List . of ( value ) ;
return this ;
}
public UserQuery isActive ( IsActive . . . value ) {
this . isActives = Arrays . asList ( value ) ;
return this ;
}
public UserQuery isActive ( Collection < IsActive > values ) {
this . isActives = values ;
return this ;
}
2023-12-01 12:18:20 +01:00
public UserQuery userRoleSubQuery ( UserRoleQuery userRoleSubQuery ) {
this . userRoleQuery = userRoleSubQuery ;
return this ;
}
2024-01-05 10:05:40 +01:00
public UserQuery dmpAssociated ( Boolean dmpAssociated ) {
this . dmpAssociated = dmpAssociated ;
return this ;
}
2023-11-17 18:01:44 +01:00
public UserQuery authorize ( EnumSet < AuthorizationFlags > values ) {
this . authorize = values ;
return this ;
}
@Override
protected Boolean isFalseQuery ( ) {
return
this . isEmpty ( this . ids ) | |
this . isEmpty ( this . isActives ) | |
2023-11-20 16:09:24 +01:00
this . isEmpty ( this . emails ) | |
2023-12-01 12:18:20 +01:00
this . isEmpty ( this . excludedIds ) | |
this . isFalseQuery ( this . userRoleQuery ) ;
2023-11-17 18:01:44 +01:00
}
@Override
protected Class < UserEntity > entityClass ( ) {
return UserEntity . class ;
}
@Override
protected < X , Y > Predicate applyAuthZ ( QueryContext < X , Y > queryContext ) {
if ( this . authorize . contains ( AuthorizationFlags . None ) ) return null ;
if ( this . authorize . contains ( AuthorizationFlags . Permission ) & & this . authService . authorize ( Permission . BrowseUser ) ) return null ;
UUID userId ;
if ( this . authorize . contains ( AuthorizationFlags . Owner ) ) userId = this . userScope . getUserIdSafe ( ) ;
2024-03-14 10:23:46 +01:00
if ( this . authorize . contains ( AuthorizationFlags . DmpAssociated ) ) userId = this . userScope . getUserIdSafe ( ) ;
2023-11-17 18:01:44 +01:00
else userId = null ;
List < Predicate > predicates = new ArrayList < > ( ) ;
2024-03-11 14:20:09 +01:00
boolean usePublic = this . authorize . contains ( AuthorizationFlags . Public ) ;
2024-03-12 17:27:16 +01:00
if ( userId ! = null | | usePublic ) {
UUID finalUserId = userId ;
predicates . add ( queryContext . CriteriaBuilder . or (
userId ! = null ? queryContext . CriteriaBuilder . in ( queryContext . Root . get ( UserEntity . _id ) ) . value ( userId ) : queryContext . CriteriaBuilder . or ( ) , //Creates a false query
2024-03-19 16:21:50 +01:00
queryContext . CriteriaBuilder . in ( queryContext . Root . get ( UserEntity . _id ) ) . value ( queryUtilsService . buildSubQuery ( new BuildSubQueryInput < > ( new BuildSubQueryInput . Builder < > ( DmpUserEntity . class , UUID . class )
2024-03-12 17:27:16 +01:00
. query ( queryContext . Query )
. criteriaBuilder ( queryContext . CriteriaBuilder )
. keyPathFunc ( ( subQueryRoot ) - > subQueryRoot . get ( DmpUserEntity . _userId ) )
. filterFunc ( ( subQueryRoot , cb ) - >
cb . in ( subQueryRoot . get ( DmpUserEntity . _dmpId ) ) . value ( queryUtilsService . buildDmpAuthZSubQuery ( queryContext . Query , queryContext . CriteriaBuilder , finalUserId , usePublic ) )
)
) ) )
) ) ;
2023-11-17 18:01:44 +01:00
}
if ( ! predicates . isEmpty ( ) ) {
Predicate [ ] predicatesArray = predicates . toArray ( new Predicate [ 0 ] ) ;
return queryContext . CriteriaBuilder . and ( predicatesArray ) ;
} else {
return queryContext . CriteriaBuilder . or ( ) ; //Creates a false query
}
}
@Override
protected < X , Y > Predicate applyFilters ( QueryContext < X , Y > queryContext ) {
List < Predicate > predicates = new ArrayList < > ( ) ;
if ( this . like ! = null & & ! this . like . isEmpty ( ) ) {
predicates . add ( queryContext . CriteriaBuilder . like ( queryContext . Root . get ( UserEntity . _name ) , this . like ) ) ;
}
if ( this . ids ! = null ) {
CriteriaBuilder . In < UUID > inClause = queryContext . CriteriaBuilder . in ( queryContext . Root . get ( UserEntity . _id ) ) ;
for ( UUID item : this . ids )
inClause . value ( item ) ;
predicates . add ( inClause ) ;
}
if ( this . excludedIds ! = null ) {
CriteriaBuilder . In < UUID > notInClause = queryContext . CriteriaBuilder . in ( queryContext . Root . get ( UserEntity . _id ) ) ;
for ( UUID item : this . excludedIds )
notInClause . value ( item ) ;
predicates . add ( notInClause . not ( ) ) ;
}
if ( this . isActives ! = null ) {
CriteriaBuilder . In < IsActive > inClause = queryContext . CriteriaBuilder . in ( queryContext . Root . get ( UserEntity . _isActive ) ) ;
for ( IsActive item : this . isActives )
inClause . value ( item ) ;
predicates . add ( inClause ) ;
}
2023-11-20 16:09:24 +01:00
if ( this . emails ! = null ) {
Subquery < UUID > userContactInfoSubquery = queryUtilsService . buildSubQuery ( new BuildSubQueryInput < > (
new BuildSubQueryInput . Builder < > ( UserContactInfoQuery . class , UUID . class , queryContext )
. keyPathFunc ( ( subQueryRoot ) - > subQueryRoot . get ( UserContactInfoEntity . _id ) )
. filterFunc ( ( subQueryRoot , cb ) - > {
2024-01-05 10:05:40 +01:00
CriteriaBuilder . In < String > inClause = cb . in ( subQueryRoot . get ( UserContactInfoEntity . _value ) ) ;
2023-11-20 16:09:24 +01:00
for ( String item : this . emails )
inClause . value ( item ) ;
return inClause ;
}
)
) ) ;
predicates . add ( queryContext . CriteriaBuilder . in ( queryContext . Root . get ( UserEntity . _id ) ) . value ( userContactInfoSubquery ) ) ;
}
2023-12-01 12:18:20 +01:00
if ( this . userRoleQuery ! = null ) {
2023-12-05 10:32:17 +01:00
QueryContext < UserRoleEntity , UUID > subQuery = this . applySubQuery ( this . userRoleQuery , queryContext , UUID . class , userRoleEntityRoot - > userRoleEntityRoot . get ( UserRoleEntity . _userId ) ) ;
2023-12-04 17:16:57 +01:00
predicates . add ( queryContext . CriteriaBuilder . in ( queryContext . Root . get ( UserEntity . _id ) ) . value ( subQuery . Query ) ) ;
2023-12-01 12:18:20 +01:00
}
2024-01-05 10:41:57 +01:00
if ( this . dmpAssociated ! = null ) {
2024-01-05 10:05:40 +01:00
UUID userId ;
if ( this . userScope . isSet ( ) ) userId = this . userScope . getUserIdSafe ( ) ;
else throw new MyNotFoundException ( " Only user scoped allowed " ) ;
Subquery < UUID > dmpUserDmpQuery = queryUtilsService . buildSubQuery ( new BuildSubQueryInput < > (
2024-03-11 08:47:03 +01:00
new BuildSubQueryInput . Builder < > ( DmpUserEntity . class , UUID . class , queryContext )
2024-01-05 10:05:40 +01:00
. keyPathFunc ( ( subQueryRoot ) - > subQueryRoot . get ( DmpUserEntity . _dmpId ) )
. filterFunc ( ( subQueryRoot , cb ) - > cb . and (
cb . equal ( subQueryRoot . get ( DmpUserEntity . _userId ) , userId ) ,
cb . equal ( subQueryRoot . get ( DmpUserEntity . _isActive ) , IsActive . Active )
) )
) ) ;
Subquery < UUID > dmpUserUserQuery = queryUtilsService . buildSubQuery ( new BuildSubQueryInput < > (
2024-03-11 08:47:03 +01:00
new BuildSubQueryInput . Builder < > ( DmpUserEntity . class , UUID . class , queryContext )
2024-01-05 10:05:40 +01:00
. keyPathFunc ( ( subQueryRoot ) - > subQueryRoot . get ( DmpUserEntity . _userId ) )
. filterFunc ( ( subQueryRoot , cb ) - > cb . and (
cb . in ( subQueryRoot . get ( DmpUserEntity . _dmpId ) ) . value ( dmpUserDmpQuery ) ,
cb . equal ( subQueryRoot . get ( DmpUserEntity . _isActive ) , IsActive . Active )
) )
) ) ;
predicates . add ( queryContext . CriteriaBuilder . in ( queryContext . Root . get ( UserEntity . _id ) ) . value ( dmpUserUserQuery ) ) ;
}
2023-11-20 16:09:24 +01:00
2023-11-17 18:01:44 +01:00
if ( ! predicates . isEmpty ( ) ) {
Predicate [ ] predicatesArray = predicates . toArray ( new Predicate [ 0 ] ) ;
return queryContext . CriteriaBuilder . and ( predicatesArray ) ;
} else {
return null ;
}
}
@Override
protected String fieldNameOf ( FieldResolver item ) {
if ( item . match ( User . _id ) | | item . match ( PublicUser . _id ) ) return UserEntity . _id ;
else if ( item . match ( User . _name ) | | item . match ( PublicUser . _name ) ) return UserEntity . _name ;
else if ( item . prefix ( User . _additionalInfo ) ) return UserEntity . _additionalInfo ;
2024-01-29 17:10:55 +01:00
else if ( item . match ( User . _additionalInfo ) ) return UserEntity . _additionalInfo ;
2023-11-17 18:01:44 +01:00
else if ( item . match ( User . _createdAt ) ) return UserEntity . _createdAt ;
else if ( item . match ( User . _updatedAt ) ) return UserEntity . _updatedAt ;
else if ( item . match ( User . _hash ) ) return UserEntity . _updatedAt ;
else if ( item . match ( User . _isActive ) ) return UserEntity . _isActive ;
else return null ;
}
@Override
protected UserEntity convert ( Tuple tuple , Set < String > columns ) {
UserEntity item = new UserEntity ( ) ;
item . setId ( QueryBase . convertSafe ( tuple , columns , UserEntity . _id , UUID . class ) ) ;
item . setName ( QueryBase . convertSafe ( tuple , columns , UserEntity . _name , String . class ) ) ;
item . setAdditionalInfo ( QueryBase . convertSafe ( tuple , columns , UserEntity . _additionalInfo , String . class ) ) ;
item . setCreatedAt ( QueryBase . convertSafe ( tuple , columns , UserEntity . _createdAt , Instant . class ) ) ;
item . setUpdatedAt ( QueryBase . convertSafe ( tuple , columns , UserEntity . _updatedAt , Instant . class ) ) ;
item . setIsActive ( QueryBase . convertSafe ( tuple , columns , UserEntity . _isActive , IsActive . class ) ) ;
return item ;
}
}