187 lines
7.2 KiB
Python
187 lines
7.2 KiB
Python
from django.contrib.contenttypes.models import ContentType
|
|
from django.core.management.base import BaseCommand
|
|
from django.db.models import Count, F
|
|
from tqdm import tqdm
|
|
|
|
from catalog.book.tests import uniq
|
|
from catalog.models import *
|
|
from common.models.lang import detect_language
|
|
|
|
|
|
class Command(BaseCommand):
|
|
help = "catalog app utilities"
|
|
|
|
def add_arguments(self, parser):
|
|
parser.add_argument(
|
|
"--verbose",
|
|
action="store_true",
|
|
)
|
|
parser.add_argument(
|
|
"--fix",
|
|
action="store_true",
|
|
)
|
|
parser.add_argument(
|
|
"--purge",
|
|
action="store_true",
|
|
help="purge deleted items",
|
|
)
|
|
parser.add_argument(
|
|
"--localize",
|
|
action="store_true",
|
|
help="migrate localized title/description",
|
|
)
|
|
parser.add_argument(
|
|
"--integrity",
|
|
action="store_true",
|
|
help="check and fix integrity for merged and deleted items",
|
|
)
|
|
|
|
def handle(self, *args, **options):
|
|
self.verbose = options["verbose"]
|
|
self.fix = options["fix"]
|
|
if options["purge"]:
|
|
self.purge()
|
|
if options["integrity"]:
|
|
self.integrity()
|
|
if options["localize"]:
|
|
self.localize()
|
|
self.stdout.write(self.style.SUCCESS("Done."))
|
|
|
|
def localize(self):
|
|
c = Item.objects.all().count()
|
|
qs = Item.objects.filter(is_deleted=False, merged_to_item__isnull=True)
|
|
for i in tqdm(qs.iterator(), total=c):
|
|
localized_title = [{"lang": detect_language(i.title), "text": i.title}]
|
|
if i.__class__ != Edition:
|
|
if hasattr(i, "orig_title") and i.orig_title: # type:ignore
|
|
localized_title += [
|
|
{
|
|
"lang": detect_language(i.orig_title), # type:ignore
|
|
"text": i.orig_title, # type:ignore
|
|
}
|
|
]
|
|
if hasattr(i, "other_title") and i.other_title: # type:ignore
|
|
for title in i.other_title: # type:ignore
|
|
localized_title += [
|
|
{"lang": detect_language(title), "text": title}
|
|
]
|
|
else:
|
|
# Edition has no other_title
|
|
subtitle = i.metadata.get("subtitle")
|
|
i.metadata["localized_subtitle"] = (
|
|
[{"lang": detect_language(subtitle), "text": subtitle}]
|
|
if subtitle
|
|
else []
|
|
)
|
|
lang = i.metadata.get("language")
|
|
if isinstance(lang, str) and lang:
|
|
i.metadata["language"] = [lang]
|
|
if i.__class__ == Podcast and i.metadata.get("host", None) is None:
|
|
i.metadata["host"] = i.metadata.get("hosts", [])
|
|
i.localized_title = uniq(localized_title)
|
|
localized_desc = [{"lang": detect_language(i.brief), "text": i.brief}]
|
|
i.localized_description = localized_desc
|
|
i.save(update_fields=["metadata"])
|
|
|
|
def purge(self):
|
|
for cls in Item.__subclasses__():
|
|
if self.fix:
|
|
self.stdout.write(f"Cleaning up {cls}...")
|
|
cls.objects.filter(is_deleted=True).delete()
|
|
|
|
def integrity(self):
|
|
self.stdout.write("Checking circulated merge...")
|
|
for i in Item.objects.filter(merged_to_item=F("id")):
|
|
self.stdout.write(f"! {i} : {i.absolute_url}?skipcheck=1")
|
|
if self.fix:
|
|
i.merged_to_item = None
|
|
i.save()
|
|
|
|
self.stdout.write("Checking chained merge...")
|
|
for i in (
|
|
Item.objects.filter(merged_to_item__isnull=False)
|
|
.annotate(n=Count("merged_from_items"))
|
|
.exclude(n=0)
|
|
):
|
|
self.stdout.write(f"! {i} : {i.absolute_url}?skipcheck=1")
|
|
if self.fix:
|
|
for j in i.merged_from_items.all():
|
|
j.merged_to_item = i.merged_to_item
|
|
j.save()
|
|
|
|
self.stdout.write("Checking deleted merge...")
|
|
for i in Item.objects.filter(merged_to_item__isnull=False, is_deleted=True):
|
|
self.stdout.write(f"! {i} : {i.absolute_url}?skipcheck=1")
|
|
if self.fix:
|
|
i.is_deleted = False
|
|
i.save()
|
|
|
|
self.stdout.write("Checking deleted item with external resources...")
|
|
for i in (
|
|
Item.objects.filter(is_deleted=True)
|
|
.annotate(n=Count("external_resources"))
|
|
.exclude(n=0)
|
|
):
|
|
self.stdout.write(f"! {i} : {i.absolute_url}?skipcheck=1")
|
|
if self.fix:
|
|
for r in i.external_resources.all():
|
|
r.item = None
|
|
r.save()
|
|
|
|
self.stdout.write("Checking merged item with external resources...")
|
|
for i in (
|
|
Item.objects.filter(merged_to_item__isnull=False)
|
|
.annotate(n=Count("external_resources"))
|
|
.exclude(n=0)
|
|
):
|
|
self.stdout.write(f"! {i} : {i.absolute_url}?skipcheck=1")
|
|
if self.fix:
|
|
for r in i.external_resources.all():
|
|
r.item = i.merged_to_item
|
|
r.save()
|
|
|
|
tvshow_ct_id = ContentType.objects.get_for_model(TVShow).id
|
|
self.stdout.write("Checking TVShow merged to other class...")
|
|
for i in (
|
|
TVShow.objects.filter(merged_to_item__isnull=False)
|
|
.filter(merged_to_item__isnull=False)
|
|
.exclude(merged_to_item__polymorphic_ctype_id=tvshow_ct_id)
|
|
):
|
|
if i.child_items.all().exists():
|
|
self.stdout.write(f"! with season {i} : {i.absolute_url}?skipcheck=1")
|
|
if self.fix:
|
|
i.merged_to_item = None
|
|
i.save()
|
|
else:
|
|
self.stdout.write(f"! no season {i} : {i.absolute_url}?skipcheck=1")
|
|
if self.fix:
|
|
i.recast_to(i.merged_to_item.__class__) # type:ignore
|
|
|
|
self.stdout.write("Checking TVSeason is child of other class...")
|
|
for i in TVSeason.objects.filter(show__isnull=False).exclude(
|
|
show__polymorphic_ctype_id=tvshow_ct_id
|
|
):
|
|
if not i.show:
|
|
continue
|
|
self.stdout.write(f"! {i.show} : {i.show.absolute_url}?skipcheck=1")
|
|
if self.fix:
|
|
i.show = None
|
|
i.save()
|
|
|
|
self.stdout.write("Checking deleted item with child TV Season...")
|
|
for i in TVSeason.objects.filter(show__is_deleted=True):
|
|
if not i.show:
|
|
continue
|
|
self.stdout.write(f"! {i.show} : {i.show.absolute_url}?skipcheck=1")
|
|
if self.fix:
|
|
i.show.is_deleted = False
|
|
i.show.save()
|
|
|
|
self.stdout.write("Checking merged item with child TV Season...")
|
|
for i in TVSeason.objects.filter(show__merged_to_item__isnull=False):
|
|
if not i.show:
|
|
continue
|
|
self.stdout.write(f"! {i.show} : {i.show.absolute_url}?skipcheck=1")
|
|
if self.fix:
|
|
i.show = i.show.merged_to_item
|
|
i.save()
|