Fix for unclickable cites in admin.
[wolnelektury.git] / apps / catalogue / fields.py
index 2c4e4d5..0ff2ca9 100644 (file)
@@ -7,22 +7,25 @@ from django.core.files import File
 from django.db import models
 from django.db.models.fields.files import FieldFile
 from catalogue import app_settings
+from catalogue.constants import LANGUAGES_3TO2
 from catalogue.utils import remove_zip, truncate_html_words
-from celery import Task
-from celery.task import task
+from celery.task import Task, task
+from celery.utils.log import get_task_logger
 from waiter.utils import clear_cache
 
+task_logger = get_task_logger(__name__)
+
 
 class EbookFieldFile(FieldFile):
     """Represents contents of an ebook file field."""
 
     def build(self):
         """Build the ebook immediately."""
-        return self.field.builder(self)
+        return self.field.builder.build(self)
 
     def build_delay(self):
         """Builds the ebook in a delayed task."""
-        return self.field.builder.delay(self)
+        return self.field.builder.delay(self.instance, self.field.attname)
 
 
 class EbookField(models.FileField):
@@ -33,6 +36,11 @@ class EbookField(models.FileField):
         super(EbookField, self).__init__(*args, **kwargs)
         self.format_name = format_name
 
+    def deconstruct(self):
+        name, path, args, kwargs = super(EbookField, self).deconstruct()
+        args.insert(0, self.format_name)
+        return name, path, args, kwargs
+
     @property
     def builder(self):
         """Finds a celery task suitable for the format of the field."""
@@ -44,7 +52,7 @@ class EbookField(models.FileField):
         def has(model_instance):
             return bool(getattr(model_instance, self.attname, None))
         has.__doc__ = None
-        has.__name__ = "has_%s" % self.attname
+        has.__name__ = str("has_%s" % self.attname)
         has.short_description = self.name
         has.boolean = True
         setattr(cls, 'has_%s' % self.attname, has)
@@ -75,7 +83,14 @@ class BuildEbook(Task):
         """
         return getattr(wldoc, "as_%s" % fieldfile.field.format_name)()
 
-    def run(self, fieldfile):
+    def run(self, obj, field_name):
+        """Just run `build` on FieldFile, can't pass it directly to Celery."""
+        task_logger.info("%s -> %s" % (obj.slug, field_name))
+        ret = self.build(getattr(obj, field_name))
+        obj.flush_includes()
+        return ret
+
+    def build(self, fieldfile):
         book = fieldfile.instance
         out = self.transform(book.wldocument(), fieldfile)
         fieldfile.save(None, File(open(out.get_filename())), save=False)
@@ -102,48 +117,56 @@ class BuildTxt(BuildEbook):
 class BuildPdf(BuildEbook):
     @staticmethod
     def transform(wldoc, fieldfile):
-        return wldoc.as_pdf(morefloats=settings.LIBRARIAN_PDF_MOREFLOATS)
+        return wldoc.as_pdf(morefloats=settings.LIBRARIAN_PDF_MOREFLOATS,
+            cover=True)
 
-    def run(self, fieldfile):
-        BuildEbook.run(self, fieldfile)
+    def build(self, fieldfile):
+        BuildEbook.build(self, fieldfile)
         clear_cache(fieldfile.instance.slug)
 
 
+@BuildEbook.register('epub')
+@task(ignore_result=True)
+class BuildEpub(BuildEbook):
+    @staticmethod
+    def transform(wldoc, fieldfile):
+        return wldoc.as_epub(cover=True)
+
+
 @BuildEbook.register('html')
 @task(ignore_result=True)
 class BuildHtml(BuildEbook):
-    def run(self, fieldfile):
+    def build(self, fieldfile):
         from django.core.files.base import ContentFile
-        from slughifi import slughifi
+        from fnpdjango.utils.text.slughifi import slughifi
         from sortify import sortify
         from librarian import html
         from catalogue.models import Fragment, Tag
 
         book = fieldfile.instance
 
