package eu.eudat.elastic.query; import co.elastic.clients.elasticsearch._types.query_dsl.Query; import co.elastic.clients.elasticsearch._types.query_dsl.QueryBuilders; import eu.eudat.authorization.AuthorizationFlags; import eu.eudat.authorization.Permission; import eu.eudat.commons.enums.DmpAccessType; import eu.eudat.commons.enums.DmpStatus; import eu.eudat.commons.enums.DmpVersionStatus; import eu.eudat.commons.scope.user.UserScope; import eu.eudat.service.elastic.AppElasticProperties; import eu.eudat.elastic.data.DmpElasticEntity; import eu.eudat.elastic.data.nested.NestedDescriptionElasticEntity; import eu.eudat.service.elastic.ElasticService; import gr.cite.commons.web.authz.service.AuthorizationService; import gr.cite.tools.data.query.FieldResolver; import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.elastic.configuration.ElasticProperties; import gr.cite.tools.elastic.mapper.FieldBasedMapper; import gr.cite.tools.elastic.query.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.*; import java.util.stream.Collectors; @Component //Like in C# make it Transient @Scope(BeanDefinition.SCOPE_PROTOTYPE) public class DmpElasticQuery extends ElasticQuery { private String like; private Collection ids; private Collection excludedIds; private Collection statuses; private Collection versionStatuses; private Collection accessTypes; private Collection versions; private Collection groupIds; private EnumSet authorize = EnumSet.of(AuthorizationFlags.None); public DmpElasticQuery like(String value) { this.like = value; return this; } public DmpElasticQuery ids(UUID value) { this.ids = List.of(value); return this; } public DmpElasticQuery ids(UUID... value) { this.ids = Arrays.asList(value); return this; } public DmpElasticQuery ids(Collection values) { this.ids = values; return this; } public DmpElasticQuery excludedIds(Collection values) { this.excludedIds = values; return this; } public DmpElasticQuery excludedIds(UUID value) { this.excludedIds = List.of(value); return this; } public DmpElasticQuery excludedIds(UUID... value) { this.excludedIds = Arrays.asList(value); return this; } public DmpElasticQuery versionStatuses(DmpVersionStatus value) { this.versionStatuses = List.of(value); return this; } public DmpElasticQuery versionStatuses(DmpVersionStatus... value) { this.versionStatuses = Arrays.asList(value); return this; } public DmpElasticQuery versionStatuses(Collection values) { this.versionStatuses = values; return this; } public DmpElasticQuery accessTypes(DmpAccessType value) { this.accessTypes = List.of(value); return this; } public DmpElasticQuery accessTypes(DmpAccessType... value) { this.accessTypes = Arrays.asList(value); return this; } public DmpElasticQuery accessTypes(Collection values) { this.accessTypes = values; return this; } public DmpElasticQuery statuses(DmpStatus value) { this.statuses = List.of(value); return this; } public DmpElasticQuery statuses(DmpStatus... value) { this.statuses = Arrays.asList(value); return this; } public DmpElasticQuery statuses(Collection values) { this.statuses = values; return this; } public DmpElasticQuery versions(Integer value) { this.versions = List.of(value); return this; } public DmpElasticQuery versions(Integer... value) { this.versions = Arrays.asList(value); return this; } public DmpElasticQuery versions(Collection values) { this.versions = values; return this; } public DmpElasticQuery groupIds(UUID value) { this.groupIds = List.of(value); return this; } public DmpElasticQuery groupIds(UUID... value) { this.groupIds = Arrays.asList(value); return this; } public DmpElasticQuery groupIds(Collection values) { this.groupIds = values; return this; } public DmpElasticQuery authorize(EnumSet values) { this.authorize = values; return this; } private final QueryFactory queryFactory; private final AppElasticProperties appElasticProperties; private final ElasticService elasticService; private final UserScope userScope; private final AuthorizationService authService; @Autowired() public DmpElasticQuery(ElasticsearchTemplate elasticsearchTemplate, ElasticProperties elasticProperties, QueryFactory queryFactory, AppElasticProperties appElasticProperties, ElasticService elasticService, UserScope userScope, AuthorizationService authService) { super(elasticsearchTemplate, elasticProperties); this.queryFactory = queryFactory; this.appElasticProperties = appElasticProperties; this.elasticService = elasticService; this.userScope = userScope; this.authService = authService; } @Override protected Boolean isFalseQuery() { return this.isEmpty(this.ids) || this.isEmpty(this.versionStatuses) || this.isEmpty(this.excludedIds) || this.isEmpty(this.accessTypes)|| this.isEmpty(this.statuses); } @Override protected Class entityClass() { return DmpElasticEntity.class; } @Override protected Query applyAuthZ() { if (this.authorize.contains(AuthorizationFlags.None)) return null; if (this.authorize.contains(AuthorizationFlags.Permission) && this.authService.authorize(Permission.BrowseDmp)) return null; UUID userId = null; boolean usePublic = this.authorize.contains(AuthorizationFlags.Public); if (this.authorize.contains(AuthorizationFlags.DmpAssociated)) userId = this.userScope.getUserIdSafe(); List predicates = new ArrayList<>(); if (usePublic) { predicates.add(this.and( this.equals(this.elasticFieldOf(DmpElasticEntity._status), DmpStatus.Finalized.getValue()), this.equals(this.elasticFieldOf(DmpElasticEntity._accessType), DmpAccessType.Public.getValue()) )); } if (userId != null) { NestedCollaboratorElasticQuery query = this.queryFactory.query(NestedCollaboratorElasticQuery.class).nestedPath(DmpElasticEntity._collaborators); query.ids(userId); predicates.add(this.nestedQuery(query).build()._toQuery()); } return this.or(predicates)._toQuery(); } @Override protected Query applyFilters() { List predicates = new ArrayList<>(); if (like != null && !like.isBlank()) { if (!like.startsWith("*")) like = "*" + like; if (!like.endsWith("*")) like = like + "*"; ElasticFields elasticFields = this.elasticFieldsOf(); elasticFields.add("*", null, true); predicates.add(this.or( this.like(elasticFields, List.of(like))._toQuery(), QueryBuilders.nested().path(DmpElasticEntity._collaborators).query( this.like(elasticFields, List.of(like))._toQuery() ).build()._toQuery(), QueryBuilders.nested().path(DmpElasticEntity._references).query( this.like(elasticFields, List.of(like))._toQuery() ).build()._toQuery(), QueryBuilders.nested().path(DmpElasticEntity._descriptions + "." + NestedDescriptionElasticEntity._references).query( this.like(elasticFields, List.of(like))._toQuery() ).build()._toQuery(), QueryBuilders.nested().path(DmpElasticEntity._descriptions + "." + NestedDescriptionElasticEntity._tags).query( this.like(elasticFields, List.of(like))._toQuery() ).build()._toQuery(), QueryBuilders.nested().path(DmpElasticEntity._descriptions).query( this.like(elasticFields, List.of(like))._toQuery() ).build()._toQuery() )._toQuery()); } if (ids != null) { predicates.add(this.containsUUID(this.elasticFieldOf(DmpElasticEntity._id), ids)._toQuery()); } if (groupIds != null) { predicates.add(this.containsUUID(this.elasticFieldOf(DmpElasticEntity._groupId), groupIds)._toQuery()); } if (versions != null) { predicates.add(this.contains(this.elasticFieldOf(DmpElasticEntity._version), versions.toArray(new Integer[versions.size()]))._toQuery()); } if (excludedIds != null) { predicates.add(this.not(this.containsUUID(this.elasticFieldOf(DmpElasticEntity._id), excludedIds)._toQuery())._toQuery()); } if (statuses != null) { predicates.add(this.contains(this.elasticFieldOf(DmpElasticEntity._status), statuses.stream().map(x-> x.getValue()).collect(Collectors.toList()).toArray(new Short[statuses.size()]))._toQuery()); } if (versionStatuses != null) { predicates.add(this.contains(this.elasticFieldOf(DmpElasticEntity._versionStatus), versionStatuses.stream().map(x-> x.getValue()).collect(Collectors.toList()).toArray(new Short[versionStatuses.size()]))._toQuery()); } if (accessTypes != null) { predicates.add(this.contains(this.elasticFieldOf(DmpElasticEntity._accessType), accessTypes.stream().map(x-> x.getValue()).collect(Collectors.toList()).toArray(new Short[accessTypes.size()]))._toQuery()); } if (!predicates.isEmpty()) { return this.and(predicates); } else { return null; } } @Override public DmpElasticEntity convert(Map rawData, Set columns) { DmpElasticEntity mocDoc = new DmpElasticEntity(); if (columns.contains(DmpElasticEntity._id)) mocDoc.setId(FieldBasedMapper.shallowSafeConversion(rawData.get(DmpElasticEntity._id), UUID.class)); if (columns.contains(DmpElasticEntity._label)) mocDoc.setLabel(FieldBasedMapper.shallowSafeConversion(rawData.get(DmpElasticEntity._label), String.class)); if (columns.contains(DmpElasticEntity._description)) mocDoc.setDescription(FieldBasedMapper.shallowSafeConversion(rawData.get(DmpElasticEntity._description), String.class)); if (columns.contains(DmpElasticEntity._status)) mocDoc.setStatus(FieldBasedMapper.shallowSafeConversion(rawData.get(DmpElasticEntity._status), DmpStatus.class)); if (columns.contains(DmpElasticEntity._versionStatus)) mocDoc.setVersionStatus(FieldBasedMapper.shallowSafeConversion(rawData.get(DmpElasticEntity._versionStatus), DmpVersionStatus.class)); if (columns.contains(DmpElasticEntity._version)) mocDoc.setVersion(FieldBasedMapper.shallowSafeConversion(rawData.get(DmpElasticEntity._version), Short.class)); if (columns.contains(DmpElasticEntity._groupId)) mocDoc.setGroupId(FieldBasedMapper.shallowSafeConversion(rawData.get(DmpElasticEntity._groupId), UUID.class)); if (columns.contains(DmpElasticEntity._accessType)) mocDoc.setAccessType(FieldBasedMapper.shallowSafeConversion(rawData.get(DmpElasticEntity._accessType), DmpAccessType.class)); if (columns.contains(DmpElasticEntity._finalizedAt)) mocDoc.setFinalizedAt(FieldBasedMapper.shallowSafeConversion(rawData.get(DmpElasticEntity._finalizedAt), Date.class)); mocDoc.setCollaborators(this.convertNested(rawData, columns, this.queryFactory.query(NestedCollaboratorElasticQuery.class), DmpElasticEntity._collaborators, null)); mocDoc.setReferences(this.convertNested(rawData, columns, this.queryFactory.query(NestedReferenceElasticQuery.class), DmpElasticEntity._references, null)); mocDoc.setDescriptions(this.convertNested(rawData, columns, this.queryFactory.query(NestedDescriptionElasticQuery.class), DmpElasticEntity._descriptions, null)); return mocDoc; } @Override protected ElasticField fieldNameOf(FieldResolver item) { if (item.match(DmpElasticEntity._id)) return this.elasticFieldOf(DmpElasticEntity._id); else if (item.match(DmpElasticEntity._label)) return this.elasticFieldOf(DmpElasticEntity._label); else if (item.match(DmpElasticEntity._description)) return this.elasticFieldOf(DmpElasticEntity._description); else if (item.match(DmpElasticEntity._status)) return this.elasticFieldOf(DmpElasticEntity._status); else if (item.match(DmpElasticEntity._version)) return this.elasticFieldOf(DmpElasticEntity._version); else if (item.match(DmpElasticEntity._versionStatus)) return this.elasticFieldOf(DmpElasticEntity._versionStatus); else if (item.match(DmpElasticEntity._groupId)) return this.elasticFieldOf(DmpElasticEntity._groupId); else if (item.match(DmpElasticEntity._finalizedAt)) return this.elasticFieldOf(DmpElasticEntity._finalizedAt); else if (item.match(DmpElasticEntity._accessType)) return this.elasticFieldOf(DmpElasticEntity._accessType); else if (item.prefix(DmpElasticEntity._collaborators)) return this.queryFactory.query(NestedCollaboratorElasticQuery.class).nestedPath(DmpElasticEntity._collaborators).fieldNameOf(this.extractPrefixed(item, DmpElasticEntity._collaborators)); else if (item.prefix(DmpElasticEntity._references)) return this.queryFactory.query(NestedReferenceElasticQuery.class).nestedPath(DmpElasticEntity._references).fieldNameOf(this.extractPrefixed(item, DmpElasticEntity._references)); else if (item.prefix(DmpElasticEntity._descriptions)) return this.queryFactory.query(NestedDescriptionElasticQuery.class).nestedPath(DmpElasticEntity._descriptions).fieldNameOf(this.extractPrefixed(item, DmpElasticEntity._descriptions)); else return null; } @Override protected String[] getIndex() { List indexNames = new ArrayList<>(); indexNames.add(this.appElasticProperties.getDmpIndexName()); try { this.elasticService.ensureDescriptionIndex(); } catch (IOException e) { throw new RuntimeException(e); } return indexNames.toArray(new String[indexNames.size()]); } @Override protected UUID toKey(String key) { return UUID.fromString(key); } @Override protected ElasticField getKeyField() { return this.elasticFieldOf(DmpElasticEntity._id); } @Override protected ElasticNestedQuery nestedQueryOf(FieldResolver item) { if (item.prefix(DmpElasticEntity._collaborators)) return this.queryFactory.query(NestedCollaboratorElasticQuery.class).nestedPath(DmpElasticEntity._collaborators); else if (item.prefix(DmpElasticEntity._references)) return this.queryFactory.query(NestedReferenceElasticQuery.class).nestedPath(DmpElasticEntity._references); else if (item.prefix(DmpElasticEntity._descriptions)) return this.queryFactory.query(NestedDescriptionElasticQuery.class).nestedPath(DmpElasticEntity._descriptions); else return null; } }