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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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 { ...@@ -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"),
} }
} }
......
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