Assigning isbn.
authorRadek Czajka <rczajka@rczajka.pl>
Thu, 28 Sep 2023 07:18:58 +0000 (09:18 +0200)
committerRadek Czajka <rczajka@rczajka.pl>
Thu, 28 Sep 2023 07:18:58 +0000 (09:18 +0200)
src/documents/templates/documents/book_detail.html
src/documents/templatetags/documents.py
src/isbn/models.py
src/isbn/product_forms.py
src/isbn/templates/isbn/isbn_status.html [new file with mode: 0644]
src/isbn/templatetags/isbn.py [new file with mode: 0644]
src/isbn/urls.py
src/isbn/views.py

index f534cd6..a286302 100644 (file)
@@ -2,6 +2,7 @@
 {% load book_list i18n %}
 {% load bootstrap4 %}
 {% load depot %}
+{% load isbn %}
 
 
 {% block titleextra %}{{ book.title }}{% endblock %}
               <a href="{% url 'documents_book_mobi' book.slug %}" rel="nofollow">{% trans "MOBI version" %}</a><br/>
             </p>
 
+            {% isbn_status book %}
+
             {% if user.is_authenticated %}
               <!--
                    Angel photos:
index b0a34bc..b694e22 100644 (file)
@@ -37,6 +37,7 @@ def main_tabs(context):
         tabs.append(Tab('upload', _('Upload'), reverse("documents_upload")))
 
     tabs.append(Tab('cover', _('Covers'), reverse("cover_image_list")))
+    tabs.append(Tab('isbn', 'ISBN', reverse("isbn_list")))
 
     return {"tabs": tabs, "active_tab": active}
 
index 43d01bf..d2d6290 100644 (file)
@@ -1,3 +1,4 @@
+from datetime import date
 from django.apps import apps
 from django.db import models
 from lxml import etree
@@ -114,6 +115,36 @@ class Isbn(models.Model):
     def get_code(self, dashes=True):
         return self.pool.get_code(self.suffix, dashes=dashes)
 
+    @classmethod
+    def get_for_book(cls, book, form):
+        isbn = cls.objects.filter(book=book, form=form).first()
+        if isbn is None:
+            return cls.assign(book, form)
+        return isbn
+
+    @classmethod
+    def assign(cls, book, form):
+        pool = IsbnPool.objects.filter(purpose=IsbnPool.PURPOSE_WL).first()
+        suffix = pool.isbn_set.aggregate(s=models.Max('suffix'))['s'] + 1
+        assert suffix <= pool.suffix_to
+        return pool.isbn_set.create(
+            book=book, form=form, suffix=suffix, datestamp=date.today()
+        )
+
+    @classmethod
+    def formats_from_document(cls, document):
+        # This is a document
+        meta = document.wldocument(librarian2=True).meta
+        is_parent = len(meta.parts)
+        formats = []
+        for form, config in FORMS:
+            if config.book and (not is_parent or config.parent):
+                formats.append((
+                    form,
+                    getattr(meta, f'isbn_{form}')
+                ))
+        return formats
+
     @classmethod
     def import_from_documents(cls):
         Book = apps.get_model('documents', 'Book')
index 206ca1d..1d81c10 100644 (file)
@@ -1,10 +1,14 @@
+from collections import namedtuple
+
+FormConfig = namedtuple('FormConfig', ['book', 'parent', 'product_form', 'product_form_detail'])
+
 FORMS = [
-    ('html', ('EC', 'E105')),
-    ('txt', ('EB', 'E112')),
-    ('pdf', ('EB', 'E107')),
-    ('epub', ('ED', 'E101')),
-    ('mobi', ('ED', 'E127')),
-    ('mp3', ('AN', 'A103')),
-    ('paperback', ('BC', '')),
+    ('html', FormConfig(True, False, 'EC', 'E105')),
+    ('txt', FormConfig(True, False, 'EB', 'E112')),
+    ('pdf', FormConfig(True, True, 'EB', 'E107')),
+    ('epub', FormConfig(True, True, 'ED', 'E101')),
+    ('mobi', FormConfig(True, True, 'ED', 'E127')),
+    ('mp3', FormConfig(False, False, 'AN', 'A103')),
+    ('paperback', FormConfig(False, False, 'BC', '')),
 ]
 
