diff options
Diffstat (limited to 'ishtar_common')
-rw-r--r-- | ishtar_common/admin.py | 75 | ||||
-rw-r--r-- | ishtar_common/migrations/0217_auto_20211015_1728.py (renamed from ishtar_common/migrations/0217_auto_20211013_1517.py) | 3 | ||||
-rw-r--r-- | ishtar_common/models_rest.py | 54 | ||||
-rw-r--r-- | ishtar_common/rest.py | 8 |
4 files changed, 136 insertions, 4 deletions
diff --git a/ishtar_common/admin.py b/ishtar_common/admin.py index 7444aa9cd..39d7de021 100644 --- a/ishtar_common/admin.py +++ b/ishtar_common/admin.py @@ -21,6 +21,7 @@ import csv import json from io import TextIOWrapper, BytesIO import os +import requests import shutil import tempfile import urllib @@ -1482,7 +1483,8 @@ serialize_importer_action.short_description = SERIALIZE_DESC @admin.register(models.ImporterType, site=admin_site) class ImporterTypeAdmin(ImportJSONActionAdmin): list_display = ("name", "associated_models", "available") - actions = importer_type_actions + [serialize_importer_action, + actions = importer_type_actions + [ + serialize_importer_action, change_value("available", True, _("Make available")), change_value("available", False, _("Make unavailable")), ] @@ -2110,6 +2112,7 @@ class ApiSearchModelAdminForm(forms.ModelForm): class Meta: model = models.ApiUser exclude = [] + content_type = forms.ModelChoiceField( label=_("Content type"), queryset=get_main_content_types_query() ) @@ -2121,3 +2124,73 @@ class ApiSearchModelAdmin(admin.ModelAdmin): admin_site.register(models.ApiSearchModel, ApiSearchModelAdmin) + + +def send_error_message(request, msg, return_url, message_type=messages.ERROR): + messages.add_message( + request, + message_type, + msg, + ) + return HttpResponseRedirect(return_url) + + +def update_types_from_source(modeladmin, request, queryset): + return_url = ( + reverse( + "admin:%s_%s_changelist" + % (modeladmin.model._meta.app_label, modeladmin.model._meta.model_name) + ) + + "?" + + urllib.parse.urlencode(request.GET) + ) + if queryset.count() != 1: + return send_error_message( + request, + str(_("Select only one source.")), + return_url, + message_type=messages.WARNING, + ) + 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) + print(result) + return response + + +class ApiExternalSource(admin.ModelAdmin): + model = models_rest.ApiExternalSource + actions = [update_types_from_source] + list_display = ("name", "url", "key") + + +admin_site.register(models_rest.ApiExternalSource, ApiExternalSource) diff --git a/ishtar_common/migrations/0217_auto_20211013_1517.py b/ishtar_common/migrations/0217_auto_20211015_1728.py index 1429da5ef..47bfa7c6e 100644 --- a/ishtar_common/migrations/0217_auto_20211013_1517.py +++ b/ishtar_common/migrations/0217_auto_20211015_1728.py @@ -1,4 +1,4 @@ -# Generated by Django 2.2.24 on 2021-10-13 15:17 +# Generated by Django 2.2.24 on 2021-10-15 17:28 from django.conf import settings import django.contrib.postgres.fields @@ -197,6 +197,7 @@ class Migration(migrations.Migration): ('distant_label', models.TextField(blank=True, default='', verbose_name='Distant value')), ('local_slug', models.SlugField(allow_unicode=True, max_length=200, verbose_name='Local key')), ('local_label', models.TextField(blank=True, default='', verbose_name='Local value')), + ('do_not_match', models.BooleanField(default=False, verbose_name='Disable match for this search')), ('search_model', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType', verbose_name='Search model')), ('source', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ishtar_common.ApiExternalSource')), ], diff --git a/ishtar_common/models_rest.py b/ishtar_common/models_rest.py index db7d21834..a74df2c8a 100644 --- a/ishtar_common/models_rest.py +++ b/ishtar_common/models_rest.py @@ -47,6 +47,58 @@ class ApiExternalSource(models.Model): verbose_name = _("API - External source") verbose_name_plural = _("API - External sources") + def update_matches(self, content): + result = { + "created": 0, + "updated": 0, + "deleted": 0, + "search_model do not exist": [], + "type do not exist": [], + } + updated = [] + for search_model in content: + app, model_name = search_model.split(".") + try: + ct = ContentType.objects.get(app_label=app, model=model_name) + except ContentType.DoesNotExist: + result["search_model do not exist"].append(search_model) + continue + for ct_type, keys, values in content[search_model]: + tapp, tmodel_name = ct_type.split(".") + try: + ct_type = ContentType.objects.get( + app_label=tapp, model=tmodel_name + ) + except ContentType.DoesNotExist: + result["type do not exist"].append(search_model) + continue + t_model = ct_type.model_class() + for slug, label in values: + m, created = ApiKeyMatch.objects.get_or_create( + source=self, search_model=ct, search_keys=keys, + distant_slug=slug, defaults={"distant_label": label}) + updated = False + if not created and m.distant_label != label: + updated = True + m.distant_label = label + if not m.do_not_match and not m.local_slug: + slug_key = "txt_idx" + if hasattr(t_model, "slug"): + slug_key = "slug" + q = t_model.objects.filter(**{slug_key: m.distant_slug}) + if q.count(): + local_value = q.all()[0] + setattr(m, "local_slug", getattr(local_value, slug_key)) + m.local_value = str(local_value) + updated = True + if updated: + m.save() + if not created: + result["updated"] += 1 + if created: + result["created"] += 1 + return result + class ApiKeyMatch(models.Model): source = models.ForeignKey(ApiExternalSource, on_delete=models.CASCADE) @@ -62,6 +114,8 @@ class ApiKeyMatch(models.Model): allow_unicode=True) local_label = models.TextField(verbose_name=_("Local value"), blank=True, default="") + do_not_match = models.BooleanField( + verbose_name=_("Disable match for this search"), default=False) class Meta: verbose_name = _("API - Key match") diff --git a/ishtar_common/rest.py b/ishtar_common/rest.py index 602bba293..0ae951dd1 100644 --- a/ishtar_common/rest.py +++ b/ishtar_common/rest.py @@ -1,3 +1,5 @@ +import json + from django.conf import settings from django.db.models import Q from django.utils.translation import activate, deactivate @@ -94,9 +96,11 @@ class FacetAPIView(APIView): search_keys.append(str(search_key).lower()) deactivate() values[ct_model].append( - [search_keys, values_ct] + [f"{type.model._meta.app_label}.{type.model._meta.model_name}", + search_keys, values_ct] ) - return Response(values) + #values = json.dumps(values) + return Response(values, content_type="json") def _get_base_search_model_queries(self): """ |