Covers, child books, editor notes in catalogue.
authorRadek Czajka <rczajka@rczajka.pl>
Tue, 15 Oct 2024 12:18:47 +0000 (14:18 +0200)
committerRadek Czajka <rczajka@rczajka.pl>
Tue, 15 Oct 2024 12:18:47 +0000 (14:18 +0200)
src/catalogue/admin.py
src/catalogue/migrations/0054_book_cover.py [new file with mode: 0644]
src/catalogue/migrations/0055_book_parent_book_parent_number_editornote.py [new file with mode: 0644]
src/catalogue/models.py

index 36d464c..399f9fd 100644 (file)
@@ -240,6 +240,26 @@ class CoverLicenseFilter(LicenseFilter):
     license_name_field = 'document_book__dc_cover_image__license_name'
 
 
     license_name_field = 'document_book__dc_cover_image__license_name'
 
 
+class ChildrenFilter(admin.SimpleListFilter):
+    title = 'Status utworu podrzędnego'
+    parameter_name = 'book_children'
+
+    def lookups(self, requesrt, model_admin):
+        return [
+            ('no', 'bez podrzędnych'),
+            ('only', 'tylko podrzędne'),
+        ]
+
+    def queryset(self, request, queryset):
+        v = self.value()
+        if v == 'no':
+            return queryset.filter(parent=None)
+        elif v == 'only':
+            return queryset.exclude(parent=None)
+        else:
+            return queryset
+
+
 def add_title(base_class, suffix):
     class TitledCategoryFilter(base_class):
         def __init__(self, *args, **kwargs):
 def add_title(base_class, suffix):
     class TitledCategoryFilter(base_class):
         def __init__(self, *args, **kwargs):
@@ -308,6 +328,11 @@ class SourcesInline(admin.TabularInline):
     extra = 1
 
 
     extra = 1
 
 
+class SourcesInline(admin.TabularInline):
+    model = models.EditorNote
+    extra = 1
+
+
 class BookAdmin(WikidataAdminMixin, NumericFilterModelAdmin, VersionAdmin):
     inlines = [SourcesInline]
     list_display = [
 class BookAdmin(WikidataAdminMixin, NumericFilterModelAdmin, VersionAdmin):
     inlines = [SourcesInline]
     list_display = [
@@ -325,10 +350,11 @@ class BookAdmin(WikidataAdminMixin, NumericFilterModelAdmin, VersionAdmin):
         "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", "epochs", "genres", "kinds"]
+    autocomplete_fields = ["parent", "authors", "translators", "based_on", "epochs", "genres", "kinds"]
     filter_horizontal = ['collections']
     prepopulated_fields = {"slug": ("title",)}
     list_filter = [
     filter_horizontal = ['collections']
     prepopulated_fields = {"slug": ("title",)}
     list_filter = [
+        ChildrenFilter,
         "language",
         "based_on__language",
         ("pd_year", RangeNumericFilter),
         "language",
         "based_on__language",
         ("pd_year", RangeNumericFilter),
@@ -414,6 +440,7 @@ class BookAdmin(WikidataAdminMixin, NumericFilterModelAdmin, VersionAdmin):
             {
                 "fields": [
                     "title",
             {
                 "fields": [
                     "title",
+                    ("parent", "parent_number"),
                     ("slug", 'documents_book_link'),
                     "authors",
                     "translators",
                     ("slug", 'documents_book_link'),
                     "authors",
                     "translators",
@@ -564,6 +591,16 @@ class GenreAdmin(CategoryAdmin):
         'plural',
         'is_epoch_specific',
         'has_description',
         'plural',
         'is_epoch_specific',
         'has_description',
+        'thema',
+    ]
+    fields = [
+        'wikidata',
+        'name',
+        'plural',
+        'slug',
+        'is_epoch_specific',
+        'thema',
+        'description',
     ]
 
 
     ]
 
 
diff --git a/src/catalogue/migrations/0054_book_cover.py b/src/catalogue/migrations/0054_book_cover.py
new file mode 100644 (file)
index 0000000..a238d37
--- /dev/null
@@ -0,0 +1,18 @@
+# Generated by Django 4.1.9 on 2024-08-29 13:52
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("catalogue", "0053_alter_thema_code"),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name="book",
+            name="cover",
+            field=models.FileField(blank=True, upload_to="catalogue/cover"),
+        ),
+    ]
diff --git a/src/catalogue/migrations/0055_book_parent_book_parent_number_editornote.py b/src/catalogue/migrations/0055_book_parent_book_parent_number_editornote.py
new file mode 100644 (file)
index 0000000..0fa1966
--- /dev/null
@@ -0,0 +1,67 @@
+# Generated by Django 4.1.9 on 2024-10-15 13:53
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ("catalogue", "0054_book_cover"),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name="book",
+            name="parent",
+            field=models.ForeignKey(
+                blank=True,
+                null=True,
+                on_delete=django.db.models.deletion.SET_NULL,
+                to="catalogue.book",
+            ),
+        ),
+        migrations.AddField(
+            model_name="book",
+            name="parent_number",
+            field=models.IntegerField(blank=True, null=True),
+        ),
+        migrations.CreateModel(
+            name="EditorNote",
+            fields=[
+                (
+                    "id",
+                    models.AutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                ("created_at", models.DateTimeField(auto_now_add=True)),
+                ("changed_at", models.DateTimeField(auto_now=True)),
+                ("note", models.TextField(blank=True)),
+                (
+                    "rate",
+                    models.IntegerField(
+                        choices=[(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)], default=3
+                    ),
+                ),
+                (
+                    "book",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE, to="catalogue.book"
+                    ),
+                ),
+                (
+                    "user",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        to=settings.AUTH_USER_MODEL,
+                    ),
+                ),
+            ],
+        ),
+    ]
index be7c37f..d4111cb 100644 (file)
@@ -1,6 +1,7 @@
 from collections import Counter
 from datetime import date, timedelta
 import decimal
 from collections import Counter
 from datetime import date, timedelta
 import decimal
