fixes #932: bookimport works with parent-child relations in unsorted xml files
[wolnelektury.git] / apps / catalogue / models.py
index ce92614..b1ffdb6 100644 (file)
@@ -44,7 +44,7 @@ class TagSubcategoryManager(models.Manager):
 class Tag(TagBase):
     name = models.CharField(_('name'), max_length=50, db_index=True)
     slug = models.SlugField(_('slug'), max_length=120, db_index=True)
-    sort_key = models.SlugField(_('sort key'), max_length=120, db_index=True)
+    sort_key = models.CharField(_('sort key'), max_length=120, db_index=True)
     category = models.CharField(_('category'), max_length=50, blank=False, null=False,
         db_index=True, choices=TAG_CATEGORIES)
     description = models.TextField(_('description'), blank=True)
@@ -169,7 +169,7 @@ class Book(models.Model):
     title = models.CharField(_('title'), max_length=120)
     slug = models.SlugField(_('slug'), max_length=120, unique=True, db_index=True)
     description = models.TextField(_('description'), blank=True)
-    created_at = models.DateTimeField(_('creation date'), auto_now=True)
+    created_at = models.DateTimeField(_('creation date'), auto_now_add=True)
     _short_html = models.TextField(_('short HTML'), editable=False)
     parent_number = models.IntegerField(_('parent number'), default=0)
     extra_info = JSONField(_('extra information'))
@@ -186,6 +186,7 @@ class Book(models.Model):
     txt_file = models.FileField(_('TXT file'), upload_to=book_upload_path('txt'), blank=True)
     mp3_file = models.FileField(_('MP3 file'), upload_to=book_upload_path('mp3'), blank=True)
     ogg_file = models.FileField(_('OGG file'), upload_to=book_upload_path('ogg'), blank=True)
+    daisy_file = models.FileField(_('DAISY file'), upload_to=book_upload_path('daisy.zip'), blank=True)
 
     parent = models.ForeignKey('self', blank=True, null=True, related_name='children')
 
@@ -244,7 +245,7 @@ class Book(models.Model):
         book_tag, created = Tag.objects.get_or_create(slug=slug, category='book')
         if created:
             book_tag.name = self.title[:50]
-            book_tag.sort_key = slug
+            book_tag.sort_key = self.title.lower()
             book_tag.save()
         return book_tag
 
@@ -273,6 +274,8 @@ class Book(models.Model):
                 formats.append(u'<a href="%s">MP3</a>' % self.mp3_file.url)
             if self.ogg_file:
                 formats.append(u'<a href="%s">OGG</a>' % self.ogg_file.url)
+            if self.daisy_file:
+                formats.append(u'<a href="%s">DAISY</a>' % self.daisy_file.url)
 
             formats = [mark_safe(format) for format in formats]
 
@@ -357,17 +360,19 @@ class Book(models.Model):
         try:
             epub.transform(BookImportDocProvider(self), self.slug, epub_file)
             self.epub_file.save('%s.epub' % self.slug, ContentFile(epub_file.getvalue()), save=False)
+            self.save()
             FileRecord(slug=self.slug, type='epub', sha1=sha1(epub_file.getvalue()).hexdigest()).save()
         except NoDublinCore:
             pass
 
-        if remove_descendants:
-            book_descendants = list(self.children.all())
-            while len(book_descendants) > 0:
-                child_book = book_descendants.pop(0)
-                if child_book.has_epub_file():
-                    child_book.epub_file.delete()
-                book_descendants += list(child_book.children.all())
+        book_descendants = list(self.children.all())
+        while len(book_descendants) > 0:
+            child_book = book_descendants.pop(0)
+            if remove_descendants and child_book.has_epub_file():
+                child_book.epub_file.delete()
+            # save anyway, to refresh short_html
+            child_book.save()
+            book_descendants += list(child_book.children.all())
 
 
     @classmethod
@@ -390,6 +395,17 @@ class Book(models.Model):
         from markupstring import MarkupString
         from django.core.files.storage import default_storage
 
+        # check for parts before we do anything
+        children = []
+        if hasattr(book_info, 'parts'):
+            for part_url in book_info.parts:
+                base, slug = part_url.rsplit('/', 1)
+                try:
+                    children.append(Book.objects.get(slug=slug))
+                except Book.DoesNotExist, e:
+                    raise Book.DoesNotExist(_('Book with slug = "%s" does not exist.') % slug)
+
+
         # Read book metadata
         book_base, book_slug = book_info.url.rsplit('/', 1)
         book, created = Book.objects.get_or_create(slug=book_slug)
@@ -422,7 +438,7 @@ class Book(models.Model):
                 tag, created = Tag.objects.get_or_create(slug=slughifi(tag_name), category=category)
                 if created:
                     tag.name = tag_name
-                    tag.sort_key = slughifi(tag_sort_key)
+                    tag.sort_key = tag_sort_key.lower()
                     tag.save()
                 book_tags.append(tag)
 
@@ -430,24 +446,28 @@ class Book(models.Model):
 
         book_tag = book.book_tag()
 
-        if hasattr(book_info, 'parts'):
-            for n, part_url in enumerate(book_info.parts):
-                base, slug = part_url.rsplit('/', 1)
-                try:
-                    child_book = Book.objects.get(slug=slug)
-                    child_book.parent = book
-                    child_book.parent_number = n
-                    child_book.save()
-                except Book.DoesNotExist, e:
-                    raise Book.DoesNotExist(_('Book with slug = "%s" does not exist.') % slug)
+        for n, child_book in enumerate(children):
+            child_book.parent = book
+            child_book.parent_number = n
+            child_book.save()
 
         # Save XML and HTML files
         book.xml_file.save('%s.xml' % book.slug, raw_file, save=False)
 
+        # delete old fragments when overwriting
+        book.fragments.all().delete()
+
         html_file = NamedTemporaryFile()
         if html.transform(book.xml_file.path, html_file, parse_dublincore=False):
             book.html_file.save('%s.html' % book.slug, File(html_file), save=False)
 
+            # 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
+
             # Extract fragments
             closed_fragments, open_fragments = html.extract_fragments(book.html_file.path)
             for fragment in closed_fragments.values():
@@ -462,7 +482,7 @@ class Book(models.Model):
                     tag, created = Tag.objects.get_or_create(slug=slughifi(theme_name), category='theme')
                     if created:
                         tag.name = theme_name
-                        tag.sort_key = slughifi(theme_name)
+                        tag.sort_key = theme_name.lower()
                         tag.save()
                     themes.append(tag)
                 if not themes:
@@ -476,9 +496,10 @@ class Book(models.Model):
                     defaults={'text': text, 'short_text': short_text})
 
                 new_fragment.save()
-                new_fragment.tags = set(book_tags + themes + [book_tag])
+                new_fragment.tags = set(book_tags + themes + [book_tag] + ancestor_tags)
 
-        book.build_epub(remove_descendants=False)
+        if not book.parent:
+            book.build_epub(remove_descendants=False)
 
         book_descendants = list(book.children.all())
         # add l-tag to descendants and their fragments
@@ -494,8 +515,8 @@ class Book(models.Model):
             book_descendants += list(child_book.children.all())
 
         # refresh cache
-        book.tag_counter
-        book.theme_counter
+        book.reset_tag_counter()
+        book.reset_theme_counter()
 
         book.save()
         return book