Add audience->woblink series mapping.
authorRadek Czajka <rczajka@rczajka.pl>
Fri, 18 Aug 2023 11:11:04 +0000 (13:11 +0200)
committerRadek Czajka <rczajka@rczajka.pl>
Fri, 18 Aug 2023 11:11:04 +0000 (13:11 +0200)
src/catalogue/admin.py
src/catalogue/migrations/0050_audience_woblink.py [new file with mode: 0644]
src/catalogue/models.py
src/catalogue/static/catalogue/woblink_admin.js
src/catalogue/urls.py
src/catalogue/views.py
src/depot/publishers/woblink.py

index 614450e..43ae866 100644 (file)
@@ -24,9 +24,22 @@ class NotableBookInline(OrderableAdmin, admin.TabularInline):
     ordering_field_hide_input = True
 
 
     ordering_field_hide_input = True
 
 
-class WoblinkAuthorWidget(forms.Select):
+class WoblinkCatalogueWidget(forms.Select):
     class Media:
     class Media:
-        js = ("catalogue/woblink_admin.js",)
+        js = (
+            "admin/js/vendor/jquery/jquery.min.js",
+            "admin/js/vendor/select2/select2.full.min.js",
+            "admin/js/vendor/select2/i18n/pl.js",
+            "catalogue/woblink_admin.js",
+            "admin/js/jquery.init.js",
+            "admin/js/autocomplete.js",
+        )
+        css = {
+            "screen": (
+                "admin/css/vendor/select2/select2.min.css",
+                "admin/css/autocomplete.css",
+            ),
+        }
 
     def __init__(self):
         self.attrs = {}
 
     def __init__(self):
         self.attrs = {}
@@ -34,7 +47,7 @@ class WoblinkAuthorWidget(forms.Select):
         self.field = None
 
     def get_url(self):
         self.field = None
 
     def get_url(self):
-        return reverse('catalogue_woblink_author_autocomplete')
+        return reverse('catalogue_woblink_autocomplete', args=[self.category])
 
     def build_attrs(self, base_attrs, extra_attrs=None):
         attrs = super().build_attrs(base_attrs, extra_attrs=extra_attrs)
 
     def build_attrs(self, base_attrs, extra_attrs=None):
         attrs = super().build_attrs(base_attrs, extra_attrs=extra_attrs)
@@ -60,6 +73,9 @@ class WoblinkAuthorWidget(forms.Select):
         )
         return attrs
 
         )
         return attrs
 
+class WoblinkAuthorWidget(WoblinkCatalogueWidget):
+    category = 'author'
+
 class AuthorForm(forms.ModelForm):
     class Meta:
         model = models.Author
 class AuthorForm(forms.ModelForm):
     class Meta:
         model = models.Author
@@ -287,7 +303,8 @@ class BookAdmin(WikidataAdminMixin, NumericFilterModelAdmin):
         "translators__first_name", "translators__last_name",
         "scans_source", "text_source", "notes", "estimate_source",
     ]
         "translators__first_name", "translators__last_name",
         "scans_source", "text_source", "notes", "estimate_source",
     ]
-    autocomplete_fields = ["authors", "translators", "based_on", "collections", "epochs", "genres", "kinds"]
+    autocomplete_fields = ["authors", "translators", "based_on", "epochs", "genres", "kinds"]
+    filter_horizontal = ['collections']
     prepopulated_fields = {"slug": ("title",)}
     list_filter = [
         "language",
     prepopulated_fields = {"slug": ("title",)}
     list_filter = [
         "language",
@@ -562,8 +579,26 @@ class ThemaAdmin(admin.ModelAdmin):
     prepopulated_fields = {"slug": ["name"]}
 
 
     prepopulated_fields = {"slug": ["name"]}
 
 
+
+class WoblinkSeriesWidget(WoblinkCatalogueWidget):
+    category = 'series'
+
+class AudienceForm(forms.ModelForm):
+    class Meta:
+        model = models.Audience
+        fields = '__all__'
+        widgets = {
+            'woblink': WoblinkSeriesWidget,
+        }
+
 @admin.register(models.Audience)
 @admin.register(models.Audience)
-class ThemaAdmin(admin.ModelAdmin):
-    list_display = ['code', 'name', 'thema']
-    search_fields = ['code', 'name', 'description', 'thema']
+class AudienceAdmin(admin.ModelAdmin):
+    form = AudienceForm
+    list_display = ['code', 'name', 'thema', 'woblink']
+    search_fields = ['code', 'name', 'description', 'thema', 'woblink']
     prepopulated_fields = {"slug": ["name"]}
     prepopulated_fields = {"slug": ["name"]}
+    fields = ['code', 'name', 'slug', 'description', 'thema', ('woblink', 'woblink_id')]
+    readonly_fields = ['woblink_id']
+
+    def woblink_id(self, obj):
+        return obj.woblink or ''
diff --git a/src/catalogue/migrations/0050_audience_woblink.py b/src/catalogue/migrations/0050_audience_woblink.py
new file mode 100644 (file)
index 0000000..51e5512
--- /dev/null
@@ -0,0 +1,18 @@
+# Generated by Django 4.1.9 on 2023-08-18 12:38
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("catalogue", "0049_thema_public_description"),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name="audience",
+            name="woblink",
+            field=models.IntegerField(blank=True, null=True),
+        ),
+    ]
index be63708..38d3167 100644 (file)
@@ -610,6 +610,7 @@ class Audience(models.Model):
         max_length=32, blank=True,
         help_text='OdpowiadajÄ…cy kwalifikator Thema.'
     )
         max_length=32, blank=True,
         help_text='OdpowiadajÄ…cy kwalifikator Thema.'
     )
