From 265d73dffcdea6560f38087eac0219777084c181 Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Thu, 15 Jun 2023 14:40:03 +0200 Subject: [PATCH] Nicer references. --- requirements/requirements.txt | 2 +- src/catalogue/models/book.py | 74 +++++++++---------- src/references/admin.py | 5 +- ...emove_reference_first_section_occurence.py | 30 ++++++++ src/references/models.py | 9 ++- src/references/templates/references/map.html | 15 +++- .../templates/references/popup.html | 39 ++++++++-- 7 files changed, 125 insertions(+), 49 deletions(-) create mode 100644 src/references/migrations/0002_remove_reference_first_section_occurence.py diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 86afdfcec..7dcdbb3c4 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -40,7 +40,7 @@ mutagen==1.45.1 sorl-thumbnail==12.8.0 # home-brewed & dependencies -librarian==2.4.12 +librarian==2.5 # celery tasks celery[redis]==5.2.7 diff --git a/src/catalogue/models/book.py b/src/catalogue/models/book.py index bcbefeaa1..3eb6023d0 100644 --- a/src/catalogue/models/book.py +++ b/src/catalogue/models/book.py @@ -20,6 +20,7 @@ from fnpdjango.storage import BofhFileSystemStorage from lxml import html from librarian.cover import WLCover from librarian.html import transform_abstrakt +from librarian.builders import builders from newtagging import managers from catalogue import constants from catalogue import fields @@ -713,45 +714,42 @@ class Book(models.Model): cls.published.send(sender=cls, instance=book) return book - def get_master(self): - master_tags = [ - 'opowiadanie', - 'powiesc', - 'dramat_wierszowany_l', - 'dramat_wierszowany_lp', - 'dramat_wspolczesny', 'liryka_l', 'liryka_lp', - 'wywiad', - ] - from librarian.parser import WLDocument - wld = WLDocument.from_file(self.xml_file.path, parse_dublincore=False) - root = wld.edoc.getroot() - for master in root.iter(): - if master.tag in master_tags: - return master - def update_references(self): - from references.models import Entity, Reference - master = self.get_master() - if master is None: - master = [] - found = set() - for i, sec in enumerate(master): - for ref in sec.findall('.//ref'): - href = ref.attrib.get('href', '') - if not href or href in found: - continue - found.add(href) - entity, created = Entity.objects.get_or_create( - uri=href - ) - ref, created = Reference.objects.get_or_create( - book=self, - entity=entity - ) - ref.first_section = 'sec%d' % (i + 1) - entity.populate() - entity.save() - Reference.objects.filter(book=self).exclude(entity__uri__in=found).delete() + Entity = apps.get_model('references', 'Entity') + doc = self.wldocument2() + doc._compat_assign_section_ids() + doc._compat_assign_ordered_ids() + refs = {} + for ref_elem in doc.references(): + uri = ref_elem.attrib.get('href', '') + if not uri: + continue + if uri in refs: + ref = refs[uri] + else: + entity, entity_created = Entity.objects.get_or_create(uri=uri) + if entity_created: + entity.populate() + entity.save() + ref, ref_created = entity.reference_set.get_or_create(book=self) + refs[uri] = ref + if not ref_created: + ref.occurence_set.all().delete() + sec = ref_elem.get_link() + m = re.match(r'sec(\d+)', sec) + assert m is not None + sec = int(m.group(1)) + snippet = ref_elem.get_snippet() + b = builders['html-snippet']() + for s in snippet: + s.html_build(b) + html = b.output().get_bytes().decode('utf-8') + + ref.occurence_set.create( + section=sec, + html=html + ) + self.reference_set.exclude(entity__uri__in=refs).delete() @property def references(self): diff --git a/src/references/admin.py b/src/references/admin.py index 191d0e689..cba8b88e2 100644 --- a/src/references/admin.py +++ b/src/references/admin.py @@ -2,4 +2,7 @@ from django.contrib import admin from . import models -admin.site.register(models.Entity) +@admin.register(models.Entity) +class EntityAdmin(admin.ModelAdmin): + list_display = ['uri', 'label'] + search_fields = ['uri', 'label'] diff --git a/src/references/migrations/0002_remove_reference_first_section_occurence.py b/src/references/migrations/0002_remove_reference_first_section_occurence.py new file mode 100644 index 000000000..0c1e077eb --- /dev/null +++ b/src/references/migrations/0002_remove_reference_first_section_occurence.py @@ -0,0 +1,30 @@ +# Generated by Django 4.0.8 on 2023-06-15 11:12 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('references', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='reference', + name='first_section', + ), + migrations.CreateModel( + name='Occurence', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('section', models.IntegerField()), + ('html', models.TextField()), + ('reference', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='references.reference')), + ], + options={ + 'ordering': ('section',), + }, + ), + ] diff --git a/src/references/models.py b/src/references/models.py index 9246ee322..d4733ffcf 100644 --- a/src/references/models.py +++ b/src/references/models.py @@ -76,8 +76,15 @@ class Entity(models.Model): class Reference(models.Model): book = models.ForeignKey('catalogue.Book', models.CASCADE) entity = models.ForeignKey(Entity, models.CASCADE) - first_section = models.CharField(max_length=255) class Meta: unique_together = (('book', 'entity'),) + +class Occurence(models.Model): + reference = models.ForeignKey(Reference, models.CASCADE) + section = models.IntegerField() + html = models.TextField() + + class Meta: + ordering = ('section',) diff --git a/src/references/templates/references/map.html b/src/references/templates/references/map.html index 1ea650819..242d92f9a 100644 --- a/src/references/templates/references/map.html +++ b/src/references/templates/references/map.html @@ -23,23 +23,34 @@ display: flex; flex-wrap: wrap; gap: 5px; + max-height: 350px; + overflow-y: scroll; } .l-popup-books img { display: block; } + .l-popup-books .c-search-result-fragment { + padding: 0 0 20px 0; + border-width: 0; + border-radius: 0; + } + .l-popup-book-header { + display: flex; + gap: 16px; + } {% endblock %} {% block global-content %} -
+
{% endblock %} {% block extrabody %}