From a7c64b2ae44b54daac2d4bce4dc0c2d675e04504 Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Fri, 18 Aug 2023 13:11:04 +0200 Subject: [PATCH 1/1] Add audience->woblink series mapping. --- src/catalogue/admin.py | 49 ++++++++++++++++--- .../migrations/0050_audience_woblink.py | 18 +++++++ src/catalogue/models.py | 1 + .../static/catalogue/woblink_admin.js | 7 ++- src/catalogue/urls.py | 4 +- src/catalogue/views.py | 23 ++++----- src/depot/publishers/woblink.py | 46 ++++++++++++++--- 7 files changed, 116 insertions(+), 32 deletions(-) create mode 100644 src/catalogue/migrations/0050_audience_woblink.py diff --git a/src/catalogue/admin.py b/src/catalogue/admin.py index 614450eb..43ae8664 100644 --- a/src/catalogue/admin.py +++ b/src/catalogue/admin.py @@ -24,9 +24,22 @@ class NotableBookInline(OrderableAdmin, admin.TabularInline): ordering_field_hide_input = True -class WoblinkAuthorWidget(forms.Select): +class WoblinkCatalogueWidget(forms.Select): 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 = {} @@ -34,7 +47,7 @@ class WoblinkAuthorWidget(forms.Select): 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) @@ -60,6 +73,9 @@ class WoblinkAuthorWidget(forms.Select): ) return attrs +class WoblinkAuthorWidget(WoblinkCatalogueWidget): + category = '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", ] - 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", @@ -562,8 +579,26 @@ class ThemaAdmin(admin.ModelAdmin): 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) -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"]} + 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 index 00000000..51e5512a --- /dev/null +++ b/src/catalogue/migrations/0050_audience_woblink.py @@ -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), + ), + ] diff --git a/src/catalogue/models.py b/src/catalogue/models.py index be637083..38d31678 100644 --- a/src/catalogue/models.py +++ b/src/catalogue/models.py @@ -610,6 +610,7 @@ class Audience(models.Model): max_length=32, blank=True, help_text='Odpowiadający kwalifikator Thema.' ) + woblink = models.IntegerField(null=True, blank=True) class Meta: ordering = ('code',) diff --git a/src/catalogue/static/catalogue/woblink_admin.js b/src/catalogue/static/catalogue/woblink_admin.js index a5bdfd14..6f1ca909 100644 --- a/src/catalogue/static/catalogue/woblink_admin.js +++ b/src/catalogue/static/catalogue/woblink_admin.js @@ -4,11 +4,10 @@ $(".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( - fname + ' ' + lname + (fname + ' ' + lname).trim() ).trigger('input'); }); diff --git a/src/catalogue/urls.py b/src/catalogue/urls.py index e0b1a507..6679b380 100644 --- a/src/catalogue/urls.py +++ b/src/catalogue/urls.py @@ -34,6 +34,6 @@ urlpatterns = [ 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'), + path('woblink//autocomplete', views.woblink_autocomplete, + name='catalogue_woblink_autocomplete'), ] diff --git a/src/catalogue/views.py b/src/catalogue/views.py index 73015802..80e97271 100644 --- a/src/catalogue/views.py +++ b/src/catalogue/views.py @@ -383,7 +383,7 @@ def publish_collection(request, pk): @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({}) @@ -391,15 +391,12 @@ def woblink_author_autocomplete(request): 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}) diff --git a/src/depot/publishers/woblink.py b/src/depot/publishers/woblink.py index 00dca5ec..bac0f73b 100644 --- a/src/depot/publishers/woblink.py +++ b/src/depot/publishers/woblink.py @@ -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 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 @@ -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' + SEARCH_CATALOGUE_URL = BASE_URL + '{category}/autocomplete/{term}' + ROLE_AUTHOR = 1 ROLE_TRANSLATOR = 4 @@ -148,6 +150,28 @@ class Woblink(BasePublisher): 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: @@ -219,7 +243,8 @@ class Woblink(BasePublisher): 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) @@ -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), + "series": self.get_series(wldoc.meta, errors=errors), } def with_form_name(self, data, name): @@ -371,6 +397,14 @@ class Woblink(BasePublisher): 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), @@ -378,7 +412,7 @@ class Woblink(BasePublisher): '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') @@ -402,8 +436,8 @@ class Woblink(BasePublisher): 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, @@ -423,7 +457,7 @@ class Woblink(BasePublisher): 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', -- 2.20.1