+import io
 import re
 from urllib.request import urlopen
 from django.apps import apps
 import re
 from urllib.request import urlopen
 from django.apps import apps
@@ -11,6 +12,9 @@ from django.urls import reverse
 from django.utils.translation import gettext_lazy as _
 from admin_ordering.models import OrderableModel
 from wikidata.client import Client
 from django.utils.translation import gettext_lazy as _
 from admin_ordering.models import OrderableModel
 from wikidata.client import Client
+from librarian import DCNS
+from librarian.cover import make_cover
+from librarian.dcparser import BookInfo, Person
 from .constants import WIKIDATA
 from .wikidata import WikidataModel
 from .wikimedia import WikiMedia
 from .constants import WIKIDATA
 from .wikidata import WikidataModel
 from .wikimedia import WikiMedia
@@ -260,6 +264,8 @@ class Kind(Category):
 
 class Book(WikidataModel):
     slug = models.SlugField(max_length=255, blank=True, null=True, unique=True)
 
 class Book(WikidataModel):
     slug = models.SlugField(max_length=255, blank=True, null=True, unique=True)
+    parent = models.ForeignKey('self', models.SET_NULL, null=True, blank=True)
+    parent_number = models.IntegerField(null=True, blank=True)
     authors = models.ManyToManyField(Author, blank=True, verbose_name=_("authors"))
     translators = models.ManyToManyField(
         Author,
     authors = models.ManyToManyField(Author, blank=True, verbose_name=_("authors"))
     translators = models.ManyToManyField(
         Author,
@@ -297,6 +303,8 @@ class Book(WikidataModel):
     free_license = models.BooleanField(_('free license'), default=False)
     polona_missing = models.BooleanField(_('missing on Polona'), default=False)
 
     free_license = models.BooleanField(_('free license'), default=False)
     polona_missing = models.BooleanField(_('missing on Polona'), default=False)
 
+    cover = models.FileField(blank=True, upload_to='catalogue/cover')
+
     monthly_views_reader = models.IntegerField(default=0)
     monthly_views_page = models.IntegerField(default=0)
     
     monthly_views_reader = models.IntegerField(default=0)
     monthly_views_page = models.IntegerField(default=0)
     
@@ -327,6 +335,25 @@ class Book(WikidataModel):
             txt = f"{txt}, tłum. {tstr}"
         return txt
 
             txt = f"{txt}, tłum. {tstr}"
         return txt
 
+    def build_cover(self):
+        width, height = 212, 300
+        # TODO: BookInfo shouldn't be required to build a cover.
+        info = BookInfo(rdf_attrs={}, dc_fields={
+            DCNS('creator'): [Person('Mickiewicz', 'Adam')],
+            DCNS('title'): ['Ziutek'],
+            DCNS('date'): ['1900-01-01'],
+            DCNS('publisher'): ['F'],
+            DCNS('language'): ['pol'],
+            DCNS('identifier.url'): ['test'],
+            DCNS('rights'): ['-'],
+        })
+        cover = make_cover(info, width=width, height=height)
+        out = io.BytesIO()
+        ext = cover.ext()
+        cover.save(out)
+        self.cover.save(f'{self.slug}.{ext}', out, save=False)
+        type(self).objects.filter(pk=self.pk).update(cover=self.cover)
+
     def get_absolute_url(self):
         return reverse("catalogue_book", args=[self.slug])
 
     def get_absolute_url(self):
         return reverse("catalogue_book", args=[self.slug])
 
@@ -444,6 +471,18 @@ class Book(WikidataModel):
     chars_out_verse = lambda self: self.content_stats.get('chars_out_verse', '')
     chars_out_verse_with_fn = lambda self: self.content_stats.get('chars_out_verse_with_fn', '')
 
     chars_out_verse = lambda self: self.content_stats.get('chars_out_verse', '')
     chars_out_verse_with_fn = lambda self: self.content_stats.get('chars_out_verse_with_fn', '')
 
+
+class EditorNote(models.Model):
+    book = models.ForeignKey(Book, models.CASCADE)
+    user = models.ForeignKey(settings.AUTH_USER_MODEL, models.CASCADE)
+    created_at = models.DateTimeField(auto_now_add=True)
+    changed_at = models.DateTimeField(auto_now=True)
+    note = models.TextField(blank=True)
+    rate = models.IntegerField(default=3, choices=[
+        (n, n) for n in range(1, 6)
+    ])
+
+
 class CollectionCategory(models.Model):
     name = models.CharField(_("name"), max_length=255)
     parent = models.ForeignKey('self', models.SET_NULL, related_name='children', null=True, blank=True, verbose_name=_("parent"))
 class CollectionCategory(models.Model):
     name = models.CharField(_("name"), max_length=255)
     parent = models.ForeignKey('self', models.SET_NULL, related_name='children', null=True, blank=True, verbose_name=_("parent"))