diff --git a/src/isbn/templates/isbn/isbn_status.html b/src/isbn/templates/isbn/isbn_status.html
new file mode 100644 (file)
index 0000000..c46204f
--- /dev/null
@@ -0,0 +1,19 @@
+<div class="row mb-4">
+  <div class="col-4">
+    ISBN
+    {% for form, value in formats %}
+      <span class="badge badge-{% if value %}primary{% else %}secondary{% endif %}" title="{{ value }}">{{ form }}</span>
+    {% endfor %}
+  </div>
+  <div class="col-4">
+    {% if can_generate %}
+      <form method="post" action="{% url 'isbn_generate' book.pk %}">
+        {% csrf_token %}
+        <button class="btn btn-primary btn-sm">
+          uzupełnij
+        </button>
+      </form>
+    {% endif %}
+    {{ error }}
+  </div>
+</div>
diff --git a/src/isbn/templatetags/isbn.py b/src/isbn/templatetags/isbn.py
new file mode 100644 (file)
index 0000000..263842e
--- /dev/null
@@ -0,0 +1,36 @@
+from django.template import Library
+from isbn.models import Isbn
+
+
+register = Library()
+
+
+@register.inclusion_tag('isbn/isbn_status.html', takes_context=True)
+def isbn_status(context, book):
+    user = context['request'].user
+    formats = Isbn.formats_from_document(book)
+
+    can_generate = False
+    error = ''
+    for f, v in formats:
+        if not v:
+            can_generate = True
+
+    if can_generate:
+        if not user.has_perm('isbn.add_isbn'):
+            can_generate = False
+
+    if can_generate:
+        try:
+            book.catalogue_book
+        except:
+            can_generate = False
+            error = 'Brak książki w katalogu.'
+
+    return {
+        'book': book,
+        'formats': formats,
+        'can_generate': can_generate,
+        'error': error,
+    }
+
index a27781a..afd0056 100644 (file)
@@ -4,4 +4,5 @@ from . import views
 
 urlpatterns = [
     path('', views.isbn_list, name='isbn_list'),
+    path('genarate/<int:document_id>/', views.generate, name='isbn_generate'),
 ]
index 70c101a..acf76c7 100644 (file)
@@ -1,4 +1,8 @@
-from django.shortcuts import render
+from django.contrib.auth.decorators import permission_required
+from django.shortcuts import render, get_object_or_404, redirect
+from librarian import DCNS, RDFNS
+from lxml import etree
+from documents.models import Book
 from .models import Isbn, IsbnPool
 
 
@@ -7,3 +11,45 @@ def isbn_list(request):
         'pools': IsbnPool.objects.all(),
         'list': Isbn.objects.all(),
     })
+
+
+MIME = {
+    'html': 'text/html',
+    'pdf': 'application/pdf',
+    'txt': 'text/plain',
+    'epub': 'application/epub+zip',
+    'mobi': 'application/x-mobipocket-ebook',
+}
+
+
+@permission_required('isbn.add_isbn')
+def generate(request, document_id):
+    document = get_object_or_404(Book, id=document_id)
+    book = document.catalogue_book
+    chunk = document[0]
+    head = chunk.head
+    orig_xml = head.materialize()
+    tree = etree.fromstring(orig_xml)
+    rdfdesc = tree.find('.//' + RDFNS('Description'))
+
+    for form, value in Isbn.formats_from_document(document):
+        if value: continue
+        isbn = Isbn.get_for_book(book, form)
+
+        etree.SubElement(rdfdesc, DCNS('relation.hasFormat'), id="mobi").text = f"https://wolnelektury.pl/media/book/{form}mobi/{book.slug}.{form}"
+        etree.SubElement(
+            rdfdesc, 'meta', refines=f'#{form}', id=f'{form}-id', property='dcterms:identifier'
+        ).text = 'ISBN-' + isbn.get_code(True)
+        etree.SubElement(rdfdesc, 'meta', refines=f'#{form}-id', property='identifier-type').text = 'ISBN'
+        etree.SubElement(rdfdesc, 'meta', refines=f'#{form}', property='dcterms:format').text = MIME[form]
+
+    xml = etree.tostring(tree, encoding='unicode')
+    chunk.commit(
+        text=xml,
+        author=request.user,
+        parent=head,
+        description='Auto ISBN',
+        publishable=head.publishable
+    )
+
+    return redirect(document.get_absolute_url())