From d4cc226285f1707c21c2b350f4784cc810516cc0 Mon Sep 17 00:00:00 2001 From: Nathan Buckingham Date: Mon, 29 Jul 2024 14:52:46 -0400 Subject: [PATCH] 116466: Port fixes for rss on search to 7.6 --- .../dspace/app/rest/OpenSearchController.java | 152 +++++++++++------- .../rest/utils/HttpHeadersInitializer.java | 2 +- 2 files changed, 95 insertions(+), 59 deletions(-) diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/OpenSearchController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/OpenSearchController.java index 665504139cb..d8ccd4203bb 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/OpenSearchController.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/OpenSearchController.java @@ -7,6 +7,9 @@ */ package org.dspace.app.rest; +import static org.dspace.app.rest.utils.HttpHeadersInitializer.CONTENT_DISPOSITION; +import static org.dspace.app.rest.utils.HttpHeadersInitializer.CONTENT_DISPOSITION_INLINE; + import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -21,8 +24,11 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; +import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.Logger; +import org.dspace.app.rest.parameter.SearchFilter; import org.dspace.app.rest.utils.ContextUtil; +import org.dspace.app.rest.utils.RestDiscoverQueryBuilder; import org.dspace.app.rest.utils.ScopeResolver; import org.dspace.app.util.SyndicationFeed; import org.dspace.app.util.factory.UtilServiceFactory; @@ -49,6 +55,9 @@ import org.dspace.discovery.configuration.DiscoverySortFieldConfiguration; import org.dspace.discovery.indexobject.IndexableItem; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @@ -86,22 +95,28 @@ public class OpenSearchController { @Autowired private ScopeResolver scopeResolver; + @Autowired + private RestDiscoverQueryBuilder restDiscoverQueryBuilder; + /** * This method provides the OpenSearch query on the path /search * It will pass the result as a OpenSearchDocument directly to the client */ @GetMapping("/search") public void search(HttpServletRequest request, - HttpServletResponse response, - @RequestParam(name = "query", required = false) String query, - @RequestParam(name = "start", required = false) Integer start, - @RequestParam(name = "rpp", required = false) Integer count, - @RequestParam(name = "format", required = false) String format, - @RequestParam(name = "sort", required = false) String sort, - @RequestParam(name = "sort_direction", required = false) String sortDirection, - @RequestParam(name = "scope", required = false) String dsoObject, - Model model) throws IOException, ServletException { + HttpServletResponse response, + @RequestParam(name = "query", required = false) String query, + @RequestParam(name = "start", required = false) Integer start, + @RequestParam(name = "rpp", required = false) Integer count, + @RequestParam(name = "format", required = false) String format, + @RequestParam(name = "sort", required = false) String sort, + @RequestParam(name = "sort_direction", required = false) String sortDirection, + @RequestParam(name = "scope", required = false) String dsoObject, + @RequestParam(name = "configuration", required = false) String configuration, + List searchFilters, + Model model) throws IOException, ServletException { context = ContextUtil.obtainContext(request); + if (start == null) { start = 0; } @@ -133,84 +148,105 @@ public void search(HttpServletRequest request, // then the rest - we are processing the query IndexableObject container = null; - // support pagination parameters - DiscoverQuery queryArgs = new DiscoverQuery(); - if (query == null) { - query = ""; - } else { - queryArgs.setQuery(query); + DiscoverQuery queryArgs; + + DiscoveryConfiguration discoveryConfiguration = null; + if (StringUtils.isNotBlank(configuration)) { + discoveryConfiguration = searchConfigurationService.getDiscoveryConfiguration(configuration); } - queryArgs.setStart(start); - queryArgs.setMaxResults(count); - queryArgs.setDSpaceObjectFilter(IndexableItem.TYPE); + if (discoveryConfiguration == null) { + discoveryConfiguration = searchConfigurationService.getDiscoveryConfiguration("default"); + } + // If we have search filters, use RestDiscoverQueryBuilder. + if (searchFilters != null && searchFilters.size() > 0) { + IndexableObject scope = scopeResolver.resolveScope(context, dsoObject); + Sort pageSort = sort == null || sortDirection == null + ? Sort.unsorted() + : Sort.by(new Sort.Order(Sort.Direction.fromString(sortDirection), sort)); + // TODO count can't be < 1 so I put an arbitrary number + Pageable page = PageRequest.of(start, count > 0 ? count : 10, pageSort); + queryArgs = restDiscoverQueryBuilder.buildQuery(context, scope, + discoveryConfiguration, query, searchFilters, IndexableItem.TYPE, page); + queryArgs.setFacetMinCount(-1); + } else { // Else, use the older behavior. + // support pagination parameters + queryArgs = new DiscoverQuery(); + if (query == null) { + query = ""; + } else { + queryArgs.setQuery(query); + } + queryArgs.setStart(start); + queryArgs.setMaxResults(count); + queryArgs.setDSpaceObjectFilter(IndexableItem.TYPE); - if (sort != null) { - DiscoveryConfiguration discoveryConfiguration = - searchConfigurationService.getDiscoveryConfiguration(""); - if (discoveryConfiguration != null) { - DiscoverySortConfiguration searchSortConfiguration = discoveryConfiguration - .getSearchSortConfiguration(); - if (searchSortConfiguration != null) { - DiscoverySortFieldConfiguration sortFieldConfiguration = searchSortConfiguration - .getSortFieldConfiguration(sort); - if (sortFieldConfiguration != null) { - String sortField = searchService - .toSortFieldIndex(sortFieldConfiguration.getMetadataField(), - sortFieldConfiguration.getType()); + if (sort != null) { + if (discoveryConfiguration != null) { + DiscoverySortConfiguration searchSortConfiguration = discoveryConfiguration + .getSearchSortConfiguration(); + if (searchSortConfiguration != null) { + DiscoverySortFieldConfiguration sortFieldConfiguration = searchSortConfiguration + .getSortFieldConfiguration(sort); + if (sortFieldConfiguration != null) { + String sortField = searchService + .toSortFieldIndex(sortFieldConfiguration.getMetadataField(), + sortFieldConfiguration.getType()); - if (sortDirection != null && sortDirection.equals("DESC")) { - queryArgs.setSortField(sortField, SORT_ORDER.desc); + if (sortDirection != null && sortDirection.equals("DESC")) { + queryArgs.setSortField(sortField, SORT_ORDER.desc); + } else { + queryArgs.setSortField(sortField, SORT_ORDER.asc); + } } else { - queryArgs.setSortField(sortField, SORT_ORDER.asc); + throw new IllegalArgumentException(sort + " is not a valid sort field"); } - } else { - throw new IllegalArgumentException(sort + " is not a valid sort field"); } } + } else { + // this is the default sort so we want to switch this to date accessioned + queryArgs.setSortField("dc.date.accessioned_dt", SORT_ORDER.desc); } - } else { - // this is the default sort so we want to switch this to date accessioned - queryArgs.setSortField("dc.date.accessioned_dt", SORT_ORDER.desc); - } - if (dsoObject != null) { - container = scopeResolver.resolveScope(context, dsoObject); - DiscoveryConfiguration discoveryConfiguration = searchConfigurationService - .getDiscoveryConfiguration(context, container); - queryArgs.setDiscoveryConfigurationName(discoveryConfiguration.getId()); - queryArgs.addFilterQueries(discoveryConfiguration.getDefaultFilterQueries() - .toArray( - new String[discoveryConfiguration.getDefaultFilterQueries() - .size()])); + if (dsoObject != null) { + container = scopeResolver.resolveScope(context, dsoObject); + discoveryConfiguration = searchConfigurationService + .getDiscoveryConfigurationByNameOrIndexableObject(context, "site", container); + queryArgs.setDiscoveryConfigurationName(discoveryConfiguration.getId()); + queryArgs.addFilterQueries(discoveryConfiguration.getDefaultFilterQueries() + .toArray( + new String[discoveryConfiguration.getDefaultFilterQueries() + .size()])); + } } // Perform the search DiscoverResult qResults = null; try { qResults = SearchUtils.getSearchService().search(context, - container, queryArgs); + container, queryArgs); } catch (SearchServiceException e) { log.error(LogHelper.getHeader(context, "opensearch", "query=" - + queryArgs.getQuery() - + ",error=" + e.getMessage()), e); + + queryArgs.getQuery() + + ",error=" + e.getMessage()), e); throw new RuntimeException(e.getMessage(), e); } // Log log.info("opensearch done, query=\"" + query + "\",results=" - + qResults.getTotalSearchResults()); + + qResults.getTotalSearchResults()); // format and return results Map labelMap = getLabels(request); List dsoResults = qResults.getIndexableObjects(); Document resultsDoc = openSearchService.getResultsDoc(context, format, query, - (int) qResults.getTotalSearchResults(), qResults.getStart(), - qResults.getMaxResults(), container, dsoResults, labelMap); + (int) qResults.getTotalSearchResults(), qResults.getStart(), + qResults.getMaxResults(), container, dsoResults, labelMap); try { Transformer xf = TransformerFactory.newInstance().newTransformer(); response.setContentType(openSearchService.getContentType(format)); + response.addHeader(CONTENT_DISPOSITION, CONTENT_DISPOSITION_INLINE); xf.transform(new DOMSource(resultsDoc), - new StreamResult(response.getWriter())); + new StreamResult(response.getWriter())); } catch (TransformerException e) { log.error(e); throw new ServletException(e.toString()); @@ -231,7 +267,7 @@ public void search(HttpServletRequest request, */ @GetMapping("/service") public void service(HttpServletRequest request, - HttpServletResponse response) throws IOException { + HttpServletResponse response) throws IOException { log.debug("Show OpenSearch Service document"); if (openSearchService == null) { openSearchService = UtilServiceFactory.getInstance().getOpenSearchService(); @@ -240,7 +276,7 @@ public void service(HttpServletRequest request, String svcDescrip = openSearchService.getDescription(null); log.debug("opensearchdescription is " + svcDescrip); response.setContentType(openSearchService - .getContentType("opensearchdescription")); + .getContentType("opensearchdescription")); response.setContentLength(svcDescrip.length()); response.getWriter().write(svcDescrip); } else { diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/HttpHeadersInitializer.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/HttpHeadersInitializer.java index a69da4c5e86..d5e28f4cd97 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/HttpHeadersInitializer.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/HttpHeadersInitializer.java @@ -39,6 +39,7 @@ public class HttpHeadersInitializer { MULTIPART_BOUNDARY; public static final String CONTENT_DISPOSITION_INLINE = "inline"; public static final String CONTENT_DISPOSITION_ATTACHMENT = "attachment"; + public static final String CONTENT_DISPOSITION = "Content-Disposition"; private static final String IF_NONE_MATCH = "If-None-Match"; private static final String IF_MODIFIED_SINCE = "If-Modified-Since"; private static final String ETAG = "ETag"; @@ -52,7 +53,6 @@ public class HttpHeadersInitializer { private static final String APPLICATION_OCTET_STREAM = "application/octet-stream"; private static final String IMAGE = "image"; private static final String ACCEPT = "Accept"; - private static final String CONTENT_DISPOSITION = "Content-Disposition"; private static final String CONTENT_DISPOSITION_FORMAT = "%s;filename=\"%s\""; private static final String CACHE_CONTROL = "Cache-Control";