1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.ActivityPub.UtilsTest do
6 use Pleroma.DataCase, async: true
11 alias Pleroma.Web.ActivityPub.Utils
12 alias Pleroma.Web.AdminAPI.AccountView
13 alias Pleroma.Web.CommonAPI
15 import Pleroma.Factory
17 require Pleroma.Constants
19 describe "fetch the latest Follow" do
20 test "fetches the latest Follow activity" do
21 %Activity{data: %{"type" => "Follow"}} = activity = insert(:follow_activity)
22 follower = User.get_cached_by_ap_id(activity.data["actor"])
23 followed = User.get_cached_by_ap_id(activity.data["object"])
25 assert activity == Utils.fetch_latest_follow(follower, followed)
29 describe "determine_explicit_mentions()" do
30 test "works with an object that has mentions" do
35 "href" => "https://example.com/~alyssa",
36 "name" => "Alyssa P. Hacker"
41 assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"]
44 test "works with an object that does not have mentions" do
47 %{"type" => "Hashtag", "href" => "https://example.com/tag/2hu", "name" => "2hu"}
51 assert Utils.determine_explicit_mentions(object) == []
54 test "works with an object that has mentions and other tags" do
59 "href" => "https://example.com/~alyssa",
60 "name" => "Alyssa P. Hacker"
62 %{"type" => "Hashtag", "href" => "https://example.com/tag/2hu", "name" => "2hu"}
66 assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"]
69 test "works with an object that has no tags" do
72 assert Utils.determine_explicit_mentions(object) == []
75 test "works with an object that has only IR tags" do
76 object = %{"tag" => ["2hu"]}
78 assert Utils.determine_explicit_mentions(object) == []
81 test "works with an object has tags as map" do
85 "href" => "https://example.com/~alyssa",
86 "name" => "Alyssa P. Hacker"
90 assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"]
94 describe "make_like_data" do
97 other_user = insert(:user)
98 third_user = insert(:user)
99 [user: user, other_user: other_user, third_user: third_user]
102 test "addresses actor's follower address if the activity is public", %{
104 other_user: other_user,
105 third_user: third_user
107 expected_to = Enum.sort([user.ap_id, other_user.follower_address])
108 expected_cc = Enum.sort(["https://www.w3.org/ns/activitystreams#Public", third_user.ap_id])
111 CommonAPI.post(user, %{
113 "hey @#{other_user.nickname}, @#{third_user.nickname} how about beering together this weekend?"
116 %{"to" => to, "cc" => cc} = Utils.make_like_data(other_user, activity, nil)
117 assert Enum.sort(to) == expected_to
118 assert Enum.sort(cc) == expected_cc
121 test "does not adress actor's follower address if the activity is not public", %{
123 other_user: other_user,
124 third_user: third_user
126 expected_to = Enum.sort([user.ap_id])
127 expected_cc = [third_user.ap_id]
130 CommonAPI.post(user, %{
131 status: "@#{other_user.nickname} @#{third_user.nickname} bought a new swimsuit!",
132 visibility: "private"
135 %{"to" => to, "cc" => cc} = Utils.make_like_data(other_user, activity, nil)
136 assert Enum.sort(to) == expected_to
137 assert Enum.sort(cc) == expected_cc
141 test "make_json_ld_header/0" do
142 assert Utils.make_json_ld_header() == %{
144 "https://www.w3.org/ns/activitystreams",
145 "http://localhost:4001/schemas/litepub-0.1.jsonld",
153 describe "get_existing_votes" do
154 test "fetches existing votes" do
156 other_user = insert(:user)
159 CommonAPI.post(user, %{
160 status: "How do I pronounce LaTeX?",
162 options: ["laytekh", "lahtekh", "latex"],
168 object = Object.normalize(activity, fetch: false)
169 {:ok, votes, object} = CommonAPI.vote(other_user, object, [0, 1])
170 assert Enum.sort(Utils.get_existing_votes(other_user.ap_id, object)) == Enum.sort(votes)
173 test "fetches only Create activities" do
175 other_user = insert(:user)
178 CommonAPI.post(user, %{
179 status: "Are we living in a society?",
181 options: ["yes", "no"],
186 object = Object.normalize(activity, fetch: false)
187 {:ok, [vote], object} = CommonAPI.vote(other_user, object, [0])
188 {:ok, _activity} = CommonAPI.favorite(user, activity.id)
189 [fetched_vote] = Utils.get_existing_votes(other_user.ap_id, object)
190 assert fetched_vote.id == vote.id
194 describe "update_follow_state_for_all/2" do
195 test "updates the state of all Follow activities with the same actor and object" do
196 user = insert(:user, is_locked: true)
197 follower = insert(:user)
199 {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user)
200 {:ok, _, _, follow_activity_two} = CommonAPI.follow(follower, user)
203 follow_activity_two.data
204 |> Map.put("state", "accept")
206 cng = Ecto.Changeset.change(follow_activity_two, data: data)
208 {:ok, follow_activity_two} = Repo.update(cng)
210 {:ok, follow_activity_two} =
211 Utils.update_follow_state_for_all(follow_activity_two, "accept")
213 assert refresh_record(follow_activity).data["state"] == "accept"
214 assert refresh_record(follow_activity_two).data["state"] == "accept"
217 test "also updates the state of accepted follows" do
219 follower = insert(:user)
221 {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user)
222 {:ok, _, _, follow_activity_two} = CommonAPI.follow(follower, user)
224 {:ok, follow_activity_two} =
225 Utils.update_follow_state_for_all(follow_activity_two, "reject")
227 assert refresh_record(follow_activity).data["state"] == "reject"
228 assert refresh_record(follow_activity_two).data["state"] == "reject"
232 describe "update_element_in_object/3" do
233 test "updates likes" do
235 activity = insert(:note_activity)
236 object = Object.normalize(activity, fetch: false)
238 assert {:ok, updated_object} =
239 Utils.update_element_in_object(
245 assert updated_object.data["likes"] == [user.ap_id]
246 assert updated_object.data["like_count"] == 1
250 describe "add_like_to_object/2" do
251 test "add actor to likes" do
253 user2 = insert(:user)
254 object = insert(:note)
256 assert {:ok, updated_object} =
257 Utils.add_like_to_object(
258 %Activity{data: %{"actor" => user.ap_id}},
262 assert updated_object.data["likes"] == [user.ap_id]
263 assert updated_object.data["like_count"] == 1
265 assert {:ok, updated_object2} =
266 Utils.add_like_to_object(
267 %Activity{data: %{"actor" => user2.ap_id}},
271 assert updated_object2.data["likes"] == [user2.ap_id, user.ap_id]
272 assert updated_object2.data["like_count"] == 2
276 describe "remove_like_from_object/2" do
277 test "removes ap_id from likes" do
279 user2 = insert(:user)
280 object = insert(:note, data: %{"likes" => [user.ap_id, user2.ap_id], "like_count" => 2})
282 assert {:ok, updated_object} =
283 Utils.remove_like_from_object(
284 %Activity{data: %{"actor" => user.ap_id}},
288 assert updated_object.data["likes"] == [user2.ap_id]
289 assert updated_object.data["like_count"] == 1
293 describe "get_existing_like/2" do
294 test "fetches existing like" do
295 note_activity = insert(:note_activity)
296 assert object = Object.normalize(note_activity, fetch: false)
299 refute Utils.get_existing_like(user.ap_id, object)
300 {:ok, like_activity} = CommonAPI.favorite(user, note_activity.id)
302 assert ^like_activity = Utils.get_existing_like(user.ap_id, object)
306 describe "get_get_existing_announce/2" do
307 test "returns nil if announce not found" do
308 actor = insert(:user)
309 refute Utils.get_existing_announce(actor.ap_id, %{data: %{"id" => "test"}})
312 test "fetches existing announce" do
313 note_activity = insert(:note_activity)
314 assert object = Object.normalize(note_activity, fetch: false)
315 actor = insert(:user)
317 {:ok, announce} = CommonAPI.repeat(note_activity.id, actor)
318 assert Utils.get_existing_announce(actor.ap_id, object) == announce
322 describe "fetch_latest_block/2" do
323 test "fetches last block activities" do
324 user1 = insert(:user)
325 user2 = insert(:user)
327 assert {:ok, %Activity{} = _} = CommonAPI.block(user1, user2)
328 assert {:ok, %Activity{} = _} = CommonAPI.block(user1, user2)
329 assert {:ok, %Activity{} = activity} = CommonAPI.block(user1, user2)
331 assert Utils.fetch_latest_block(user1, user2) == activity
335 describe "recipient_in_message/3" do
336 test "returns true when recipient in `to`" do
337 recipient = insert(:user)
338 actor = insert(:user)
339 assert Utils.recipient_in_message(recipient, actor, %{"to" => recipient.ap_id})
341 assert Utils.recipient_in_message(
344 %{"to" => [recipient.ap_id], "cc" => ""}
348 test "returns true when recipient in `cc`" do
349 recipient = insert(:user)
350 actor = insert(:user)
351 assert Utils.recipient_in_message(recipient, actor, %{"cc" => recipient.ap_id})
353 assert Utils.recipient_in_message(
356 %{"cc" => [recipient.ap_id], "to" => ""}
360 test "returns true when recipient in `bto`" do
361 recipient = insert(:user)
362 actor = insert(:user)
363 assert Utils.recipient_in_message(recipient, actor, %{"bto" => recipient.ap_id})
365 assert Utils.recipient_in_message(
368 %{"bcc" => "", "bto" => [recipient.ap_id]}
372 test "returns true when recipient in `bcc`" do
373 recipient = insert(:user)
374 actor = insert(:user)
375 assert Utils.recipient_in_message(recipient, actor, %{"bcc" => recipient.ap_id})
377 assert Utils.recipient_in_message(
380 %{"bto" => "", "bcc" => [recipient.ap_id]}
384 test "returns true when message without addresses fields" do
385 recipient = insert(:user)
386 actor = insert(:user)
387 assert Utils.recipient_in_message(recipient, actor, %{"bccc" => recipient.ap_id})
389 assert Utils.recipient_in_message(
392 %{"btod" => "", "bccc" => [recipient.ap_id]}
396 test "returns false" do
397 recipient = insert(:user)
398 actor = insert(:user)
399 refute Utils.recipient_in_message(recipient, actor, %{"to" => "ap_id"})
403 describe "lazy_put_activity_defaults/2" do
404 test "returns map with id and published data" do
405 note_activity = insert(:note_activity)
406 object = Object.normalize(note_activity, fetch: false)
407 res = Utils.lazy_put_activity_defaults(%{"context" => object.data["id"]})
408 assert res["context"] == object.data["id"]
410 assert res["published"]
413 test "returns map with fake id and published data" do
415 "context" => "pleroma:fakecontext",
416 "id" => "pleroma:fakeid",
418 } = Utils.lazy_put_activity_defaults(%{}, true)
421 test "returns activity data with object" do
422 note_activity = insert(:note_activity)
423 object = Object.normalize(note_activity, fetch: false)
426 Utils.lazy_put_activity_defaults(%{
427 "context" => object.data["id"],
431 assert res["context"] == object.data["id"]
433 assert res["published"]
434 assert res["object"]["id"]
435 assert res["object"]["published"]
436 assert res["object"]["context"] == object.data["id"]
440 describe "make_flag_data" do
441 test "returns empty map when params is invalid" do
442 assert Utils.make_flag_data(%{}, %{}) == %{}
445 test "returns map with Flag object" do
446 reporter = insert(:user)
447 target_account = insert(:user)
448 {:ok, activity} = CommonAPI.post(target_account, %{status: "foobar"})
449 context = Utils.generate_context_id()
452 target_ap_id = target_account.ap_id
453 activity_ap_id = activity.data["id"]
456 Utils.make_flag_data(
460 account: target_account,
461 statuses: [%{"id" => activity.data["id"]}],
469 "id" => activity_ap_id,
470 "content" => content,
471 "published" => activity.object.data["published"],
473 AccountView.render("show.json", %{user: target_account, skip_visibility_check: true})
478 "content" => ^content,
479 "context" => ^context,
480 "object" => [^target_ap_id, ^note_obj],
486 describe "add_announce_to_object/2" do
487 test "adds actor to announcement" do
489 object = insert(:note)
492 insert(:note_activity,
494 "actor" => user.ap_id,
495 "cc" => [Pleroma.Constants.as_public()]
499 assert {:ok, updated_object} = Utils.add_announce_to_object(activity, object)
500 assert updated_object.data["announcements"] == [user.ap_id]
501 assert updated_object.data["announcement_count"] == 1
505 describe "remove_announce_from_object/2" do
506 test "removes actor from announcements" do
508 user2 = insert(:user)
512 data: %{"announcements" => [user.ap_id, user2.ap_id], "announcement_count" => 2}
515 activity = insert(:note_activity, data: %{"actor" => user.ap_id})
517 assert {:ok, updated_object} = Utils.remove_announce_from_object(activity, object)
518 assert updated_object.data["announcements"] == [user2.ap_id]
519 assert updated_object.data["announcement_count"] == 1
523 describe "get_cached_emoji_reactions/1" do
524 test "returns the data or an emtpy list" do
525 object = insert(:note)
526 assert Utils.get_cached_emoji_reactions(object) == []
528 object = insert(:note, data: %{"reactions" => [["x", ["lain"]]]})
529 assert Utils.get_cached_emoji_reactions(object) == [["x", ["lain"]]]
531 object = insert(:note, data: %{"reactions" => %{}})
532 assert Utils.get_cached_emoji_reactions(object) == []