book.tags = set(meta_tags + book_shelves)
- book_tag = book.book_tag()
-
+ obsolete_children = set(b for b in book.children.all() if b not in children)
for n, child_book in enumerate(children):
child_book.parent = book
child_book.parent_number = n
child_book.save()
+ # Disown unfaithful children and let them cope on their own.
+ for child in obsolete_children:
+ child.parent = None
+ child.parent_number = 0
+ child.save()
+ tasks.fix_tree_tags.delay(child)
# Save XML and HTML files
book.xml_file.save('%s.xml' % book.slug, raw_file, save=False)
+ book.build_cover(book_info)
# delete old fragments when overwriting
book.fragments.all().delete()
if book.build_html():
+ # No direct saves behind this point.
if not settings.NO_BUILD_TXT and build_txt:
book.build_txt()
- book.build_cover(book_info)
-
if not settings.NO_BUILD_EPUB and build_epub:
book.build_epub()
book.search_index(index_tags=search_index_tags, reuse_index=search_index_reuse)
#index_book.delay(book.id, book_info)
- book_descendants = list(book.children.all())
- descendants_tags = set()
- # add l-tag to descendants and their fragments
- while len(book_descendants) > 0:
- child_book = book_descendants.pop(0)
- descendants_tags.update(child_book.tags)
- child_book.tags = list(child_book.tags) + [book_tag]
- child_book.save()
- for fragment in child_book.fragments.all().iterator():
- fragment.tags = set(list(fragment.tags) + [book_tag])
- book_descendants += list(child_book.children.all())
-
- for tag in descendants_tags:
- tasks.touch_tag(tag)
+ tasks.fix_tree_tags.delay(book)
+ cls.published.send(sender=book)
+ return book
- book.save()
+ def fix_tree_tags(self):
+ """Fixes the l-tags on the book's subtree.
- # refresh cache
- book.reset_tag_counter()
- book.reset_theme_counter()
+ Makes sure that:
+ * the book has its parents book-tags,
+ * its fragments have the book's and its parents book-tags,
+ * runs those for every child book too,
+ * touches all relevant tags,
+ * resets tag and theme counter on the book and its ancestry.
+ """
+ def fix_subtree(book, parent_tags):
+ affected_tags = set(book.tags)
+ book.tags = list(book.tags.exclude(category='book')) + parent_tags
+ sub_parent_tags = parent_tags + [book.book_tag()]
+ for frag in book.fragments.all():
+ affected_tags.update(frag.tags)
+ frag.tags = list(frag.tags.exclude(category='book')) + sub_parent_tags
+ for child in book.children.all():
+ affected_tags.update(fix_subtree(child, sub_parent_tags))
+ return affected_tags
+
+ parent_tags = []
+ parent = self.parent
+ while parent is not None:
+ parent_tags.append(parent.book_tag())
+ parent = parent.parent
+
+ affected_tags = fix_subtree(self, parent_tags)
+ for tag in affected_tags:
+ tasks.touch_tag(tag)
- cls.published.send(sender=book)
- return book
+ book = self
+ while book is not None:
+ book.reset_tag_counter()
+ book.reset_theme_counter()
+ book = book.parent
def related_info(self):
"""Keeps info about related objects (tags, media) in cache field."""
'wrong related theme list')
+class TreeImportTest(WLTestCase):
+ def setUp(self):
+ WLTestCase.setUp(self)
+ self.child_info = BookInfoStub(
+ genre='X-Genre',
+ epoch='X-Epoch',
+ kind='X-Kind',
+ author=PersonStub(("Joe",), "Doe"),
+ **info_args("Child")
+ )
+ self.CHILD_TEXT = """<utwor>
+ <opowiadanie>
+ <akap><begin id="m01" /><motyw id="m01">Pies</motyw>
+ Ala ma kota<end id="m01" /></akap>
+ </opowiadanie></utwor>
+ """
+ self.child = models.Book.from_text_and_meta(
+ ContentFile(self.CHILD_TEXT), self.child_info)
+
+ self.book_info = BookInfoStub(
+ genre='X-Genre',
+ epoch='X-Epoch',
+ kind='X-Kind',
+ author=PersonStub(("Joe",), "Doe"),
+ parts=[self.child_info.url],
+ **info_args("Book")
+ )
+ self.BOOK_TEXT = """<utwor />"""
+ self.book = models.Book.from_text_and_meta(
+ ContentFile(self.BOOK_TEXT), self.book_info)
+
+ self.parent_info = BookInfoStub(
+ genre='X-Genre',
+ epoch='X-Epoch',
+ kind='X-Kind',
+ author=PersonStub(("Jim",), "Lazy"),
+ parts=[self.book_info.url],
+ **info_args("Parent")
+ )
+ self.PARENT_TEXT = """<utwor />"""
+ self.parent = models.Book.from_text_and_meta(
+ ContentFile(self.PARENT_TEXT), self.parent_info)
+
+ def test_ok(self):
+ self.assertEqual(
+ list(self.client.get('/katalog/gatunek/x-genre/'
+ ).context['object_list']),
+ [self.parent],
+ u"There should be only parent on common tag page."
+ )
+ pies = models.Tag.objects.get(slug='pies')
+ self.assertEqual(self.parent.theme_counter, {pies.pk: 1},
+ u"There should be child theme in parent theme counter."
+ )
+ epoch = models.Tag.objects.get(slug='x-epoch')
+ self.assertEqual(epoch.book_count, 1,
+ u"There should be only parent in common tag's counter."
+ )
+
+ def test_child_republish(self):
+ CHILD_TEXT = """<utwor>
+ <opowiadanie>
+ <akap><begin id="m01" /><motyw id="m01">Pies, Kot</motyw>
+ Ala ma kota<end id="m01" /></akap>
+ </opowiadanie></utwor>
+ """
+ models.Book.from_text_and_meta(
+ ContentFile(CHILD_TEXT), self.child_info, overwrite=True)
+ self.assertEqual(
+ list(self.client.get('/katalog/gatunek/x-genre/'
+ ).context['object_list']),
+ [self.parent],
+ u"There should only be parent on common tag page."
+ )
+ pies = models.Tag.objects.get(slug='pies')
+ kot = models.Tag.objects.get(slug='kot')
+ self.assertEqual(self.parent.theme_counter, {pies.pk: 1, kot.pk: 1},
+ u"There should be child themes in parent theme counter."
+ )
+ epoch = models.Tag.objects.get(slug='x-epoch')
+ self.assertEqual(epoch.book_count, 1,
+ u"There should only be parent in common tag's counter."
+ )
+
+ def test_book_change_child(self):
+ second_child_info = BookInfoStub(
+ genre='X-Genre',
+ epoch='X-Epoch',
+ kind='Other-Kind',
+ author=PersonStub(("Joe",), "Doe"),
+ **info_args("Second Child")
+ )
+ SECOND_CHILD_TEXT = """<utwor>
+ <opowiadanie>
+ <akap><begin id="m01" /><motyw id="m01">Kot</motyw>
+ Ala ma kota<end id="m01" /></akap>
+ </opowiadanie></utwor>
+ """
+ # Import a second child.
+ second_child = models.Book.from_text_and_meta(
+ ContentFile(SECOND_CHILD_TEXT), second_child_info)
+ # The book has only this new child now.
+ self.book_info.parts = [second_child_info.url]
+ self.book = models.Book.from_text_and_meta(
+ ContentFile(self.BOOK_TEXT), self.book_info, overwrite=True)
+
+ self.assertEqual(
+ set(self.client.get('/katalog/gatunek/x-genre/'
+ ).context['object_list']),
+ set([self.parent, self.child]),
+ u"There should be parent and old child on common tag page."
+ )
+ kot = models.Tag.objects.get(slug='kot')
+ self.assertEqual(self.parent.theme_counter, {kot.pk: 1},
+ u"There should only be new child themes in parent theme counter."
+ )
+ epoch = models.Tag.objects.get(slug='x-epoch')
+ self.assertEqual(epoch.book_count, 2,
+ u"There should be parent and old child in common tag's counter."
+ )
+ self.assertEqual(
+ list(self.client.get('/katalog/lektura/parent/motyw/kot/'
+ ).context['fragments']),
+ [second_child.fragments.all()[0]],
+ u"There should be new child's fragments on parent's theme page."
+ )
+ self.assertEqual(
+ list(self.client.get('/katalog/lektura/parent/motyw/pies/'
+ ).context['fragments']),
+ [],
+ u"There should be no old child's fragments on parent's theme page."
+ )
+
+
class MultilingualBookImportTest(WLTestCase):
def setUp(self):
WLTestCase.setUp(self)