+    woblink = models.IntegerField(null=True, blank=True)
 
     class Meta:
         ordering = ('code',)
 
     class Meta:
         ordering = ('code',)
index a5bdfd1..6f1ca90 100644 (file)
@@ -4,11 +4,10 @@
         $(".admin-woblink").on("select2:open", function(e) {
             console.log("TRIGGER", e);
             let $input = $(".select2-container--open input");
         $(".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);
+            let fname = $("#id_first_name_pl").val() || '';
+            let lname = $("#id_last_name_pl").val() || '';
             $input.val(
             $input.val(
-                fname + ' ' + lname
+                (fname + ' ' + lname).trim()
             ).trigger('input');
         });
 
             ).trigger('input');
         });
 
index e0b1a50..6679b38 100644 (file)
@@ -34,6 +34,6 @@ urlpatterns = [
     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('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'),
+    path('woblink/<category>/autocomplete', views.woblink_autocomplete,
+         name='catalogue_woblink_autocomplete'),
 ]
 ]
index 7301580..80e9727 100644 (file)
@@ -383,7 +383,7 @@ def publish_collection(request, pk):
 
 
 @login_required
 
 
 @login_required
-def woblink_author_autocomplete(request):
+def woblink_autocomplete(request, category):
     shop = depot.models.Shop.objects.filter(shop='woblink').first()
     if shop is None:
         return JsonResponse({})
     shop = depot.models.Shop.objects.filter(shop='woblink').first()
     if shop is None:
         return JsonResponse({})
@@ -391,15 +391,12 @@ def woblink_author_autocomplete(request):
     term = request.GET.get('term')
     if not term:
         return JsonResponse({})
     term = request.GET.get('term')
     if not term:
         return JsonResponse({})
-    response = woblink.session.get(
-        'https://publisher.woblink.com/author/autocomplete/' + term
-    ).json()
-    return JsonResponse({
-        "results": [
-            {
-                "id": item['autId'],
-                "text": item['autFullname'],
-            }
-            for item in response
-        ],
-    })
+
+    if category == 'author':
+        results = woblink.search_author_catalogue(term)
+    elif category == 'series':
+        results = woblink.search_series_catalogue(term)
+    else:
+        raise Http404
+
+    return JsonResponse({"results": results})
index 00dca5e..bac0f73 100644 (file)
@@ -8,7 +8,7 @@ from django.utils.html import escape, format_html
 from django.utils.safestring import mark_safe
 from librarian.builders.html import SnippetHtmlBuilder
 from librarian.functions import lang_code_3to2
 from django.utils.safestring import mark_safe
 from librarian.builders.html import SnippetHtmlBuilder
 from librarian.functions import lang_code_3to2
-from catalogue.models import Author, Thema
+from catalogue.models import Audience, Author, Thema
 from .. import models
 from .base import BasePublisher
 from .woblink_constants import WOBLINK_CATEGORIES
 from .. import models
 from .base import BasePublisher
 from .woblink_constants import WOBLINK_CATEGORIES
@@ -129,6 +129,8 @@ class Woblink(BasePublisher):
     GENERATE_DEMO_URL = BASE_URL + 'task/run/generate-%s-demo/%s/%d'
     CHECK_DEMO_URL = BASE_URL + 'task/run/check-%s-demo/%s'
 
     GENERATE_DEMO_URL = BASE_URL + 'task/run/generate-%s-demo/%s/%d'
     CHECK_DEMO_URL = BASE_URL + 'task/run/check-%s-demo/%s'
 
+    SEARCH_CATALOGUE_URL = BASE_URL + '{category}/autocomplete/{term}'
+
     ROLE_AUTHOR = 1
     ROLE_TRANSLATOR = 4
 
     ROLE_AUTHOR = 1
     ROLE_TRANSLATOR = 4
 
@@ -148,6 +150,28 @@ class Woblink(BasePublisher):
             data=data,
         )
 
             data=data,
         )
 
