From d69e526757846193a8b01edb812cbb6a4e539500 Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Wed, 20 Nov 2019 17:15:57 +0100
Subject: [PATCH] jsondatastore: add a search endpoint (#29889)

---
 passerelle/apps/jsondatastore/models.py | 26 +++++++++++++++++++++
 tests/test_jsondatastore.py             | 31 +++++++++++++++++++++++++
 2 files changed, 57 insertions(+)

diff --git a/passerelle/apps/jsondatastore/models.py b/passerelle/apps/jsondatastore/models.py
index 766caf3a..eab0c58a 100644
--- a/passerelle/apps/jsondatastore/models.py
+++ b/passerelle/apps/jsondatastore/models.py
@@ -17,8 +17,11 @@
 import json
 import uuid
 
+import unidecode
+
 from django.db import models
 from django.template import Context, Template
+from django.utils.encoding import force_text
 from django.utils.translation import ugettext_lazy as _
 
 from jsonfield import JSONField
@@ -93,6 +96,29 @@ class JsonDataStore(BaseResource):
             objects = [o for o in objects if o.content.get(key) == value]
         return {'data': [x.to_json() for x in objects]}
 
+    @endpoint(perm='can_access', name='search', pattern=r'$',
+              description=_('List content'))
+    def search(self, request, name_id=None, url_field='url', text_field='text',
+               description_field='description', **kwargs):
+        objects = JsonData.objects.filter(datastore=self)
+        if name_id is not None:
+            objects = objects.filter(name_id=name_id)
+
+        def match(value1, value2):
+            val1 = unidecode.unidecode(force_text(value1)).upper()
+            val2 = unidecode.unidecode(force_text(value2)).upper()
+            return val1 in val2
+
+        for key, value in kwargs.items():
+            objects = [o for o in objects if match(value, o.content.get(key))]
+        data = []
+        for obj in objects:
+            data.append({
+                'url': obj.content.get(url_field),
+                'text': obj.content.get(text_field),
+                'description': obj.content.get(description_field)})
+        return {'err': 0, 'data': data}
+
     @endpoint(perm='can_access', methods=['post'], name='data',
               pattern=r'create$',
               example_pattern='create',
diff --git a/tests/test_jsondatastore.py b/tests/test_jsondatastore.py
index fdfaf4d9..a91c123f 100644
--- a/tests/test_jsondatastore.py
+++ b/tests/test_jsondatastore.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 import pytest
 
 from django.contrib.contenttypes.models import ContentType
@@ -221,3 +222,33 @@ def test_jsondatastore_list_by_attribute_filter(app, jsondatastore):
     resp = app.get('/jsondatastore/foobar/data/',
                    params={'key3': ''})
     assert [d['id'] for d in resp.json['data']] == []
+
+
+def test_jsondatastore_search(app, jsondatastore):
+    resp = app.post_json('/jsondatastore/foobar/data/create?name_id=name1',
+                         params={'me': 1, 'text': 'val1', 'url': 'foÖ'})
+    resp = app.post_json('/jsondatastore/foobar/data/create?name_id=name2',
+                         params={'me': 2, 'text': 'val1', 'url': 'val2'})
+    resp = app.post_json('/jsondatastore/foobar/data/create?name_id=name1',
+                         params={'me': 3, 'text': 'val1', 'url': 'val3'})
+
+    # JSON conformes with combo/apps/search/README
+    resp = app.get('/jsondatastore/foobar/search/',
+                   params={'me': 2})
+    assert resp.json['data'] == [{'text': 'val1', 'url': 'val2', 'description': None}]
+
+    resp = app.get('/jsondatastore/foobar/search/',
+                   params={'me': 2, 'description_field': 'me'})
+    assert resp.json['data'] == [{'text': 'val1', 'url': 'val2', 'description': 2}]
+
+    resp = app.get('/jsondatastore/foobar/search/',
+                   params={'text': 'val1', 'url': 'val'})
+    assert sorted([d['url'] for d in resp.json['data']]) == ['val2', 'val3']
+
+    resp = app.get('/jsondatastore/foobar/search/?name_id=name1',
+                   params={'url': 'Oö', 'url_field': 'me'})
+    assert [d['url'] for d in resp.json['data']] == [1]
+
+    resp = app.get('/jsondatastore/foobar/search/',
+                   params={'key3': 'another value'})
+    assert [d['url'] for d in resp.json['data']] == []
-- 
2.24.0

