Merge pull request #2905 from bookwyrm-social/broken-editions
Adds management command to repair editions in bad state
This commit is contained in:
commit
9d69f2fb3e
5 changed files with 57 additions and 2 deletions
21
bookwyrm/management/commands/repair_editions.py
Normal file
21
bookwyrm/management/commands/repair_editions.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
""" Repair editions with missing works """
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from bookwyrm import models
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
"""command-line options"""
|
||||||
|
|
||||||
|
help = "Repairs an edition that is in a broken state"
|
||||||
|
|
||||||
|
# pylint: disable=unused-argument
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
"""Find and repair broken editions"""
|
||||||
|
# Find broken editions
|
||||||
|
editions = models.Edition.objects.filter(parent_work__isnull=True)
|
||||||
|
self.stdout.write(f"Repairing {editions.count()} edition(s):")
|
||||||
|
|
||||||
|
# Do repair
|
||||||
|
for edition in editions:
|
||||||
|
edition.repair()
|
||||||
|
self.stdout.write(".", ending="")
|
|
@ -381,6 +381,19 @@ class Edition(Book):
|
||||||
|
|
||||||
return super().save(*args, **kwargs)
|
return super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def repair(self):
|
||||||
|
"""If an edition is in a bad state (missing a work), let's fix that"""
|
||||||
|
# made sure it actually NEEDS reapir
|
||||||
|
if self.parent_work:
|
||||||
|
return
|
||||||
|
|
||||||
|
new_work = Work.objects.create(title=self.title)
|
||||||
|
new_work.authors.set(self.authors.all())
|
||||||
|
|
||||||
|
self.parent_work = new_work
|
||||||
|
self.save(update_fields=["parent_work"], broadcast=False)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def viewer_aware_objects(cls, viewer):
|
def viewer_aware_objects(cls, viewer):
|
||||||
"""annotate a book query with metadata related to the user"""
|
"""annotate a book query with metadata related to the user"""
|
||||||
|
|
|
@ -12,6 +12,10 @@ register = template.Library()
|
||||||
@register.filter(name="rating")
|
@register.filter(name="rating")
|
||||||
def get_rating(book, user):
|
def get_rating(book, user):
|
||||||
"""get the overall rating of a book"""
|
"""get the overall rating of a book"""
|
||||||
|
# this shouldn't happen, but it CAN
|
||||||
|
if not book.parent_work:
|
||||||
|
return None
|
||||||
|
|
||||||
return cache.get_or_set(
|
return cache.get_or_set(
|
||||||
f"book-rating-{book.parent_work.id}",
|
f"book-rating-{book.parent_work.id}",
|
||||||
lambda u, b: models.Review.objects.filter(
|
lambda u, b: models.Review.objects.filter(
|
||||||
|
|
|
@ -24,8 +24,7 @@ class Book(TestCase):
|
||||||
title="Example Work", remote_id="https://example.com/book/1"
|
title="Example Work", remote_id="https://example.com/book/1"
|
||||||
)
|
)
|
||||||
self.first_edition = models.Edition.objects.create(
|
self.first_edition = models.Edition.objects.create(
|
||||||
title="Example Edition",
|
title="Example Edition", parent_work=self.work
|
||||||
parent_work=self.work,
|
|
||||||
)
|
)
|
||||||
self.second_edition = models.Edition.objects.create(
|
self.second_edition = models.Edition.objects.create(
|
||||||
title="Another Example Edition",
|
title="Another Example Edition",
|
||||||
|
@ -143,3 +142,15 @@ class Book(TestCase):
|
||||||
for article in articles
|
for article in articles
|
||||||
)
|
)
|
||||||
self.assertTrue(all(book.sort_title == "test edition" for book in books))
|
self.assertTrue(all(book.sort_title == "test edition" for book in books))
|
||||||
|
|
||||||
|
def test_repair_edition(self):
|
||||||
|
"""Fix editions with no works"""
|
||||||
|
edition = models.Edition.objects.create(title="test")
|
||||||
|
edition.authors.set([models.Author.objects.create(name="Author Name")])
|
||||||
|
self.assertIsNone(edition.parent_work)
|
||||||
|
|
||||||
|
edition.repair()
|
||||||
|
edition.refresh_from_db()
|
||||||
|
|
||||||
|
self.assertEqual(edition.parent_work.title, "test")
|
||||||
|
self.assertEqual(edition.parent_work.authors.count(), 1)
|
||||||
|
|
|
@ -71,6 +71,12 @@ class RatingTags(TestCase):
|
||||||
)
|
)
|
||||||
self.assertEqual(rating_tags.get_rating(self.book, self.local_user), 5)
|
self.assertEqual(rating_tags.get_rating(self.book, self.local_user), 5)
|
||||||
|
|
||||||
|
def test_get_rating_broken_edition(self, *_):
|
||||||
|
"""Don't have a server error if an edition is missing a work"""
|
||||||
|
broken_book = models.Edition.objects.create(title="Test")
|
||||||
|
broken_book.parent_work = None
|
||||||
|
self.assertIsNone(rating_tags.get_rating(broken_book, self.local_user))
|
||||||
|
|
||||||
def test_get_user_rating(self, *_):
|
def test_get_user_rating(self, *_):
|
||||||
"""get a user's most recent rating of a book"""
|
"""get a user's most recent rating of a book"""
|
||||||
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"):
|
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue