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 vote_object = Object.normalize(vote)
228 {:ok, _activity, _object} = ActivityPub.like(user, vote_object)
229 [fetched_vote] = Utils.get_existing_votes(other_user.ap_id, object)
230 assert fetched_vote.id == vote.id
234 describe "update_follow_state_for_all/2" do
235 test "updates the state of all Follow activities with the same actor and object" do
236 user = insert(:user, locked: true)
237 follower = insert(:user)
239 {:ok, follow_activity} = ActivityPub.follow(follower, user)
240 {:ok, follow_activity_two} = ActivityPub.follow(follower, user)
243 follow_activity_two.data
244 |> Map.put("state", "accept")
246 cng = Ecto.Changeset.change(follow_activity_two, data: data)
248 {:ok, follow_activity_two} = Repo.update(cng)
250 {:ok, follow_activity_two} =
251 Utils.update_follow_state_for_all(follow_activity_two, "accept")
253 assert refresh_record(follow_activity).data["state"] == "accept"
254 assert refresh_record(follow_activity_two).data["state"] == "accept"
258 describe "update_follow_state/2" do
259 test "updates the state of the given follow activity" do
260 user = insert(:user, locked: true)
261 follower = insert(:user)
263 {:ok, follow_activity} = ActivityPub.follow(follower, user)
264 {:ok, follow_activity_two} = ActivityPub.follow(follower, user)
267 follow_activity_two.data
268 |> Map.put("state", "accept")
270 cng = Ecto.Changeset.change(follow_activity_two, data: data)
272 {:ok, follow_activity_two} = Repo.update(cng)
274 {:ok, follow_activity_two} = Utils.update_follow_state(follow_activity_two, "reject")
276 assert refresh_record(follow_activity).data["state"] == "pending"
277 assert refresh_record(follow_activity_two).data["state"] == "reject"
281 describe "update_element_in_object/3" do
282 test "updates likes" do
284 activity = insert(:note_activity)
285 object = Object.normalize(activity)
287 assert {:ok, updated_object} =
288 Utils.update_element_in_object(
294 assert updated_object.data["likes"] == [user.ap_id]
295 assert updated_object.data["like_count"] == 1
299 describe "add_like_to_object/2" do
300 test "add actor to likes" do
302 user2 = insert(:user)
303 object = insert(:note)
305 assert {:ok, updated_object} =
306 Utils.add_like_to_object(
307 %Activity{data: %{"actor" => user.ap_id}},
311 assert updated_object.data["likes"] == [user.ap_id]
312 assert updated_object.data["like_count"] == 1
314 assert {:ok, updated_object2} =
315 Utils.add_like_to_object(
316 %Activity{data: %{"actor" => user2.ap_id}},
320 assert updated_object2.data["likes"] == [user2.ap_id, user.ap_id]
321 assert updated_object2.data["like_count"] == 2
325 describe "remove_like_from_object/2" do
326 test "removes ap_id from likes" do
328 user2 = insert(:user)
329 object = insert(:note, data: %{"likes" => [user.ap_id, user2.ap_id], "like_count" => 2})
331 assert {:ok, updated_object} =
332 Utils.remove_like_from_object(
333 %Activity{data: %{"actor" => user.ap_id}},
337 assert updated_object.data["likes"] == [user2.ap_id]
338 assert updated_object.data["like_count"] == 1
342 describe "get_existing_like/2" do
343 test "fetches existing like" do
344 note_activity = insert(:note_activity)
345 assert object = Object.normalize(note_activity)
348 refute Utils.get_existing_like(user.ap_id, object)
349 {:ok, like_activity, _object} = ActivityPub.like(user, object)
351 assert ^like_activity = Utils.get_existing_like(user.ap_id, object)
355 describe "get_get_existing_announce/2" do
356 test "returns nil if announce not found" do
357 actor = insert(:user)
358 refute Utils.get_existing_announce(actor.ap_id, %{data: %{"id" => "test"}})
361 test "fetches existing announce" do
362 note_activity = insert(:note_activity)
363 assert object = Object.normalize(note_activity)
364 actor = insert(:user)
366 {:ok, announce, _object} = ActivityPub.announce(actor, object)
367 assert Utils.get_existing_announce(actor.ap_id, object) == announce
371 describe "fetch_latest_block/2" do
372 test "fetches last block activities" do
373 user1 = insert(:user)
374 user2 = insert(:user)
376 assert {:ok, %Activity{} = _} = ActivityPub.block(user1, user2)
377 assert {:ok, %Activity{} = _} = ActivityPub.block(user1, user2)
378 assert {:ok, %Activity{} = activity} = ActivityPub.block(user1, user2)
380 assert Utils.fetch_latest_block(user1, user2) == activity
384 describe "recipient_in_message/3" do
385 test "returns true when recipient in `to`" do
386 recipient = insert(:user)
387 actor = insert(:user)
388 assert Utils.recipient_in_message(recipient, actor, %{"to" => recipient.ap_id})
390 assert Utils.recipient_in_message(
393 %{"to" => [recipient.ap_id], "cc" => ""}
397 test "returns true when recipient in `cc`" do
398 recipient = insert(:user)
399 actor = insert(:user)
400 assert Utils.recipient_in_message(recipient, actor, %{"cc" => recipient.ap_id})
402 assert Utils.recipient_in_message(
405 %{"cc" => [recipient.ap_id], "to" => ""}
409 test "returns true when recipient in `bto`" do
410 recipient = insert(:user)
411 actor = insert(:user)
412 assert Utils.recipient_in_message(recipient, actor, %{"bto" => recipient.ap_id})
414 assert Utils.recipient_in_message(
417 %{"bcc" => "", "bto" => [recipient.ap_id]}
421 test "returns true when recipient in `bcc`" do
422 recipient = insert(:user)
423 actor = insert(:user)
424 assert Utils.recipient_in_message(recipient, actor, %{"bcc" => recipient.ap_id})
426 assert Utils.recipient_in_message(
429 %{"bto" => "", "bcc" => [recipient.ap_id]}
433 test "returns true when message without addresses fields" do
434 recipient = insert(:user)
435 actor = insert(:user)
436 assert Utils.recipient_in_message(recipient, actor, %{"bccc" => recipient.ap_id})
438 assert Utils.recipient_in_message(
441 %{"btod" => "", "bccc" => [recipient.ap_id]}
445 test "returns false" do
446 recipient = insert(:user)
447 actor = insert(:user)
448 refute Utils.recipient_in_message(recipient, actor, %{"to" => "ap_id"})
452 describe "lazy_put_activity_defaults/2" do
453 test "returns map with id and published data" do
454 note_activity = insert(:note_activity)
455 object = Object.normalize(note_activity)
456 res = Utils.lazy_put_activity_defaults(%{"context" => object.data["id"]})
457 assert res["context"] == object.data["id"]
458 assert res["context_id"] == object.id
460 assert res["published"]
463 test "returns map with fake id and published data" do
465 "context" => "pleroma:fakecontext",
467 "id" => "pleroma:fakeid",
469 } = Utils.lazy_put_activity_defaults(%{}, true)
472 test "returns activity data with object" do
473 note_activity = insert(:note_activity)
474 object = Object.normalize(note_activity)
477 Utils.lazy_put_activity_defaults(%{
478 "context" => object.data["id"],
482 assert res["context"] == object.data["id"]
483 assert res["context_id"] == object.id
485 assert res["published"]
486 assert res["object"]["id"]
487 assert res["object"]["published"]
488 assert res["object"]["context"] == object.data["id"]
489 assert res["object"]["context_id"] == object.id
493 describe "make_flag_data" do
494 test "returns empty map when params is invalid" do
495 assert Utils.make_flag_data(%{}, %{}) == %{}
498 test "returns map with Flag object" do
499 reporter = insert(:user)
500 target_account = insert(:user)
501 {:ok, activity} = CommonAPI.post(target_account, %{"status" => "foobar"})
502 context = Utils.generate_context_id()
505 target_ap_id = target_account.ap_id
506 activity_ap_id = activity.data["id"]
509 Utils.make_flag_data(
513 account: target_account,
514 statuses: [%{"id" => activity.data["id"]}],
522 "id" => activity_ap_id,
523 "content" => content,
524 "published" => activity.object.data["published"],
525 "actor" => AccountView.render("show.json", %{user: target_account})
530 "content" => ^content,
531 "context" => ^context,
532 "object" => [^target_ap_id, ^note_obj],
538 describe "add_announce_to_object/2" do
539 test "adds actor to announcement" do
541 object = insert(:note)
544 insert(:note_activity,
546 "actor" => user.ap_id,
547 "cc" => [Pleroma.Constants.as_public()]
551 assert {:ok, updated_object} = Utils.add_announce_to_object(activity, object)
552 assert updated_object.data["announcements"] == [user.ap_id]
553 assert updated_object.data["announcement_count"] == 1
557 describe "remove_announce_from_object/2" do
558 test "removes actor from announcements" do
560 user2 = insert(:user)
564 data: %{"announcements" => [user.ap_id, user2.ap_id], "announcement_count" => 2}
567 activity = insert(:note_activity, data: %{"actor" => user.ap_id})
569 assert {:ok, updated_object} = Utils.remove_announce_from_object(activity, object)
570 assert updated_object.data["announcements"] == [user2.ap_id]
571 assert updated_object.data["announcement_count"] == 1
575 describe "get_cached_emoji_reactions/1" do
576 test "returns the data or an emtpy list" do
577 object = insert(:note)
578 assert Utils.get_cached_emoji_reactions(object) == []
580 object = insert(:note, data: %{"reactions" => [["x", ["lain"]]]})
581 assert Utils.get_cached_emoji_reactions(object) == [["x", ["lain"]]]
583 object = insert(:note, data: %{"reactions" => %{}})
584 assert Utils.get_cached_emoji_reactions(object) == []