Allow assigning woblink authors in catalogue.
authorRadek Czajka <rczajka@rczajka.pl>
Tue, 18 Jul 2023 11:21:20 +0000 (13:21 +0200)
committerRadek Czajka <rczajka@rczajka.pl>
Tue, 18 Jul 2023 11:21:20 +0000 (13:21 +0200)
src/catalogue/admin.py
src/catalogue/migrations/0047_author_woblink.py [new file with mode: 0644]
src/catalogue/models.py
src/catalogue/static/catalogue/woblink_admin.js [new file with mode: 0644]
src/catalogue/urls.py
src/catalogue/views.py
src/depot/woblink.py [new file with mode: 0644]
src/documents/migrations/0010_alter_book_cover.py [new file with mode: 0644]

index 2759f9a..77f1078 100644 (file)
@@ -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(
+                '<a href="https://woblink.com/autor/{slug}-{w}" target="_blank">{w}</a>',
+                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 (file)
index 0000000..d4b3aa8
--- /dev/null
@@ -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),
+        ),
+    ]
index 1aa145c..d2befb9 100644 (file)
@@ -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 (file)
index 0000000..a5bdfd1
--- /dev/null
@@ -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($('<a href="https://woblink.com/autor/-' + e.params.data.id + '" target="_blank">Podgląd</a>'));
+
+        });
+
+
+    });
+})(jQuery);
index 2bcba23..ac9cede 100644 (file)
@@ -28,4 +28,7 @@ urlpatterns = [
     path('publish/kind/<int:pk>/', views.publish_kind, name='catalogue_publish_kind'),
     path('publish/epoch/<int:pk>/', views.publish_epoch, name='catalogue_publish_epoch'),
     path('publish/collection/<int:pk>/', views.publish_collection, name='catalogue_publish_collection'),
+
+    path('woblink/author/autocomplete', views.woblink_author_autocomplete,
+         name='catalogue_woblink_author_autocomplete'),
 ]
index 17d61a4..6eb6e63 100644 (file)
@@ -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 (file)
index 0000000..ffd6b4d
--- /dev/null
@@ -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 (file)
index 0000000..0b57d35
--- /dev/null
@@ -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"),
+        ),
+    ]