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.commons.enums.DescriptionStatus; import eu.eudat.commons.enums.DmpAccessType; import eu.eudat.commons.enums.DmpStatus; import eu.eudat.commons.scope.user.UserScope; import eu.eudat.service.elastic.AppElasticProperties; import eu.eudat.elastic.data.DescriptionElasticEntity; import eu.eudat.elastic.data.DmpElasticEntity; import eu.eudat.elastic.data.nested.NestedDmpElasticEntity; 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.ElasticField; import gr.cite.tools.elastic.query.ElasticFields; import gr.cite.tools.elastic.query.ElasticNestedQuery; import gr.cite.tools.elastic.query.ElasticQuery; 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.time.Instant; import java.util.*; @Component //Like in C# make it Transient @Scope(BeanDefinition.SCOPE_PROTOTYPE) public class DescriptionElasticQuery extends ElasticQuery { private Collection ids; private String like; private InnerObjectDmpElasticQuery dmpSubQuery; private Instant createdAfter; private Instant createdBefore; private Instant finalizedAfter; private Instant finalizedBefore; private Collection excludedIds; private Collection statuses; private EnumSet authorize = EnumSet.of(AuthorizationFlags.None); public DescriptionElasticQuery like(String value) { this.like = value; return this; } public DescriptionElasticQuery ids(UUID value) { this.ids = List.of(value); return this; } public DescriptionElasticQuery ids(UUID... value) { this.ids = Arrays.asList(value); return this; } public DescriptionElasticQuery ids(Collection values) { this.ids = values; return this; } public DescriptionElasticQuery dmpSubQuery(InnerObjectDmpElasticQuery subQuery) { this.dmpSubQuery = subQuery; return this; } public DescriptionElasticQuery createdAfter(Instant value) { this.createdAfter = value; return this; } public DescriptionElasticQuery createdBefore(Instant value) { this.createdBefore = value; return this; } public DescriptionElasticQuery finalizedAfter(Instant value) { this.finalizedAfter = value; return this; } public DescriptionElasticQuery finalizedBefore(Instant value) { this.finalizedBefore = value; return this; } public DescriptionElasticQuery excludedIds(Collection values) { this.excludedIds = values; return this; } public DescriptionElasticQuery excludedIds(UUID value) { this.excludedIds = List.of(value); return this; } public DescriptionElasticQuery excludedIds(UUID... value) { this.excludedIds = Arrays.asList(value); return this; } public DescriptionElasticQuery statuses(DescriptionStatus value) { this.statuses = List.of(value); return this; } public DescriptionElasticQuery statuses(DescriptionStatus... value) { this.statuses = Arrays.asList(value); return this; } public DescriptionElasticQuery statuses(Collection values) { this.statuses = values; return this; } public DescriptionElasticQuery 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 DescriptionElasticQuery(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.excludedIds) || this.isEmpty(this.statuses); } @Override protected Class entityClass() { return DescriptionElasticEntity.class; } @Override protected Query applyAuthZ() { if (this.authorize.contains(AuthorizationFlags.None)) return null; //if (this.authorize.contains(AuthorizationFlags.Permission) && this.authService.authorize(Permission.BrowseDescription)) 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(new ElasticField(DescriptionElasticEntity._dmp + "." + DmpElasticEntity._status, this.entityClass()).disableInfer(true), DmpStatus.Finalized.getValue()), this.equals(new ElasticField(DescriptionElasticEntity._dmp + "." + DmpElasticEntity._accessType, this.entityClass()).disableInfer(true), DmpAccessType.Public.getValue()) )); } if (userId != null) { NestedCollaboratorElasticQuery query = this.queryFactory.query(NestedCollaboratorElasticQuery.class).nestedPath(DescriptionElasticEntity._dmp + "." + NestedDmpElasticEntity._collaborators); query.ids(userId); predicates.add(this.nestedQuery(query).build()._toQuery()); } if (!predicates.isEmpty()) { return this.or(predicates)._toQuery(); } else { return this.equals(this.elasticFieldOf(DescriptionElasticEntity._id), UUID.randomUUID()); } } @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(DescriptionElasticEntity._tags).query( this.like(elasticFields, List.of(like))._toQuery() ).build()._toQuery(), QueryBuilders.nested().path(DescriptionElasticEntity._references).query( this.like(elasticFields, List.of(like))._toQuery() ).build()._toQuery(), QueryBuilders.nested().path(DescriptionElasticEntity._dmp + "." + NestedDmpElasticEntity._references).query( this.like(elasticFields, List.of(like))._toQuery() ).build()._toQuery(), QueryBuilders.nested().path(DescriptionElasticEntity._dmp + "." + NestedDmpElasticEntity._collaborators).query( this.like(elasticFields, List.of(like))._toQuery() ).build()._toQuery(), QueryBuilders.nested().path(DescriptionElasticEntity._dmp + "." + NestedDmpElasticEntity._dois).query( this.like(elasticFields, List.of(like))._toQuery() ).build()._toQuery() )._toQuery()); } if (ids != null) { predicates.add(this.containsUUID(this.elasticFieldOf(DescriptionElasticEntity._id), ids)._toQuery()); } if (excludedIds != null) { predicates.add(this.not(this.containsUUID(this.elasticFieldOf(DescriptionElasticEntity._id), excludedIds)._toQuery())._toQuery()); } if (statuses != null) { predicates.add(this.contains(this.elasticFieldOf(DescriptionElasticEntity._status), statuses.stream().map(DescriptionStatus::getValue).toList().toArray(new Short[statuses.size()]))._toQuery()); } if (this.finalizedAfter != null) { predicates.add(this.dateGreaterThanQuery(this.elasticFieldOf(DescriptionElasticEntity._finalizedAt), this.finalizedAfter)._toQuery()); } if (this.finalizedBefore != null) { predicates.add(this.dateLessThanQuery(this.elasticFieldOf(DescriptionElasticEntity._finalizedAt), this.finalizedBefore)._toQuery()); } if (this.createdAfter != null) { predicates.add(this.dateGreaterThanQuery(this.elasticFieldOf(DescriptionElasticEntity._createdAt), this.createdAfter)._toQuery()); } if (this.createdBefore != null) { predicates.add(this.dateLessThanQuery(this.elasticFieldOf(DescriptionElasticEntity._createdAt), this.createdBefore)._toQuery()); } if (dmpSubQuery != null) { predicates.add(dmpSubQuery.innerPath(DescriptionElasticEntity._dmp).applyFilters()); } if (!predicates.isEmpty()) { return this.and(predicates); } else { return null; } } @Override public DescriptionElasticEntity convert(Map rawData, Set columns) { DescriptionElasticEntity mocDoc = new DescriptionElasticEntity(); if (columns.contains(DescriptionElasticEntity._id)) mocDoc.setId(FieldBasedMapper.shallowSafeConversion(rawData.get(DescriptionElasticEntity._id), UUID.class)); if (columns.contains(DescriptionElasticEntity._label)) mocDoc.setLabel(FieldBasedMapper.shallowSafeConversion(rawData.get(DescriptionElasticEntity._label), String.class)); if (columns.contains(DescriptionElasticEntity._description)) mocDoc.setDescription(FieldBasedMapper.shallowSafeConversion(rawData.get(DescriptionElasticEntity._description), String.class)); if (columns.contains(DescriptionElasticEntity._status)) mocDoc.setStatus(FieldBasedMapper.shallowSafeConversion(rawData.get(DescriptionElasticEntity._status), DescriptionStatus.class)); if (columns.contains(DescriptionElasticEntity._finalizedAt)) mocDoc.setFinalizedAt(FieldBasedMapper.shallowSafeConversion(rawData.get(DescriptionElasticEntity._finalizedAt), Date.class)); if (columns.contains(DescriptionElasticEntity._createdAt)) mocDoc.setFinalizedAt(FieldBasedMapper.shallowSafeConversion(rawData.get(DescriptionElasticEntity._createdAt), Date.class)); mocDoc.setTags(this.convertNested(rawData, columns, this.queryFactory.query(NestedTagElasticQuery.class), DescriptionElasticEntity._tags, null)); mocDoc.setReferences(this.convertNested(rawData, columns, this.queryFactory.query(NestedReferenceElasticQuery.class), DescriptionElasticEntity._references, null)); mocDoc.setDescriptionTemplate(this.convertInnerObject(rawData, columns, this.queryFactory.query(InnerObjectDescriptionTemplateElasticQuery.class), DescriptionElasticEntity._descriptionTemplate, null)); mocDoc.setDmp(this.convertInnerObject(rawData, columns, this.queryFactory.query(InnerObjectDmpElasticQuery.class), DescriptionElasticEntity._dmp, null)); return mocDoc; } @Override protected ElasticField fieldNameOf(FieldResolver item) { if (item.match(DescriptionElasticEntity._id)) return this.elasticFieldOf(DescriptionElasticEntity._id); else if (item.match(DescriptionElasticEntity._label)) return this.elasticFieldOf(DescriptionElasticEntity._label); else if (item.match(DescriptionElasticEntity._description)) return this.elasticFieldOf(DescriptionElasticEntity._description); else if (item.match(DescriptionElasticEntity._status)) return this.elasticFieldOf(DescriptionElasticEntity._status); else if (item.match(DescriptionElasticEntity._finalizedAt)) return this.elasticFieldOf(DescriptionElasticEntity._finalizedAt); else if (item.match(DescriptionElasticEntity._createdAt)) return this.elasticFieldOf(DescriptionElasticEntity._createdAt); else if (item.prefix(DescriptionElasticEntity._references)) return this.queryFactory.query(NestedReferenceElasticQuery.class).nestedPath(DescriptionElasticEntity._references).fieldNameOf(this.extractPrefixed(item, DescriptionElasticEntity._references)); else if (item.prefix(DescriptionElasticEntity._tags)) return this.queryFactory.query(NestedTagElasticQuery.class).nestedPath(DescriptionElasticEntity._tags).fieldNameOf(this.extractPrefixed(item, DescriptionElasticEntity._tags)); else if (item.prefix(DescriptionElasticEntity._descriptionTemplate)) return this.queryFactory.query(InnerObjectDescriptionTemplateElasticQuery.class).innerPath(DescriptionElasticEntity._descriptionTemplate).fieldNameOf(this.extractPrefixed(item, DescriptionElasticEntity._description)); else if (item.prefix(DescriptionElasticEntity._dmp)) return this.queryFactory.query(InnerObjectDmpElasticQuery.class).innerPath(DescriptionElasticEntity._dmp).fieldNameOf(this.extractPrefixed(item, DescriptionElasticEntity._dmp)); else return null; } @Override protected String[] getIndex() { List indexNames = new ArrayList<>(); indexNames.add(this.appElasticProperties.getDescriptionIndexName()); 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(DescriptionElasticEntity._id); } @Override protected ElasticNestedQuery nestedQueryOf(FieldResolver item) { if (item.prefix(DescriptionElasticEntity._references)) return this.queryFactory.query(NestedReferenceElasticQuery.class).nestedPath(DescriptionElasticEntity._references); else if (item.prefix(DescriptionElasticEntity._tags)) return this.queryFactory.query(NestedTagElasticQuery.class).nestedPath(DescriptionElasticEntity._tags); else return null; } }