+    def search_catalogue(self, category, term):
+        return self.session.get(
+            self.SEARCH_CATALOGUE_URL.format(category=category, term=term)
+        ).json()
+
+    def search_author_catalogue(self, term):
+        return [
+            {
+                'id': item['autId'],
+                'text': item['autFullname']
+            }
+            for item in self.search_catalogue('author', term)
+        ]
+    def search_series_catalogue(self, term):
+        return [
+            {
+                'id': item['id'],
+                'text': item['name']
+            }
+            for item in self.search_catalogue('series', term)
+        ]
+        
     def get_isbn(self, meta, errors=None):
         if not meta.isbn_epub:
             if errors is not None:
     def get_isbn(self, meta, errors=None):
         if not meta.isbn_epub:
             if errors is not None:
@@ -219,7 +243,8 @@ class Woblink(BasePublisher):
         return category_ids
 
     def get_series(self, meta, errors=None):
         return category_ids
 
     def get_series(self, meta, errors=None):
-        pass
+        return list(Audience.objects.filter(code__in=audiences).exclude(
+            woblink=None).values_list('woblink', flat=True))
 
     def get_abstract(self, wldoc, errors=None, description_add=None):
         description = self.get_description(wldoc, description_add)
 
     def get_abstract(self, wldoc, errors=None, description_add=None):
         description = self.get_description(wldoc, description_add)
@@ -351,6 +376,7 @@ class Woblink(BasePublisher):
             "lang2code": self.get_lang2code(wldoc.meta, errors=errors),
             "genres": self.get_genres(wldoc.meta, errors=errors),
             "price": self.get_price(shop, wldoc, errors=errors),
             "lang2code": self.get_lang2code(wldoc.meta, errors=errors),
             "genres": self.get_genres(wldoc.meta, errors=errors),
             "price": self.get_price(shop, wldoc, errors=errors),
+            "series": self.get_series(wldoc.meta, errors=errors),
         }
 
     def with_form_name(self, data, name):
         }
 
     def with_form_name(self, data, name):
@@ -371,6 +397,14 @@ class Woblink(BasePublisher):
             for (author_type, author_id) in data['authors']
         ]
 
             for (author_type, author_id) in data['authors']
         ]
 
+        series_data = [
+            {
+                'PublicationId': woblink_id,
+                'SeriesId': series_id,
+            }
+            for series_id in data['series']
+        ]
+
         d = {
             'pubTitle': book_data['title'],
             'npwAuthorHasPublications': json.dumps(authors_data),
         d = {
             'pubTitle': book_data['title'],
             'npwAuthorHasPublications': json.dumps(authors_data),
@@ -378,7 +412,7 @@ class Woblink(BasePublisher):
             'pubNote': data['abstract']['rest'],
             'pubCulture': data['lang2code'],
             'npwPublicationHasAwards': '[]',
             'pubNote': data['abstract']['rest'],
             'pubCulture': data['lang2code'],
             'npwPublicationHasAwards': '[]',
-            'npwPublicationHasSeriess': '[]', # TODO
+            'npwPublicationHasSeriess': json.dumps(series_id),
                 # "[{\"Id\":6153,\"PublicationId\":73876,\"SeriesId\":1615,\"Tome\":null}]"
         }
         d = self.with_form_name(d, 'EditPublicationStep1')
                 # "[{\"Id\":6153,\"PublicationId\":73876,\"SeriesId\":1615,\"Tome\":null}]"
         }
         d = self.with_form_name(d, 'EditPublicationStep1')
@@ -402,8 +436,8 @@ class Woblink(BasePublisher):
                 if legacy is None:
                     legacy = WOBLINK_CATEGORIES[p].get('legacy')
             else:
                 if legacy is None:
                     legacy = WOBLINK_CATEGORIES[p].get('legacy')
             else:
-                gd.setdefault(p, {})
-                ds[p]['isMain'] = True
+                gd.setdefault(g, {})
+                gd[g]['isMain'] = True
         gd = [
             {
                 "pubId": woblink_id,
         gd = [
             {
                 "pubId": woblink_id,
@@ -423,7 +457,7 @@ class Woblink(BasePublisher):
     def edit_step3(self, woblink_id, book_data):
         d = {
             'pubBasePrice': book_data['price'],
     def edit_step3(self, woblink_id, book_data):
         d = {
             'pubBasePrice': book_data['price'],
-            'pubPremiereDate': '2023-08-09', #date.today().isoformat(),
+            'pubPremiereDate': date.today().isoformat(),
             'pubIsLicenseIndefinite': '1',
             'pubFileFormat': 'epub+mobi',
             'pubIsAcs': '0',
             'pubIsLicenseIndefinite': '1',
             'pubFileFormat': 'epub+mobi',
             'pubIsAcs': '0',