diff --git a/api/funkwhale_api/federation/serializers.py b/api/funkwhale_api/federation/serializers.py index 8a2fcefeaaef75ac7d35d72694cd442114bccad6..a0a247f6a0d91a14550e544ba80077993cec26ab 100644 --- a/api/funkwhale_api/federation/serializers.py +++ b/api/funkwhale_api/federation/serializers.py @@ -556,6 +556,7 @@ def get_additional_fields(data): PAGINATED_COLLECTION_JSONLD_MAPPING = { "totalItems": jsonld.first_val(contexts.AS.totalItems), "actor": jsonld.first_id(contexts.AS.actor), + "attributedTo": jsonld.first_id(contexts.AS.attributedTo), "first": jsonld.first_id(contexts.AS.first), "last": jsonld.first_id(contexts.AS.last), "partOf": jsonld.first_id(contexts.AS.partOf), @@ -565,7 +566,8 @@ PAGINATED_COLLECTION_JSONLD_MAPPING = { class PaginatedCollectionSerializer(jsonld.JsonLdSerializer): type = serializers.ChoiceField(choices=[contexts.AS.Collection]) totalItems = serializers.IntegerField(min_value=0) - actor = serializers.URLField(max_length=500) + actor = serializers.URLField(max_length=500, required=False) + attributedTo = serializers.URLField(max_length=500, required=False) id = serializers.URLField(max_length=500) first = serializers.URLField(max_length=500) last = serializers.URLField(max_length=500) @@ -573,6 +575,18 @@ class PaginatedCollectionSerializer(jsonld.JsonLdSerializer): class Meta: jsonld_mapping = PAGINATED_COLLECTION_JSONLD_MAPPING + def validate(self, validated_data): + d = super().validate(validated_data) + actor = d.get("actor") + attributed_to = d.get("attributedTo") + if not actor and not attributed_to: + raise serializers.ValidationError( + "You need to provide at least actor or attributedTo" + ) + + d["attributedTo"] = attributed_to or actor + return d + def to_representation(self, conf): paginator = Paginator(conf["items"], conf.get("page_size", 20)) first = funkwhale_utils.set_query_parameter(conf["id"], page=1) @@ -580,7 +594,9 @@ class PaginatedCollectionSerializer(jsonld.JsonLdSerializer): last = funkwhale_utils.set_query_parameter(conf["id"], page=paginator.num_pages) d = { "id": conf["id"], + # XXX Stable release: remove the obsolete actor field "actor": conf["actor"].fid, + "attributedTo": conf["actor"].fid, "totalItems": paginator.count, "type": conf.get("type", "Collection"), "current": current, @@ -624,7 +640,9 @@ class LibrarySerializer(PaginatedCollectionSerializer): "name": library.name, "summary": library.description, "page_size": 100, + # XXX Stable release: remove the obsolete actor field "actor": library.actor, + "attributedTo": library.actor, "items": library.uploads.for_federation(), "type": "Library", } @@ -637,7 +655,7 @@ class LibrarySerializer(PaginatedCollectionSerializer): def create(self, validated_data): actor = utils.retrieve_ap_object( - validated_data["actor"], + validated_data["attributedTo"], actor=self.context.get("fetch_actor"), queryset=models.Actor, serializer_class=ActorSerializer, @@ -661,7 +679,8 @@ class CollectionPageSerializer(jsonld.JsonLdSerializer): type = serializers.ChoiceField(choices=[contexts.AS.CollectionPage]) totalItems = serializers.IntegerField(min_value=0) items = serializers.ListField() - actor = serializers.URLField(max_length=500) + actor = serializers.URLField(max_length=500, required=False) + attributedTo = serializers.URLField(max_length=500, required=False) id = serializers.URLField(max_length=500) first = serializers.URLField(max_length=500) last = serializers.URLField(max_length=500) @@ -674,6 +693,7 @@ class CollectionPageSerializer(jsonld.JsonLdSerializer): "totalItems": jsonld.first_val(contexts.AS.totalItems), "items": jsonld.raw(contexts.AS.items), "actor": jsonld.first_id(contexts.AS.actor), + "attributedTo": jsonld.first_id(contexts.AS.attributedTo), "first": jsonld.first_id(contexts.AS.first), "last": jsonld.first_id(contexts.AS.last), "next": jsonld.first_id(contexts.AS.next), @@ -706,7 +726,9 @@ class CollectionPageSerializer(jsonld.JsonLdSerializer): d = { "id": id, "partOf": conf["id"], + # XXX Stable release: remove the obsolete actor field "actor": conf["actor"].fid, + "attributedTo": conf["actor"].fid, "totalItems": page.paginator.count, "type": "CollectionPage", "first": first, diff --git a/api/tests/federation/test_serializers.py b/api/tests/federation/test_serializers.py index 6872947f7f26e1421b30fa47c77a5d9b69ab74db..ad9ede5f44d866493e3b5ca87c05519c91b50360 100644 --- a/api/tests/federation/test_serializers.py +++ b/api/tests/federation/test_serializers.py @@ -334,6 +334,7 @@ def test_paginated_collection_serializer(factories): "type": "Collection", "id": conf["id"], "actor": actor.fid, + "attributedTo": actor.fid, "totalItems": len(uploads), "current": conf["id"] + "?page=1", "last": conf["id"] + "?page=3", @@ -352,6 +353,7 @@ def test_paginated_collection_serializer_validation(): "id": "https://test.federation/test", "totalItems": 5, "actor": "http://test.actor", + "attributedTo": "http://test.actor", "first": "https://test.federation/test?page=1", "last": "https://test.federation/test?page=1", "items": [], @@ -362,7 +364,7 @@ def test_paginated_collection_serializer_validation(): assert serializer.is_valid(raise_exception=True) is True assert serializer.validated_data["totalItems"] == 5 assert serializer.validated_data["id"] == data["id"] - assert serializer.validated_data["actor"] == data["actor"] + assert serializer.validated_data["attributedTo"] == data["actor"] def test_collection_page_serializer_validation(): @@ -373,6 +375,7 @@ def test_collection_page_serializer_validation(): "id": base + "?page=2", "totalItems": 5, "actor": "https://test.actor", + "attributedTo": "https://test.actor", "items": [], "first": "https://test.federation/test?page=1", "last": "https://test.federation/test?page=3", @@ -386,7 +389,7 @@ def test_collection_page_serializer_validation(): assert serializer.is_valid(raise_exception=True) is True assert serializer.validated_data["totalItems"] == 5 assert serializer.validated_data["id"] == data["id"] - assert serializer.validated_data["actor"] == data["actor"] + assert serializer.validated_data["attributedTo"] == data["actor"] assert serializer.validated_data["items"] == [] assert serializer.validated_data["prev"] == data["prev"] assert serializer.validated_data["next"] == data["next"] @@ -398,7 +401,7 @@ def test_collection_page_serializer_can_validate_child(): "@context": jsonld.get_default_context(), "type": "CollectionPage", "id": "https://test.page?page=2", - "actor": "https://test.actor", + "attributedTo": "https://test.actor", "first": "https://test.page?page=1", "last": "https://test.page?page=3", "partOf": "https://test.page", @@ -430,6 +433,7 @@ def test_collection_page_serializer(factories): "type": "CollectionPage", "id": conf["id"] + "?page=2", "actor": actor.fid, + "attributedTo": actor.fid, "totalItems": len(uploads), "partOf": conf["id"], "prev": conf["id"] + "?page=1", @@ -464,6 +468,7 @@ def test_music_library_serializer_to_ap(factories): "name": library.name, "summary": library.description, "actor": library.actor.fid, + "attributedTo": library.actor.fid, "totalItems": 0, "current": library.fid + "?page=1", "last": library.fid + "?page=1", @@ -487,7 +492,7 @@ def test_music_library_serializer_from_public(factories, mocker): "type": "Library", "id": "https://library.id", "followers": "https://library.id/followers", - "actor": actor.fid, + "attributedTo": actor.fid, "totalItems": 12, "first": "https://library.id?page=1", "last": "https://library.id?page=2", @@ -527,7 +532,7 @@ def test_music_library_serializer_from_private(factories, mocker): "type": "Library", "id": "https://library.id", "followers": "https://library.id/followers", - "actor": actor.fid, + "attributedTo": actor.fid, "totalItems": 12, "first": "https://library.id?page=1", "last": "https://library.id?page=2", diff --git a/changes/changelog.d/619.enhancement b/changes/changelog.d/619.enhancement new file mode 100644 index 0000000000000000000000000000000000000000..16a95a641955503ad7c8325c5a526a3e5f70738c --- /dev/null +++ b/changes/changelog.d/619.enhancement @@ -0,0 +1 @@ +Use attributedTo instead of actor in library ActivityPub payload (#619) diff --git a/docs/federation/index.rst b/docs/federation/index.rst index 3123455ff43d8f23c7b7e6b1112a48969de3e2f4..70f766035fe96b49e179648cbb1989e456bd2953 100644 --- a/docs/federation/index.rst +++ b/docs/federation/index.rst @@ -585,7 +585,7 @@ Example { "type": "Library", "id": "https://awesome.music/federation/music/libraries/dc702491-f6ce-441b-9da0-cecbed08bcc6", - "actor": "https://awesome.music/federation/actors/MyNameIsTroll", + "attributedTo": "https://awesome.music/federation/actors/Alice", "name": "My awesome library", "followers": "https://awesome.music/federation/music/libraries/dc702491-f6ce-441b-9da0-cecbed08bcc6/followers", "summary": "This library is for restricted use only",