Let pins federate

- save object ids on pin, instead of activity ids
- pins federation
- removed pinned_activities field from the users table
- activityPub endpoint for user pins
- pulling remote users pins
This commit is contained in:
Alexander Strizhakov 2021-02-03 16:09:28 +03:00
commit 3ec1dbd922
No known key found for this signature in database
GPG key ID: 022896A53AEF1381
38 changed files with 1127 additions and 122 deletions

39
test/fixtures/collections/featured.json vendored Normal file
View file

@ -0,0 +1,39 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://{{domain}}/schemas/litepub-0.1.jsonld",
{
"@language": "und"
}
],
"id": "https://{{domain}}/users/{{nickname}}/collections/featured",
"orderedItems": [
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://{{domain}}/schemas/litepub-0.1.jsonld",
{
"@language": "und"
}
],
"actor": "https://{{domain}}/users/{{nickname}}",
"attachment": [],
"attributedTo": "https://{{domain}}/users/{{nickname}}",
"cc": [
"https://{{domain}}/users/{{nickname}}/followers"
],
"content": "",
"id": "https://{{domain}}/objects/{{object_id}}",
"published": "2021-02-12T15:13:43.915429Z",
"sensitive": false,
"source": "",
"summary": "",
"tag": [],
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"type": "Note"
}
],
"type": "OrderedCollection"
}

41
test/fixtures/masto_pin.json vendored Normal file
View file

@ -0,0 +1,41 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"Emoji": "toot:Emoji",
"Hashtag": "as:Hashtag",
"PropertyValue": "schema:PropertyValue",
"alsoKnownAs": {
"@id": "as:alsoKnownAs",
"@type": "@id"
},
"atomUri": "ostatus:atomUri",
"conversation": "ostatus:conversation",
"featured": {
"@id": "toot:featured",
"@type": "@id"
},
"focalPoint": {
"@container": "@list",
"@id": "toot:focalPoint"
},
"inReplyToAtomUri": "ostatus:inReplyToAtomUri",
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
"movedTo": {
"@id": "as:movedTo",
"@type": "@id"
},
"ostatus": "http://ostatus.org#",
"schema": "http://schema.org#",
"sensitive": "as:sensitive",
"toot": "http://joinmastodon.org/ns#",
"value": "schema:value"
}
],
"id": "https://example.com/users/nickname/statuses/{{id}}",
"actor": "https://example.com/users/nickname",
"object": "https://example.com/users/nickname/statuses/101355175004496751",
"target": "https://example.com/users/nickname/collections/featured",
"type": "{{type}}"
}

27
test/fixtures/statuses/note.json vendored Normal file
View file

@ -0,0 +1,27 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://example.com/schemas/litepub-0.1.jsonld",
{
"@language": "und"
}
],
"actor": "https://example.com/users/{{nickname}}",
"attachment": [],
"attributedTo": "https://example.com/users/{{nickname}}",
"cc": [
"https://example.com/users/{{nickname}}/followers"
],
"content": "Content",
"context": "https://example.com/contexts/e4b180e1-7403-477f-aeb4-de57e7a3fe7f",
"conversation": "https://example.com/contexts/e4b180e1-7403-477f-aeb4-de57e7a3fe7f",
"id": "https://example.com/objects/{{object_id}}",
"published": "2019-12-15T22:00:05.279583Z",
"sensitive": false,
"summary": "",
"tag": [],
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"type": "Note"
}

View file

@ -0,0 +1,18 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
{
"ostatus": "http://ostatus.org#",
"atomUri": "ostatus:atomUri",
"inReplyToAtomUri": "ostatus:inReplyToAtomUri",
"conversation": "ostatus:conversation",
"sensitive": "as:sensitive",
"toot": "http://joinmastodon.org/ns#",
"votersCount": "toot:votersCount"
}
],
"id": "https://{{domain}}/users/{{nickname}}/collections/featured",
"type": "OrderedCollection",
"totalItems": 0,
"orderedItems": []
}

41
test/fixtures/users_mock/user.json vendored Normal file
View file

