From 82b3920c64a77f00e2b38d8f0e1601cd74e427e4 Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Tue, 18 Jul 2023 13:21:20 +0200 Subject: [PATCH 1/1] Allow assigning woblink authors in catalogue. --- src/catalogue/admin.py | 80 +++++++++++++++++-- .../migrations/0047_author_woblink.py | 18 +++++ src/catalogue/models.py | 2 + .../static/catalogue/woblink_admin.js | 22 +++++ src/catalogue/urls.py | 3 + src/catalogue/views.py | 24 +++++- src/depot/woblink.py | 24 ++++++ .../migrations/0010_alter_book_cover.py | 18 +++++ 8 files changed, 181 insertions(+), 10 deletions(-) create mode 100644 src/catalogue/migrations/0047_author_woblink.py create mode 100644 src/catalogue/static/catalogue/woblink_admin.js create mode 100644 src/depot/woblink.py create mode 100644 src/documents/migrations/0010_alter_book_cover.py diff --git a/src/catalogue/admin.py b/src/catalogue/admin.py index 2759f9a3..77f1078c 100644 --- a/src/catalogue/admin.py +++ b/src/catalogue/admin.py @@ -1,8 +1,11 @@ # This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later. # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. # +import json from django.contrib import admin from django.db.models import Min +from django import forms +from django.urls import reverse from django.utils.html import escape, format_html from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _ @@ -21,7 +24,52 @@ class NotableBookInline(OrderableAdmin, admin.TabularInline): ordering_field_hide_input = True +class WoblinkAuthorWidget(forms.Select): + class Media: + js = ("catalogue/woblink_admin.js",) + + def __init__(self): + self.attrs = {} + self.choices = [] + self.field = None + + def get_url(self): + return reverse('catalogue_woblink_author_autocomplete') + + def build_attrs(self, base_attrs, extra_attrs=None): + attrs = super().build_attrs(base_attrs, extra_attrs=extra_attrs) + attrs.setdefault("class", "") + attrs.update( + { + "data-ajax--cache": "true", + "data-ajax--delay": 250, + "data-ajax--type": "GET", + "data-ajax--url": self.get_url(), + "data-app-label": '', + "data-model-name": '', + "data-field-name": '', + "data-theme": "admin-autocomplete", + "data-allow-clear": json.dumps(not self.is_required), + + "data-placeholder": "", # Chyba że znaleziony? + "lang": "pl", + "class": attrs["class"] + + (" " if attrs["class"] else "") + + "admin-autocomplete admin-woblink", + } + ) + return attrs + +class AuthorForm(forms.ModelForm): + class Meta: + model = models.Author + fields = '__all__' + widgets = { + 'woblink': WoblinkAuthorWidget, + } + class AuthorAdmin(WikidataAdminMixin, TabbedTranslationAdmin): + form = AuthorForm list_display = [ "first_name", "last_name", @@ -31,6 +79,7 @@ class AuthorAdmin(WikidataAdminMixin, TabbedTranslationAdmin): "nationality", "priority", "wikidata_link", + "woblink_link", "slug", ] list_display_links = [ @@ -49,10 +98,20 @@ class AuthorAdmin(WikidataAdminMixin, TabbedTranslationAdmin): ] list_per_page = 10000000 search_fields = ["first_name", "last_name", "wikidata"] - readonly_fields = ["wikidata_link", "description_preview"] + readonly_fields = ["wikidata_link", "description_preview", "woblink_link"] + prepopulated_fields = {"slug": ("first_name", "last_name")} + autocomplete_fields = ["collections", "place_of_birth", "place_of_death"] + inlines = [ + NotableBookInline, + ] fieldsets = [ - (None, {"fields": [("wikidata", "wikidata_link")]}), + (None, { + "fields": [ + ("wikidata", "wikidata_link"), + ("woblink", "woblink_link"), + ] + }), ( _("Identification"), { @@ -92,16 +151,21 @@ class AuthorAdmin(WikidataAdminMixin, TabbedTranslationAdmin): }, ), ] - - prepopulated_fields = {"slug": ("first_name", "last_name")} - autocomplete_fields = ["collections", "place_of_birth", "place_of_death"] - inlines = [ - NotableBookInline, - ] def description_preview(self, obj): return obj.generate_description() + def woblink_link(self, obj): + if obj.woblink: + return format_html( + '{w}', + w=obj.woblink, + slug=obj.slug, + ) + else: + return "" + woblink_link.admin_order_field = "woblink" + admin.site.register(models.Author, AuthorAdmin) diff --git a/src/catalogue/migrations/0047_author_woblink.py b/src/catalogue/migrations/0047_author_woblink.py new file mode 100644 index 00000000..d4b3aa8f --- /dev/null +++ b/src/catalogue/migrations/0047_author_woblink.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.9 on 2023-07-18 11:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("catalogue", "0046_thema"), + ] + + operations = [ + migrations.AddField( + model_name="author", + name="woblink", + field=models.IntegerField(blank=True, null=True), + ), + ] diff --git a/src/catalogue/models.py b/src/catalogue/models.py index 1aa145c8..d2befb90 100644 --- a/src/catalogue/models.py +++ b/src/catalogue/models.py @@ -85,6 +85,8 @@ class Author(WikidataModel): ) collections = models.ManyToManyField("Collection", blank=True, verbose_name=_("collections")) + woblink = models.IntegerField(null=True, blank=True) + class Meta: verbose_name = _('author') verbose_name_plural = _('authors') diff --git a/src/catalogue/static/catalogue/woblink_admin.js b/src/catalogue/static/catalogue/woblink_admin.js new file mode 100644 index 00000000..a5bdfd14 --- /dev/null +++ b/src/catalogue/static/catalogue/woblink_admin.js @@ -0,0 +1,22 @@ +(function($) { + $(function() { + + $(".admin-woblink").on("select2:open", function(e) { + console.log("TRIGGER", e); + let $input = $(".select2-container--open input"); + let fname = $("#id_first_name_pl").val(); + let lname = $("#id_last_name_pl").val(); + console.log('A', fname, lname); + $input.val( + fname + ' ' + lname + ).trigger('input'); + }); + + $(".admin-woblink").on("select2:select", function(e) { + $('.fieldBox.field-woblink_link div').empty().append($('Podgląd')); + + }); + + + }); +})(jQuery); diff --git a/src/catalogue/urls.py b/src/catalogue/urls.py index 2bcba237..ac9cede0 100644 --- a/src/catalogue/urls.py +++ b/src/catalogue/urls.py @@ -28,4 +28,7 @@ urlpatterns = [ path('publish/kind//', views.publish_kind, name='catalogue_publish_kind'), path('publish/epoch//', views.publish_epoch, name='catalogue_publish_epoch'), path('publish/collection//', views.publish_collection, name='catalogue_publish_collection'), + + path('woblink/author/autocomplete', views.woblink_author_autocomplete, + name='catalogue_woblink_author_autocomplete'), ] diff --git a/src/catalogue/views.py b/src/catalogue/views.py index 17d61a41..6eb6e63f 100644 --- a/src/catalogue/views.py +++ b/src/catalogue/views.py @@ -3,7 +3,7 @@ # from django.apps import apps from django.db.models import Prefetch -from django.http import Http404 +from django.http import Http404, JsonResponse from django.urls import reverse from django.utils.formats import localize_input from django.contrib.auth.decorators import login_required @@ -20,7 +20,7 @@ from rest_framework.permissions import IsAdminUser from rest_framework.response import Response from rest_framework.views import APIView from rest_framework import serializers - +from depot.woblink import get_woblink_session @@ -296,3 +296,23 @@ def publish_collection(request, pk): return redirect(reverse( 'admin:catalogue_collection_change', args=[collection.pk] )) + + +@login_required +def woblink_author_autocomplete(request): + session = get_woblink_session() + term = request.GET.get('term') + if not term: + return JsonResponse({}) + response = session.get( + 'https://publisher.woblink.com/author/autocomplete/' + term + ).json() + return JsonResponse({ + "results": [ + { + "id": item['autId'], + "text": item['autFullname'], + } + for item in response + ], + }) diff --git a/src/depot/woblink.py b/src/depot/woblink.py new file mode 100644 index 00000000..ffd6b4d5 --- /dev/null +++ b/src/depot/woblink.py @@ -0,0 +1,24 @@ +import re +from django.conf import settings +import requests + + +def get_woblink_session(*args, **kwargs): + session = requests.Session() + response = session.get('https://publisher.woblink.com/login') + token = re.search( + r'name="_csrf_token" value="([^"]+)"', + response.text + ).group(1) + data = { + '_csrf_token': token, + } + data.update(settings.WOBLINK_CREDENTIALS) + response = session.post( + 'https://publisher.woblink.com/login_check', + data=data, + ) + return session + + + diff --git a/src/documents/migrations/0010_alter_book_cover.py b/src/documents/migrations/0010_alter_book_cover.py new file mode 100644 index 00000000..0b57d354 --- /dev/null +++ b/src/documents/migrations/0010_alter_book_cover.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.9 on 2023-07-18 11:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("documents", "0009_book_cover"), + ] + + operations = [ + migrations.AlterField( + model_name="book", + name="cover", + field=models.FileField(blank=True, upload_to="documents/cover"), + ), + ] -- 2.20.1