kopia lustrzana https://dev.funkwhale.audio/funkwhale/funkwhale
Fix #858: Broadcast/handle rejected follows
rodzic
191f28f79c
commit
cd109ddeb6
|
@ -34,6 +34,8 @@ def update_follow(follow, approved):
|
|||
follow.save(update_fields=["approved"])
|
||||
if approved:
|
||||
routes.outbox.dispatch({"type": "Accept"}, context={"follow": follow})
|
||||
else:
|
||||
routes.outbox.dispatch({"type": "Reject"}, context={"follow": follow})
|
||||
|
||||
|
||||
class LibraryFollowViewSet(
|
||||
|
@ -57,7 +59,7 @@ class LibraryFollowViewSet(
|
|||
|
||||
def get_queryset(self):
|
||||
qs = super().get_queryset()
|
||||
return qs.filter(actor=self.request.user.actor)
|
||||
return qs.filter(actor=self.request.user.actor).exclude(approved=False)
|
||||
|
||||
def perform_create(self, serializer):
|
||||
follow = serializer.save(actor=self.request.user.actor)
|
||||
|
|
|
@ -82,6 +82,37 @@ def outbox_accept(context):
|
|||
}
|
||||
|
||||
|
||||
@outbox.register({"type": "Reject"})
|
||||
def outbox_reject_follow(context):
|
||||
follow = context["follow"]
|
||||
if follow._meta.label == "federation.LibraryFollow":
|
||||
actor = follow.target.actor
|
||||
else:
|
||||
actor = follow.target
|
||||
payload = serializers.RejectFollowSerializer(follow, context={"actor": actor}).data
|
||||
yield {
|
||||
"actor": actor,
|
||||
"type": "Reject",
|
||||
"payload": with_recipients(payload, to=[follow.actor]),
|
||||
"object": follow,
|
||||
"related_object": follow.target,
|
||||
}
|
||||
|
||||
|
||||
@inbox.register({"type": "Reject"})
|
||||
def inbox_reject_follow(payload, context):
|
||||
serializer = serializers.RejectFollowSerializer(data=payload, context=context)
|
||||
if not serializer.is_valid(raise_exception=context.get("raise_exception", False)):
|
||||
logger.debug(
|
||||
"Discarding invalid follow reject from %s: %s",
|
||||
context["actor"].fid,
|
||||
serializer.errors,
|
||||
)
|
||||
return
|
||||
|
||||
serializer.save()
|
||||
|
||||
|
||||
@inbox.register({"type": "Undo", "object.type": "Follow"})
|
||||
def inbox_undo_follow(payload, context):
|
||||
serializer = serializers.UndoFollowSerializer(data=payload, context=context)
|
||||
|
|
|
@ -688,11 +688,10 @@ class APIFollowSerializer(serializers.ModelSerializer):
|
|||
]
|
||||
|
||||
|
||||
class AcceptFollowSerializer(serializers.Serializer):
|
||||
class FollowActionSerializer(serializers.Serializer):
|
||||
id = serializers.URLField(max_length=500, required=False)
|
||||
actor = serializers.URLField(max_length=500)
|
||||
object = FollowSerializer()
|
||||
type = serializers.ChoiceField(choices=["Accept"])
|
||||
|
||||
def validate_actor(self, v):
|
||||
expected = self.context.get("actor")
|
||||
|
@ -720,12 +719,13 @@ class AcceptFollowSerializer(serializers.Serializer):
|
|||
follow_class.objects.filter(
|
||||
target=target, actor=validated_data["object"]["actor"]
|
||||
)
|
||||
.exclude(approved=True)
|
||||
.select_related()
|
||||
.get()
|
||||
)
|
||||
except follow_class.DoesNotExist:
|
||||
raise serializers.ValidationError("No follow to accept")
|
||||
raise serializers.ValidationError(
|
||||
"No follow to {}".format(self.action_type)
|
||||
)
|
||||
return validated_data
|
||||
|
||||
def to_representation(self, instance):
|
||||
|
@ -736,12 +736,18 @@ class AcceptFollowSerializer(serializers.Serializer):
|
|||
|
||||
return {
|
||||
"@context": jsonld.get_default_context(),
|
||||
"id": instance.get_federation_id() + "/accept",
|
||||
"type": "Accept",
|
||||
"id": instance.get_federation_id() + "/{}".format(self.action_type),
|
||||
"type": self.action_type.title(),
|
||||
"actor": actor.fid,
|
||||
"object": FollowSerializer(instance).data,
|
||||
}
|
||||
|
||||
|
||||
class AcceptFollowSerializer(FollowActionSerializer):
|
||||
|
||||
type = serializers.ChoiceField(choices=["Accept"])
|
||||
action_type = "accept"
|
||||
|
||||
def save(self):
|
||||
follow = self.validated_data["follow"]
|
||||
follow.approved = True
|
||||
|
@ -751,6 +757,18 @@ class AcceptFollowSerializer(serializers.Serializer):
|
|||
return follow
|
||||
|
||||
|
||||
class RejectFollowSerializer(FollowActionSerializer):
|
||||
|
||||
type = serializers.ChoiceField(choices=["Reject"])
|
||||
action_type = "reject"
|
||||
|
||||
def save(self):
|
||||
follow = self.validated_data["follow"]
|
||||
follow.approved = False
|
||||
follow.save()
|
||||
return follow
|
||||
|
||||
|
||||
class UndoFollowSerializer(serializers.Serializer):
|
||||
id = serializers.URLField(max_length=500)
|
||||
actor = serializers.URLField(max_length=500)
|
||||
|
|
|
@ -126,12 +126,9 @@ def test_user_can_accept_or_reject_own_follows(
|
|||
|
||||
assert follow.approved is expected
|
||||
|
||||
if action == "accept":
|
||||
mocked_dispatch.assert_called_once_with(
|
||||
{"type": "Accept"}, context={"follow": follow}
|
||||
{"type": action.title()}, context={"follow": follow}
|
||||
)
|
||||
if action == "reject":
|
||||
mocked_dispatch.assert_not_called()
|
||||
|
||||
|
||||
def test_user_can_list_inbox_items(factories, logged_in_api_client):
|
||||
|
|
|
@ -16,6 +16,7 @@ from funkwhale_api.moderation import serializers as moderation_serializers
|
|||
[
|
||||
({"type": "Follow"}, routes.inbox_follow),
|
||||
({"type": "Accept"}, routes.inbox_accept),
|
||||
({"type": "Reject"}, routes.inbox_reject_follow),
|
||||
({"type": "Create", "object": {"type": "Audio"}}, routes.inbox_create_audio),
|
||||
(
|
||||
{"type": "Update", "object": {"type": "Library"}},
|
||||
|
@ -51,6 +52,7 @@ def test_inbox_routes(route, handler):
|
|||
({"type": "Accept"}, routes.outbox_accept),
|
||||
({"type": "Flag"}, routes.outbox_flag),
|
||||
({"type": "Follow"}, routes.outbox_follow),
|
||||
({"type": "Reject"}, routes.outbox_reject_follow),
|
||||
({"type": "Create", "object": {"type": "Audio"}}, routes.outbox_create_audio),
|
||||
(
|
||||
{"type": "Update", "object": {"type": "Library"}},
|
||||
|
@ -669,6 +671,46 @@ def test_outbox_delete_follow_library(factories):
|
|||
assert activity["related_object"] == follow.target
|
||||
|
||||
|
||||
def test_inbox_reject_follow_library(factories):
|
||||
local_actor = factories["users.User"]().create_actor()
|
||||
remote_actor = factories["federation.Actor"]()
|
||||
follow = factories["federation.LibraryFollow"](
|
||||
actor=local_actor, target__actor=remote_actor, approved=True
|
||||
)
|
||||
assert follow.approved is True
|
||||
serializer = serializers.RejectFollowSerializer(
|
||||
follow, context={"actor": remote_actor}
|
||||
)
|
||||
ii = factories["federation.InboxItem"](actor=local_actor)
|
||||
routes.inbox_reject_follow(
|
||||
serializer.data,
|
||||
context={"actor": remote_actor, "inbox_items": [ii], "raise_exception": True},
|
||||
)
|
||||
follow.refresh_from_db()
|
||||
assert follow.approved is False
|
||||
|
||||
|
||||
def test_outbox_reject_follow_library(factories):
|
||||
remote_actor = factories["federation.Actor"]()
|
||||
local_actor = factories["federation.Actor"](local=True)
|
||||
follow = factories["federation.LibraryFollow"](
|
||||
actor=remote_actor, target__actor=local_actor
|
||||
)
|
||||
|
||||
activity = list(routes.outbox_reject_follow({"follow": follow}))[0]
|
||||
|
||||
serializer = serializers.RejectFollowSerializer(
|
||||
follow, context={"actor": local_actor}
|
||||
)
|
||||
expected = serializer.data
|
||||
expected["to"] = [remote_actor]
|
||||
|
||||
assert activity["payload"] == expected
|
||||
assert activity["actor"] == local_actor
|
||||
assert activity["object"] == follow
|
||||
assert activity["related_object"] == follow.target
|
||||
|
||||
|
||||
def test_handle_library_entry_update_can_manage(factories, mocker):
|
||||
update_library_entity = mocker.patch(
|
||||
"funkwhale_api.music.tasks.update_library_entity"
|
||||
|
|
|
@ -318,6 +318,22 @@ def test_accept_follow_serializer_validates_on_context(factories):
|
|||
assert "object" in serializer.errors["object"]
|
||||
|
||||
|
||||
def test_reject_follow_serializer_representation(factories):
|
||||
follow = factories["federation.Follow"](approved=None)
|
||||
|
||||
expected = {
|
||||
"@context": jsonld.get_default_context(),
|
||||
"id": follow.get_federation_id() + "/reject",
|
||||
"type": "Reject",
|
||||
"actor": follow.target.fid,
|
||||
"object": serializers.FollowSerializer(follow).data,
|
||||
}
|
||||
|
||||
serializer = serializers.RejectFollowSerializer(follow)
|
||||
|
||||
assert serializer.data == expected
|
||||
|
||||
|
||||
def test_undo_follow_serializer_representation(factories):
|
||||
follow = factories["federation.Follow"](approved=True)
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Broadcast/handle rejected follows (#858)
|
Ładowanie…
Reference in New Issue