Skip to content

Commit

Permalink
Merge pull request #115 from plone/erral-issue-111-master
Browse files Browse the repository at this point in the history
Use `munge_search_term` from CMFPlone
  • Loading branch information
mauritsvanrees authored Jul 21, 2022
2 parents 47c5c8f + b95b805 commit ddebcab
Show file tree
Hide file tree
Showing 4 changed files with 301 additions and 229 deletions.
2 changes: 2 additions & 0 deletions news/111.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Use function from Products.CMFPlone to handle cleaning of search terms. Fixes #111
[erral]
132 changes: 74 additions & 58 deletions plone/app/querystring/querybuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,20 @@
from plone.batching import Batch
from plone.registry.interfaces import IRegistry
from Products.CMFCore.utils import getToolByName
from zope.component import getMultiAdapter, getUtility, getUtilitiesFor
from Products.CMFPlone.browser.search import munge_search_term
from zope.component import getMultiAdapter
from zope.component import getUtilitiesFor
from zope.component import getUtility
from zope.i18n import translate
from zope.i18nmessageid import MessageFactory
from zope.publisher.browser import BrowserView

import json
import logging

logger = logging.getLogger("plone.app.querystring")
_ = MessageFactory("plone")

logger = logging.getLogger('plone.app.querystring')
_ = MessageFactory('plone')

BAD_CHARS = ('?', '-', '+', '*')


def quote_chars(s):
# We need to quote parentheses when searching text indices
if '(' in s:
s = s.replace('(', '"("')
if ')' in s:
s = s.replace(')', '")"')
return s

class ContentListingView(BrowserView):
"""BrowserView for displaying query results"""
Expand All @@ -39,16 +31,25 @@ def __call__(self, **kw):


class QueryBuilder(BrowserView):
""" This view is used by the javascripts,
fetching configuration or results"""
"""This view is used by the javascripts,
fetching configuration or results"""

def __init__(self, context, request):
super(QueryBuilder, self).__init__(context, request)
self._results = None

def __call__(self, query, batch=False, b_start=0, b_size=30,
sort_on=None, sort_order=None, limit=0, brains=False,
custom_query=None):
def __call__(
self,
query,
batch=False,
b_start=0,
b_size=30,
sort_on=None,
sort_order=None,
limit=0,
brains=False,
custom_query=None,
):
"""Create a zope catalog query and return results.
:param query: The querystring to be parsed into a zope catalog query.
Expand Down Expand Up @@ -95,32 +96,45 @@ def __call__(self, query, batch=False, b_start=0, b_size=30,
sort_order=sort_order,
limit=limit,
brains=brains,
custom_query=custom_query)
custom_query=custom_query,
)
return self._results

def html_results(self, query):
"""html results, used for in the edit screen of a collection,
used in the live update results"""
used in the live update results"""
options = dict(original_context=self.context)
results = self(query, sort_on=self.request.get('sort_on', None),
sort_order=self.request.get('sort_order', None),
limit=10)
results = self(
query,
sort_on=self.request.get("sort_on", None),
sort_order=self.request.get("sort_order", None),
limit=10,
)

return getMultiAdapter(
(results, self.request),
name='display_query_results'
(results, self.request), name="display_query_results"
)(**options)

def _makequery(self, query=None, batch=False, b_start=0, b_size=30,
sort_on=None, sort_order=None, limit=0, brains=False,
custom_query=None):
def _makequery(
self,
query=None,
batch=False,
b_start=0,
b_size=30,
sort_on=None,
sort_order=None,
limit=0,
brains=False,
custom_query=None,
):
"""Parse the (form)query and return using multi-adapter"""
query_modifiers = getUtilitiesFor(IQueryModifier)
for name, modifier in sorted(query_modifiers, key=itemgetter(0)):
query = modifier(query)

parsedquery = queryparser.parseFormquery(
self.context, query, sort_on, sort_order)
self.context, query, sort_on, sort_order
)

index_modifiers = getUtilitiesFor(IParsedQueryIndexModifier)
for name, modifier in index_modifiers:
Expand All @@ -134,36 +148,37 @@ def _makequery(self, query=None, batch=False, b_start=0, b_size=30,
parsedquery[new_name] = query

# Check for valid indexes
catalog = getToolByName(self.context, 'portal_catalog')
valid_indexes = [index for index in parsedquery
if index in catalog.indexes()]
catalog = getToolByName(self.context, "portal_catalog")
valid_indexes = [
index for index in parsedquery if index in catalog.indexes()
]

# We'll ignore any invalid index, but will return an empty set if none
# of the indexes are valid.
if not valid_indexes:
logger.warning(
"Using empty query because there are no valid indexes used.")
"Using empty query because there are no valid indexes used."
)
parsedquery = {}

empty_query = not parsedquery # store emptiness

if batch:
parsedquery['b_start'] = b_start
parsedquery['b_size'] = b_size
parsedquery["b_start"] = b_start
parsedquery["b_size"] = b_size
elif limit:
parsedquery['sort_limit'] = limit
parsedquery["sort_limit"] = limit

if 'path' not in parsedquery:
parsedquery['path'] = {'query': ''}
if "path" not in parsedquery:
parsedquery["path"] = {"query": ""}

if isinstance(custom_query, dict) and custom_query:
# Update the parsed query with an extra query dictionary. This may
# override the parsed query. The custom_query is a dictonary of
# index names and their associated query values.
for key in custom_query:
if (
isinstance(parsedquery.get(key), dict)
and isinstance(custom_query.get(key), dict)
if isinstance(parsedquery.get(key), dict) and isinstance(
custom_query.get(key), dict
):
parsedquery[key].update(custom_query[key])
continue
Expand All @@ -175,8 +190,11 @@ def _makequery(self, query=None, batch=False, b_start=0, b_size=30,
results = []
if not empty_query:
results = catalog(**parsedquery)
if getattr(results, 'actual_result_count', False) and limit\
and results.actual_result_count > limit:
if (
getattr(results, "actual_result_count", False)
and limit
and results.actual_result_count > limit
):
results.actual_result_count = limit

if not brains:
Expand All @@ -189,33 +207,31 @@ def number_of_results(self, query):
"""Get the number of results"""
results = self(query, sort_on=None, sort_order=None, limit=1)
return translate(
_(u"batch_x_items_matching_your_criteria",
default=u"${number} items matching your search terms.",
mapping={'number': results.actual_result_count}),
context=self.request
_(
u"batch_x_items_matching_your_criteria",
default=u"${number} items matching your search terms.",
mapping={"number": results.actual_result_count},
),
context=self.request,
)

def filter_query(self, query):
text = query.get('SearchableText', None)
text = query.get("SearchableText", None)
if isinstance(text, dict):
text = text.get('query', '')
text = text.get("query", "")
if text:
query['SearchableText'] = self.munge_search_term(text)
query["SearchableText"] = self.munge_search_term(text)
return query

def munge_search_term(self, q):
for char in BAD_CHARS:
q = q.replace(char, ' ')
r = q.split()
r = " AND ".join(r)
r = quote_chars(r) + '*'
return r
return munge_search_term(q)


class RegistryConfiguration(BrowserView):
def __call__(self):
registry = getUtility(IRegistry)
reader = getMultiAdapter(
(registry, self.request), IQuerystringRegistryReader)
(registry, self.request), IQuerystringRegistryReader
)
data = reader()
return json.dumps(data)
Loading

0 comments on commit ddebcab

Please sign in to comment.