Code layout change.
[wolnelektury.git] / apps / catalogue / fields.py
diff --git a/apps/catalogue/fields.py b/apps/catalogue/fields.py
deleted file mode 100644 (file)
index 0ff2ca9..0000000
+++ /dev/null
@@ -1,243 +0,0 @@
-# -*- coding: utf-8 -*-
-# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-from django.conf import settings
-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.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.build(self)
-
-    def build_delay(self):
-        """Builds the ebook in a delayed task."""
-        return self.field.builder.delay(self.instance, self.field.attname)
-
-
-class EbookField(models.FileField):
-    """Represents an ebook file field, attachable to a model."""
-    attr_class = EbookFieldFile
-
-    def __init__(self, format_name, *args, **kwargs):
-        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."""
-        return BuildEbook.for_format(self.format_name)
-
-    def contribute_to_class(self, cls, name):
-        super(EbookField, self).contribute_to_class(cls, name)
-
-        def has(model_instance):
-            return bool(getattr(model_instance, self.attname, None))
-        has.__doc__ = None
-        has.__name__ = str("has_%s" % self.attname)
-        has.short_description = self.name
-        has.boolean = True
-        setattr(cls, 'has_%s' % self.attname, has)
-
-
-class BuildEbook(Task):
-    formats = {}
-
-    @classmethod
-    def register(cls, format_name):
-        """A decorator for registering subclasses for particular formats."""
-        def wrapper(builder):
-            cls.formats[format_name] = builder
-            return builder
-        return wrapper
-
-    @classmethod
-    def for_format(cls, format_name):
-        """Returns a celery task suitable for specified format."""
-        return cls.formats.get(format_name, BuildEbookTask)
-
-    @staticmethod
-    def transform(wldoc, fieldfile):
-        """Transforms an librarian.WLDocument into an librarian.OutputFile.
-
-        By default, it just calls relevant wldoc.as_??? method.
-
-        """
-        return getattr(wldoc, "as_%s" % fieldfile.field.format_name)()
-
-    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)
-        if book.pk is not None:
-            type(book).objects.filter(pk=book.pk).update(**{
-                fieldfile.field.attname: fieldfile
-            })
-        if fieldfile.field.format_name in app_settings.FORMAT_ZIPS:
-            remove_zip(app_settings.FORMAT_ZIPS[fieldfile.field.format_name])
-# Don't decorate BuildEbook, because we want to subclass it.
-BuildEbookTask = task(BuildEbook, ignore_result=True)
-
-
-@BuildEbook.register('txt')
-@task(ignore_result=True)
-class BuildTxt(BuildEbook):
-    @staticmethod
-    def transform(wldoc, fieldfile):
-        return wldoc.as_text()
-
-
-@BuildEbook.register('pdf')
-@task(ignore_result=True)
-class BuildPdf(BuildEbook):
-    @staticmethod
-    def transform(wldoc, fieldfile):
-        return wldoc.as_pdf(morefloats=settings.LIBRARIAN_PDF_MOREFLOATS,
-            cover=True)
-
-    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 build(self, fieldfile):
-        from django.core.files.base import ContentFile
-        from fnpdjango.utils.text.slughifi import slughifi
-        from sortify import sortify
-        from librarian import html
-        from catalogue.models import Fragment, Tag
-
-        book = fieldfile.instance
-
-        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
-            })
-
-            # Extract fragments
-            closed_fragments, open_fragments = html.extract_fragments(fieldfile.path)
-            for fragment in closed_fragments.values():
-                try:
-                    theme_names = [s.strip() for s in fragment.themes.split(',')]
-                except AttributeError:
-                    continue
-                themes = []
-                for theme_name in theme_names:
-                    if not theme_name:
-                        continue
-                    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
-
-                text = fragment.to_string()
-                short_text = truncate_html_words(text, 15)
-                if text == short_text:
-                    short_text = ''
-                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.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):
-    """
-        Deletes the old file before saving the new one.
-    """
-
-    def save(self, name, content, *args, **kwargs):
-        leave = kwargs.pop('leave', None)
-        # delete if there's a file already and there's a new one coming
-        if not leave and self and (not hasattr(content, 'path') or
-                                   content.path != self.path):
-            self.delete(save=False)
-        return super(OverwritingFieldFile, self).save(
-                name, content, *args, **kwargs)
-
-
-class OverwritingFileField(models.FileField):
-    attr_class = OverwritingFieldFile