@ -0,0 +1,41 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://example.com/schemas/litepub-0.1.jsonld",
{
"@language": "und"
}
],
"attachment": [],
"endpoints": {
"oauthAuthorizationEndpoint": "https://example.com/oauth/authorize",
"oauthRegistrationEndpoint": "https://example.com/api/v1/apps",
"oauthTokenEndpoint": "https://example.com/oauth/token",
"sharedInbox": "https://example.com/inbox"
},
"followers": "https://example.com/users/{{nickname}}/followers",
"following": "https://example.com/users/{{nickname}}/following",
"icon": {
"type": "Image",
"url": "https://example.com/media/4e914f5b84e4a259a3f6c2d2edc9ab642f2ab05f3e3d9c52c81fc2d984b3d51e.jpg"
},
"id": "https://example.com/users/{{nickname}}",
"image": {
"type": "Image",
"url": "https://example.com/media/f739efddefeee49c6e67e947c4811fdc911785c16ae43da4c3684051fbf8da6a.jpg?name=f739efddefeee49c6e67e947c4811fdc911785c16ae43da4c3684051fbf8da6a.jpg"
},
"inbox": "https://example.com/users/{{nickname}}/inbox",
"manuallyApprovesFollowers": false,
"name": "{{nickname}}",
"outbox": "https://example.com/users/{{nickname}}/outbox",
"preferredUsername": "{{nickname}}",
"publicKey": {
"id": "https://example.com/users/{{nickname}}#main-key",
"owner": "https://example.com/users/{{nickname}}",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5DLtwGXNZElJyxFGfcVc\nXANhaMadj/iYYQwZjOJTV9QsbtiNBeIK54PJrYuU0/0YIdrvS1iqheX5IwXRhcwa\nhm3ZyLz7XeN9st7FBni4BmZMBtMpxAuYuu5p/jbWy13qAiYOhPreCx0wrWgm/lBD\n9mkgaxIxPooBE0S4ZWEJIDIV1Vft3AWcRUyWW1vIBK0uZzs6GYshbQZB952S0yo4\nFzI1hABGHncH8UvuFauh4EZ8tY7/X5I0pGRnDOcRN1dAht5w5yTA+6r5kebiFQjP\nIzN/eCO/a9Flrj9YGW7HDNtjSOH0A31PLRGlJtJO3yK57dnf5ppyCZGfL4emShQo\ncQIDAQAB\n-----END PUBLIC KEY-----\n\n"
},
"summary": "your friendly neighborhood pleroma developer<br>I like cute things and distributed systems, and really hate delete and redrafts",
"tag": [],
"type": "Person",
"url": "https://example.com/users/{{nickname}}"
}

View file

@ -2338,4 +2338,49 @@ defmodule Pleroma.UserTest do
assert User.active_user_count(6) == 3
assert User.active_user_count(1) == 1
end
describe "pins" do
setup do
user = insert(:user)
[user: user, object_id: object_id_from_created_activity(user)]
end
test "unique pins", %{user: user, object_id: object_id} do
assert {:ok, %{pinned_objects: %{^object_id => pinned_at1} = pins} = updated_user} =
User.add_pinned_object_id(user, object_id)
assert Enum.count(pins) == 1
assert {:ok, %{pinned_objects: %{^object_id => pinned_at2} = pins}} =
User.add_pinned_object_id(updated_user, object_id)
assert pinned_at1 == pinned_at2
assert Enum.count(pins) == 1
end
test "respects max_pinned_statuses limit", %{user: user, object_id: object_id} do
clear_config([:instance, :max_pinned_statuses], 1)
{:ok, updated} = User.add_pinned_object_id(user, object_id)
object_id2 = object_id_from_created_activity(user)
{:error, %{errors: errors}} = User.add_pinned_object_id(updated, object_id2)
assert Keyword.has_key?(errors, :pinned_objects)
end
test "remove_pinned_object_id/2", %{user: user, object_id: object_id} do
assert {:ok, updated} = User.add_pinned_object_id(user, object_id)
{:ok, after_remove} = User.remove_pinned_object_id(updated, object_id)
assert after_remove.pinned_objects == %{}
end
end
defp object_id_from_created_activity(user) do
%{id: id} = insert(:note_activity, user: user)
%{object: %{data: %{"id" => object_id}}} = Activity.get_by_id_with_object(id)
object_id
end
end

View file

@ -636,6 +636,86 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|> post("/inbox", non_create_data)
|> json_response(400)
end
test "accepts Add/Remove activities", %{conn: conn} do
object_id = "c61d6733-e256-4fe1-ab13-1e369789423f"
status =
File.read!("test/fixtures/statuses/note.json")
|> String.replace("{{nickname}}", "lain")
|> String.replace("{{object_id}}", object_id)
object_url = "https://example.com/objects/#{object_id}"
user =
File.read!("test/fixtures/users_mock/user.json")
|> String.replace("{{nickname}}", "lain")
actor = "https://example.com/users/lain"
Tesla.Mock.mock(fn
%{
method: :get,
url: ^object_url
} ->
%Tesla.Env{
status: 200,
body: status,
headers: [{"content-type", "application/activity+json"}]
}
%{
method: :get,
url: ^actor
} ->
%Tesla.Env{
status: 200,
body: user,
headers: [{"content-type", "application/activity+json"}]
}
end)
data = %{
"id" => "https://example.com/objects/d61d6733-e256-4fe1-ab13-1e369789423f",
"actor" => actor,
"object" => object_url,
"target" => "https://example.com/users/lain/collections/featured",
"type" => "Add",
"to" => [Pleroma.Constants.as_public()]
}
assert "ok" ==
conn
|> assign(:valid_signature, true)
|> put_req_header("content-type", "application/activity+json")
|> post("/inbox", data)
|> json_response(200)
ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
assert Activity.get_by_ap_id(data["id"])
user = User.get_cached_by_ap_id(data["actor"])
assert user.pinned_objects[data["object"]]
data = %{
"id" => "https://example.com/objects/d61d6733-e256-4fe1-ab13-1e369789423d",
"actor" => actor,
"object" => object_url,
"target" => "https://example.com/users/lain/collections/featured",
"type" => "Remove",
"to" => [Pleroma.Constants.as_public()]
}
assert "ok" ==
conn
|> assign(:valid_signature, true)
|> put_req_header("content-type", "application/activity+json")
|> post("/inbox", data)
|> json_response(200)
ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
user = refresh_record(user)
refute user.pinned_objects[data["object"]]
end
end
describe "/users/:nickname/inbox" do
@ -1772,4 +1852,29 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|> json_response(403)
end
end
test "pinned collection", %{conn: conn} do
clear_config([:instance, :max_pinned_statuses], 2)
user = insert(:user)
objects = insert_list(2, :note, user: user)
Enum.reduce(objects, user, fn %{data: %{"id" => object_id}}, user ->
{:ok, updated} = User.add_pinned_object_id(user, object_id)
updated
end)
%{nickname: nickname, featured_address: featured_address, pinned_objects: pinned_objects} =
refresh_record(user)
%{"id" => ^featured_address, "orderedItems" => items} =
conn
|> get("/users/#{nickname}/collections/featured")
|> json_response(200)
object_ids = Enum.map(items, & &1["id"])
assert Enum.all?(pinned_objects, fn {obj_id, _} ->
obj_id in object_ids
end)
end
end

View file

@ -235,6 +235,83 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
"url" => [%{"href" => "https://jk.nipponalba.scot/images/profile.jpg"}]
}
end
test "fetches user featured collection" do
ap_id = "https://example.com/users/lain"
featured_url = "https://example.com/users/lain/collections/featured"
user_data =
"test/fixtures/users_mock/user.json"
|> File.read!()
|> String.replace("{{nickname}}", "lain")
|> Jason.decode!()
|> Map.put("featured", featured_url)
|> Jason.encode!()
object_id = Ecto.UUID.generate()
featured_data =
"test/fixtures/collections/featured.json"
|> File.read!()
|> String.replace("{{domain}}", "example.com")
|> String.replace("{{nickname}}", "lain")
|> String.replace("{{object_id}}", object_id)
object_url = "https://example.com/objects/#{object_id}"
object_data =
"test/fixtures/statuses/note.json"
|> File.read!()
|> String.replace("{{object_id}}", object_id)
|> String.replace("{{nickname}}", "lain")
Tesla.Mock.mock(fn
%{
method: :get,
url: ^ap_id
} ->
%Tesla.Env{
status: 200,
body: user_data,
headers: [{"content-type", "application/activity+json"}]
}
%{
method: :get,
url: ^featured_url
} ->
%Tesla.Env{
status: 200,
body: featured_data,
headers: [{"content-type", "application/activity+json"}]
}
end)
Tesla.Mock.mock_global(fn
%{
method: :get,
url: ^object_url
} ->
%Tesla.Env{
status: 200,
body: object_data,
headers: [{"content-type", "application/activity+json"}]
}
end)
{:ok, user} = ActivityPub.make_user_from_ap_id(ap_id)
Process.sleep(50)
assert user.featured_address == featured_url
assert Map.has_key?(user.pinned_objects, object_url)
in_db = Pleroma.User.get_by_ap_id(ap_id)
assert in_db.featured_address == featured_url
assert Map.has_key?(user.pinned_objects, object_url)
assert %{data: %{"id" => ^object_url}} = Object.get_by_ap_id(object_url)
end
end
test "it fetches the appropriate tag-restricted posts" do

View file

@ -6,6 +6,8 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
use Oban.Testing, repo: Pleroma.Repo
use Pleroma.DataCase
require Pleroma.Constants
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.Tests.ObanHelpers
@ -106,6 +108,78 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert activity.data["target"] == new_user.ap_id
assert activity.data["type"] == "Move"
end
test "it accepts Add/Remove activities" do
user =
"test/fixtures/users_mock/user.json"
|> File.read!()
|> String.replace("{{nickname}}", "lain")
object_id = "c61d6733-e256-4fe1-ab13-1e369789423f"
object =
"test/fixtures/statuses/note.json"
|> File.read!()
|> String.replace("{{nickname}}", "lain")
|> String.replace("{{object_id}}", object_id)
object_url = "https://example.com/objects/#{object_id}"
actor = "https://example.com/users/lain"
Tesla.Mock.mock(fn
%{
method: :get,
url: ^actor
} ->
%Tesla.Env{
status: 200,
body: user,
headers: [{"content-type", "application/activity+json"}]
}
%{
method: :get,
url: ^object_url
} ->
%Tesla.Env{
status: 200,
body: object,
headers: [{"content-type", "application/activity+json"}]
}
end)
message = %{
"id" => "https://example.com/objects/d61d6733-e256-4fe1-ab13-1e369789423f",
"actor" => actor,
"object" => object_url,
"target" => "https://example.com/users/lain/collections/featured",
"type" => "Add",
"to" => [Pleroma.Constants.as_public()],
"cc" => ["https://example.com/users/lain/followers"]
}
assert {:ok, activity} = Transmogrifier.handle_incoming(message)
assert activity.data == message
user = User.get_cached_by_ap_id(actor)
assert user.pinned_objects[object_url]
remove = %{
"id" => "http://localhost:400/objects/d61d6733-e256-4fe1-ab13-1e369789423d",
"actor" => actor,
"object" => object_url,
"target" => "http://example.com/users/lain/collections/featured",
"type" => "Remove",
"to" => [Pleroma.Constants.as_public()],
"cc" => ["https://example.com/users/lain/followers"]
}
assert {:ok, activity} = Transmogrifier.handle_incoming(remove)
assert activity.data == remove
user = refresh_record(user)
refute user.pinned_objects[object_url]
end
end
describe "prepare outgoing" do

View file

@ -827,13 +827,17 @@ defmodule Pleroma.Web.CommonAPITest do
[user: user, activity: activity]
end
test "activity not found error", %{user: user} do
assert {:error, :not_found} = CommonAPI.pin("id", user)
end
test "pin status", %{user: user, activity: activity} do
assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
id = activity.id
%{data: %{"id" => object_id}} = Object.normalize(activity)
user = refresh_record(user)
assert %User{pinned_activities: [^id]} = user
assert user.pinned_objects |> Map.keys() == [object_id]
end
test "pin poll", %{user: user} do
@ -845,10 +849,11 @@ defmodule Pleroma.Web.CommonAPITest do
assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
id = activity.id
%{data: %{"id" => object_id}} = Object.normalize(activity)
user = refresh_record(user)
assert %User{pinned_activities: [^id]} = user
assert user.pinned_objects |> Map.keys() == [object_id]
end
test "unlisted statuses can be pinned", %{user: user} do
@ -859,7 +864,7 @@ defmodule Pleroma.Web.CommonAPITest do
test "only self-authored can be pinned", %{activity: activity} do
user = insert(:user)
assert {:error, "Could not pin"} = CommonAPI.pin(activity.id, user)
assert {:error, :ownership_error} = CommonAPI.pin(activity.id, user)
end
test "max pinned statuses", %{user: user, activity: activity_one} do
@ -869,8 +874,12 @@ defmodule Pleroma.Web.CommonAPITest do
user = refresh_record(user)
assert {:error, "You have already pinned the maximum number of statuses"} =
CommonAPI.pin(activity_two.id, user)
assert {:error, :pinned_statuses_limit_reached} = CommonAPI.pin(activity_two.id, user)
end
test "only public can be pinned", %{user: user} do
{:ok, activity} = CommonAPI.post(user, %{status: "private status", visibility: "private"})
{:error, :visibility_error} = CommonAPI.pin(activity.id, user)
end
test "unpin status", %{user: user, activity: activity} do
@ -884,7 +893,7 @@ defmodule Pleroma.Web.CommonAPITest do
user = refresh_record(user)
assert %User{pinned_activities: []} = user
assert user.pinned_objects == %{}
end
test "should unpin when deleting a status", %{user: user, activity: activity} do
@ -896,7 +905,40 @@ defmodule Pleroma.Web.CommonAPITest do
user = refresh_record(user)
assert %User{pinned_activities: []} = user
assert user.pinned_objects == %{}
end
test "ephemeral activity won't be deleted if was pinned", %{user: user} do
{:ok, activity} = CommonAPI.post(user, %{status: "Hello!", expires_in: 601})
assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity.id)
{:ok, _activity} = CommonAPI.pin(activity.id, user)
refute Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity.id)
user = refresh_record(user)
{:ok, _} = CommonAPI.unpin(activity.id, user)
# recreates expiration job on unpin
assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity.id)
end
test "ephemeral activity deletion job won't be deleted on pinning error", %{
user: user,
activity: activity
} do
clear_config([:instance, :max_pinned_statuses], 1)
{:ok, _activity} = CommonAPI.pin(activity.id, user)
{:ok, activity2} = CommonAPI.post(user, %{status: "another status", expires_in: 601})
assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity2.id)
user = refresh_record(user)
{:error, :pinned_statuses_limit_reached} = CommonAPI.pin(activity2.id, user)
assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity2.id)
end
end

View file

@ -1223,6 +1223,13 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|> json_response_and_validate_schema(200)
end
test "non authenticated user", %{activity: activity} do
assert build_conn()
|> put_req_header("content-type", "application/json")
|> post("/api/v1/statuses/#{activity.id}/pin")
|> json_response(403) == %{"error" => "Invalid credentials."}
end
test "/pin: returns 400 error when activity is not public", %{conn: conn, user: user} do
{:ok, dm} = CommonAPI.post(user, %{status: "test", visibility: "direct"})
@ -1231,7 +1238,18 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|> put_req_header("content-type", "application/json")
|> post("/api/v1/statuses/#{dm.id}/pin")
assert json_response_and_validate_schema(conn, 400) == %{"error" => "Could not pin"}
assert json_response_and_validate_schema(conn, 422) == %{
"error" => "Non-public status cannot be pinned"
}
end
test "pin by another user", %{activity: activity} do
%{conn: conn} = oauth_access(["write:accounts"])
assert conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/statuses/#{activity.id}/pin")
|> json_response(422) == %{"error" => "Someone else's status cannot be pinned"}
end
test "unpin status", %{conn: conn, user: user, activity: activity} do
@ -1252,13 +1270,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|> json_response_and_validate_schema(200)
end
test "/unpin: returns 400 error when activity is not exist", %{conn: conn} do
conn =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/statuses/1/unpin")
assert json_response_and_validate_schema(conn, 400) == %{"error" => "Could not unpin"}
test "/unpin: returns 404 error when activity doesn't exist", %{conn: conn} do
assert conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/statuses/1/unpin")
|> json_response_and_validate_schema(404) == %{"error" => "Record not found"}
end
test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do

View file

@ -286,7 +286,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
direct_conversation_id: nil,
thread_muted: false,
emoji_reactions: [],
parent_visible: false
parent_visible: false,
pinned_at: nil
}
}

View file

@ -27,6 +27,16 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do
body: File.read!("test/fixtures/tesla_mock/status.emelie.json")
}
%{method: :get, url: "https://mastodon.social/users/emelie/collections/featured"} ->
%Tesla.Env{
status: 200,
headers: [{"content-type", "application/activity+json"}],
body:
File.read!("test/fixtures/users_mock/masto_featured.json")
|> String.replace("{{domain}}", "mastodon.social")
|> String.replace("{{nickname}}", "emelie")
}
%{method: :get, url: "https://mastodon.social/users/emelie"} ->
%Tesla.Env{
status: 200,
@ -52,6 +62,16 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do
headers: [{"content-type", "application/activity+json"}],
body: File.read!("test/fixtures/tesla_mock/emelie.json")
}
%{method: :get, url: "https://mastodon.social/users/emelie/collections/featured"} ->
%Tesla.Env{
status: 200,
headers: [{"content-type", "application/activity+json"}],
body:
File.read!("test/fixtures/users_mock/masto_featured.json")
|> String.replace("{{domain}}", "mastodon.social")
|> String.replace("{{nickname}}", "emelie")
}
end)
response =
@ -70,6 +90,16 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do
headers: [{"content-type", "application/activity+json"}],
body: File.read!("test/fixtures/tesla_mock/emelie.json")
}
%{method: :get, url: "https://mastodon.social/users/emelie/collections/featured"} ->
%Tesla.Env{
status: 200,
headers: [{"content-type", "application/activity+json"}],
body:
File.read!("test/fixtures/users_mock/masto_featured.json")
|> String.replace("{{domain}}", "mastodon.social")
|> String.replace("{{nickname}}", "emelie")
}
end)
user = insert(:user)

View file

@ -48,13 +48,15 @@ defmodule Pleroma.Factory do
%{
ap_id: ap_id,
follower_address: ap_id <> "/followers",
following_address: ap_id <> "/following"
following_address: ap_id <> "/following",
featured_address: ap_id <> "/collections/featured"
}
else
%{
ap_id: User.ap_id(user),
follower_address: User.ap_followers(user),
following_address: User.ap_following(user)
following_address: User.ap_following(user),
featured_address: User.ap_featured_collection(user)
}
end

View file

@ -89,6 +89,18 @@ defmodule HttpRequestMock do
}}
end
def get("https://mastodon.sdf.org/users/rinpatch/collections/featured", _, _, _) do
{:ok,
%Tesla.Env{
status: 200,
body:
File.read!("test/fixtures/users_mock/masto_featured.json")
|> String.replace("{{domain}}", "mastodon.sdf.org")
|> String.replace("{{nickname}}", "rinpatch"),
headers: [{"content-type", "application/activity+json"}]
}}
end
def get("https://patch.cx/objects/tesla_mock/poll_attachment", _, _, _) do
{:ok,
%Tesla.Env{
@ -905,6 +917,17 @@ defmodule HttpRequestMock do
}}
end
def get("https://mastodon.social/users/lambadalambda/collections/featured", _, _, _) do
{:ok,
%Tesla.Env{
status: 200,
body:
File.read!("test/fixtures/users_mock/masto_featured.json")
|> String.replace("{{domain}}", "mastodon.social")
|> String.replace("{{nickname}}", "lambadalambda")
}}
end
def get("https://apfed.club/channel/indio", _, _, _) do
{:ok,
%Tesla.Env{