X-Git-Url: https://git.mdrn.pl/wolnelektury.git/blobdiff_plain/265d73dffcdea6560f38087eac0219777084c181..4faaa8414a1038804df9999a094c8dfe4c5f513f:/src/catalogue/models/book.py diff --git a/src/catalogue/models/book.py b/src/catalogue/models/book.py index 3eb6023d0..7d3666277 100644 --- a/src/catalogue/models/book.py +++ b/src/catalogue/models/book.py @@ -1,5 +1,5 @@ -# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later. -# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. +# This file is part of Wolne Lektury, licensed under GNU Affero GPLv3 or later. +# Copyright © Fundacja Wolne Lektury. See NOTICE for more information. # from collections import OrderedDict import json @@ -19,7 +19,7 @@ from django.utils.translation import gettext_lazy as _, get_language from fnpdjango.storage import BofhFileSystemStorage from lxml import html from librarian.cover import WLCover -from librarian.html import transform_abstrakt +from librarian.builders.html import AbstraktHtmlBuilder from librarian.builders import builders from newtagging import managers from catalogue import constants @@ -35,29 +35,29 @@ bofh_storage = BofhFileSystemStorage() class Book(models.Model): """Represents a book imported from WL-XML.""" - title = models.CharField(_('title'), max_length=32767) - sort_key = models.CharField(_('sort key'), max_length=120, db_index=True, editable=False) + title = models.CharField('tytuł', max_length=32767) + sort_key = models.CharField('klucz sortowania', max_length=120, db_index=True, editable=False) sort_key_author = models.CharField( - _('sort key by author'), max_length=120, db_index=True, editable=False, default='') - slug = models.SlugField(_('slug'), max_length=120, db_index=True, unique=True) - common_slug = models.SlugField(_('slug'), max_length=120, db_index=True) - language = models.CharField(_('language code'), max_length=3, db_index=True, default=app_settings.DEFAULT_LANGUAGE) - description = models.TextField(_('description'), blank=True) - abstract = models.TextField(_('abstract'), blank=True) - toc = models.TextField(_('toc'), blank=True) - created_at = models.DateTimeField(_('creation date'), auto_now_add=True, db_index=True) - changed_at = models.DateTimeField(_('change date'), auto_now=True, db_index=True) - parent_number = models.IntegerField(_('parent number'), default=0) - extra_info = models.TextField(_('extra information'), default='{}') + 'klucz sortowania wg autora', max_length=120, db_index=True, editable=False, default='') + slug = models.SlugField('slug', max_length=120, db_index=True, unique=True) + common_slug = models.SlugField('wspólny slug', max_length=120, db_index=True) + language = models.CharField('kod języka', max_length=3, db_index=True, default=app_settings.DEFAULT_LANGUAGE) + description = models.TextField('opis', blank=True) + abstract = models.TextField('abstrakt', blank=True) + toc = models.TextField('spis treści', blank=True) + created_at = models.DateTimeField('data utworzenia', auto_now_add=True, db_index=True) + changed_at = models.DateTimeField('data motyfikacji', auto_now=True, db_index=True) + parent_number = models.IntegerField('numer w ramach rodzica', default=0) + extra_info = models.TextField('dodatkowe informacje', default='{}') gazeta_link = models.CharField(blank=True, max_length=240) wiki_link = models.CharField(blank=True, max_length=240) - print_on_demand = models.BooleanField(_('print on demand'), default=False) - recommended = models.BooleanField(_('recommended'), default=False) - audio_length = models.CharField(_('audio length'), blank=True, max_length=8) - preview = models.BooleanField(_('preview'), default=False) - preview_until = models.DateField(_('preview until'), blank=True, null=True) + print_on_demand = models.BooleanField('druk na żądanie', default=False) + recommended = models.BooleanField('polecane', default=False) + audio_length = models.CharField('długość audio', blank=True, max_length=8) + preview = models.BooleanField('prapremiera', default=False) + preview_until = models.DateField('prapremiera do', blank=True, null=True) preview_key = models.CharField(max_length=32, blank=True, null=True) - findable = models.BooleanField(_('findable'), default=True, db_index=True) + findable = models.BooleanField('wyszukiwalna', default=True, db_index=True) # files generated during publication xml_file = fields.XmlField(storage=bofh_storage, with_etag=False) @@ -68,15 +68,15 @@ class Book(models.Model): mobi_file = fields.MobiField(storage=bofh_storage) pdf_file = fields.PdfField(storage=bofh_storage) - cover = fields.CoverField(_('cover'), storage=bofh_storage) + cover = fields.CoverField('okładka', storage=bofh_storage) # Cleaner version of cover for thumbs - cover_clean = fields.CoverCleanField(_('clean cover')) - cover_thumb = fields.CoverThumbField(_('cover thumbnail')) + cover_clean = fields.CoverCleanField('czysta okładka') + cover_thumb = fields.CoverThumbField('miniatura okładki') cover_api_thumb = fields.CoverApiThumbField( - _('cover thumbnail for mobile app')) - simple_cover = fields.SimpleCoverField(_('cover for mobile app')) + 'mniaturka okładki dla aplikacji') + simple_cover = fields.SimpleCoverField('okładka dla aplikacji') cover_ebookpoint = fields.CoverEbookpointField( - _('cover for Ebookpoint')) + 'okładka dla Ebookpoint') ebook_formats = constants.EBOOK_FORMATS formats = ebook_formats + ['html', 'xml'] @@ -91,6 +91,7 @@ class Book(models.Model): tagged = managers.ModelTaggedItemManager(Tag) tags = managers.TagDescriptor(Tag) tag_relations = GenericRelation(Tag.intermediary_table_model) + translators = models.ManyToManyField(Tag, blank=True) html_built = django.dispatch.Signal() published = django.dispatch.Signal() @@ -104,8 +105,8 @@ class Book(models.Model): class Meta: ordering = ('sort_key_author', 'sort_key') - verbose_name = _('book') - verbose_name_plural = _('books') + verbose_name = 'książka' + verbose_name_plural = 'książki' app_label = 'catalogue' def __str__(self): @@ -154,12 +155,6 @@ class Book(models.Model): def genre_unicode(self): return self.tag_unicode('genre') - def translators(self): - translators = self.get_extra_info_json().get('translators') or [] - return [ - '\xa0'.join(reversed(translator.split(', ', 1))) for translator in translators - ] - def translator(self): translators = self.get_extra_info_json().get('translators') if not translators: @@ -331,6 +326,12 @@ class Book(models.Model): total += app_settings.GET_MP3_LENGTH(media.file.path) return int(total) + def get_time(self): + try: + return round(self.xml_file.size / 1000 * 40) + except ValueError: + return 0 + def has_media(self, type_): if type_ in Book.formats: return bool(getattr(self, "%s_file" % type_)) @@ -397,7 +398,7 @@ class Book(models.Model): def has_description(self): return len(self.description) > 0 - has_description.short_description = _('description') + has_description.short_description = 'opis' has_description.boolean = True def has_mp3_file(self): @@ -416,7 +417,7 @@ class Book(models.Model): has_daisy_file.boolean = True def has_sync_file(self): - return self.has_media("sync") + return settings.FEATURE_SYNCHRO and self.has_media("sync") def get_sync(self): with self.get_media('sync').first().file.open('r') as f: @@ -556,11 +557,8 @@ class Book(models.Model): urlretrieve('%s/%s' % (remote_gallery_url, ilustr_src), ilustr_path) def load_abstract(self): - abstract = self.wldocument(parse_dublincore=False).edoc.getroot().find('.//abstrakt') - if abstract is not None: - self.abstract = transform_abstrakt(abstract) - else: - self.abstract = '' + self.abstract = AbstraktHtmlBuilder().build( + self.wldocument2()).get_bytes().decode('utf-8') def load_toc(self): self.toc = '' @@ -594,7 +592,7 @@ class Book(models.Model): @classmethod def from_text_and_meta(cls, raw_file, book_info, overwrite=False, dont_build=None, search_index=True, - remote_gallery_url=None, days=0, findable=True): + remote_gallery_url=None, days=0, findable=True, logo=None, logo_mono=None, logo_alt=None): from catalogue import tasks if dont_build is None: @@ -608,7 +606,7 @@ class Book(models.Model): try: children.append(Book.objects.get(slug=part_url.slug)) except Book.DoesNotExist: - raise Book.DoesNotExist(_('Book "%s" does not exist.') % part_url.slug) + raise Book.DoesNotExist('Książka "%s" nie istnieje.' % part_url.slug) # Read book metadata book_slug = book_info.url.slug @@ -624,7 +622,7 @@ class Book(models.Model): book.preview_until = date.today() + timedelta(days) else: if not overwrite: - raise Book.AlreadyExists(_('Book %s already exists') % book_slug) + raise Book.AlreadyExists('Książka %s już istnieje' % book_slug) # Save shelves for this book book_shelves = list(book.tags.filter(category='set')) old_cover = book.cover_info() @@ -641,21 +639,26 @@ class Book(models.Model): book.common_slug = book_info.variant_of.slug else: book.common_slug = book.slug - book.extra_info = json.dumps(book_info.to_dict()) + extra = book_info.to_dict() + if logo: + extra['logo'] = logo + if logo_mono: + extra['logo_mono'] = logo_mono + if logo_alt: + extra['logo_alt'] = logo_alt + book.extra_info = json.dumps(extra) book.load_abstract() book.load_toc() book.save() meta_tags = Tag.tags_from_info(book_info) - for tag in meta_tags: - if not tag.for_books: - tag.for_books = True - tag.save() - - book.tags = set(meta_tags + book_shelves) + just_tags = [t for (t, rel) in meta_tags if not rel] + book.tags = set(just_tags + book_shelves) book.save() # update sort_key_author + book.translators.set([t for (t, rel) in meta_tags if rel == 'translator']) + cover_changed = old_cover != book.cover_info() obsolete_children = set(b for b in book.children.all() if b not in children) @@ -714,13 +717,14 @@ class Book(models.Model): cls.published.send(sender=cls, instance=book) return book + # TODO TEST def update_references(self): Entity = apps.get_model('references', 'Entity') doc = self.wldocument2() - doc._compat_assign_section_ids() - doc._compat_assign_ordered_ids() + doc.assign_ids() + refs = {} - for ref_elem in doc.references(): + for i, ref_elem in enumerate(doc.references()): uri = ref_elem.attrib.get('href', '') if not uri: continue @@ -729,16 +733,18 @@ class Book(models.Model): else: entity, entity_created = Entity.objects.get_or_create(uri=uri) if entity_created: - entity.populate() - entity.save() + try: + entity.populate() + except: + pass + else: + 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)) + anchor = ref_elem.get_link() + snippet = ref_elem.get_snippet() b = builders['html-snippet']() for s in snippet: @@ -746,7 +752,8 @@ class Book(models.Model): html = b.output().get_bytes().decode('utf-8') ref.occurence_set.create( - section=sec, + section=i, + anchor=anchor, html=html ) self.reference_set.exclude(entity__uri__in=refs).delete() @@ -939,7 +946,7 @@ class Book(models.Model): def stage_note(self): stage = self.get_extra_info_json().get('stage') if stage and stage < '0.4': - return (_('This work needs modernisation'), + return (_('Ten utwór wymaga uwspółcześnienia'), reverse('infopage', args=['wymagajace-uwspolczesnienia'])) else: return None, None