Skip to content
Snippets Groups Projects
Verified Commit 377f237f authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Rejecting media files on an instance or account now purge existing media

parent cb3daced
No related branches found
No related tags found
No related merge requests found
......@@ -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)
delete_qs(models.LibraryFollow.objects.filter(target__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(models.Follow.objects.filter(actor_id__in=ids))
if not only:
delete_qs(models.LibraryFollow.objects.filter(target__actor_id__in=ids))
delete_qs(models.Follow.objects.filter(actor_id__in=ids))
# purge audio content
delete_qs(music_models.Upload.objects.filter(library__actor_id__in=ids))
delete_qs(music_models.Library.objects.filter(actor_id__in=ids))
if not only or "media" in only:
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
delete_qs(models.InboxItem.objects.filter(actor_id__in=ids))
delete_qs(models.Activity.objects.filter(actor_id__in=ids))
if not only:
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")
def purge_actors(ids=[], domains=[]):
def purge_actors(ids=[], domains=[], only=[]):
actors = models.Actor.objects.filter(
Q(id__in=ids) | Q(domain_id__in=domains)
).order_by("id")
found_ids = list(actors.values_list("id", flat=True))
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
def save(self, *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:
only = []
if self.instance.reject_media:
only.append("media")
target = instance.target
if target["type"] == "domain":
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":
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
......@@ -223,11 +223,46 @@ def test_handle_purge_actors(factories, mocker):
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):
handle_purge_actors = mocker.spy(tasks, "handle_purge_actors")
factories["federation.Actor"]()
to_delete = 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):
policy = factories["moderation.InstancePolicy"](for_domain=True, block_all=False)
@pytest.mark.parametrize(
"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")
serializer = serializers.ManageInstancePolicySerializer(
policy, data={"block_all": True}, partial=True
policy, data={param: True}, partial=True
)
serializer.is_valid(raise_exception=True)
serializer.save()
policy.refresh_from_db()
assert policy.block_all is True
assert getattr(policy, param) is True
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()
# setting to false should have no effect
serializer = serializers.ManageInstancePolicySerializer(
policy, data={"block_all": False}, partial=True
policy, data={param: False}, partial=True
)
serializer.is_valid(raise_exception=True)
serializer.save()
policy.refresh_from_db()
assert policy.block_all is False
assert getattr(policy, param) is False
assert on_commit.call_count == 0
def test_instance_policy_serializer_purges_target_actor(factories, mocker):
policy = factories["moderation.InstancePolicy"](for_actor=True, block_all=False)
@pytest.mark.parametrize(
"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")
serializer = serializers.ManageInstancePolicySerializer(
policy, data={"block_all": True}, partial=True
policy, data={param: True}, partial=True
)
serializer.is_valid(raise_exception=True)
serializer.save()
policy.refresh_from_db()
assert policy.block_all is True
assert getattr(policy, param) is True
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()
# setting to false should have no effect
serializer = serializers.ManageInstancePolicySerializer(
policy, data={"block_all": False}, partial=True
policy, data={param: False}, partial=True
)
serializer.is_valid(raise_exception=True)
serializer.save()
policy.refresh_from_db()
assert policy.block_all is False
assert getattr(policy, param) is False
assert on_commit.call_count == 0
......@@ -119,7 +119,7 @@ export default {
label: this.$gettext("Silence notifications"),
},
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"),
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment