diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2018-07-04 11:43:34 +0200 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2018-08-13 18:26:03 +0200 |
commit | b83bc8404f77600e8d313d9cdd6672d8208de01f (patch) | |
tree | 7c570daeb42e18b384f4069751935b507b0da767 | |
parent | af27a6bb1e153b0c20cfed9c645b30adedde3347 (diff) | |
download | Ishtar-b83bc8404f77600e8d313d9cdd6672d8208de01f.tar.bz2 Ishtar-b83bc8404f77600e8d313d9cdd6672d8208de01f.zip |
Search: do not parse for parentheses inside quotes (refs #4180)
-rw-r--r-- | archaeological_operations/models.py | 20 | ||||
-rw-r--r-- | archaeological_operations/tests.py | 109 | ||||
-rw-r--r-- | ishtar_common/views_item.py | 24 |
3 files changed, 83 insertions, 70 deletions
diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py index b1fa4fcd8..2c51c262b 100644 --- a/archaeological_operations/models.py +++ b/archaeological_operations/models.py @@ -371,7 +371,7 @@ class Operation(ClosedItem, BaseHistorizedItem, OwnPerms, ValueGetter, ), 'operation_type': ( pgettext_lazy( - "key for text search (no accent, no spaces)", u"operation-type" + "key for text search (no accent, no spaces)", u"type" ), 'operation_type__pk' ), @@ -385,6 +385,24 @@ class Operation(ClosedItem, BaseHistorizedItem, OwnPerms, ValueGetter, "key for text search (no accent, no spaces)", u"year"), 'year' ), + 'operation_code': ( + pgettext_lazy( + "key for text search (no accent, no spaces)", u"operation-code" + ), + 'operation_code' + ), + 'code_patriarche': ( + pgettext_lazy( + "key for text search (no accent, no spaces)", u"patriarche" + ), + 'code_patriarche' + ), + 'towns': ( + pgettext_lazy( + "key for text search (no accent, no spaces)", u"town" + ), + 'towns__cached_label__iexact' + ), } for v in ALT_NAMES.values(): EXTRA_REQUEST_KEYS[v[0]] = v[1] diff --git a/archaeological_operations/tests.py b/archaeological_operations/tests.py index 19724ff8b..cfcbe010b 100644 --- a/archaeological_operations/tests.py +++ b/archaeological_operations/tests.py @@ -1548,6 +1548,18 @@ class OperationSearchTest(TestCase, OperationInitTest): result = json.loads(response.content) self.assertEqual(result['recordsTotal'], 1) + def _test_search(self, c, term, query_string, number, name=""): + q = term + if query_string: + q = u'{}="{}"'.format(term, query_string) + search = {'search_vector': q} + response = c.get(reverse('get-operation'), search) + self.assertEqual(response.status_code, 200) + result = json.loads(response.content) + self.assertEqual(result['recordsTotal'], number, + u"{} - {} - {} result(s) expected got {}".format( + name, q, number, result['recordsTotal'])) + def test_facet_search_vector(self): ope1 = self.operations[0] ope2 = self.operations[1] @@ -1555,14 +1567,21 @@ class OperationSearchTest(TestCase, OperationInitTest): c = Client() c.login(username=self.username, password=self.password) - neo = models.Period.objects.get(txt_idx='neolithic') - final_neo = models.Period.objects.get(txt_idx='final-neolithic') - gallo = models.Period.objects.get(txt_idx="gallo-roman") - ope1.periods.add(final_neo) ope1.year = 2042 ope1.save() ope2.year = 2020 ope2.save() + + data = {'numero_insee': '05000', 'name': 'Champoleon (test)'} + town = self.create_towns(datas=data)[-1] + + ope1.towns.add(town) + + neo = models.Period.objects.get(txt_idx='neolithic') + final_neo = models.Period.objects.get(txt_idx='final-neolithic') + gallo = models.Period.objects.get(txt_idx="gallo-roman") + + ope1.periods.add(final_neo) ope1.periods.add(gallo) ope2.periods.add(neo) ope3.periods.add(gallo) @@ -1570,79 +1589,49 @@ class OperationSearchTest(TestCase, OperationInitTest): villa = models.RemainType.objects.get(txt_idx='villa') ope1.remains.add(villa) - # simple - search_q = unicode( + search_period_q = unicode( pgettext("key for text search (no accent, no spaces)", u"period") ) - search = {'search_vector': u'{}="{}"'.format(search_q, final_neo.label)} - response = c.get(reverse('get-operation'), search) - self.assertEqual(response.status_code, 200) - result = json.loads(response.content) - self.assertEqual(result['recordsTotal'], 1) - # integer field + self._test_search(c, search_period_q, final_neo.label, 1, "Simple") + search_year_q = unicode( pgettext("key for text search (no accent, no spaces)", u"year") ) - search = {'search_vector': u'{}="2042"'.format(search_year_q)} - response = c.get(reverse('get-operation'), search) - self.assertEqual(response.status_code, 200) - result = json.loads(response.content) - self.assertEqual(result['recordsTotal'], 1) + self._test_search(c, search_year_q, "2042", 1, "Integer") - # many integer field - search = {'search_vector': u'{}="2042";"2020"'.format(search_year_q)} - response = c.get(reverse('get-operation'), search) - self.assertEqual(response.status_code, 200) - result = json.loads(response.content) - self.assertEqual(result['recordsTotal'], 2) + self._test_search(c, search_year_q, '2042";"2020', 2, "Many integer") - # hierarchic - search = {'search_vector': u'{}="{}"'.format(search_q, neo.label)} - response = c.get(reverse('get-operation'), search) - self.assertEqual(response.status_code, 200) - result = json.loads(response.content) - self.assertEqual(result['recordsTotal'], 2) + search_town_q = unicode( + pgettext("key for text search (no accent, no spaces)", u"town") + ) + self._test_search(c, search_town_q, town.cached_label, 1, + "String search with parenthesis and minus") - # exclude - search = {'search_vector': u'-{}="{}"'.format(search_q, neo.label)} - response = c.get(reverse('get-operation'), search) - self.assertEqual(response.status_code, 200) - result = json.loads(response.content) - self.assertEqual(result['recordsTotal'], 1) + self._test_search(c, search_period_q, neo.label, 2, "Hierarchic") - # OR - search = {'search_vector': u'{}="{}";"{}"'.format(search_q, neo.label, - gallo.label)} - response = c.get(reverse('get-operation'), search) - self.assertEqual(response.status_code, 200) - result = json.loads(response.content) - self.assertEqual(result['recordsTotal'], 3) + self._test_search(c, u'-{}="{}"'.format(search_period_q, neo.label), "", + 1, "Exclude") - # OR - alt syntax - search = {'search_vector': u'{}="{}" {}="{}"'.format( - search_q, neo.label, search_q, gallo.label)} - response = c.get(reverse('get-operation'), search) - self.assertEqual(response.status_code, 200) - result = json.loads(response.content) - self.assertEqual(result['recordsTotal'], 3) + self._test_search(c, search_period_q, + u'{}";"{}'.format(neo.label, gallo.label), + 3, "OR") + + self._test_search( + c, u'{}="{}" {}="{}"'.format(search_period_q, neo.label, + search_period_q, gallo.label), "", 3, + "OR alt syntax") # open search '*' - search = {'search_vector': u'{}="{}*"'.format(search_q, neo.label[:3])} - response = c.get(reverse('get-operation'), search) - self.assertEqual(response.status_code, 200) - result = json.loads(response.content) - self.assertEqual(result['recordsTotal'], 2) + self._test_search(c, search_period_q, + u'{}*'.format(neo.label[:3]), 2, "Open search") # non hierarchic search - search_q = unicode( + search_remain_q = unicode( pgettext("key for text search (no accent, no spaces)", u"remain") ) - search = {'search_vector': u'{}="{}"'.format(search_q, villa.label)} - response = c.get(reverse('get-operation'), search) - self.assertEqual(response.status_code, 200) - result = json.loads(response.content) - self.assertEqual(result['recordsTotal'], 1) + self._test_search(c, search_remain_q, villa.label, + 1, "Non hierarchic search") def create_relations(self): rel1 = models.RelationType.objects.create( diff --git a/ishtar_common/views_item.py b/ishtar_common/views_item.py index d2e66ae69..a818c2719 100644 --- a/ishtar_common/views_item.py +++ b/ishtar_common/views_item.py @@ -295,15 +295,21 @@ def _parse_parentheses(s): groups = [] depth = 0 + inside_quote = False for char in s: - if char == u'(': - _push_to_list([], groups, depth) - depth += 1 - elif char == ')': - if depth > 0: - depth -= 1 - else: - _push_to_list(char, groups, depth) + if char == u'"': + inside_quote = not inside_quote + if not inside_quote: + if char == u'(': + _push_to_list([], groups, depth) + depth += 1 + elif char == u')': + if depth > 0: + depth -= 1 + else: + _push_to_list(char, groups, depth) + continue + _push_to_list(char, groups, depth) # for non tolerant to parentheses mismatch check depth is equal to 0 return groups @@ -643,7 +649,6 @@ def _contruct_query(relation_types, dct, or_reqs, and_reqs): # manage multi value not already managed for key in dct.keys(): if ";" in dct[key]: - print(key, dct[key]) values = [v for v in dct[key].split(u';') if v] if not values: dct.pop(key) @@ -958,6 +963,7 @@ def get_item(model, func_name, default_name, extra_request_keys=[], dct = {upper_key: current} query &= Q(**dct) + # print(query) items = model.objects.filter(query) if exc_query: items = items.exclude(exc_query) |