1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
6 use Oban.Testing, repo: Pleroma.Repo
11 alias Pleroma.Chat.MessageReference
12 alias Pleroma.Notification
15 alias Pleroma.Tests.ObanHelpers
17 alias Pleroma.Web.ActivityPub.ActivityPub
18 alias Pleroma.Web.ActivityPub.Builder
19 alias Pleroma.Web.ActivityPub.SideEffects
20 alias Pleroma.Web.ActivityPub.Utils
21 alias Pleroma.Web.CommonAPI
22 alias Pleroma.Web.CommonAPI.ActivityDraft
25 import Pleroma.Factory
27 defp get_announces_of_object(%{data: %{"id" => id}} = _object) do
28 Pleroma.Activity.Queries.by_type("Announce")
29 |> Pleroma.Activity.Queries.by_object_id(id)
33 describe "handle_after_transaction" do
34 test "it streams out notifications and streams" do
35 author = insert(:user, local: true)
36 recipient = insert(:user, local: true)
38 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
40 {:ok, create_activity_data, _meta} =
41 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
43 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
45 {:ok, _create_activity, meta} =
46 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
48 assert [notification] = meta[:notifications]
55 stream: fn _, _ -> nil end
66 SideEffects.handle_after_transaction(meta)
68 assert called(Pleroma.Web.Streamer.stream(["user", "user:notification"], notification))
69 assert called(Pleroma.Web.Streamer.stream(["user", "user:pleroma_chat"], :_))
70 assert called(Pleroma.Web.Push.send(notification))
75 describe "blocking users" do
78 blocked = insert(:user)
79 User.follow(blocked, user)
80 User.follow(user, blocked)
82 {:ok, block_data, []} = Builder.block(user, blocked)
83 {:ok, block, _meta} = ActivityPub.persist(block_data, local: true)
85 %{user: user, blocked: blocked, block: block}
88 test "it unfollows and blocks", %{user: user, blocked: blocked, block: block} do
89 assert User.following?(user, blocked)
90 assert User.following?(blocked, user)
92 {:ok, _, _} = SideEffects.handle(block)
94 refute User.following?(user, blocked)
95 refute User.following?(blocked, user)
96 assert User.blocks?(user, blocked)
99 test "it updates following relationship", %{user: user, blocked: blocked, block: block} do
100 {:ok, _, _} = SideEffects.handle(block)
102 refute Pleroma.FollowingRelationship.get(user, blocked)
103 assert User.get_follow_state(user, blocked) == nil
104 assert User.get_follow_state(blocked, user) == nil
105 assert User.get_follow_state(user, blocked, nil) == nil
106 assert User.get_follow_state(blocked, user, nil) == nil
109 test "it blocks but does not unfollow if the relevant setting is set", %{
114 clear_config([:activitypub, :unfollow_blocked], false)
115 assert User.following?(user, blocked)
116 assert User.following?(blocked, user)
118 {:ok, _, _} = SideEffects.handle(block)
120 refute User.following?(user, blocked)
121 assert User.following?(blocked, user)
122 assert User.blocks?(user, blocked)
126 describe "update users" do
128 user = insert(:user, local: false)
130 {:ok, update_data, []} =
131 Builder.update(user, %{"id" => user.ap_id, "type" => "Person", "name" => "new name!"})
133 {:ok, update, _meta} = ActivityPub.persist(update_data, local: true)
135 %{user: user, update_data: update_data, update: update}
138 test "it updates the user", %{user: user, update: update} do
139 {:ok, _, _} = SideEffects.handle(update)
140 user = User.get_by_id(user.id)
141 assert user.name == "new name!"
144 test "it uses a given changeset to update", %{user: user, update: update} do
145 changeset = Ecto.Changeset.change(user, %{default_scope: "direct"})
147 assert user.default_scope == "public"
148 {:ok, _, _} = SideEffects.handle(update, user_update_changeset: changeset)
149 user = User.get_by_id(user.id)
150 assert user.default_scope == "direct"
154 describe "update notes" do
157 Pleroma.Web.ActivityPub.Utils.make_date()
161 note = insert(:note, user: user, data: %{"published" => make_time.()})
162 _note_activity = insert(:note_activity, note: note)
166 |> Map.put("summary", "edited summary")
167 |> Map.put("content", "edited content")
168 |> Map.put("updated", make_time.())
170 {:ok, update_data, []} = Builder.update(user, updated_note)
171 {:ok, update, _meta} = ActivityPub.persist(update_data, local: true)
177 update_data: update_data,
179 updated_note: updated_note
183 test "it updates the note", %{
184 object_id: object_id,
186 updated_note: updated_note
188 {:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
189 updated_time = updated_note["updated"]
191 new_note = Pleroma.Object.get_by_id(object_id)
194 "summary" => "edited summary",
195 "content" => "edited content",
196 "updated" => ^updated_time
200 test "it rejects updates with no updated attribute in object", %{
201 object_id: object_id,
203 updated_note: updated_note
205 old_note = Pleroma.Object.get_by_id(object_id)
206 updated_note = Map.drop(updated_note, ["updated"])
207 {:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
208 new_note = Pleroma.Object.get_by_id(object_id)
209 assert old_note.data == new_note.data
212 test "it rejects updates with updated attribute older than what we have in the original object",
214 object_id: object_id,
216 updated_note: updated_note
218 old_note = Pleroma.Object.get_by_id(object_id)
219 {:ok, creation_time, _} = DateTime.from_iso8601(old_note.data["published"])
222 Map.put(updated_note, "updated", DateTime.to_iso8601(DateTime.add(creation_time, -10)))
224 {:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
225 new_note = Pleroma.Object.get_by_id(object_id)
226 assert old_note.data == new_note.data
229 test "it rejects updates with updated attribute older than the last Update", %{
230 object_id: object_id,
232 updated_note: updated_note
234 old_note = Pleroma.Object.get_by_id(object_id)
235 {:ok, creation_time, _} = DateTime.from_iso8601(old_note.data["published"])
238 Map.put(updated_note, "updated", DateTime.to_iso8601(DateTime.add(creation_time, +10)))
240 {:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
242 old_note = Pleroma.Object.get_by_id(object_id)
243 {:ok, update_time, _} = DateTime.from_iso8601(old_note.data["updated"])
246 Map.put(updated_note, "updated", DateTime.to_iso8601(DateTime.add(update_time, -5)))
248 {:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
250 new_note = Pleroma.Object.get_by_id(object_id)
251 assert old_note.data == new_note.data
254 test "it updates using object_data", %{
255 object_id: object_id,
257 updated_note: updated_note
259 updated_note = Map.put(updated_note, "summary", "mew mew")
260 {:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
261 new_note = Pleroma.Object.get_by_id(object_id)
262 assert %{"summary" => "mew mew", "content" => "edited content"} = new_note.data
265 test "it records the original note in formerRepresentations", %{
267 object_id: object_id,
269 updated_note: updated_note
271 {:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
272 %{data: new_note} = Pleroma.Object.get_by_id(object_id)
273 assert %{"summary" => "edited summary", "content" => "edited content"} = new_note
275 assert [Map.drop(note.data, ["id", "formerRepresentations"])] ==
276 new_note["formerRepresentations"]["orderedItems"]
278 assert new_note["formerRepresentations"]["totalItems"] == 1
281 test "it puts the original note at the front of formerRepresentations", %{
284 object_id: object_id,
286 updated_note: updated_note
288 {:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
289 %{data: first_edit} = Pleroma.Object.get_by_id(object_id)
291 second_updated_note =
293 |> Map.put("summary", "edited summary 2")
294 |> Map.put("content", "edited content 2")
297 first_edit["updated"]
298 |> DateTime.from_iso8601()
301 |> DateTime.to_iso8601()
304 {:ok, second_update_data, []} = Builder.update(user, second_updated_note)
305 {:ok, update, _meta} = ActivityPub.persist(second_update_data, local: true)
306 {:ok, _, _} = SideEffects.handle(update, object_data: second_updated_note)
307 %{data: new_note} = Pleroma.Object.get_by_id(object_id)
308 assert %{"summary" => "edited summary 2", "content" => "edited content 2"} = new_note
310 original_version = Map.drop(note.data, ["id", "formerRepresentations"])
311 first_edit = Map.drop(first_edit, ["id", "formerRepresentations"])
313 assert [first_edit, original_version] ==
314 new_note["formerRepresentations"]["orderedItems"]
316 assert new_note["formerRepresentations"]["totalItems"] == 2
319 test "it does not prepend to formerRepresentations if no actual changes are made", %{
321 object_id: object_id,
323 updated_note: updated_note
325 {:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
326 %{data: first_edit} = Pleroma.Object.get_by_id(object_id)
332 first_edit["updated"]
333 |> DateTime.from_iso8601()
336 |> DateTime.to_iso8601()
339 {:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
340 %{data: new_note} = Pleroma.Object.get_by_id(object_id)
341 assert %{"summary" => "edited summary", "content" => "edited content"} = new_note
343 original_version = Map.drop(note.data, ["id", "formerRepresentations"])
345 assert [original_version] ==
346 new_note["formerRepresentations"]["orderedItems"]
348 assert new_note["formerRepresentations"]["totalItems"] == 1
352 describe "update questions" do
359 data: %{"published" => Pleroma.Web.ActivityPub.Utils.make_date()}
362 %{user: user, data: question.data, id: question.id}
365 test "allows updating choice count without generating edit history", %{
372 |> Enum.map(fn choice -> put_in(choice, ["replies", "totalItems"], 5) end)
376 |> Map.put("oneOf", new_choices)
377 |> Map.put("updated", Pleroma.Web.ActivityPub.Utils.make_date())
379 {:ok, update_data, []} = Builder.update(user, updated_question)
380 {:ok, update, _meta} = ActivityPub.persist(update_data, local: true)
382 {:ok, _, _} = SideEffects.handle(update, object_data: updated_question)
384 %{data: new_question} = Pleroma.Object.get_by_id(id)
386 assert [%{"replies" => %{"totalItems" => 5}}, %{"replies" => %{"totalItems" => 5}}] =
387 new_question["oneOf"]
389 refute Map.has_key?(new_question, "formerRepresentations")
392 test "allows updating choice count without updated field", %{
399 |> Enum.map(fn choice -> put_in(choice, ["replies", "totalItems"], 5) end)
403 |> Map.put("oneOf", new_choices)
405 {:ok, update_data, []} = Builder.update(user, updated_question)
406 {:ok, update, _meta} = ActivityPub.persist(update_data, local: true)
408 {:ok, _, _} = SideEffects.handle(update, object_data: updated_question)
410 %{data: new_question} = Pleroma.Object.get_by_id(id)
412 assert [%{"replies" => %{"totalItems" => 5}}, %{"replies" => %{"totalItems" => 5}}] =
413 new_question["oneOf"]
415 refute Map.has_key?(new_question, "formerRepresentations")
418 test "allows updating choice count with updated field same as the creation date", %{
425 |> Enum.map(fn choice -> put_in(choice, ["replies", "totalItems"], 5) end)
429 |> Map.put("oneOf", new_choices)
430 |> Map.put("updated", data["published"])
432 {:ok, update_data, []} = Builder.update(user, updated_question)
433 {:ok, update, _meta} = ActivityPub.persist(update_data, local: true)
435 {:ok, _, _} = SideEffects.handle(update, object_data: updated_question)
437 %{data: new_question} = Pleroma.Object.get_by_id(id)
439 assert [%{"replies" => %{"totalItems" => 5}}, %{"replies" => %{"totalItems" => 5}}] =
440 new_question["oneOf"]
442 refute Map.has_key?(new_question, "formerRepresentations")
446 describe "EmojiReact objects" do
448 poster = insert(:user)
451 {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
453 {:ok, emoji_react_data, []} = Builder.emoji_react(user, post.object, "👌")
454 {:ok, emoji_react, _meta} = ActivityPub.persist(emoji_react_data, local: true)
456 %{emoji_react: emoji_react, user: user, poster: poster}
459 test "adds the reaction to the object", %{emoji_react: emoji_react, user: user} do
460 {:ok, emoji_react, _} = SideEffects.handle(emoji_react)
461 object = Object.get_by_ap_id(emoji_react.data["object"])
463 assert object.data["reaction_count"] == 1
464 assert ["👌", [user.ap_id], nil] in object.data["reactions"]
467 test "creates a notification", %{emoji_react: emoji_react, poster: poster} do
468 {:ok, emoji_react, _} = SideEffects.handle(emoji_react)
469 assert Repo.get_by(Notification, user_id: poster.id, activity_id: emoji_react.id)
473 describe "Question objects" do
476 question = build(:question, user: user)
477 question_activity = build(:question_activity, question: question)
478 activity_data = Map.put(question_activity.data, "object", question.data["id"])
479 meta = [object_data: question.data, local: false]
481 {:ok, activity, meta} = ActivityPub.persist(activity_data, meta)
483 %{activity: activity, meta: meta}
486 test "enqueues the poll end", %{activity: activity, meta: meta} do
487 {:ok, activity, meta} = SideEffects.handle(activity, meta)
490 worker: Pleroma.Workers.PollWorker,
491 args: %{op: "poll_end", activity_id: activity.id},
492 scheduled_at: NaiveDateTime.from_iso8601!(meta[:object_data]["closed"])
497 describe "delete users with confirmation pending" do
499 user = insert(:user, is_confirmed: false)
500 {:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id)
501 {:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true)
502 {:ok, delete: delete_user, user: user}
505 test "when activation is required", %{delete: delete, user: user} do
506 clear_config([:instance, :account_activation_required], true)
507 {:ok, _, _} = SideEffects.handle(delete)
508 ObanHelpers.perform_all()
510 refute User.get_cached_by_id(user.id)
514 describe "Undo objects" do
516 poster = insert(:user)
518 {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
519 {:ok, like} = CommonAPI.favorite(user, post.id)
520 {:ok, reaction} = CommonAPI.react_with_emoji(post.id, user, "👍")
521 {:ok, announce} = CommonAPI.repeat(post.id, user)
522 {:ok, block} = CommonAPI.block(user, poster)
524 {:ok, undo_data, _meta} = Builder.undo(user, like)
525 {:ok, like_undo, _meta} = ActivityPub.persist(undo_data, local: true)
527 {:ok, undo_data, _meta} = Builder.undo(user, reaction)
528 {:ok, reaction_undo, _meta} = ActivityPub.persist(undo_data, local: true)
530 {:ok, undo_data, _meta} = Builder.undo(user, announce)
531 {:ok, announce_undo, _meta} = ActivityPub.persist(undo_data, local: true)
533 {:ok, undo_data, _meta} = Builder.undo(user, block)
534 {:ok, block_undo, _meta} = ActivityPub.persist(undo_data, local: true)
537 like_undo: like_undo,
540 reaction_undo: reaction_undo,
542 announce_undo: announce_undo,
544 block_undo: block_undo,
551 test "deletes the original block", %{
552 block_undo: block_undo,
555 {:ok, _block_undo, _meta} = SideEffects.handle(block_undo)
557 refute Activity.get_by_id(block.id)
560 test "unblocks the blocked user", %{block_undo: block_undo, block: block} do
561 blocker = User.get_by_ap_id(block.data["actor"])
562 blocked = User.get_by_ap_id(block.data["object"])
564 {:ok, _block_undo, _} = SideEffects.handle(block_undo)
565 refute User.blocks?(blocker, blocked)
568 test "an announce undo removes the announce from the object", %{
569 announce_undo: announce_undo,
572 {:ok, _announce_undo, _} = SideEffects.handle(announce_undo)
574 object = Object.get_by_ap_id(post.data["object"])
576 assert object.data["announcement_count"] == 0
577 assert object.data["announcements"] == []
580 test "deletes the original announce", %{announce_undo: announce_undo, announce: announce} do
581 {:ok, _announce_undo, _} = SideEffects.handle(announce_undo)
582 refute Activity.get_by_id(announce.id)
585 test "a reaction undo removes the reaction from the object", %{
586 reaction_undo: reaction_undo,
589 {:ok, _reaction_undo, _} = SideEffects.handle(reaction_undo)
591 object = Object.get_by_ap_id(post.data["object"])
593 assert object.data["reaction_count"] == 0
594 assert object.data["reactions"] == []
597 test "deletes the original reaction", %{reaction_undo: reaction_undo, reaction: reaction} do
598 {:ok, _reaction_undo, _} = SideEffects.handle(reaction_undo)
599 refute Activity.get_by_id(reaction.id)
602 test "a like undo removes the like from the object", %{like_undo: like_undo, post: post} do
603 {:ok, _like_undo, _} = SideEffects.handle(like_undo)
605 object = Object.get_by_ap_id(post.data["object"])
607 assert object.data["like_count"] == 0
608 assert object.data["likes"] == []
611 test "deletes the original like", %{like_undo: like_undo, like: like} do
612 {:ok, _like_undo, _} = SideEffects.handle(like_undo)
613 refute Activity.get_by_id(like.id)
617 describe "like objects" do
619 poster = insert(:user)
621 {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
623 {:ok, like_data, _meta} = Builder.like(user, post.object)
624 {:ok, like, _meta} = ActivityPub.persist(like_data, local: true)
626 %{like: like, user: user, poster: poster}
629 test "add the like to the original object", %{like: like, user: user} do
630 {:ok, like, _} = SideEffects.handle(like)
631 object = Object.get_by_ap_id(like.data["object"])
632 assert object.data["like_count"] == 1
633 assert user.ap_id in object.data["likes"]
636 test "creates a notification", %{like: like, poster: poster} do
637 {:ok, like, _} = SideEffects.handle(like)
638 assert Repo.get_by(Notification, user_id: poster.id, activity_id: like.id)
642 describe "creation of ChatMessages" do
643 test "notifies the recipient" do
644 author = insert(:user, local: false)
645 recipient = insert(:user, local: true)
647 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
649 {:ok, create_activity_data, _meta} =
650 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
652 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
654 {:ok, _create_activity, _meta} =
655 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
657 assert Repo.get_by(Notification, user_id: recipient.id, activity_id: create_activity.id)
660 test "it streams the created ChatMessage" do
661 author = insert(:user, local: true)
662 recipient = insert(:user, local: true)
664 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
666 {:ok, create_activity_data, _meta} =
667 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
669 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
671 {:ok, _create_activity, meta} =
672 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
674 assert [_, _] = meta[:streamables]
677 test "it creates a Chat and MessageReferences for the local users and bumps the unread count, except for the author" do
678 author = insert(:user, local: true)
679 recipient = insert(:user, local: true)
681 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
683 {:ok, create_activity_data, _meta} =
684 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
686 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
690 Pleroma.Web.Streamer,
693 stream: fn _, _ -> nil end
700 send: fn _ -> nil end
704 {:ok, _create_activity, meta} =
705 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
707 # The notification gets created
708 assert [notification] = meta[:notifications]
709 assert notification.activity_id == create_activity.id
711 # But it is not sent out
712 refute called(Pleroma.Web.Streamer.stream(["user", "user:notification"], notification))
713 refute called(Pleroma.Web.Push.send(notification))
715 # Same for the user chat stream
716 assert [{topics, _}, _] = meta[:streamables]
717 assert topics == ["user", "user:pleroma_chat"]
718 refute called(Pleroma.Web.Streamer.stream(["user", "user:pleroma_chat"], :_))
720 chat = Chat.get(author.id, recipient.ap_id)
722 [cm_ref] = MessageReference.for_chat_query(chat) |> Repo.all()
724 assert cm_ref.object.data["content"] == "hey"
725 assert cm_ref.unread == false
727 chat = Chat.get(recipient.id, author.ap_id)
729 [cm_ref] = MessageReference.for_chat_query(chat) |> Repo.all()
731 assert cm_ref.object.data["content"] == "hey"
732 assert cm_ref.unread == true
736 test "it creates a Chat for the local users and bumps the unread count" do
737 author = insert(:user, local: false)
738 recipient = insert(:user, local: true)
740 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
742 {:ok, create_activity_data, _meta} =
743 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
745 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
747 {:ok, _create_activity, _meta} =
748 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
750 # An object is created
751 assert Object.get_by_ap_id(chat_message_data["id"])
753 # The remote user won't get a chat
754 chat = Chat.get(author.id, recipient.ap_id)
757 # The local user will get a chat
758 chat = Chat.get(recipient.id, author.ap_id)
761 author = insert(:user, local: true)
762 recipient = insert(:user, local: true)
764 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
766 {:ok, create_activity_data, _meta} =
767 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
769 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
771 {:ok, _create_activity, _meta} =
772 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
774 # Both users are local and get the chat
775 chat = Chat.get(author.id, recipient.ap_id)
778 chat = Chat.get(recipient.id, author.ap_id)
783 describe "announce objects" do
785 poster = insert(:user)
787 {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
788 {:ok, private_post} = CommonAPI.post(poster, %{status: "hey", visibility: "private"})
790 {:ok, announce_data, _meta} = Builder.announce(user, post.object, public: true)
792 {:ok, private_announce_data, _meta} =
793 Builder.announce(user, private_post.object, public: false)
795 {:ok, relay_announce_data, _meta} =
796 Builder.announce(Pleroma.Web.ActivityPub.Relay.get_actor(), post.object, public: true)
798 {:ok, announce, _meta} = ActivityPub.persist(announce_data, local: true)
799 {:ok, private_announce, _meta} = ActivityPub.persist(private_announce_data, local: true)
800 {:ok, relay_announce, _meta} = ActivityPub.persist(relay_announce_data, local: true)
806 private_announce: private_announce,
807 relay_announce: relay_announce
811 test "adds the announce to the original object", %{announce: announce, user: user} do
812 {:ok, announce, _} = SideEffects.handle(announce)
813 object = Object.get_by_ap_id(announce.data["object"])
814 assert object.data["announcement_count"] == 1
815 assert user.ap_id in object.data["announcements"]
818 test "does not add the announce to the original object if the actor is a service actor", %{
819 relay_announce: announce
821 {:ok, announce, _} = SideEffects.handle(announce)
822 object = Object.get_by_ap_id(announce.data["object"])
823 assert object.data["announcement_count"] == nil
826 test "creates a notification", %{announce: announce, poster: poster} do
827 {:ok, announce, _} = SideEffects.handle(announce)
828 assert Repo.get_by(Notification, user_id: poster.id, activity_id: announce.id)
831 test "it streams out the announce", %{announce: announce} do
834 Pleroma.Web.Streamer,
837 stream: fn _, _ -> nil end
844 send: fn _ -> nil end
848 {:ok, announce, _} = SideEffects.handle(announce)
850 assert called(Pleroma.Web.Streamer.stream(["user", "list"], announce))
852 assert called(Pleroma.Web.Push.send(:_))
857 describe "removing a follower" do
860 followed = insert(:user)
862 {:ok, _, _, follow_activity} = CommonAPI.follow(user, followed)
864 {:ok, reject_data, []} = Builder.reject(followed, follow_activity)
865 {:ok, reject, _meta} = ActivityPub.persist(reject_data, local: true)
867 %{user: user, followed: followed, reject: reject}
870 test "", %{user: user, followed: followed, reject: reject} do
871 assert User.following?(user, followed)
872 assert Pleroma.FollowingRelationship.get(user, followed)
874 {:ok, _, _} = SideEffects.handle(reject)
876 refute User.following?(user, followed)
877 refute Pleroma.FollowingRelationship.get(user, followed)
878 assert User.get_follow_state(user, followed) == nil
879 assert User.get_follow_state(user, followed, nil) == nil
883 describe "removing a follower from remote" do
886 followed = insert(:user, local: false)
888 # Mock a local-to-remote follow
889 {:ok, follow_data, []} = Builder.follow(user, followed)
893 |> Map.put("state", "accept")
895 {:ok, follow, _meta} = ActivityPub.persist(follow_data, local: true)
896 {:ok, _, _} = SideEffects.handle(follow)
898 # Mock a remote-to-local accept
899 {:ok, accept_data, _} = Builder.accept(followed, follow)
900 {:ok, accept, _} = ActivityPub.persist(accept_data, local: false)
901 {:ok, _, _} = SideEffects.handle(accept)
903 # Mock a remote-to-local reject
904 {:ok, reject_data, []} = Builder.reject(followed, follow)
905 {:ok, reject, _meta} = ActivityPub.persist(reject_data, local: false)
907 %{user: user, followed: followed, reject: reject}
910 test "", %{user: user, followed: followed, reject: reject} do
911 assert User.following?(user, followed)
912 assert Pleroma.FollowingRelationship.get(user, followed)
914 {:ok, _, _} = SideEffects.handle(reject)
916 refute User.following?(user, followed)
917 refute Pleroma.FollowingRelationship.get(user, followed)
919 assert Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(user, followed).data["state"] ==
922 assert User.get_follow_state(user, followed) == nil
923 assert User.get_follow_state(user, followed, nil) == nil
927 describe "Group actors" do
932 nickname: "poster@example.com",
933 ap_id: "https://example.com/users/poster"
936 group = insert(:user, actor_type: "Group")
938 make_create = fn mentioned_users ->
939 mentions = mentioned_users |> Enum.map(fn u -> "@#{u.nickname}" end) |> Enum.join(" ")
940 {:ok, draft} = ActivityDraft.create(poster, %{status: "#{mentions} hey"})
942 create_activity_data =
943 Utils.make_create_data(draft.changes |> Map.put(:published, nil), %{})
944 |> put_in(["object", "id"], "https://example.com/object")
945 |> put_in(["id"], "https://example.com/activity")
947 assert Enum.all?(mentioned_users, fn u -> u.ap_id in create_activity_data["to"] end)
952 %{poster: poster, group: group, make_create: make_create}
955 test "group should boost it", %{make_create: make_create, group: group} do
956 create_activity_data = make_create.([group])
957 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
959 {:ok, _create_activity, _meta} =
960 SideEffects.handle(create_activity,
962 object_data: create_activity_data["object"]
965 object = Object.normalize(create_activity, fetch: false)
966 assert [announce] = get_announces_of_object(object)
967 assert announce.actor == group.ap_id
970 test "remote group should not boost it", %{make_create: make_create, group: group} do
972 insert(:user, actor_type: "Group", local: false, nickname: "remotegroup@example.com")
974 create_activity_data = make_create.([group, remote_group])
975 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
977 {:ok, _create_activity, _meta} =
978 SideEffects.handle(create_activity,
980 object_data: create_activity_data["object"]
983 object = Object.normalize(create_activity, fetch: false)
984 assert [announce] = get_announces_of_object(object)
985 assert announce.actor == group.ap_id
988 test "group should not boost it if group is blocking poster", %{
989 make_create: make_create,
993 {:ok, _} = CommonAPI.block(group, poster)
994 create_activity_data = make_create.([group])
995 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
997 {:ok, _create_activity, _meta} =
998 SideEffects.handle(create_activity,
1000 object_data: create_activity_data["object"]
1003 object = Object.normalize(create_activity, fetch: false)
1004 assert [] = get_announces_of_object(object)