def test_get_actor(factories, r_mock): actor = factories["federation.Actor"].build() payload = serializers.ActorSerializer(actor).data r_mock.get(actor.fid, json=payload) new_actor = actors.get_actor(actor.fid) assert new_actor.pk is not None assert serializers.ActorSerializer(new_actor).data == payload
def test_get_actor(factories, r_mock, mocker): update_domain_nodeinfo = mocker.patch( "funkwhale_api.federation.tasks.update_domain_nodeinfo") actor = factories["federation.Actor"].build() payload = serializers.ActorSerializer(actor).data r_mock.get(actor.fid, json=payload) new_actor = actors.get_actor(actor.fid) assert new_actor.pk is not None assert serializers.ActorSerializer(new_actor).data == payload update_domain_nodeinfo.assert_called_once_with( domain_name=new_actor.domain_id)
def test_fetch_channel_actor_returns_channel_and_fetch_outbox( factories, r_mock, settings, mocker): obj = factories["audio.Channel"]() fetch = factories["federation.Fetch"](url=obj.actor.fid) payload = serializers.ActorSerializer(obj.actor).data fetch_collection = mocker.patch.object( tasks, "fetch_collection", return_value={"next_page": "http://outbox.url/page2"}) fetch_collection_delayed = mocker.patch.object(tasks.fetch_collection, "delay") r_mock.get(obj.fid, json=payload) tasks.fetch(fetch_id=fetch.pk) fetch.refresh_from_db() assert fetch.status == "finished" assert fetch.object == obj fetch_collection.assert_called_once_with( obj.actor.outbox_url, channel_id=obj.pk, max_pages=1, ) fetch_collection_delayed.assert_called_once_with( "http://outbox.url/page2", max_pages=settings.FEDERATION_COLLECTION_MAX_PAGES - 1, is_page=True, channel_id=obj.pk, )
def test_fetch_rel_alternate(factories, r_mock, mocker): actor = factories["federation.Actor"]() fetch = factories["federation.Fetch"](url="http://example.page") html_text = """ <html> <head> <link rel="alternate" type="application/activity+json" href="{}" /> </head> </html> """.format(actor.fid) ap_payload = serializers.ActorSerializer(actor).data init = mocker.spy(serializers.ActorSerializer, "__init__") save = mocker.spy(serializers.ActorSerializer, "save") r_mock.get(fetch.url, text=html_text) r_mock.get(actor.fid, json=ap_payload) tasks.fetch(fetch_id=fetch.pk) fetch.refresh_from_db() assert fetch.status == "finished" assert fetch.object == actor assert init.call_count == 1 assert init.call_args[0][1] == actor assert init.call_args[1]["data"] == ap_payload assert save.call_count == 1
def test_fetch_webfinger(factories, r_mock, mocker): actor = factories["federation.Actor"]() fetch = factories["federation.Fetch"]( url="webfinger://{}".format(actor.full_username)) payload = serializers.ActorSerializer(actor).data init = mocker.spy(serializers.ActorSerializer, "__init__") save = mocker.spy(serializers.ActorSerializer, "save") webfinger_payload = { "subject": "acct:{}".format(actor.full_username), "aliases": ["https://test.webfinger"], "links": [{ "rel": "self", "type": "application/activity+json", "href": actor.fid }], } webfinger_url = "https://{}/.well-known/webfinger?resource={}".format( actor.domain_id, webfinger_payload["subject"]) r_mock.get(actor.fid, json=payload) r_mock.get(webfinger_url, json=webfinger_payload) tasks.fetch(fetch_id=fetch.pk) fetch.refresh_from_db() assert fetch.status == "finished" assert fetch.object == actor assert init.call_count == 1 assert init.call_args[0][1] == actor assert init.call_args[1]["data"] == payload assert save.call_count == 1
def test_actor_serializer_only_mandatory_field_from_ap(db): payload = { "id": "https://test.federation/user", "type": "Person", "following": "https://test.federation/user/following", "followers": "https://test.federation/user/followers", "inbox": "https://test.federation/user/inbox", "outbox": "https://test.federation/user/outbox", "preferredUsername": "******", } serializer = serializers.ActorSerializer(data=payload) assert serializer.is_valid(raise_exception=True) actor = serializer.build() assert actor.fid == payload["id"] assert actor.inbox_url == payload["inbox"] assert actor.outbox_url == payload["outbox"] assert actor.followers_url == payload["followers"] assert actor.following_url == payload["following"] assert actor.preferred_username == payload["preferredUsername"] assert actor.domain == "test.federation" assert actor.type == "Person" assert actor.manually_approves_followers is None
def test_local_actor_detail(factories, api_client): user = factories["users.User"](with_actor=True) url = reverse( "federation:actors-detail", kwargs={"preferred_username": user.actor.preferred_username}, ) serializer = serializers.ActorSerializer(user.actor) response = api_client.get(url) assert response.status_code == 200 assert response.data == serializer.data
def test_service_actor_detail(factories, api_client): actor = actors.get_service_actor() url = reverse( "federation:actors-detail", kwargs={"preferred_username": actor.preferred_username}, ) serializer = serializers.ActorSerializer(actor) response = api_client.get(url) assert response.status_code == 200 assert response.data == serializer.data
def test_actor_serializer_to_ap(): expected = { "@context": [ "https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1", {}, ], "id": "https://test.federation/user", "type": "Person", "following": "https://test.federation/user/following", "followers": "https://test.federation/user/followers", "inbox": "https://test.federation/user/inbox", "outbox": "https://test.federation/user/outbox", "preferredUsername": "******", "name": "Real User", "summary": "Hello world", "manuallyApprovesFollowers": False, "publicKey": { "id": "https://test.federation/user#main-key", "owner": "https://test.federation/user", "publicKeyPem": "yolo", }, "endpoints": { "sharedInbox": "https://test.federation/inbox" }, } ac = models.Actor( fid=expected["id"], inbox_url=expected["inbox"], outbox_url=expected["outbox"], shared_inbox_url=expected["endpoints"]["sharedInbox"], followers_url=expected["followers"], following_url=expected["following"], public_key=expected["publicKey"]["publicKeyPem"], preferred_username=expected["preferredUsername"], name=expected["name"], domain="test.federation", summary=expected["summary"], type="Person", manually_approves_followers=False, ) serializer = serializers.ActorSerializer(ac) assert serializer.data == expected
def test_get_actor_refresh(factories, preferences, mocker): preferences["federation__actor_fetch_delay"] = 0 actor = factories["federation.Actor"]() payload = serializers.ActorSerializer(actor).data # actor changed their username in the meantime payload["preferredUsername"] = "******" mocker.patch("funkwhale_api.federation.actors.get_actor_data", return_value=payload) new_actor = actors.get_actor(actor.fid) assert new_actor == actor assert new_actor.last_fetch_date > actor.last_fetch_date assert new_actor.preferred_username == "New me"
def test_actor_serializer_from_ap(db): payload = { "id": "https://test.federation/user", "type": "Person", "following": "https://test.federation/user/following", "followers": "https://test.federation/user/followers", "inbox": "https://test.federation/user/inbox", "outbox": "https://test.federation/user/outbox", "preferredUsername": "******", "name": "Real User", "summary": "Hello world", "url": "https://test.federation/@user", "manuallyApprovesFollowers": False, "publicKey": { "id": "https://test.federation/user#main-key", "owner": "https://test.federation/user", "publicKeyPem": "yolo", }, "endpoints": { "sharedInbox": "https://test.federation/inbox" }, } serializer = serializers.ActorSerializer(data=payload) assert serializer.is_valid(raise_exception=True) actor = serializer.build() assert actor.fid == payload["id"] assert actor.inbox_url == payload["inbox"] assert actor.outbox_url == payload["outbox"] assert actor.shared_inbox_url == payload["endpoints"]["sharedInbox"] assert actor.followers_url == payload["followers"] assert actor.following_url == payload["following"] assert actor.public_key == payload["publicKey"]["publicKeyPem"] assert actor.preferred_username == payload["preferredUsername"] assert actor.name == payload["name"] assert actor.domain == "test.federation" assert actor.summary == payload["summary"] assert actor.type == "Person" assert actor.manually_approves_followers == payload[ "manuallyApprovesFollowers"]
def test_reel2bits_channel_from_actor_ap(db, mocker): mocker.patch("funkwhale_api.federation.tasks.update_domain_nodeinfo") payload = { "@context": [ "https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1", { "Hashtag": "as:Hashtag", "PropertyValue": "schema:PropertyValue", "artwork": "reel2bits:artwork", "featured": "toot:featured", "genre": "reel2bits:genre", "licence": "reel2bits:licence", "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", "reel2bits": "http://reel2bits.org/ns#", "schema": "http://schema.org#", "sensitive": "as:sensitive", "tags": "reel2bits:tags", "toot": "http://joinmastodon.org/ns#", "transcode_url": "reel2bits:transcode_url", "transcoded": "reel2bits:transcoded", "value": "schema:value", }, ], "endpoints": { "sharedInbox": "https://r2b.example/inbox" }, "followers": "https://r2b.example/user/anna/followers", "following": "https://r2b.example/user/anna/followings", "icon": { "type": "Image", "url": "https://r2b.example/uploads/avatars/anna/f4930.jpg", }, "id": "https://r2b.example/user/anna", "inbox": "https://r2b.example/user/anna/inbox", "manuallyApprovesFollowers": False, "name": "Anna", "outbox": "https://r2b.example/user/anna/outbox", "preferredUsername": "******", "publicKey": { "id": "https://r2b.example/user/anna#main-key", "owner": "https://r2b.example/user/anna", "publicKeyPem": "MIIBIxaeikqh", }, "type": "Person", "url": [ { "type": "Link", "mediaType": "text/html", "href": "https://r2b.example/@anna", }, { "type": "Link", "mediaType": "application/rss+xml", "href": "https://r2b.example/@anna.rss", }, ], } serializer = serializers.ActorSerializer(data=payload) assert serializer.is_valid(raise_exception=True) actor = serializer.save() assert actor.fid == payload["id"] assert actor.url == payload["url"][0]["href"] assert actor.inbox_url == payload["inbox"] assert actor.shared_inbox_url == payload["endpoints"]["sharedInbox"] assert actor.outbox_url is payload["outbox"] assert actor.following_url == payload["following"] assert actor.followers_url == payload["followers"] assert actor.followers_url == payload["followers"] assert actor.type == payload["type"] assert actor.preferred_username == payload["preferredUsername"] assert actor.name == payload["name"] assert actor.manually_approves_followers is payload[ "manuallyApprovesFollowers"] assert actor.private_key is None assert actor.public_key == payload["publicKey"]["publicKeyPem"] assert actor.domain_id == "r2b.example" channel = actor.get_channel() assert channel.attributed_to == actor assert channel.rss_url == payload["url"][1]["href"] assert channel.artist.name == actor.name assert channel.artist.attributed_to == actor
def test_pleroma_actor_from_ap(factories): payload = { "@context": [ "https://www.w3.org/ns/activitystreams", "https://test.federation/schemas/litepub-0.1.jsonld", { "@language": "und" }, ], "endpoints": { "oauthAuthorizationEndpoint": "https://test.federation/oauth/authorize", "oauthRegistrationEndpoint": "https://test.federation/api/v1/apps", "oauthTokenEndpoint": "https://test.federation/oauth/token", "sharedInbox": "https://test.federation/inbox", "uploadMedia": "https://test.federation/api/ap/upload_media", }, "followers": "https://test.federation/internal/fetch/followers", "following": "https://test.federation/internal/fetch/following", "id": "https://test.federation/internal/fetch", "inbox": "https://test.federation/internal/fetch/inbox", "invisible": True, "manuallyApprovesFollowers": False, "name": "Pleroma", "preferredUsername": "******", "publicKey": { "id": "https://test.federation/internal/fetch#main-key", "owner": "https://test.federation/internal/fetch", "publicKeyPem": "PEM", }, "summary": "An internal service actor for this Pleroma instance. No user-serviceable parts inside.", "type": "Application", "url": "https://test.federation/internal/fetch", } serializer = serializers.ActorSerializer(data=payload) assert serializer.is_valid(raise_exception=True) actor = serializer.save() assert actor.fid == payload["id"] assert actor.url == payload["url"] assert actor.inbox_url == payload["inbox"] assert actor.shared_inbox_url == payload["endpoints"]["sharedInbox"] assert actor.outbox_url is None assert actor.following_url == payload["following"] assert actor.followers_url == payload["followers"] assert actor.followers_url == payload["followers"] assert actor.type == payload["type"] assert actor.preferred_username == payload["preferredUsername"] assert actor.name == payload["name"] assert actor.summary_obj.text == payload["summary"] assert actor.summary_obj.content_type == "text/html" assert actor.fid == payload["url"] assert actor.manually_approves_followers is payload[ "manuallyApprovesFollowers"] assert actor.private_key is None assert actor.public_key == payload["publicKey"]["publicKeyPem"] assert actor.domain_id == "test.federation"
def test_local_actor_serializer_to_ap(factories): expected = { "@context": [ "https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1", {}, ], "id": "https://test.federation/user", "type": "Person", "following": "https://test.federation/user/following", "followers": "https://test.federation/user/followers", "inbox": "https://test.federation/user/inbox", "outbox": "https://test.federation/user/outbox", "preferredUsername": "******", "name": "Real User", "summary": "Hello world", "manuallyApprovesFollowers": False, "publicKey": { "id": "https://test.federation/user#main-key", "owner": "https://test.federation/user", "publicKeyPem": "yolo", }, "endpoints": { "sharedInbox": "https://test.federation/inbox" }, } ac = models.Actor.objects.create( fid=expected["id"], inbox_url=expected["inbox"], outbox_url=expected["outbox"], shared_inbox_url=expected["endpoints"]["sharedInbox"], followers_url=expected["followers"], following_url=expected["following"], public_key=expected["publicKey"]["publicKeyPem"], preferred_username=expected["preferredUsername"], name=expected["name"], domain="test.federation", summary=expected["summary"], type="Person", manually_approves_followers=False, ) user = factories["users.User"]() user.actor = ac user.save() ac.refresh_from_db() expected["icon"] = { "type": "Image", "mediaType": "image/jpeg", "url": utils.full_url(user.avatar.crop["400x400"].url), } serializer = serializers.ActorSerializer(ac) assert serializer.data == expected