<commit_before>package no.kantega.openaksess.search.controller;

import no.kantega.openaksess.search.query.AksessSearchContextCreator;
import no.kantega.openaksess.search.security.AksessSearchContext;
import no.kantega.publishing.api.content.ContentStatus;
import no.kantega.publishing.api.content.Language;
import no.kantega.publishing.common.data.Content;
import no.kantega.publishing.common.data.enums.ContentVisibilityStatus;
import no.kantega.publishing.controls.AksessController;
import no.kantega.search.api.search.QueryStringGenerator;
import no.kantega.search.api.search.SearchQuery;
import no.kantega.search.api.search.SearchResponse;
import no.kantega.search.api.search.Searcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

import static no.kantega.publishing.api.ContentUtil.tryGetFromRequest;
import static org.apache.commons.lang.StringUtils.isNotEmpty;
import static org.springframework.web.bind.ServletRequestUtils.*;

/**
 * Performs search for Aksess content.
 */
@Controller
public class ContentSearchController implements AksessController {
    @Autowired
    private Searcher searcher;

    @Autowired
    private AksessSearchContextCreator aksessSearchContextCreator;

    @Value("${oa.usefuzzysearch:false}")
    private boolean useFuzzySearch;

    private boolean searchAllSites = false;
    private boolean showOnlyVisibleContent = true;
    private boolean showOnlyPublishedContent = true;
    private List<String> facetFields = Collections.emptyList();
    private List<String> facetQueries = Collections.emptyList();

    /**
     * q - The query string. e.g. «cheese sale».
     * page - The result page wanted.
     * facetFields - The indexed fields to generate facet values from. e.g. «indexedContentType»
     * groupfield - Group results by the value they are having in this field.
     * resultsprpage - The number of results per page.
     * includeContentWithoutSite - if set to true, indexed content with siteId:-1 is included in search.
     * excludelinks - By default links for the paginating of results are generated. Set this parameter to true if this is not desired.
     * excludedefaultfacets - Faceting on location and documenttype is enabled by default. To disable this set this parameter to true.
     * filter - Additional filters may be added by setting this parameter. Each filter have to be on the format «field:value».
     * offset - To offset the results returned set the number of results to offset by in this parameter.
     */
    @RequestMapping("/search")
    public @ResponseBody Map<String, Object> handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        Map<String, Object> model = new HashMap<>();
        String query = getQuery(request);
        if (isNotEmpty(query)) {
            SearchResponse searchResponse = performSearch(request, query);
            model.put("searchResponse", searchResponse);

            if(includeLinks(request)){
                addLinks(model, searchResponse);
            }
        }

