From fd28890ac78d5869ac68ec6db7183bc168d03891 Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Tue, 28 May 2024 14:22:44 +0200 Subject: [PATCH] Allow multiple sources. --- src/catalogue/models.py | 16 +++- .../templates/catalogue/book_detail.html | 93 +++++++++++-------- src/sources/document.py | 21 +++-- ..._booksource_options_booksource_ordering.py | 22 +++++ src/sources/models.py | 14 +-- src/sources/urls.py | 2 +- src/sources/views.py | 15 +-- .../templates/wiki/document_details_base.html | 2 +- src/wiki/urls.py | 2 +- src/wiki/views.py | 20 ++-- 10 files changed, 126 insertions(+), 81 deletions(-) create mode 100644 src/sources/migrations/0004_alter_booksource_options_booksource_ordering.py diff --git a/src/catalogue/models.py b/src/catalogue/models.py index f492809f..be7c37f7 100644 --- a/src/catalogue/models.py +++ b/src/catalogue/models.py @@ -384,11 +384,8 @@ class Book(WikidataModel): for work_type in WorkType.objects.all() } - def scans_gallery(self): - bs = self.booksource_set.first() - if bs is None: - return '' - return bs.pk + def scans_galleries(self): + return [bs.pk for bs in self.booksource_set.all()] def is_published(self): return any(b.is_published() for b in self.document_books.all()) @@ -429,6 +426,15 @@ class Book(WikidataModel): self._content_stats = stats return stats + @property + def are_sources_ready(self): + if not self.booksource_set.exists(): + return False + for bs in self.booksource_set.all(): + if not bs.source.has_view_files() or not bs.source.has_ocr_files() or bs.source.modified_at > bs.source.processed_at: + return False + return True + chars = lambda self: self.content_stats.get('chars', '') chars_with_fn = lambda self: self.content_stats.get('chars_with_fn', '') words = lambda self: self.content_stats.get('words', '') diff --git a/src/catalogue/templates/catalogue/book_detail.html b/src/catalogue/templates/catalogue/book_detail.html index 37cbb662..331ba841 100644 --- a/src/catalogue/templates/catalogue/book_detail.html +++ b/src/catalogue/templates/catalogue/book_detail.html @@ -120,48 +120,59 @@ Źródło
- {% for bs in book.booksource_set.all %} - - {{ bs.source }} - - {% if bs.page_start or bs.page_end %} - (strony {{ bs.page_start }}—{{ bs.page_end }}) - {% else %} - - (źródło w całości przypisane do utworu {{ book }}) - - {% endif %} - - {% if not bs.source.has_upload_files %} - -
- Źródło nie ma jeszcze załadowanych skanów. - - Załaduj skany. -
+ + + {% for bs in book.booksource_set.all %} + + + + + + {% empty %} + Brak źródła. + Możesz je dodać. + {% endfor %} + +
+ + {{ bs.source }} + + + {% if bs.page_start or bs.page_end %} + (strony {{ bs.page_start }}—{{ bs.page_end }}) + {% else %} + + (źródło w całości przypisane do utworu {{ book }}) + + {% endif %} + + {% if not bs.source.has_upload_files %} +
+ Źródło nie ma jeszcze załadowanych skanów. + + Załaduj skany. +
+ {% elif not bs.source.has_view_files %} +
+ Trwa generowanie podglądu. +
+ {% elif not bs.source.has_ocr_files %} +
+ Trwa OCR. +
+ {% elif bs.source.modified_at > bs.source.processed_at %} +
+ Zmodyfikowano skany, trwa aktualizacja. +
+ {% endif %} +
- {% elif not bs.source.has_view_files %} -
- Trwa generowanie podglądu. -
- {% elif not bs.source.has_ocr_files %} -
- Trwa OCR. -
- {% elif bs.source.modified_at > bs.source.processed_at %} -
- Zmodyfikowano skany, trwa aktualizacja. -
- {% else %} -
- {% csrf_token %} - -
- {% endif %} - {% empty %} - Brak źródła. - Możesz je dodać. - {% endfor %} +
+ {% csrf_token %} + +
diff --git a/src/sources/document.py b/src/sources/document.py index 876bda9b..7c31110f 100644 --- a/src/sources/document.py +++ b/src/sources/document.py @@ -6,19 +6,20 @@ from . import ocr from django.conf import settings -def build_document_texts(book_source): +def build_document_texts(book): texts = [] for builder in text_builders: root = etree.Element('utwor') # add meta - add_rdf(root, book_source) + add_rdf(root, book) # add master master = etree.SubElement(root, 'powiesc') - for page in book_source.get_ocr_files(): - builder(master, page) - + for book_source in book.booksource_set.all(): + for page in book_source.get_ocr_files(): + builder(master, page) + texts.append(etree.tostring(root, encoding='unicode', pretty_print=True)) return texts @@ -30,9 +31,7 @@ text_builders = [ ] -def add_rdf(root, book_source): - book = book_source.book - +def add_rdf(root, book): # TODO: to librarian rdf = etree.SubElement(root, RDFNS('RDF')) desc = etree.SubElement(rdf, RDFNS('Description'), **{}) @@ -55,7 +54,11 @@ def add_rdf(root, book_source): etree.SubElement(desc, DCNS('language')).text = book.language # 3to2? #description #source_name - etree.SubElement(desc, DCNS('source')).text = book_source.source.name + # TODO: allow multiple source meta entries. + sources = [] + for book_source in book.booksource_set.all(): + sources.append(book_source.source.name) + etree.SubElement(desc, DCNS('source')).text = ';\n '.join(sources) #url etree.SubElement(desc, DCNS('identifier.url')).text = f'https://wolnelektury.pl/katalog/lektura/{book.slug}/' #license? diff --git a/src/sources/migrations/0004_alter_booksource_options_booksource_ordering.py b/src/sources/migrations/0004_alter_booksource_options_booksource_ordering.py new file mode 100644 index 00000000..a47c0d0b --- /dev/null +++ b/src/sources/migrations/0004_alter_booksource_options_booksource_ordering.py @@ -0,0 +1,22 @@ +# Generated by Django 4.1.9 on 2024-05-22 15:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("sources", "0003_source_modified_at_source_processed_at"), + ] + + operations = [ + migrations.AlterModelOptions( + name="booksource", + options={"ordering": ("ordering", "page_start")}, + ), + migrations.AddField( + model_name="booksource", + name="ordering", + field=models.IntegerField(default=1), + ), + ] diff --git a/src/sources/models.py b/src/sources/models.py index efa086a5..dd521da0 100644 --- a/src/sources/models.py +++ b/src/sources/models.py @@ -119,11 +119,12 @@ class Source(models.Model): class BookSource(models.Model): book = models.ForeignKey('catalogue.Book', models.CASCADE) source = models.ForeignKey(Source, models.CASCADE) + ordering = models.IntegerField(default=1) page_start = models.IntegerField(null=True, blank=True) page_end = models.IntegerField(null=True, blank=True) class Meta: - ordering = ('page_start',) + ordering = ('ordering', 'page_start',) def __str__(self): return f'{self.source} -> {self.book}' @@ -151,16 +152,17 @@ class BookSource(models.Model): def get_document(self): return self.book.document_books.first() - - def prepare_document(self, user=None): + + @classmethod + def prepare_document(cls, book, user=None): DBook = apps.get_model('documents', 'Book') - texts = document.build_document_texts(self) + texts = document.build_document_texts(book) - dbook = self.get_document() + dbook = book.document_books.first() if dbook is None: dbook = DBook.create( user, texts[0], - title=self.book.title, + title=book.title, slug=str(uuid.uuid4()), ) else: diff --git a/src/sources/urls.py b/src/sources/urls.py index 49e27634..de52d042 100644 --- a/src/sources/urls.py +++ b/src/sources/urls.py @@ -5,5 +5,5 @@ from . import views urlpatterns = [ path('source//', views.SourceView.as_view(), name='source'), path('upload//', views.SourceUploadView.as_view(), name='source_upload'), - path('prepare//', views.prepare, name='source_book_prepare'), + path('prepare/book//', views.prepare, name='source_book_prepare'), ] diff --git a/src/sources/views.py b/src/sources/views.py index 2faaecea..663ebacf 100644 --- a/src/sources/views.py +++ b/src/sources/views.py @@ -3,6 +3,7 @@ from django.shortcuts import render, get_object_or_404, redirect from django.utils.translation import gettext as _ from django.views.generic import DetailView from fileupload.views import UploadView +import catalogue.models from . import models @@ -39,17 +40,11 @@ class SourceUploadView(UploadView): return response -def prepare(request, bsid): - bs = get_object_or_404(models.BookSource, id=bsid) +def prepare(request, pk): + book = get_object_or_404(catalogue.models.Book, id=pk) if request.POST: - dbook = bs.prepare_document(request.user) + dbook = models.BookSource.prepare_document(book, request.user) return redirect('wiki_editor', dbook.slug, dbook[0].slug) else: - return render( - request, - 'sources/prepare.html', - { - 'book_source': bs, - } - ) + return redirect(book.get_absolute_url()) diff --git a/src/wiki/templates/wiki/document_details_base.html b/src/wiki/templates/wiki/document_details_base.html index a7009c50..1906f018 100644 --- a/src/wiki/templates/wiki/document_details_base.html +++ b/src/wiki/templates/wiki/document_details_base.html @@ -26,7 +26,7 @@ data-chunk-id="{{ chunk.pk }}" style="display:none"> {{ chunk.book.slug }} - {{ chunk.book.catalogue_book.scans_gallery }} + {{ chunk.book.catalogue_book.scans_galleries|join:',' }} {{ chunk.book.gallery }} {% if chunk.gallery_start %}{{ chunk.gallery_start }}{% endif %} {{ revision }} diff --git a/src/wiki/urls.py b/src/wiki/urls.py index bf7f5b8c..9940dc8d 100644 --- a/src/wiki/urls.py +++ b/src/wiki/urls.py @@ -15,7 +15,7 @@ urlpatterns = [ views.editor_readonly, name="wiki_editor_readonly"), path('gallery//', views.gallery, name="wiki_gallery"), - path('scans//', views.scans_list, name="wiki_scans"), + path('scans//', views.scans_list, name="wiki_scans"), path('history//', views.history, name="wiki_history"), path('rev//', views.revision, name="wiki_revision"), path('text//', views.text, name="wiki_text"), diff --git a/src/wiki/views.py b/src/wiki/views.py index e22c0286..47f41f1e 100644 --- a/src/wiki/views.py +++ b/src/wiki/views.py @@ -271,15 +271,21 @@ def gallery(request, directory): @never_cache -def scans_list(request, pk): - bs = get_object_or_404(sources.models.BookSource, pk=pk) +def scans_list(request, pks): + pks = pks.split(',') + bss = [ + get_object_or_404(sources.models.BookSource, pk=pk) + for pk in pks + ] def map_to_url(filename): return quote(("%s/%s" % (settings.MEDIA_URL, filename))) - images = [ - { - "url": map_to_url(f), - } for f in bs.get_view_files() - ] + images = [] + for bs in bss: + images.extend([ + { + "url": map_to_url(f), + } for f in bs.get_view_files() + ]) return JSONResponse(images) -- 2.20.1