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_unlike_data/3" do
106 test "returns data for unlike activity" do
108 like_activity = insert(:like_activity, data_attrs: %{"context" => "test context"})
110 object = Object.normalize(like_activity.data["object"])
112 assert Utils.make_unlike_data(user, like_activity, nil) == %{
114 "actor" => user.ap_id,
115 "object" => like_activity.data,
116 "to" => [user.follower_address, object.data["actor"]],
117 "cc" => [Pleroma.Constants.as_public()],
118 "context" => like_activity.data["context"]
121 assert Utils.make_unlike_data(user, like_activity, "9mJEZK0tky1w2xD2vY") == %{
123 "actor" => user.ap_id,
124 "object" => like_activity.data,
125 "to" => [user.follower_address, object.data["actor"]],
126 "cc" => [Pleroma.Constants.as_public()],
127 "context" => like_activity.data["context"],
128 "id" => "9mJEZK0tky1w2xD2vY"
133 describe "make_like_data" do
136 other_user = insert(:user)
137 third_user = insert(:user)
138 [user: user, other_user: other_user, third_user: third_user]
141 test "addresses actor's follower address if the activity is public", %{
143 other_user: other_user,
144 third_user: third_user
146 expected_to = Enum.sort([user.ap_id, other_user.follower_address])
147 expected_cc = Enum.sort(["https://www.w3.org/ns/activitystreams#Public", third_user.ap_id])
150 CommonAPI.post(user, %{
152 "hey @#{other_user.nickname}, @#{third_user.nickname} how about beering together this weekend?"
155 %{"to" => to, "cc" => cc} = Utils.make_like_data(other_user, activity, nil)
156 assert Enum.sort(to) == expected_to
157 assert Enum.sort(cc) == expected_cc
160 test "does not adress actor's follower address if the activity is not public", %{
162 other_user: other_user,
163 third_user: third_user
165 expected_to = Enum.sort([user.ap_id])
166 expected_cc = [third_user.ap_id]
169 CommonAPI.post(user, %{
170 "status" => "@#{other_user.nickname} @#{third_user.nickname} bought a new swimsuit!",
171 "visibility" => "private"
174 %{"to" => to, "cc" => cc} = Utils.make_like_data(other_user, activity, nil)
175 assert Enum.sort(to) == expected_to
176 assert Enum.sort(cc) == expected_cc
180 test "make_json_ld_header/0" do
181 assert Utils.make_json_ld_header() == %{
183 "https://www.w3.org/ns/activitystreams",
184 "http://localhost:4001/schemas/litepub-0.1.jsonld",
192 describe "get_existing_votes" do
193 test "fetches existing votes" do
195 other_user = insert(:user)
198 CommonAPI.post(user, %{
199 "status" => "How do I pronounce LaTeX?",
201 "options" => ["laytekh", "lahtekh", "latex"],
207 object = Object.normalize(activity)
208 {:ok, votes, object} = CommonAPI.vote(other_user, object, [0, 1])
209 assert Enum.sort(Utils.get_existing_votes(other_user.ap_id, object)) == Enum.sort(votes)
212 test "fetches only Create activities" do
214 other_user = insert(:user)
217 CommonAPI.post(user, %{
218 "status" => "Are we living in a society?",
220 "options" => ["yes", "no"],
225 object = Object.normalize(activity)
226 {:ok, [vote], object} = CommonAPI.vote(other_user, object, [0])
227 {:ok, _activity} = CommonAPI.favorite(user, activity.id)
228 [fetched_vote] = Utils.get_existing_votes(other_user.ap_id, object)
229 assert fetched_vote.id == vote.id
233 describe "update_follow_state_for_all/2" do
234 test "updates the state of all Follow activities with the same actor and object" do
235 user = insert(:user, locked: true)
236 follower = insert(:user)
238 {:ok, follow_activity} = ActivityPub.follow(follower, user)
239 {:ok, follow_activity_two} = ActivityPub.follow(follower, user)
242 follow_activity_two.data
243 |> Map.put("state", "accept")
245 cng = Ecto.Changeset.change(follow_activity_two, data: data)
247 {:ok, follow_activity_two} = Repo.update(cng)
249 {:ok, follow_activity_two} =
250 Utils.update_follow_state_for_all(follow_activity_two, "accept")
252 assert refresh_record(follow_activity).data["state"] == "accept"
253 assert refresh_record(follow_activity_two).data["state"] == "accept"
257 describe "update_follow_state/2" do
258 test "updates the state of the given follow activity" do
259 user = insert(:user, locked: true)
260 follower = insert(:user)
262 {:ok, follow_activity} = ActivityPub.follow(follower, user)
263 {:ok, follow_activity_two} = ActivityPub.follow(follower, user)
266 follow_activity_two.data
267 |> Map.put("state", "accept")
269 cng = Ecto.Changeset.change(follow_activity_two, data: data)
271 {:ok, follow_activity_two} = Repo.update(cng)
273 {:ok, follow_activity_two} = Utils.update_follow_state(follow_activity_two, "reject")
275 assert refresh_record(follow_activity).data["state"] == "pending"
276 assert refresh_record(follow_activity_two).data["state"] == "reject"
280 describe "update_element_in_object/3" do
281 test "updates likes" do
283 activity = insert(:note_activity)
284 object = Object.normalize(activity)
286 assert {:ok, updated_object} =
287 Utils.update_element_in_object(
293 assert updated_object.data["likes"] == [user.ap_id]
294 assert updated_object.data["like_count"] == 1
298 describe "add_like_to_object/2" do
299 test "add actor to likes" do
301 user2 = insert(:user)
302 object = insert(:note)
304 assert {:ok, updated_object} =
305 Utils.add_like_to_object(
306 %Activity{data: %{"actor" => user.ap_id}},
310 assert updated_object.data["likes"] == [user.ap_id]
311 assert updated_object.data["like_count"] == 1
313 assert {:ok, updated_object2} =
314 Utils.add_like_to_object(
315 %Activity{data: %{"actor" => user2.ap_id}},
319 assert updated_object2.data["likes"] == [user2.ap_id, user.ap_id]
320 assert updated_object2.data["like_count"] == 2
324 describe "remove_like_from_object/2" do
325 test "removes ap_id from likes" do
327 user2 = insert(:user)
328 object = insert(:note, data: %{"likes" => [user.ap_id, user2.ap_id], "like_count" => 2})
330 assert {:ok, updated_object} =
331 Utils.remove_like_from_object(
332 %Activity{data: %{"actor" => user.ap_id}},
336 assert updated_object.data["likes"] == [user2.ap_id]
337 assert updated_object.data["like_count"] == 1
341 describe "get_existing_like/2" do
342 test "fetches existing like" do
343 note_activity = insert(:note_activity)
344 assert object = Object.normalize(note_activity)
347 refute Utils.get_existing_like(user.ap_id, object)
348 {:ok, like_activity} = CommonAPI.favorite(user, note_activity.id)
350 assert ^like_activity = Utils.get_existing_like(user.ap_id, object)
354 describe "get_get_existing_announce/2" do
355 test "returns nil if announce not found" do
356 actor = insert(:user)
357 refute Utils.get_existing_announce(actor.ap_id, %{data: %{"id" => "test"}})
360 test "fetches existing announce" do
361 note_activity = insert(:note_activity)
362 assert object = Object.normalize(note_activity)
363 actor = insert(:user)
365 {:ok, announce, _object} = ActivityPub.announce(actor, object)
366 assert Utils.get_existing_announce(actor.ap_id, object) == announce
370 describe "fetch_latest_block/2" do
371 test "fetches last block activities" do
372 user1 = insert(:user)
373 user2 = insert(:user)
375 assert {:ok, %Activity{} = _} = ActivityPub.block(user1, user2)
376 assert {:ok, %Activity{} = _} = ActivityPub.block(user1, user2)
377 assert {:ok, %Activity{} = activity} = ActivityPub.block(user1, user2)
379 assert Utils.fetch_latest_block(user1, user2) == activity
383 describe "recipient_in_message/3" do
384 test "returns true when recipient in `to`" do
385 recipient = insert(:user)
386 actor = insert(:user)
387 assert Utils.recipient_in_message(recipient, actor, %{"to" => recipient.ap_id})
389 assert Utils.recipient_in_message(
392 %{"to" => [recipient.ap_id], "cc" => ""}
396 test "returns true when recipient in `cc`" do
397 recipient = insert(:user)
398 actor = insert(:user)
399 assert Utils.recipient_in_message(recipient, actor, %{"cc" => recipient.ap_id})
401 assert Utils.recipient_in_message(
404 %{"cc" => [recipient.ap_id], "to" => ""}
408 test "returns true when recipient in `bto`" do
409 recipient = insert(:user)
410 actor = insert(:user)
411 assert Utils.recipient_in_message(recipient, actor, %{"bto" => recipient.ap_id})
413 assert Utils.recipient_in_message(
416 %{"bcc" => "", "bto" => [recipient.ap_id]}
420 test "returns true when recipient in `bcc`" do
421 recipient = insert(:user)
422 actor = insert(:user)
423 assert Utils.recipient_in_message(recipient, actor, %{"bcc" => recipient.ap_id})
425 assert Utils.recipient_in_message(
428 %{"bto" => "", "bcc" => [recipient.ap_id]}
432 test "returns true when message without addresses fields" do
433 recipient = insert(:user)
434 actor = insert(:user)
435 assert Utils.recipient_in_message(recipient, actor, %{"bccc" => recipient.ap_id})
437 assert Utils.recipient_in_message(
440 %{"btod" => "", "bccc" => [recipient.ap_id]}
444 test "returns false" do
445 recipient = insert(:user)
446 actor = insert(:user)
447 refute Utils.recipient_in_message(recipient, actor, %{"to" => "ap_id"})
451 describe "lazy_put_activity_defaults/2" do
452 test "returns map with id and published data" do
453 note_activity = insert(:note_activity)
454 object = Object.normalize(note_activity)
455 res = Utils.lazy_put_activity_defaults(%{"context" => object.data["id"]})
456 assert res["context"] == object.data["id"]
457 assert res["context_id"] == object.id
459 assert res["published"]
462 test "returns map with fake id and published data" do
464 "context" => "pleroma:fakecontext",
466 "id" => "pleroma:fakeid",
468 } = Utils.lazy_put_activity_defaults(%{}, true)
471 test "returns activity data with object" do
472 note_activity = insert(:note_activity)
473 object = Object.normalize(note_activity)
476 Utils.lazy_put_activity_defaults(%{
477 "context" => object.data["id"],
481 assert res["context"] == object.data["id"]
482 assert res["context_id"] == object.id
484 assert res["published"]
485 assert res["object"]["id"]
486 assert res["object"]["published"]
487 assert res["object"]["context"] == object.data["id"]
488 assert res["object"]["context_id"] == object.id
492 describe "make_flag_data" do
493 test "returns empty map when params is invalid" do
494 assert Utils.make_flag_data(%{}, %{}) == %{}
497 test "returns map with Flag object" do
498 reporter = insert(:user)
499 target_account = insert(:user)
500 {:ok, activity} = CommonAPI.post(target_account, %{"status" => "foobar"})
501 context = Utils.generate_context_id()
504 target_ap_id = target_account.ap_id
505 activity_ap_id = activity.data["id"]
508 Utils.make_flag_data(
512 account: target_account,
513 statuses: [%{"id" => activity.data["id"]}],
521 "id" => activity_ap_id,
522 "content" => content,
523 "published" => activity.object.data["published"],
524 "actor" => AccountView.render("show.json", %{user: target_account})
529 "content" => ^content,
530 "context" => ^context,
531 "object" => [^target_ap_id, ^note_obj],
537 describe "add_announce_to_object/2" do
538 test "adds actor to announcement" do
540 object = insert(:note)
543 insert(:note_activity,
545 "actor" => user.ap_id,
546 "cc" => [Pleroma.Constants.as_public()]
550 assert {:ok, updated_object} = Utils.add_announce_to_object(activity, object)
551 assert updated_object.data["announcements"] == [user.ap_id]
552 assert updated_object.data["announcement_count"] == 1
556 describe "remove_announce_from_object/2" do
557 test "removes actor from announcements" do
559 user2 = insert(:user)
563 data: %{"announcements" => [user.ap_id, user2.ap_id], "announcement_count" => 2}
566 activity = insert(:note_activity, data: %{"actor" => user.ap_id})
568 assert {:ok, updated_object} = Utils.remove_announce_from_object(activity, object)
569 assert updated_object.data["announcements"] == [user2.ap_id]
570 assert updated_object.data["announcement_count"] == 1
574 describe "get_cached_emoji_reactions/1" do
575 test "returns the data or an emtpy list" do
576 object = insert(:note)
577 assert Utils.get_cached_emoji_reactions(object) == []
579 object = insert(:note, data: %{"reactions" => [["x", ["lain"]]]})
580 assert Utils.get_cached_emoji_reactions(object) == [["x", ["lain"]]]
582 object = insert(:note, data: %{"reactions" => %{}})
583 assert Utils.get_cached_emoji_reactions(object) == []