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 "determine_explicit_mentions()" do
31 test "works with an object that has mentions" do
36 "href" => "https://example.com/~alyssa",
37 "name" => "Alyssa P. Hacker"
42 assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"]
45 test "works with an object that does not have mentions" do
48 %{"type" => "Hashtag", "href" => "https://example.com/tag/2hu", "name" => "2hu"}
52 assert Utils.determine_explicit_mentions(object) == []
55 test "works with an object that has mentions and other tags" do
60 "href" => "https://example.com/~alyssa",
61 "name" => "Alyssa P. Hacker"
63 %{"type" => "Hashtag", "href" => "https://example.com/tag/2hu", "name" => "2hu"}
67 assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"]
70 test "works with an object that has no tags" do
73 assert Utils.determine_explicit_mentions(object) == []
76 test "works with an object that has only IR tags" do
77 object = %{"tag" => ["2hu"]}
79 assert Utils.determine_explicit_mentions(object) == []
82 test "works with an object has tags as map" do
86 "href" => "https://example.com/~alyssa",
87 "name" => "Alyssa P. Hacker"
91 assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"]
95 describe "make_like_data" do
98 other_user = insert(:user)
99 third_user = insert(:user)
100 [user: user, other_user: other_user, third_user: third_user]
103 test "addresses actor's follower address if the activity is public", %{
105 other_user: other_user,
106 third_user: third_user
108 expected_to = Enum.sort([user.ap_id, other_user.follower_address])
109 expected_cc = Enum.sort(["https://www.w3.org/ns/activitystreams#Public", third_user.ap_id])
112 CommonAPI.post(user, %{
114 "hey @#{other_user.nickname}, @#{third_user.nickname} how about beering together this weekend?"
117 %{"to" => to, "cc" => cc} = Utils.make_like_data(other_user, activity, nil)
118 assert Enum.sort(to) == expected_to
119 assert Enum.sort(cc) == expected_cc
122 test "does not adress actor's follower address if the activity is not public", %{
124 other_user: other_user,
125 third_user: third_user
127 expected_to = Enum.sort([user.ap_id])
128 expected_cc = [third_user.ap_id]
131 CommonAPI.post(user, %{
132 status: "@#{other_user.nickname} @#{third_user.nickname} bought a new swimsuit!",
133 visibility: "private"
136 %{"to" => to, "cc" => cc} = Utils.make_like_data(other_user, activity, nil)
137 assert Enum.sort(to) == expected_to
138 assert Enum.sort(cc) == expected_cc
142 test "make_json_ld_header/0" do
143 assert Utils.make_json_ld_header() == %{
145 "https://www.w3.org/ns/activitystreams",
146 "http://localhost:4001/schemas/litepub-0.1.jsonld",
154 describe "get_existing_votes" do
155 test "fetches existing votes" do
157 other_user = insert(:user)
160 CommonAPI.post(user, %{
161 status: "How do I pronounce LaTeX?",
163 options: ["laytekh", "lahtekh", "latex"],
169 object = Object.normalize(activity)
170 {:ok, votes, object} = CommonAPI.vote(other_user, object, [0, 1])
171 assert Enum.sort(Utils.get_existing_votes(other_user.ap_id, object)) == Enum.sort(votes)
174 test "fetches only Create activities" do
176 other_user = insert(:user)
179 CommonAPI.post(user, %{
180 status: "Are we living in a society?",
182 options: ["yes", "no"],
187 object = Object.normalize(activity)
188 {:ok, [vote], object} = CommonAPI.vote(other_user, object, [0])
189 {:ok, _activity} = CommonAPI.favorite(user, activity.id)
190 [fetched_vote] = Utils.get_existing_votes(other_user.ap_id, object)
191 assert fetched_vote.id == vote.id
195 describe "update_follow_state_for_all/2" do
196 test "updates the state of all Follow activities with the same actor and object" do
197 user = insert(:user, locked: true)
198 follower = insert(:user)
200 {:ok, follow_activity} = ActivityPub.follow(follower, user)
201 {:ok, follow_activity_two} = ActivityPub.follow(follower, user)
204 follow_activity_two.data
205 |> Map.put("state", "accept")
207 cng = Ecto.Changeset.change(follow_activity_two, data: data)
209 {:ok, follow_activity_two} = Repo.update(cng)
211 {:ok, follow_activity_two} =
212 Utils.update_follow_state_for_all(follow_activity_two, "accept")
214 assert refresh_record(follow_activity).data["state"] == "accept"
215 assert refresh_record(follow_activity_two).data["state"] == "accept"
219 describe "update_follow_state/2" do
220 test "updates the state of the given follow activity" do
221 user = insert(:user, locked: true)
222 follower = insert(:user)
224 {:ok, follow_activity} = ActivityPub.follow(follower, user)
225 {:ok, follow_activity_two} = ActivityPub.follow(follower, user)
228 follow_activity_two.data
229 |> Map.put("state", "accept")
231 cng = Ecto.Changeset.change(follow_activity_two, data: data)
233 {:ok, follow_activity_two} = Repo.update(cng)
235 {:ok, follow_activity_two} = Utils.update_follow_state(follow_activity_two, "reject")
237 assert refresh_record(follow_activity).data["state"] == "pending"
238 assert refresh_record(follow_activity_two).data["state"] == "reject"
242 describe "update_element_in_object/3" do
243 test "updates likes" do
245 activity = insert(:note_activity)
246 object = Object.normalize(activity)
248 assert {:ok, updated_object} =
249 Utils.update_element_in_object(
255 assert updated_object.data["likes"] == [user.ap_id]
256 assert updated_object.data["like_count"] == 1
260 describe "add_like_to_object/2" do
261 test "add actor to likes" do
263 user2 = insert(:user)
264 object = insert(:note)
266 assert {:ok, updated_object} =
267 Utils.add_like_to_object(
268 %Activity{data: %{"actor" => user.ap_id}},
272 assert updated_object.data["likes"] == [user.ap_id]
273 assert updated_object.data["like_count"] == 1
275 assert {:ok, updated_object2} =
276 Utils.add_like_to_object(
277 %Activity{data: %{"actor" => user2.ap_id}},
281 assert updated_object2.data["likes"] == [user2.ap_id, user.ap_id]
282 assert updated_object2.data["like_count"] == 2
286 describe "remove_like_from_object/2" do
287 test "removes ap_id from likes" do
289 user2 = insert(:user)
290 object = insert(:note, data: %{"likes" => [user.ap_id, user2.ap_id], "like_count" => 2})
292 assert {:ok, updated_object} =
293 Utils.remove_like_from_object(
294 %Activity{data: %{"actor" => user.ap_id}},
298 assert updated_object.data["likes"] == [user2.ap_id]
299 assert updated_object.data["like_count"] == 1
303 describe "get_existing_like/2" do
304 test "fetches existing like" do
305 note_activity = insert(:note_activity)
306 assert object = Object.normalize(note_activity)
309 refute Utils.get_existing_like(user.ap_id, object)
310 {:ok, like_activity} = CommonAPI.favorite(user, note_activity.id)
312 assert ^like_activity = Utils.get_existing_like(user.ap_id, object)
316 describe "get_get_existing_announce/2" do
317 test "returns nil if announce not found" do
318 actor = insert(:user)
319 refute Utils.get_existing_announce(actor.ap_id, %{data: %{"id" => "test"}})
322 test "fetches existing announce" do
323 note_activity = insert(:note_activity)
324 assert object = Object.normalize(note_activity)
325 actor = insert(:user)
327 {:ok, announce} = CommonAPI.repeat(note_activity.id, actor)
328 assert Utils.get_existing_announce(actor.ap_id, object) == announce
332 describe "fetch_latest_block/2" do
333 test "fetches last block activities" do
334 user1 = insert(:user)
335 user2 = insert(:user)
337 assert {:ok, %Activity{} = _} = CommonAPI.block(user1, user2)
338 assert {:ok, %Activity{} = _} = CommonAPI.block(user1, user2)
339 assert {:ok, %Activity{} = activity} = CommonAPI.block(user1, user2)
341 assert Utils.fetch_latest_block(user1, user2) == activity
345 describe "recipient_in_message/3" do
346 test "returns true when recipient in `to`" do
347 recipient = insert(:user)
348 actor = insert(:user)
349 assert Utils.recipient_in_message(recipient, actor, %{"to" => recipient.ap_id})
351 assert Utils.recipient_in_message(
354 %{"to" => [recipient.ap_id], "cc" => ""}
358 test "returns true when recipient in `cc`" do
359 recipient = insert(:user)
360 actor = insert(:user)
361 assert Utils.recipient_in_message(recipient, actor, %{"cc" => recipient.ap_id})
363 assert Utils.recipient_in_message(
366 %{"cc" => [recipient.ap_id], "to" => ""}
370 test "returns true when recipient in `bto`" do
371 recipient = insert(:user)
372 actor = insert(:user)
373 assert Utils.recipient_in_message(recipient, actor, %{"bto" => recipient.ap_id})
375 assert Utils.recipient_in_message(
378 %{"bcc" => "", "bto" => [recipient.ap_id]}
382 test "returns true when recipient in `bcc`" do
383 recipient = insert(:user)
384 actor = insert(:user)
385 assert Utils.recipient_in_message(recipient, actor, %{"bcc" => recipient.ap_id})
387 assert Utils.recipient_in_message(
390 %{"bto" => "", "bcc" => [recipient.ap_id]}
394 test "returns true when message without addresses fields" do
395 recipient = insert(:user)
396 actor = insert(:user)
397 assert Utils.recipient_in_message(recipient, actor, %{"bccc" => recipient.ap_id})
399 assert Utils.recipient_in_message(
402 %{"btod" => "", "bccc" => [recipient.ap_id]}
406 test "returns false" do
407 recipient = insert(:user)
408 actor = insert(:user)
409 refute Utils.recipient_in_message(recipient, actor, %{"to" => "ap_id"})
413 describe "lazy_put_activity_defaults/2" do
414 test "returns map with id and published data" do
415 note_activity = insert(:note_activity)
416 object = Object.normalize(note_activity)
417 res = Utils.lazy_put_activity_defaults(%{"context" => object.data["id"]})
418 assert res["context"] == object.data["id"]
419 assert res["context_id"] == object.id
421 assert res["published"]
424 test "returns map with fake id and published data" do
426 "context" => "pleroma:fakecontext",
428 "id" => "pleroma:fakeid",
430 } = Utils.lazy_put_activity_defaults(%{}, true)
433 test "returns activity data with object" do
434 note_activity = insert(:note_activity)
435 object = Object.normalize(note_activity)
438 Utils.lazy_put_activity_defaults(%{
439 "context" => object.data["id"],
443 assert res["context"] == object.data["id"]
444 assert res["context_id"] == object.id
446 assert res["published"]
447 assert res["object"]["id"]
448 assert res["object"]["published"]
449 assert res["object"]["context"] == object.data["id"]
450 assert res["object"]["context_id"] == object.id
454 describe "make_flag_data" do
455 test "returns empty map when params is invalid" do
456 assert Utils.make_flag_data(%{}, %{}) == %{}
459 test "returns map with Flag object" do
460 reporter = insert(:user)
461 target_account = insert(:user)
462 {:ok, activity} = CommonAPI.post(target_account, %{status: "foobar"})
463 context = Utils.generate_context_id()
466 target_ap_id = target_account.ap_id
467 activity_ap_id = activity.data["id"]
470 Utils.make_flag_data(
474 account: target_account,
475 statuses: [%{"id" => activity.data["id"]}],
483 "id" => activity_ap_id,
484 "content" => content,
485 "published" => activity.object.data["published"],
486 "actor" => AccountView.render("show.json", %{user: target_account})
491 "content" => ^content,
492 "context" => ^context,
493 "object" => [^target_ap_id, ^note_obj],
499 describe "add_announce_to_object/2" do
500 test "adds actor to announcement" do
502 object = insert(:note)
505 insert(:note_activity,
507 "actor" => user.ap_id,
508 "cc" => [Pleroma.Constants.as_public()]
512 assert {:ok, updated_object} = Utils.add_announce_to_object(activity, object)
513 assert updated_object.data["announcements"] == [user.ap_id]
514 assert updated_object.data["announcement_count"] == 1
518 describe "remove_announce_from_object/2" do
519 test "removes actor from announcements" do
521 user2 = insert(:user)
525 data: %{"announcements" => [user.ap_id, user2.ap_id], "announcement_count" => 2}
528 activity = insert(:note_activity, data: %{"actor" => user.ap_id})
530 assert {:ok, updated_object} = Utils.remove_announce_from_object(activity, object)
531 assert updated_object.data["announcements"] == [user2.ap_id]
532 assert updated_object.data["announcement_count"] == 1
536 describe "get_cached_emoji_reactions/1" do
537 test "returns the data or an emtpy list" do
538 object = insert(:note)
539 assert Utils.get_cached_emoji_reactions(object) == []
541 object = insert(:note, data: %{"reactions" => [["x", ["lain"]]]})
542 assert Utils.get_cached_emoji_reactions(object) == [["x", ["lain"]]]
544 object = insert(:note, data: %{"reactions" => %{}})
545 assert Utils.get_cached_emoji_reactions(object) == []