funkwhale/api/funkwhale_api/federation/management/commands/fix_federation_ids.py

116 wiersze
3.9 KiB
Python

from django.core.management.base import BaseCommand, CommandError
from funkwhale_api.common import utils
from funkwhale_api.federation import models as federation_models
from funkwhale_api.music import models as music_models
MODELS = [
(music_models.Artist, ["fid"]),
(music_models.Album, ["fid"]),
(music_models.Track, ["fid"]),
(music_models.Upload, ["fid"]),
(music_models.Library, ["fid", "followers_url"]),
(
federation_models.Actor,
[
"fid",
"url",
"outbox_url",
"inbox_url",
"following_url",
"followers_url",
"shared_inbox_url",
],
),
(federation_models.Activity, ["fid"]),
(federation_models.Follow, ["fid"]),
(federation_models.LibraryFollow, ["fid"]),
]
class Command(BaseCommand):
help = """
Find and replace wrong protocol/domain in local federation ids.
Use with caution and only if you know what you are doing.
"""
def add_arguments(self, parser):
parser.add_argument(
"old_base_url",
type=str,
help="The invalid url prefix you want to find and replace, e.g 'http://baddomain'",
)
parser.add_argument(
"new_base_url",
type=str,
help="The url prefix you want to use in place of the bad one, e.g 'https://gooddomain'",
)
parser.add_argument(
"--noinput",
"--no-input",
action="store_false",
dest="interactive",
help="Do NOT prompt the user for input of any kind.",
)
parser.add_argument(
"--no-dry-run",
action="store_false",
dest="dry_run",
help="Commit the changes to the database",
)
def handle(self, *args, **options):
results = {}
old_prefix, new_prefix = options["old_base_url"], options["new_base_url"]
for kls, fields in MODELS:
results[kls] = {}
for field in fields:
candidates = kls.objects.filter(**{f"{field}__startswith": old_prefix})
results[kls][field] = candidates.count()
total = sum([t for k in results.values() for t in k.values()])
self.stdout.write("")
if total:
self.stdout.write(
self.style.WARNING(
"Will replace {} found occurrences of '{}' by '{}':".format(
total, old_prefix, new_prefix
)
)
)
self.stdout.write("")
for kls, fields in results.items():
for field, count in fields.items():
self.stdout.write(
"- {}/{} {}.{}".format(
count, kls.objects.count(), kls._meta.label, field
)
)
else:
self.stdout.write(f"No objects found with prefix {old_prefix}, exiting.")
return
if options["dry_run"]:
self.stdout.write(
"Run this command with --no-dry-run to perform the replacement."
)
return
self.stdout.write("")
if options["interactive"]:
message = (
"Are you sure you want to perform the replacement on {} objects?\n\n"
"Type 'yes' to continue, or 'no' to cancel: "
).format(total)
if input("".join(message)) != "yes":
raise CommandError("Command canceled.")
for kls, fields in results.items():
for field, count in fields.items():
self.stdout.write(f"Replacing {field} on {count} {kls._meta.label}")
candidates = kls.objects.all()
utils.replace_prefix(candidates, field, old=old_prefix, new=new_prefix)
self.stdout.write("")
self.stdout.write(self.style.SUCCESS("Done!"))