kopia lustrzana https://dev.funkwhale.audio/funkwhale/funkwhale
Rejecting media files on an instance or account now purge existing media
rodzic
cb3dacedbe
commit
377f237fdb
|
@ -198,27 +198,34 @@ def delete_qs(qs):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def handle_purge_actors(ids):
|
def handle_purge_actors(ids, only=[]):
|
||||||
|
"""
|
||||||
|
Empty only means we purge everything
|
||||||
|
Otherwise, we purge only the requested bits: media
|
||||||
|
"""
|
||||||
# purge follows (received emitted)
|
# purge follows (received emitted)
|
||||||
delete_qs(models.LibraryFollow.objects.filter(target__actor_id__in=ids))
|
if not only:
|
||||||
delete_qs(models.LibraryFollow.objects.filter(actor_id__in=ids))
|
delete_qs(models.LibraryFollow.objects.filter(target__actor_id__in=ids))
|
||||||
delete_qs(models.Follow.objects.filter(target_id__in=ids))
|
delete_qs(models.Follow.objects.filter(actor_id__in=ids))
|
||||||
delete_qs(models.Follow.objects.filter(actor_id__in=ids))
|
|
||||||
|
|
||||||
# purge audio content
|
# purge audio content
|
||||||
delete_qs(music_models.Upload.objects.filter(library__actor_id__in=ids))
|
if not only or "media" in only:
|
||||||
delete_qs(music_models.Library.objects.filter(actor_id__in=ids))
|
delete_qs(models.LibraryFollow.objects.filter(actor_id__in=ids))
|
||||||
|
delete_qs(models.Follow.objects.filter(target_id__in=ids))
|
||||||
|
delete_qs(music_models.Upload.objects.filter(library__actor_id__in=ids))
|
||||||
|
delete_qs(music_models.Library.objects.filter(actor_id__in=ids))
|
||||||
|
|
||||||
# purge remaining activities / deliveries
|
# purge remaining activities / deliveries
|
||||||
delete_qs(models.InboxItem.objects.filter(actor_id__in=ids))
|
if not only:
|
||||||
delete_qs(models.Activity.objects.filter(actor_id__in=ids))
|
delete_qs(models.InboxItem.objects.filter(actor_id__in=ids))
|
||||||
|
delete_qs(models.Activity.objects.filter(actor_id__in=ids))
|
||||||
|
|
||||||
|
|
||||||
@celery.app.task(name="federation.purge_actors")
|
@celery.app.task(name="federation.purge_actors")
|
||||||
def purge_actors(ids=[], domains=[]):
|
def purge_actors(ids=[], domains=[], only=[]):
|
||||||
actors = models.Actor.objects.filter(
|
actors = models.Actor.objects.filter(
|
||||||
Q(id__in=ids) | Q(domain_id__in=domains)
|
Q(id__in=ids) | Q(domain_id__in=domains)
|
||||||
).order_by("id")
|
).order_by("id")
|
||||||
found_ids = list(actors.values_list("id", flat=True))
|
found_ids = list(actors.values_list("id", flat=True))
|
||||||
logger.info("Starting purging %s accounts", len(found_ids))
|
logger.info("Starting purging %s accounts", len(found_ids))
|
||||||
handle_purge_actors(ids=found_ids)
|
handle_purge_actors(ids=found_ids, only=only)
|
||||||
|
|
|
@ -317,17 +317,25 @@ class ManageInstancePolicySerializer(serializers.ModelSerializer):
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
instance = super().save(*args, **kwargs)
|
instance = super().save(*args, **kwargs)
|
||||||
need_purge = self.instance.is_active and self.instance.block_all
|
need_purge = self.instance.is_active and (
|
||||||
|
self.instance.block_all or self.instance.reject_media
|
||||||
|
)
|
||||||
if need_purge:
|
if need_purge:
|
||||||
|
only = []
|
||||||
|
if self.instance.reject_media:
|
||||||
|
only.append("media")
|
||||||
target = instance.target
|
target = instance.target
|
||||||
if target["type"] == "domain":
|
if target["type"] == "domain":
|
||||||
common_utils.on_commit(
|
common_utils.on_commit(
|
||||||
federation_tasks.purge_actors.delay, domains=[target["obj"].pk]
|
federation_tasks.purge_actors.delay,
|
||||||
|
domains=[target["obj"].pk],
|
||||||
|
only=only,
|
||||||
)
|
)
|
||||||
if target["type"] == "actor":
|
if target["type"] == "actor":
|
||||||
common_utils.on_commit(
|
common_utils.on_commit(
|
||||||
federation_tasks.purge_actors.delay, ids=[target["obj"].pk]
|
federation_tasks.purge_actors.delay,
|
||||||
|
ids=[target["obj"].pk],
|
||||||
|
only=only,
|
||||||
)
|
)
|
||||||
|
|
||||||
return instance
|
return instance
|
||||||
|
|
|
@ -223,11 +223,46 @@ def test_handle_purge_actors(factories, mocker):
|
||||||
d.refresh_from_db()
|
d.refresh_from_db()
|
||||||
|
|
||||||
|
|
||||||
|
def test_handle_purge_actors_restrict_media(factories, mocker):
|
||||||
|
to_purge = factories["federation.Actor"]()
|
||||||
|
keeped = [
|
||||||
|
factories["music.Upload"](),
|
||||||
|
factories["federation.Activity"](),
|
||||||
|
factories["federation.InboxItem"](),
|
||||||
|
factories["federation.Follow"](),
|
||||||
|
factories["federation.LibraryFollow"](),
|
||||||
|
factories["federation.Activity"](actor=to_purge),
|
||||||
|
factories["federation.InboxItem"](actor=to_purge),
|
||||||
|
factories["federation.Follow"](actor=to_purge),
|
||||||
|
]
|
||||||
|
|
||||||
|
library = factories["music.Library"](actor=to_purge)
|
||||||
|
deleted = [
|
||||||
|
library,
|
||||||
|
factories["music.Upload"](library=library),
|
||||||
|
factories["federation.LibraryFollow"](actor=to_purge),
|
||||||
|
]
|
||||||
|
|
||||||
|
tasks.handle_purge_actors([to_purge.pk], only=["media"])
|
||||||
|
|
||||||
|
for k in keeped:
|
||||||
|
# this should not be deleted
|
||||||
|
k.refresh_from_db()
|
||||||
|
|
||||||
|
for d in deleted:
|
||||||
|
with pytest.raises(d.__class__.DoesNotExist):
|
||||||
|
d.refresh_from_db()
|
||||||
|
|
||||||
|
|
||||||
def test_purge_actors(factories, mocker):
|
def test_purge_actors(factories, mocker):
|
||||||
handle_purge_actors = mocker.spy(tasks, "handle_purge_actors")
|
handle_purge_actors = mocker.spy(tasks, "handle_purge_actors")
|
||||||
factories["federation.Actor"]()
|
factories["federation.Actor"]()
|
||||||
to_delete = factories["federation.Actor"]()
|
to_delete = factories["federation.Actor"]()
|
||||||
to_delete_domain = factories["federation.Actor"]()
|
to_delete_domain = factories["federation.Actor"]()
|
||||||
tasks.purge_actors(ids=[to_delete.pk], domains=[to_delete_domain.domain.name])
|
tasks.purge_actors(
|
||||||
|
ids=[to_delete.pk], domains=[to_delete_domain.domain.name], only=["hello"]
|
||||||
|
)
|
||||||
|
|
||||||
handle_purge_actors.assert_called_once_with(ids=[to_delete.pk, to_delete_domain.pk])
|
handle_purge_actors.assert_called_once_with(
|
||||||
|
ids=[to_delete.pk, to_delete_domain.pk], only=["hello"]
|
||||||
|
)
|
||||||
|
|
|
@ -175,65 +175,85 @@ def test_manage_domain_action_purge(factories, mocker):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_instance_policy_serializer_purges_target_domain(factories, mocker):
|
@pytest.mark.parametrize(
|
||||||
policy = factories["moderation.InstancePolicy"](for_domain=True, block_all=False)
|
"param,expected_only", [("block_all", []), ("reject_media", ["media"])]
|
||||||
|
)
|
||||||
|
def test_instance_policy_serializer_purges_target_domain(
|
||||||
|
factories, mocker, param, expected_only
|
||||||
|
):
|
||||||
|
params = {param: False}
|
||||||
|
if param != "block_all":
|
||||||
|
params["block_all"] = False
|
||||||
|
policy = factories["moderation.InstancePolicy"](for_domain=True, **params)
|
||||||
on_commit = mocker.patch("funkwhale_api.common.utils.on_commit")
|
on_commit = mocker.patch("funkwhale_api.common.utils.on_commit")
|
||||||
|
|
||||||
serializer = serializers.ManageInstancePolicySerializer(
|
serializer = serializers.ManageInstancePolicySerializer(
|
||||||
policy, data={"block_all": True}, partial=True
|
policy, data={param: True}, partial=True
|
||||||
)
|
)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
serializer.save()
|
serializer.save()
|
||||||
|
|
||||||
policy.refresh_from_db()
|
policy.refresh_from_db()
|
||||||
|
|
||||||
assert policy.block_all is True
|
assert getattr(policy, param) is True
|
||||||
on_commit.assert_called_once_with(
|
on_commit.assert_called_once_with(
|
||||||
federation_tasks.purge_actors.delay, domains=[policy.target_domain_id]
|
federation_tasks.purge_actors.delay,
|
||||||
|
domains=[policy.target_domain_id],
|
||||||
|
only=expected_only,
|
||||||
)
|
)
|
||||||
|
|
||||||
on_commit.reset_mock()
|
on_commit.reset_mock()
|
||||||
|
|
||||||
# setting to false should have no effect
|
# setting to false should have no effect
|
||||||
serializer = serializers.ManageInstancePolicySerializer(
|
serializer = serializers.ManageInstancePolicySerializer(
|
||||||
policy, data={"block_all": False}, partial=True
|
policy, data={param: False}, partial=True
|
||||||
)
|
)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
serializer.save()
|
serializer.save()
|
||||||
|
|
||||||
policy.refresh_from_db()
|
policy.refresh_from_db()
|
||||||
|
|
||||||
assert policy.block_all is False
|
assert getattr(policy, param) is False
|
||||||
assert on_commit.call_count == 0
|
assert on_commit.call_count == 0
|
||||||
|
|
||||||
|
|
||||||
def test_instance_policy_serializer_purges_target_actor(factories, mocker):
|
@pytest.mark.parametrize(
|
||||||
policy = factories["moderation.InstancePolicy"](for_actor=True, block_all=False)
|
"param,expected_only", [("block_all", []), ("reject_media", ["media"])]
|
||||||
|
)
|
||||||
|
def test_instance_policy_serializer_purges_target_actor(
|
||||||
|
factories, mocker, param, expected_only
|
||||||
|
):
|
||||||
|
params = {param: False}
|
||||||
|
if param != "block_all":
|
||||||
|
params["block_all"] = False
|
||||||
|
policy = factories["moderation.InstancePolicy"](for_actor=True, **params)
|
||||||
on_commit = mocker.patch("funkwhale_api.common.utils.on_commit")
|
on_commit = mocker.patch("funkwhale_api.common.utils.on_commit")
|
||||||
|
|
||||||
serializer = serializers.ManageInstancePolicySerializer(
|
serializer = serializers.ManageInstancePolicySerializer(
|
||||||
policy, data={"block_all": True}, partial=True
|
policy, data={param: True}, partial=True
|
||||||
)
|
)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
serializer.save()
|
serializer.save()
|
||||||
|
|
||||||
policy.refresh_from_db()
|
policy.refresh_from_db()
|
||||||
|
|
||||||
assert policy.block_all is True
|
assert getattr(policy, param) is True
|
||||||
on_commit.assert_called_once_with(
|
on_commit.assert_called_once_with(
|
||||||
federation_tasks.purge_actors.delay, ids=[policy.target_actor_id]
|
federation_tasks.purge_actors.delay,
|
||||||
|
ids=[policy.target_actor_id],
|
||||||
|
only=expected_only,
|
||||||
)
|
)
|
||||||
|
|
||||||
on_commit.reset_mock()
|
on_commit.reset_mock()
|
||||||
|
|
||||||
# setting to false should have no effect
|
# setting to false should have no effect
|
||||||
serializer = serializers.ManageInstancePolicySerializer(
|
serializer = serializers.ManageInstancePolicySerializer(
|
||||||
policy, data={"block_all": False}, partial=True
|
policy, data={param: False}, partial=True
|
||||||
)
|
)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
serializer.save()
|
serializer.save()
|
||||||
|
|
||||||
policy.refresh_from_db()
|
policy.refresh_from_db()
|
||||||
|
|
||||||
assert policy.block_all is False
|
assert getattr(policy, param) is False
|
||||||
assert on_commit.call_count == 0
|
assert on_commit.call_count == 0
|
||||||
|
|
|
@ -119,7 +119,7 @@ export default {
|
||||||
label: this.$gettext("Silence notifications"),
|
label: this.$gettext("Silence notifications"),
|
||||||
},
|
},
|
||||||
rejectMedia: {
|
rejectMedia: {
|
||||||
help: this.$gettext("Do not download any media file (audio, album cover, account avatar…) from this account or domain."),
|
help: this.$gettext("Do not download any media file (audio, album cover, account avatar…) from this account or domain. This will purge existing content as well."),
|
||||||
label: this.$gettext("Reject media"),
|
label: this.$gettext("Reject media"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue