1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.ActivityPub.UtilsTest do
11 alias Pleroma.Web.ActivityPub.ActivityPub
12 alias Pleroma.Web.ActivityPub.Utils
13 alias Pleroma.Web.AdminAPI.AccountView
14 alias Pleroma.Web.CommonAPI
16 import Pleroma.Factory
18 require Pleroma.Constants
20 describe "fetch the latest Follow" do
21 test "fetches the latest Follow activity" do
22 %Activity{data: %{"type" => "Follow"}} = activity = insert(:follow_activity)
23 follower = User.get_cached_by_ap_id(activity.data["actor"])
24 followed = User.get_cached_by_ap_id(activity.data["object"])
26 assert activity == Utils.fetch_latest_follow(follower, followed)
30 describe "fetch the latest Block" do
31 test "fetches the latest Block activity" do
32 blocker = insert(:user)
33 blocked = insert(:user)
34 {:ok, activity} = ActivityPub.block(blocker, blocked)
36 assert activity == Utils.fetch_latest_block(blocker, blocked)
40 describe "determine_explicit_mentions()" do
41 test "works with an object that has mentions" do
46 "href" => "https://example.com/~alyssa",
47 "name" => "Alyssa P. Hacker"
52 assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"]
55 test "works with an object that does not have mentions" do
58 %{"type" => "Hashtag", "href" => "https://example.com/tag/2hu", "name" => "2hu"}
62 assert Utils.determine_explicit_mentions(object) == []
65 test "works with an object that has mentions and other tags" do
70 "href" => "https://example.com/~alyssa",
71 "name" => "Alyssa P. Hacker"
73 %{"type" => "Hashtag", "href" => "https://example.com/tag/2hu", "name" => "2hu"}
77 assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"]
80 test "works with an object that has no tags" do
83 assert Utils.determine_explicit_mentions(object) == []
86 test "works with an object that has only IR tags" do
87 object = %{"tag" => ["2hu"]}
89 assert Utils.determine_explicit_mentions(object) == []
92 test "works with an object has tags as map" do
96 "href" => "https://example.com/~alyssa",
97 "name" => "Alyssa P. Hacker"
101 assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"]
105 describe "make_like_data" do
108 other_user = insert(:user)
109 third_user = insert(:user)
110 [user: user, other_user: other_user, third_user: third_user]
113 test "addresses actor's follower address if the activity is public", %{
115 other_user: other_user,
116 third_user: third_user
118 expected_to = Enum.sort([user.ap_id, other_user.follower_address])
119 expected_cc = Enum.sort(["https://www.w3.org/ns/activitystreams#Public", third_user.ap_id])
122 CommonAPI.post(user, %{
124 "hey @#{other_user.nickname}, @#{third_user.nickname} how about beering together this weekend?"
127 %{"to" => to, "cc" => cc} = Utils.make_like_data(other_user, activity, nil)
128 assert Enum.sort(to) == expected_to
129 assert Enum.sort(cc) == expected_cc
132 test "does not adress actor's follower address if the activity is not public", %{
134 other_user: other_user,
135 third_user: third_user
137 expected_to = Enum.sort([user.ap_id])
138 expected_cc = [third_user.ap_id]
141 CommonAPI.post(user, %{
142 status: "@#{other_user.nickname} @#{third_user.nickname} bought a new swimsuit!",
143 visibility: "private"
146 %{"to" => to, "cc" => cc} = Utils.make_like_data(other_user, activity, nil)
147 assert Enum.sort(to) == expected_to
148 assert Enum.sort(cc) == expected_cc
152 test "make_json_ld_header/0" do
153 assert Utils.make_json_ld_header() == %{
155 "https://www.w3.org/ns/activitystreams",
156 "http://localhost:4001/schemas/litepub-0.1.jsonld",
164 describe "get_existing_votes" do
165 test "fetches existing votes" do
167 other_user = insert(:user)
170 CommonAPI.post(user, %{
171 status: "How do I pronounce LaTeX?",
173 options: ["laytekh", "lahtekh", "latex"],
179 object = Object.normalize(activity)
180 {:ok, votes, object} = CommonAPI.vote(other_user, object, [0, 1])
181 assert Enum.sort(Utils.get_existing_votes(other_user.ap_id, object)) == Enum.sort(votes)
184 test "fetches only Create activities" do
186 other_user = insert(:user)
189 CommonAPI.post(user, %{
190 status: "Are we living in a society?",
192 options: ["yes", "no"],
197 object = Object.normalize(activity)
198 {:ok, [vote], object} = CommonAPI.vote(other_user, object, [0])
199 {:ok, _activity} = CommonAPI.favorite(user, activity.id)
200 [fetched_vote] = Utils.get_existing_votes(other_user.ap_id, object)
201 assert fetched_vote.id == vote.id
205 describe "update_follow_state_for_all/2" do
206 test "updates the state of all Follow activities with the same actor and object" do
207 user = insert(:user, locked: true)
208 follower = insert(:user)
210 {:ok, follow_activity} = ActivityPub.follow(follower, user)
211 {:ok, follow_activity_two} = ActivityPub.follow(follower, user)
214 follow_activity_two.data
215 |> Map.put("state", "accept")
217 cng = Ecto.Changeset.change(follow_activity_two, data: data)
219 {:ok, follow_activity_two} = Repo.update(cng)
221 {:ok, follow_activity_two} =
222 Utils.update_follow_state_for_all(follow_activity_two, "accept")
224 assert refresh_record(follow_activity).data["state"] == "accept"
225 assert refresh_record(follow_activity_two).data["state"] == "accept"
229 describe "update_follow_state/2" do
230 test "updates the state of the given follow activity" do
231 user = insert(:user, locked: true)
232 follower = insert(:user)
234 {:ok, follow_activity} = ActivityPub.follow(follower, user)
235 {:ok, follow_activity_two} = ActivityPub.follow(follower, user)
238 follow_activity_two.data
239 |> Map.put("state", "accept")
241 cng = Ecto.Changeset.change(follow_activity_two, data: data)
243 {:ok, follow_activity_two} = Repo.update(cng)
245 {:ok, follow_activity_two} = Utils.update_follow_state(follow_activity_two, "reject")
247 assert refresh_record(follow_activity).data["state"] == "pending"
248 assert refresh_record(follow_activity_two).data["state"] == "reject"
252 describe "update_element_in_object/3" do
253 test "updates likes" do
255 activity = insert(:note_activity)
256 object = Object.normalize(activity)
258 assert {:ok, updated_object} =
259 Utils.update_element_in_object(
265 assert updated_object.data["likes"] == [user.ap_id]
266 assert updated_object.data["like_count"] == 1
270 describe "add_like_to_object/2" do
271 test "add actor to likes" do
273 user2 = insert(:user)
274 object = insert(:note)
276 assert {:ok, updated_object} =
277 Utils.add_like_to_object(
278 %Activity{data: %{"actor" => user.ap_id}},
282 assert updated_object.data["likes"] == [user.ap_id]
283 assert updated_object.data["like_count"] == 1
285 assert {:ok, updated_object2} =
286 Utils.add_like_to_object(
287 %Activity{data: %{"actor" => user2.ap_id}},
291 assert updated_object2.data["likes"] == [user2.ap_id, user.ap_id]
292 assert updated_object2.data["like_count"] == 2
296 describe "remove_like_from_object/2" do
297 test "removes ap_id from likes" do
299 user2 = insert(:user)
300 object = insert(:note, data: %{"likes" => [user.ap_id, user2.ap_id], "like_count" => 2})
302 assert {:ok, updated_object} =
303 Utils.remove_like_from_object(
304 %Activity{data: %{"actor" => user.ap_id}},
308 assert updated_object.data["likes"] == [user2.ap_id]
309 assert updated_object.data["like_count"] == 1
313 describe "get_existing_like/2" do
314 test "fetches existing like" do
315 note_activity = insert(:note_activity)
316 assert object = Object.normalize(note_activity)
319 refute Utils.get_existing_like(user.ap_id, object)
320 {:ok, like_activity} = CommonAPI.favorite(user, note_activity.id)
322 assert ^like_activity = Utils.get_existing_like(user.ap_id, object)
326 describe "get_get_existing_announce/2" do
327 test "returns nil if announce not found" do
328 actor = insert(:user)
329 refute Utils.get_existing_announce(actor.ap_id, %{data: %{"id" => "test"}})
332 test "fetches existing announce" do
333 note_activity = insert(:note_activity)
334 assert object = Object.normalize(note_activity)
335 actor = insert(:user)
337 {:ok, announce, _object} = ActivityPub.announce(actor, object)
338 assert Utils.get_existing_announce(actor.ap_id, object) == announce
342 describe "fetch_latest_block/2" do
343 test "fetches last block activities" do
344 user1 = insert(:user)
345 user2 = insert(:user)
347 assert {:ok, %Activity{} = _} = ActivityPub.block(user1, user2)
348 assert {:ok, %Activity{} = _} = ActivityPub.block(user1, user2)
349 assert {:ok, %Activity{} = activity} = ActivityPub.block(user1, user2)
351 assert Utils.fetch_latest_block(user1, user2) == activity
355 describe "recipient_in_message/3" do
356 test "returns true when recipient in `to`" do
357 recipient = insert(:user)
358 actor = insert(:user)
359 assert Utils.recipient_in_message(recipient, actor, %{"to" => recipient.ap_id})
361 assert Utils.recipient_in_message(
364 %{"to" => [recipient.ap_id], "cc" => ""}
368 test "returns true when recipient in `cc`" do
369 recipient = insert(:user)
370 actor = insert(:user)
371 assert Utils.recipient_in_message(recipient, actor, %{"cc" => recipient.ap_id})
373 assert Utils.recipient_in_message(
376 %{"cc" => [recipient.ap_id], "to" => ""}
380 test "returns true when recipient in `bto`" do
381 recipient = insert(:user)
382 actor = insert(:user)
383 assert Utils.recipient_in_message(recipient, actor, %{"bto" => recipient.ap_id})
385 assert Utils.recipient_in_message(
388 %{"bcc" => "", "bto" => [recipient.ap_id]}
392 test "returns true when recipient in `bcc`" do
393 recipient = insert(:user)
394 actor = insert(:user)
395 assert Utils.recipient_in_message(recipient, actor, %{"bcc" => recipient.ap_id})
397 assert Utils.recipient_in_message(
400 %{"bto" => "", "bcc" => [recipient.ap_id]}
404 test "returns true when message without addresses fields" do
405 recipient = insert(:user)
406 actor = insert(:user)
407 assert Utils.recipient_in_message(recipient, actor, %{"bccc" => recipient.ap_id})
409 assert Utils.recipient_in_message(
412 %{"btod" => "", "bccc" => [recipient.ap_id]}
416 test "returns false" do
417 recipient = insert(:user)
418 actor = insert(:user)
419 refute Utils.recipient_in_message(recipient, actor, %{"to" => "ap_id"})
423 describe "lazy_put_activity_defaults/2" do
424 test "returns map with id and published data" do
425 note_activity = insert(:note_activity)
426 object = Object.normalize(note_activity)
427 res = Utils.lazy_put_activity_defaults(%{"context" => object.data["id"]})
428 assert res["context"] == object.data["id"]
429 assert res["context_id"] == object.id
431 assert res["published"]
434 test "returns map with fake id and published data" do
436 "context" => "pleroma:fakecontext",
438 "id" => "pleroma:fakeid",
440 } = Utils.lazy_put_activity_defaults(%{}, true)
443 test "returns activity data with object" do
444 note_activity = insert(:note_activity)
445 object = Object.normalize(note_activity)
448 Utils.lazy_put_activity_defaults(%{
449 "context" => object.data["id"],
453 assert res["context"] == object.data["id"]
454 assert res["context_id"] == object.id
456 assert res["published"]
457 assert res["object"]["id"]
458 assert res["object"]["published"]
459 assert res["object"]["context"] == object.data["id"]
460 assert res["object"]["context_id"] == object.id
464 describe "make_flag_data" do
465 test "returns empty map when params is invalid" do
466 assert Utils.make_flag_data(%{}, %{}) == %{}
469 test "returns map with Flag object" do
470 reporter = insert(:user)
471 target_account = insert(:user)
472 {:ok, activity} = CommonAPI.post(target_account, %{status: "foobar"})
473 context = Utils.generate_context_id()
476 target_ap_id = target_account.ap_id
477 activity_ap_id = activity.data["id"]
480 Utils.make_flag_data(
484 account: target_account,
485 statuses: [%{"id" => activity.data["id"]}],
493 "id" => activity_ap_id,
494 "content" => content,
495 "published" => activity.object.data["published"],
496 "actor" => AccountView.render("show.json", %{user: target_account})
501 "content" => ^content,
502 "context" => ^context,
503 "object" => [^target_ap_id, ^note_obj],
509 describe "add_announce_to_object/2" do
510 test "adds actor to announcement" do
512 object = insert(:note)
515 insert(:note_activity,
517 "actor" => user.ap_id,
518 "cc" => [Pleroma.Constants.as_public()]
522 assert {:ok, updated_object} = Utils.add_announce_to_object(activity, object)
523 assert updated_object.data["announcements"] == [user.ap_id]
524 assert updated_object.data["announcement_count"] == 1
528 describe "remove_announce_from_object/2" do
529 test "removes actor from announcements" do
531 user2 = insert(:user)
535 data: %{"announcements" => [user.ap_id, user2.ap_id], "announcement_count" => 2}
538 activity = insert(:note_activity, data: %{"actor" => user.ap_id})
540 assert {:ok, updated_object} = Utils.remove_announce_from_object(activity, object)
541 assert updated_object.data["announcements"] == [user2.ap_id]
542 assert updated_object.data["announcement_count"] == 1
546 describe "get_cached_emoji_reactions/1" do
547 test "returns the data or an emtpy list" do
548 object = insert(:note)
549 assert Utils.get_cached_emoji_reactions(object) == []
551 object = insert(:note, data: %{"reactions" => [["x", ["lain"]]]})
552 assert Utils.get_cached_emoji_reactions(object) == [["x", ["lain"]]]
554 object = insert(:note, data: %{"reactions" => %{}})
555 assert Utils.get_cached_emoji_reactions(object) == []