From caaea9c1f7f6702203ee947ca23a43c3ef5732fd Mon Sep 17 00:00:00 2001 From: Étienne Loks Date: Thu, 28 Oct 2021 23:23:26 +0200 Subject: Syndication - search interface --- archaeological_operations/tests.py | 33 ++++++- ishtar_common/admin.py | 106 ++++++++++++--------- ishtar_common/context_processors.py | 2 +- ishtar_common/rest.py | 1 + ishtar_common/static/js/ishtar.js | 4 + .../templates/blocks/DataTables-content.html | 18 +++- .../blocks/DataTables-external-sources.html | 25 +++-- ishtar_common/templates/blocks/DataTables.html | 51 +++++++--- ishtar_common/urls.py | 7 +- ishtar_common/views_item.py | 61 ++++++------ ishtar_common/wizards.py | 20 ++-- 11 files changed, 220 insertions(+), 108 deletions(-) diff --git a/archaeological_operations/tests.py b/archaeological_operations/tests.py index 69d3e7f26..36e786f35 100644 --- a/archaeological_operations/tests.py +++ b/archaeological_operations/tests.py @@ -4753,11 +4753,39 @@ class ApiTest(OperationInitTest, APITestCase): ) msg = str(_(f"{sheet_name} is not a correct sheet name.")) self.assertIn(msg, response) + # TODO: mark with no update - def test_query_transformation(self): + @patch("requests.get") + def test_query_transformation(self, mock_get): # POV: local # change query terms from a source Ishtar to match distant Ishtar - pass + self._mock_request(mock_get) + self.client.login(username=self.username, password=self.password) + source = self._get_source() + + url = "/admin/{}/{}/".format( + "ishtar_common", models_rest.ApiExternalSource.__name__.lower() + ) + params = { + "action": "update_types_from_source", + "_selected_action": [source.pk], + } + self.client.post(url, params, follow=True) + # change a key match + content_type = ContentType.objects.get_for_model(models.Period) + # no republic for local + models_rest.ApiKeyMatch.objects.get( + source=source, associated_type=content_type, + distant_key="republic" + ).delete() + # local have only neolithic period no detail + keys = ("old-neolithic", "middle-neolithic", "recent-neolithic", + "final-neolithic") + models_rest.ApiKeyMatch.objects.filter( + source=source, associated_type=content_type, + distant_key__in=keys).update( + local_slug="neolithic", local_label="Néolithique") + def test_external_source_query(self): # POV: local @@ -4767,5 +4795,6 @@ class ApiTest(OperationInitTest, APITestCase): pass def test_distant_sheet_display(self): + # POV: local # test query limitation pass diff --git a/ishtar_common/admin.py b/ishtar_common/admin.py index b1f32620c..94306f6b6 100644 --- a/ishtar_common/admin.py +++ b/ishtar_common/admin.py @@ -2126,13 +2126,12 @@ class ApiSearchModelAdmin(admin.ModelAdmin): admin_site.register(models.ApiSearchModel, ApiSearchModelAdmin) -def send_error_message(request, msg, return_url, message_type=messages.ERROR): +def send_error_message(request, msg, message_type=messages.ERROR): messages.add_message( request, message_type, msg, ) - return HttpResponseRedirect(return_url) def update_types_from_source(modeladmin, request, queryset): @@ -2145,74 +2144,90 @@ def update_types_from_source(modeladmin, request, queryset): + urllib.parse.urlencode(request.GET) ) if queryset.count() != 1: - return send_error_message( + send_error_message( request, str(_("Select only one source.")), - return_url, message_type=messages.WARNING, ) + return HttpResponseRedirect(return_url) source = queryset.all()[0] - try: - response = requests.get( - source.url, - timeout=20, - headers={"Authorization": f"access_token {source.key}"}, - ) - except requests.exceptions.Timeout: - return send_error_message( - request, - str(_("Timeout: failed to join {}.")).format(source.url), - return_url, - ) - if response.status_code != 200: - return send_error_message( - request, - str( - _( - "Bad response for {}. Response status code {} != 200. Check your key?" - ) - ).format(source.name, response.status_code), - return_url, - ) - try: - content = response.json() - except ValueError: - return send_error_message( - request, - str(_("Response of {} is not a valid JSON message.")).format(source.url), - return_url, - ) - result = source.update_matches(content) - if result.get("created", None): + created, updated, deleted = 0, 0, 0 + missing_models, missing_types = [], [] + for item_type in ("operation",): + curl = source.url + if not curl.endswith("/"): + curl += "/" + curl += f"api/facets/{item_type}/" + try: + response = requests.get( + curl, + timeout=20, + headers={"Authorization": f"Token {source.key}"}, + ) + except requests.exceptions.Timeout: + send_error_message( + request, + str(_("Timeout: failed to join {}.")).format(curl), + ) + continue + if response.status_code != 200: + send_error_message( + request, + str( + _( + "Bad response for {} - {}. Response status code {} != 200. Check your key?" + ) + ).format(source.name, curl, response.status_code), + ) + continue + try: + content = response.json() + except ValueError: + send_error_message( + request, + str(_("Response of {} is not a valid JSON message.")).format(curl), + return_url, + ) + continue + result = source.update_matches(content) + if result.get("created", None): + created += result['created'] + if result.get("updated", None): + updated += result['updated'] + if result.get("search_model do not exist", None): + missing_models += result["search_model do not exist"] + if result.get("type do not exist", None): + missing_types += result["type do not exist"] + if created: messages.add_message( request, messages.INFO, - str(_(f"{result['created']} matches created")), + str(_(f"{created} matches created")), ) - if result.get("updated", None): + if updated: messages.add_message( request, messages.INFO, - str(_(f"{result['updated']} matches updated")), + str(_(f"{updated} matches updated")), ) - if result.get("deleted", None): + if deleted: messages.add_message( request, messages.INFO, str(_(f"{result['deleted']} matches deleted")), ) - if result.get("search_model do not exist", None): - missing_search_models = ", ".join(result["search_model do not exist"]) + if missing_models: + missing_models = ", ".join(missing_models) messages.add_message( request, messages.INFO, str( _( - f"Theses search models have not been found: {missing_search_models}. Not the same Ishtar version?" + f"Theses search models have not been found: {missing_models}. Not the same Ishtar version?" ) ), ) - if result.get("type do not exist", None): + if missing_types: missing_types = ", ".join(result["type do not exist"]) messages.add_message( request, @@ -2239,12 +2254,13 @@ def generate_match_document(modeladmin, request, queryset): + urllib.parse.urlencode(request.GET) ) if queryset.count() != 1: - return send_error_message( + send_error_message( request, str(_("Select only one source.")), return_url, message_type=messages.WARNING, ) + return HttpResponseRedirect(return_url) src_doc = queryset.all()[0].generate_match_document() in_memory = BytesIO() with open(src_doc, "rb") as fle: diff --git a/ishtar_common/context_processors.py b/ishtar_common/context_processors.py index a03f6429b..7e96bddbd 100644 --- a/ishtar_common/context_processors.py +++ b/ishtar_common/context_processors.py @@ -54,7 +54,7 @@ def get_base_context(request): request.session["EXTERNAL_SOURCES"] = {} if q.count(): for source in q.all(): - request.session["EXTERNAL_SOURCES"][f"{source.id}-{source.name}"] = [ + request.session["EXTERNAL_SOURCES"][f"{source.id}||{source.name}"] = [ f"{app_label}-{model_name}" for app_label, model_name in ApiKeyMatch.objects.values_list( "search_model__app_label", "search_model__model" diff --git a/ishtar_common/rest.py b/ishtar_common/rest.py index 0ae951dd1..e2e8ac581 100644 --- a/ishtar_common/rest.py +++ b/ishtar_common/rest.py @@ -42,6 +42,7 @@ class SearchAPIView(APIView): self.model, "get_" + self.model.SLUG, self.model.SLUG, + no_permission_check=True # TODO: own_table_cols=get_table_cols_for_ope() - adapt columns ) search_model = self.search_model_query(request).all()[0] diff --git a/ishtar_common/static/js/ishtar.js b/ishtar_common/static/js/ishtar.js index 0fa058cca..91273b50c 100644 --- a/ishtar_common/static/js/ishtar.js +++ b/ishtar_common/static/js/ishtar.js @@ -1149,6 +1149,10 @@ var dt_multi_enable_disable_submit_button = function(e, dt, type, indexes){ } }; +var dt_update_badge = function(source_id, number){ + $("#source_badge_" + source_id).html(number); +}; + var number_with_commas = function(number) { return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); } diff --git a/ishtar_common/templates/blocks/DataTables-content.html b/ishtar_common/templates/blocks/DataTables-content.html index 814e10c18..9de143cd4 100644 --- a/ishtar_common/templates/blocks/DataTables-content.html +++ b/ishtar_common/templates/blocks/DataTables-content.html @@ -1,5 +1,5 @@ {% load i18n %} -
+
@@ -11,7 +11,7 @@
-
+