        return model;
    }

    /**
     *
     * @param request with the suggestion query in parameter «q» or «term».
     * @param limit - the number of suggestion wanted.
     * @return string suggestions matching the query.
     */
    @RequestMapping("/suggest")
    public @ResponseBody List<String> suggest(HttpServletRequest request, @RequestParam(required = false, defaultValue = "5") Integer limit) {
        String term = getQorTerm(request);
        SearchQuery query = new SearchQuery(aksessSearchContextCreator.getSearchContext(request), term);
        query.setResultsPerPage(limit);
        return searcher.suggest(query);
    }

    private String getQorTerm(HttpServletRequest request) {
        return getStringParameter(request, "q", request.getParameter("term"));
    }

    /**
     *
     * @param request with the spelling query in parameter «q» or «term».
     * @param limit - the number of spellings wanted.
     * @return strings with possible spellings.
     */
    @RequestMapping("/spelling")
    public @ResponseBody List<String> spelling(HttpServletRequest request, @RequestParam(required = false, defaultValue = "5") Integer limit) {
        String term = getQorTerm(request);
        SearchQuery query = new SearchQuery(aksessSearchContextCreator.getSearchContext(request), term);
        setLanguage(request, query);
        query.setResultsPerPage(limit);
        return searcher.spell(query);
    }

    private void setLanguage(HttpServletRequest request, SearchQuery query) {
        Content content = tryGetFromRequest(request);
        if(content.getLanguage() == Language.ENGLISH){
            query.setLanguage(no.kantega.search.api.search.Language.EN);
        }
    }

    private SearchResponse performSearch(HttpServletRequest request, String query) {
        AksessSearchContext searchContext = aksessSearchContextCreator.getSearchContext(request);
        return searcher.search(getSearchQuery(request, query, searchContext));
    }

    private SearchQuery getSearchQuery(HttpServletRequest request, String query, AksessSearchContext searchContext) {
        SearchQuery searchQuery = new SearchQuery(searchContext, query, getFilterQueries(request, searchContext));
        searchQuery.setFuzzySearch(useFuzzySearch);
        searchQuery.setPageNumber(getIntParameter(request, "page", 0));
        searchQuery.setResultsPerPage(getIntParameter(request, "resultsprpage", SearchQuery.DEFAULT_RESULTS_PER_PAGE));
        searchQuery.setOffset(getIntParameter(request, "offset", 0));

        addFacetFields(request, searchQuery, searchContext);

        searchQuery.setGroupField(getGroupField(request));
        searchQuery.setGroupQueries(getGroupQueries(request));
        searchQuery.setBoostByPublishDate(getBoostByPublishDate(request));
        return customizeQuery(searchQuery, searchContext, request);
    }

    private void addFacetFields(HttpServletRequest request, SearchQuery searchQuery, AksessSearchContext searchContext) {
        boolean excludeDefaultFacets = getBooleanParameter(request, "excludedefaultfacets", false);
        searchQuery.setFacetFields(getFacetFields(request, searchContext, excludeDefaultFacets));

        if (!excludeDefaultFacets) {
            searchQuery.setFacetQueries(facetQueries);
        }
    }

    /**
     * @param request - Current HttpServletRequest.
     * @return whether boostByPublishDate should be true or false for the current search query.
     * default returns the value of request parameter boostByPublishDate, or false if absent.
     */
    public boolean getBoostByPublishDate(HttpServletRequest request) {
        return getBooleanParameter(request, "boostByPublishDate", false);
    }

    /**
     * @param request - Current HttpServletRequest.
     * @return the field to group results by.
     */
    public String getGroupField(HttpServletRequest request) {
        return getStringParameter(request, "groupfield", null);
    }

    /**
     * @param request - Current HttpServletRequest.
     * @return the group queries to add to the current search query.
     */
    public String[] getGroupQueries(HttpServletRequest request) {
        return getStringParameters(request, "groupquery");
    }

    /**
     * Get the facet fields to be used for the current request.
     * @param request - Current HttpServletRequest.
     * @param excludeDefaultFacets true if the fields defined in the field facetFields should be included in
     *                             the facesFields-list.
     * @return all facetfields to be applied.
     */
    public List<String> getFacetFields(HttpServletRequest request, AksessSearchContext searchContext, boolean excludeDefaultFacets) {
        List<String> fields = excludeDefaultFacets? Collections.<String>emptyList() : facetFields;<commit_msg>AP-1676 - Customize SearchQuery programmatically<commit_after>package no.kantega.openaksess.search.controller;

import no.kantega.openaksess.search.query.AksessSearchContextCreator;
import no.kantega.openaksess.search.security.AksessSearchContext;
import no.kantega.publishing.api.content.ContentStatus;
import no.kantega.publishing.api.content.Language;
import no.kantega.publishing.common.data.Content;
import no.kantega.publishing.common.data.enums.ContentVisibilityStatus;
import no.kantega.publishing.controls.AksessController;
import no.kantega.search.api.search.QueryStringGenerator;
import no.kantega.search.api.search.SearchQuery;
import no.kantega.search.api.search.SearchResponse;
import no.kantega.search.api.search.Searcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

import static no.kantega.publishing.api.ContentUtil.tryGetFromRequest;
import static org.apache.commons.lang.StringUtils.isNotEmpty;
import static org.springframework.web.bind.ServletRequestUtils.*;

/**
 * Performs search for Aksess content.
 */
@Controller
public class ContentSearchController implements AksessController {
    @Autowired
    private Searcher searcher;

    @Autowired
    private AksessSearchContextCreator aksessSearchContextCreator;

    @Value("${oa.usefuzzysearch:false}")
    private boolean useFuzzySearch;

    private boolean searchAllSites = false;
    private boolean showOnlyVisibleContent = true;
    private boolean showOnlyPublishedContent = true;
    private List<String> facetFields = Collections.emptyList();
    private List<String> facetQueries = Collections.emptyList();

    /**
     * q - The query string. e.g. «cheese sale».
     * page - The result page wanted.
     * facetFields - The indexed fields to generate facet values from. e.g. «indexedContentType»
     * groupfield - Group results by the value they are having in this field.
     * resultsprpage - The number of results per page.
     * includeContentWithoutSite - if set to true, indexed content with siteId:-1 is included in search.
     * excludelinks - By default links for the paginating of results are generated. Set this parameter to true if this is not desired.
     * excludedefaultfacets - Faceting on location and documenttype is enabled by default. To disable this set this parameter to true.
     * filter - Additional filters may be added by setting this parameter. Each filter have to be on the format «field:value».
     * offset - To offset the results returned set the number of results to offset by in this parameter.
     */
    @RequestMapping("/search")
    public @ResponseBody Map<String, Object> handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        Map<String, Object> model = new HashMap<>();
        String query = getQuery(request);
        if (isNotEmpty(query)) {
            SearchResponse searchResponse = performSearch(request, query);
            model.put("searchResponse", searchResponse);

            if(includeLinks(request)){
                addLinks(model, searchResponse);
            }
        }

        return model;
    }

    /**
     *
     * @param request with the suggestion query in parameter «q» or «term».
     * @param limit - the number of suggestion wanted.
     * @return string suggestions matching the query.
     */
    @RequestMapping("/suggest")
    public @ResponseBody List<String> suggest(HttpServletRequest request, @RequestParam(required = false, defaultValue = "5") Integer limit) {
        String term = getQorTerm(request);
        SearchQuery query = new SearchQuery(aksessSearchContextCreator.getSearchContext(request), term);
        query.setResultsPerPage(limit);
        return searcher.suggest(query);
    }

    private String getQorTerm(HttpServletRequest request) {
        return getStringParameter(request, "q", request.getParameter("term"));
    }

    /**
     *
     * @param request with the spelling query in parameter «q» or «term».
     * @param limit - the number of spellings wanted.
     * @return strings with possible spellings.
     */
    @RequestMapping("/spelling")
    public @ResponseBody List<String> spelling(HttpServletRequest request, @RequestParam(required = false, defaultValue = "5") Integer limit) {
        String term = getQorTerm(request);
        SearchQuery query = new SearchQuery(aksessSearchContextCreator.getSearchContext(request), term);
        setLanguage(request, query);
        query.setResultsPerPage(limit);
        return searcher.spell(query);
    }

    private void setLanguage(HttpServletRequest request, SearchQuery query) {
        Content content = tryGetFromRequest(request);
        if(content.getLanguage() == Language.ENGLISH){
            query.setLanguage(no.kantega.search.api.search.Language.EN);
        }
    }

    private SearchResponse performSearch(HttpServletRequest request, String query) {
        AksessSearchContext searchContext = aksessSearchContextCreator.getSearchContext(request);
        return searcher.search(getSearchQuery(request, query, searchContext));
    }

    private SearchQuery getSearchQuery(HttpServletRequest request, String query, AksessSearchContext searchContext) {
        SearchQuery searchQuery = new SearchQuery(searchContext, query, getFilterQueries(request, searchContext));
        searchQuery.setFuzzySearch(useFuzzySearch);
        searchQuery.setPageNumber(getIntParameter(request, "page", 0));
        searchQuery.setResultsPerPage(getIntParameter(request, "resultsprpage", SearchQuery.DEFAULT_RESULTS_PER_PAGE));
        searchQuery.setOffset(getIntParameter(request, "offset", 0));

        addFacetFields(request, searchQuery, searchContext);

        searchQuery.setGroupField(getGroupField(request));
        searchQuery.setGroupQueries(getGroupQueries(request));
        searchQuery.setBoostByPublishDate(getBoostByPublishDate(request));
        return customizeQuery(searchQuery, searchContext, request);
    }

    /**
     * @param request - Current HttpServletRequest.
     * @return whether boostByPublishDate should be true or false for the current search query.
     * default returns the value of request parameter boostByPublishDate, or false if absent.
     */
    public boolean getBoostByPublishDate(HttpServletRequest request) {
        return getBooleanParameter(request, "boostByPublishDate", false);
    }

    /**
     * @param request - Current HttpServletRequest.
     * @return the field to group results by.
     */
    public String getGroupField(HttpServletRequest request) {
        return getStringParameter(request, "groupfield", null);
    }

    /**
     * @param request - Current HttpServletRequest.
     * @return the group queries to add to the current search query.
     */
    public String[] getGroupQueries(HttpServletRequest request) {
        return getStringParameters(request, "groupquery");
    }

    private void addFacetFields(HttpServletRequest request, SearchQuery searchQuery, AksessSearchContext searchContext) {
        boolean excludeDefaultFacets = getBooleanParameter(request, "excludedefaultfacets", false);
        searchQuery.setFacetFields(getFacetFields(request, searchContext, excludeDefaultFacets));

        if (!excludeDefaultFacets) {
            searchQuery.setFacetQueries(facetQueries);
        }
    }

    /**
     * Get the facet fields to be used for the current request.
     * @param request - Current HttpServletRequest.
     * @param excludeDefaultFacets true if the fields defined in the field facetFields should be included in
     *                             the facesFields-list.
     * @return all facetfields to be applied.
     */
    public List<String> getFacetFields(HttpServletRequest request, AksessSearchContext searchContext, boolean excludeDefaultFacets) {
        List<String> fields = excludeDefaultFacets? Collections.<String>emptyList() : facetFields;
{'fraction_non_alphanumeric': 0.08497797090952984, 'fraction_numerical': 0.0008449514152936206, 'mean_word_length': 3.849282996780802, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '145380', 'n_tokens_mistral': 4282, 'n_tokens_neox': 4247, 'n_words': 1164}