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_follow_state/2" do
233 test "updates the state of the given follow activity" do
234 user = insert(:user, is_locked: true)
235 follower = insert(:user)
237 {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user)
238 {:ok, _, _, follow_activity_two} = CommonAPI.follow(follower, user)
241 follow_activity_two.data
242 |> Map.put("state", "accept")
244 cng = Ecto.Changeset.change(follow_activity_two, data: data)
246 {:ok, follow_activity_two} = Repo.update(cng)
248 {:ok, follow_activity_two} = Utils.update_follow_state(follow_activity_two, "reject")
250 assert refresh_record(follow_activity).data["state"] == "pending"
251 assert refresh_record(follow_activity_two).data["state"] == "reject"
255 describe "update_element_in_object/3" do
256 test "updates likes" do
258 activity = insert(:note_activity)
259 object = Object.normalize(activity, fetch: false)
261 assert {:ok, updated_object} =
262 Utils.update_element_in_object(
268 assert updated_object.data["likes"] == [user.ap_id]
269 assert updated_object.data["like_count"] == 1
273 describe "add_like_to_object/2" do
274 test "add actor to likes" do
276 user2 = insert(:user)
277 object = insert(:note)
279 assert {:ok, updated_object} =
280 Utils.add_like_to_object(
281 %Activity{data: %{"actor" => user.ap_id}},
285 assert updated_object.data["likes"] == [user.ap_id]
286 assert updated_object.data["like_count"] == 1
288 assert {:ok, updated_object2} =
289 Utils.add_like_to_object(
290 %Activity{data: %{"actor" => user2.ap_id}},
294 assert updated_object2.data["likes"] == [user2.ap_id, user.ap_id]
295 assert updated_object2.data["like_count"] == 2
299 describe "remove_like_from_object/2" do
300 test "removes ap_id from likes" do
302 user2 = insert(:user)
303 object = insert(:note, data: %{"likes" => [user.ap_id, user2.ap_id], "like_count" => 2})
305 assert {:ok, updated_object} =
306 Utils.remove_like_from_object(
307 %Activity{data: %{"actor" => user.ap_id}},
311 assert updated_object.data["likes"] == [user2.ap_id]
312 assert updated_object.data["like_count"] == 1
316 describe "get_existing_like/2" do
317 test "fetches existing like" do
318 note_activity = insert(:note_activity)
319 assert object = Object.normalize(note_activity, fetch: false)
322 refute Utils.get_existing_like(user.ap_id, object)
323 {:ok, like_activity} = CommonAPI.favorite(user, note_activity.id)
325 assert ^like_activity = Utils.get_existing_like(user.ap_id, object)
329 describe "get_get_existing_announce/2" do
330 test "returns nil if announce not found" do
331 actor = insert(:user)
332 refute Utils.get_existing_announce(actor.ap_id, %{data: %{"id" => "test"}})
335 test "fetches existing announce" do
336 note_activity = insert(:note_activity)
337 assert object = Object.normalize(note_activity, fetch: false)
338 actor = insert(:user)
340 {:ok, announce} = CommonAPI.repeat(note_activity.id, actor)
341 assert Utils.get_existing_announce(actor.ap_id, object) == announce
345 describe "fetch_latest_block/2" do
346 test "fetches last block activities" do
347 user1 = insert(:user)
348 user2 = insert(:user)
350 assert {:ok, %Activity{} = _} = CommonAPI.block(user1, user2)
351 assert {:ok, %Activity{} = _} = CommonAPI.block(user1, user2)
352 assert {:ok, %Activity{} = activity} = CommonAPI.block(user1, user2)
354 assert Utils.fetch_latest_block(user1, user2) == activity
358 describe "recipient_in_message/3" do
359 test "returns true when recipient in `to`" do
360 recipient = insert(:user)
361 actor = insert(:user)
362 assert Utils.recipient_in_message(recipient, actor, %{"to" => recipient.ap_id})
364 assert Utils.recipient_in_message(
367 %{"to" => [recipient.ap_id], "cc" => ""}
371 test "returns true when recipient in `cc`" do
372 recipient = insert(:user)
373 actor = insert(:user)
374 assert Utils.recipient_in_message(recipient, actor, %{"cc" => recipient.ap_id})
376 assert Utils.recipient_in_message(
379 %{"cc" => [recipient.ap_id], "to" => ""}
383 test "returns true when recipient in `bto`" do
384 recipient = insert(:user)
385 actor = insert(:user)
386 assert Utils.recipient_in_message(recipient, actor, %{"bto" => recipient.ap_id})
388 assert Utils.recipient_in_message(
391 %{"bcc" => "", "bto" => [recipient.ap_id]}
395 test "returns true when recipient in `bcc`" do
396 recipient = insert(:user)
397 actor = insert(:user)
398 assert Utils.recipient_in_message(recipient, actor, %{"bcc" => recipient.ap_id})
400 assert Utils.recipient_in_message(
403 %{"bto" => "", "bcc" => [recipient.ap_id]}
407 test "returns true when message without addresses fields" do
408 recipient = insert(:user)
409 actor = insert(:user)
410 assert Utils.recipient_in_message(recipient, actor, %{"bccc" => recipient.ap_id})
412 assert Utils.recipient_in_message(
415 %{"btod" => "", "bccc" => [recipient.ap_id]}
419 test "returns false" do
420 recipient = insert(:user)
421 actor = insert(:user)
422 refute Utils.recipient_in_message(recipient, actor, %{"to" => "ap_id"})
426 describe "lazy_put_activity_defaults/2" do
427 test "returns map with id and published data" do
428 note_activity = insert(:note_activity)
429 object = Object.normalize(note_activity, fetch: false)
430 res = Utils.lazy_put_activity_defaults(%{"context" => object.data["id"]})
431 assert res["context"] == object.data["id"]
432 assert res["context_id"] == object.id
434 assert res["published"]
437 test "returns map with fake id and published data" do
439 "context" => "pleroma:fakecontext",
441 "id" => "pleroma:fakeid",
443 } = Utils.lazy_put_activity_defaults(%{}, true)
446 test "returns activity data with object" do
447 note_activity = insert(:note_activity)
448 object = Object.normalize(note_activity, fetch: false)
451 Utils.lazy_put_activity_defaults(%{
452 "context" => object.data["id"],
456 assert res["context"] == object.data["id"]
457 assert res["context_id"] == object.id
459 assert res["published"]
460 assert res["object"]["id"]
461 assert res["object"]["published"]
462 assert res["object"]["context"] == object.data["id"]
463 assert res["object"]["context_id"] == object.id
467 describe "make_flag_data" do
468 test "returns empty map when params is invalid" do
469 assert Utils.make_flag_data(%{}, %{}) == %{}
472 test "returns map with Flag object" do
473 reporter = insert(:user)
474 target_account = insert(:user)
475 {:ok, activity} = CommonAPI.post(target_account, %{status: "foobar"})
476 context = Utils.generate_context_id()
479 target_ap_id = target_account.ap_id
480 activity_ap_id = activity.data["id"]
483 Utils.make_flag_data(
487 account: target_account,
488 statuses: [%{"id" => activity.data["id"]}],
496 "id" => activity_ap_id,
497 "content" => content,
498 "published" => activity.object.data["published"],
500 AccountView.render("show.json", %{user: target_account, skip_visibility_check: true})
505 "content" => ^content,
506 "context" => ^context,
507 "object" => [^target_ap_id, ^note_obj],
513 describe "add_announce_to_object/2" do
514 test "adds actor to announcement" do
516 object = insert(:note)
519 insert(:note_activity,
521 "actor" => user.ap_id,
522 "cc" => [Pleroma.Constants.as_public()]
526 assert {:ok, updated_object} = Utils.add_announce_to_object(activity, object)
527 assert updated_object.data["announcements"] == [user.ap_id]
528 assert updated_object.data["announcement_count"] == 1
532 describe "remove_announce_from_object/2" do
533 test "removes actor from announcements" do
535 user2 = insert(:user)
539 data: %{"announcements" => [user.ap_id, user2.ap_id], "announcement_count" => 2}
542 activity = insert(:note_activity, data: %{"actor" => user.ap_id})
544 assert {:ok, updated_object} = Utils.remove_announce_from_object(activity, object)
545 assert updated_object.data["announcements"] == [user2.ap_id]
546 assert updated_object.data["announcement_count"] == 1
550 describe "get_cached_emoji_reactions/1" do
551 test "returns the data or an emtpy list" do
552 object = insert(:note)
553 assert Utils.get_cached_emoji_reactions(object) == []
555 object = insert(:note, data: %{"reactions" => [["x", ["lain"]]]})
556 assert Utils.get_cached_emoji_reactions(object) == [["x", ["lain"]]]
558 object = insert(:note, data: %{"reactions" => %{}})
559 assert Utils.get_cached_emoji_reactions(object) == []