-        meta_tags = list(book.tags.filter(
-            category__in=('author', 'epoch', 'genre', 'kind')))
-        book_tag = book.book_tag()
-
         html_output = self.transform(
                         book.wldocument(parse_dublincore=False),
                         fieldfile)
+
+        # Delete old fragments, create from scratch if necessary.
+        book.fragments.all().delete()
+
         if html_output:
+            meta_tags = list(book.tags.filter(
+                category__in=('author', 'epoch', 'genre', 'kind')))
+
+            lang = book.language
+            lang = LANGUAGES_3TO2.get(lang, lang)
+            if lang not in [ln[0] for ln in settings.LANGUAGES]:
+                lang = None
+
             fieldfile.save(None, ContentFile(html_output.get_string()),
                     save=False)
             type(book).objects.filter(pk=book.pk).update(**{
                 fieldfile.field.attname: fieldfile
             })
 
-            # get ancestor l-tags for adding to new fragments
-            ancestor_tags = []
-            p = book.parent
-            while p:
-                ancestor_tags.append(p.book_tag())
-                p = p.parent
-
-            # Delete old fragments and create them from scratch
-            book.fragments.all().delete()
             # Extract fragments
             closed_fragments, open_fragments = html.extract_fragments(fieldfile.path)
             for fragment in closed_fragments.values():
@@ -155,14 +178,26 @@ class BuildHtml(BuildEbook):
                 for theme_name in theme_names:
                     if not theme_name:
                         continue
-                    tag, created = Tag.objects.get_or_create(
-                                        slug=slughifi(theme_name),
-                                        category='theme')
-                    if created:
-                        tag.name = theme_name
-                        tag.sort_key = sortify(theme_name.lower())
-                        tag.save()
-                    themes.append(tag)
+                    if lang == settings.LANGUAGE_CODE:
+                        # Allow creating themes if book in default language.
+                        tag, created = Tag.objects.get_or_create(
+                                            slug=slughifi(theme_name),
+                                            category='theme')
+                        if created:
+                            tag.name = theme_name
+                            setattr(tag, "name_%s" % lang, theme_name)
+                            tag.sort_key = sortify(theme_name.lower())
+                            tag.save()
+                        themes.append(tag)
+                    elif lang is not None:
+                        # Don't create unknown themes in non-default languages.
+                        try:
+                            tag = Tag.objects.get(category='theme',
+                                    **{"name_%s" % lang: theme_name})
+                        except Tag.DoesNotExist:
+                            pass
+                        else:
+                            themes.append(tag)
                 if not themes:
                     continue
 
@@ -170,15 +205,24 @@ class BuildHtml(BuildEbook):
                 short_text = truncate_html_words(text, 15)
                 if text == short_text:
                     short_text = ''
-                new_fragment = Fragment.objects.create(anchor=fragment.id, 
+                new_fragment = Fragment.objects.create(anchor=fragment.id,
                         book=book, text=text, short_text=short_text)
 
                 new_fragment.save()
-                new_fragment.tags = set(meta_tags + themes + [book_tag] + ancestor_tags)
-            book.html_built.send(sender=book)
+                new_fragment.tags = set(meta_tags + themes)
+            book.html_built.send(sender=type(self), instance=book)
             return True
         return False
 
+@BuildEbook.register('cover_thumb')
+@task(ignore_result=True)
+class BuildCoverThumb(BuildEbook):
+    @classmethod
+    def transform(cls, wldoc, fieldfile):
+        from librarian.cover import WLCover
+        return WLCover(wldoc.book_info, height=193).output_file()
+
+
 
 class OverwritingFieldFile(FieldFile):
     """
@@ -197,19 +241,3 @@ class OverwritingFieldFile(FieldFile):
 
 class OverwritingFileField(models.FileField):
     attr_class = OverwritingFieldFile
-
-
-try:
-    # check for south
-    from south.modelsinspector import add_introspection_rules
-except ImportError:
-    pass
-else:
-    add_introspection_rules([
-        (
-            [EbookField],
-            [],
-            {'format_name': ('format_name', {})}
-        )
-    ], ["^catalogue\.fields\.EbookField"])
-    add_introspection_rules([], ["^catalogue\.fields\.OverwritingFileField"])