From: Radek Czajka Date: Tue, 15 Oct 2024 12:18:47 +0000 (+0200) Subject: Covers, child books, editor notes in catalogue. X-Git-Url: https://git.mdrn.pl/redakcja.git/commitdiff_plain/c46844cb5a794566d15437b0c4a809e9230baecf?ds=sidebyside Covers, child books, editor notes in catalogue. --- diff --git a/src/catalogue/admin.py b/src/catalogue/admin.py index 36d464c8..399f9fdd 100644 --- a/src/catalogue/admin.py +++ b/src/catalogue/admin.py @@ -240,6 +240,26 @@ class CoverLicenseFilter(LicenseFilter): 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): @@ -308,6 +328,11 @@ class SourcesInline(admin.TabularInline): extra = 1 +class SourcesInline(admin.TabularInline): + model = models.EditorNote + extra = 1 + + 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", ] - 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 = [ + ChildrenFilter, "language", "based_on__language", ("pd_year", RangeNumericFilter), @@ -414,6 +440,7 @@ class BookAdmin(WikidataAdminMixin, NumericFilterModelAdmin, VersionAdmin): { "fields": [ "title", + ("parent", "parent_number"), ("slug", 'documents_book_link'), "authors", "translators", @@ -564,6 +591,16 @@ class GenreAdmin(CategoryAdmin): '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 index 00000000..a238d370 --- /dev/null +++ b/src/catalogue/migrations/0054_book_cover.py @@ -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 index 00000000..0fa19663 --- /dev/null +++ b/src/catalogue/migrations/0055_book_parent_book_parent_number_editornote.py @@ -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, + ), + ), + ], + ), + ] diff --git a/src/catalogue/models.py b/src/catalogue/models.py index be7c37f7..d4111cb2 100644 --- a/src/catalogue/models.py +++ b/src/catalogue/models.py @@ -1,6 +1,7 @@ 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 @@ -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 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 @@ -260,6 +264,8 @@ class Kind(Category): 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, @@ -297,6 +303,8 @@ class Book(WikidataModel): 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) @@ -327,6 +335,25 @@ class Book(WikidataModel): 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]) @@ -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', '') + +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"))