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.SideEffectsTest do
6 use Oban.Testing, repo: Pleroma.Repo
11 alias Pleroma.ChatMessageReference
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.CommonAPI
22 import Pleroma.Factory
25 describe "delete objects" do
28 other_user = insert(:user)
30 {:ok, op} = CommonAPI.post(other_user, %{status: "big oof"})
31 {:ok, post} = CommonAPI.post(user, %{status: "hey", in_reply_to_id: op})
32 {:ok, favorite} = CommonAPI.favorite(user, post.id)
33 object = Object.normalize(post)
34 {:ok, delete_data, _meta} = Builder.delete(user, object.data["id"])
35 {:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id)
36 {:ok, delete, _meta} = ActivityPub.persist(delete_data, local: true)
37 {:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true)
44 delete_user: delete_user,
50 test "it handles object deletions", %{
58 with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough],
59 stream_out: fn _ -> nil end,
60 stream_out_participations: fn _, _ -> nil end do
61 {:ok, delete, _} = SideEffects.handle(delete)
62 user = User.get_cached_by_ap_id(object.data["actor"])
64 assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(delete))
65 assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out_participations(object, user))
68 object = Object.get_by_id(object.id)
69 assert object.data["type"] == "Tombstone"
70 refute Activity.get_by_id(post.id)
71 refute Activity.get_by_id(favorite.id)
73 user = User.get_by_id(user.id)
74 assert user.note_count == 0
76 object = Object.normalize(op.data["object"], false)
78 assert object.data["repliesCount"] == 0
81 test "it handles object deletions when the object itself has been pruned", %{
88 with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough],
89 stream_out: fn _ -> nil end,
90 stream_out_participations: fn _, _ -> nil end do
91 {:ok, delete, _} = SideEffects.handle(delete)
92 user = User.get_cached_by_ap_id(object.data["actor"])
94 assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(delete))
95 assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out_participations(object, user))
98 object = Object.get_by_id(object.id)
99 assert object.data["type"] == "Tombstone"
100 refute Activity.get_by_id(post.id)
102 user = User.get_by_id(user.id)
103 assert user.note_count == 0
105 object = Object.normalize(op.data["object"], false)
107 assert object.data["repliesCount"] == 0
110 test "it handles user deletions", %{delete_user: delete, user: user} do
111 {:ok, _delete, _} = SideEffects.handle(delete)
112 ObanHelpers.perform_all()
114 assert User.get_cached_by_ap_id(user.ap_id).deactivated
118 describe "EmojiReact objects" do
120 poster = insert(:user)
123 {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
125 {:ok, emoji_react_data, []} = Builder.emoji_react(user, post.object, "👌")
126 {:ok, emoji_react, _meta} = ActivityPub.persist(emoji_react_data, local: true)
128 %{emoji_react: emoji_react, user: user, poster: poster}
131 test "adds the reaction to the object", %{emoji_react: emoji_react, user: user} do
132 {:ok, emoji_react, _} = SideEffects.handle(emoji_react)
133 object = Object.get_by_ap_id(emoji_react.data["object"])
135 assert object.data["reaction_count"] == 1
136 assert ["👌", [user.ap_id]] in object.data["reactions"]
139 test "creates a notification", %{emoji_react: emoji_react, poster: poster} do
140 {:ok, emoji_react, _} = SideEffects.handle(emoji_react)
141 assert Repo.get_by(Notification, user_id: poster.id, activity_id: emoji_react.id)
145 describe "delete users with confirmation pending" do
147 user = insert(:user, confirmation_pending: true)
148 {:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id)
149 {:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true)
150 {:ok, delete: delete_user, user: user}
153 test "when activation is not required", %{delete: delete, user: user} do
154 clear_config([:instance, :account_activation_required], false)
155 {:ok, _, _} = SideEffects.handle(delete)
156 ObanHelpers.perform_all()
158 assert User.get_cached_by_id(user.id).deactivated
161 test "when activation is required", %{delete: delete, user: user} do
162 clear_config([:instance, :account_activation_required], true)
163 {:ok, _, _} = SideEffects.handle(delete)
164 ObanHelpers.perform_all()
166 refute User.get_cached_by_id(user.id)
170 describe "Undo objects" do
172 poster = insert(:user)
174 {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
175 {:ok, like} = CommonAPI.favorite(user, post.id)
176 {:ok, reaction} = CommonAPI.react_with_emoji(post.id, user, "👍")
177 {:ok, announce} = CommonAPI.repeat(post.id, user)
178 {:ok, block} = ActivityPub.block(user, poster)
179 User.block(user, poster)
181 {:ok, undo_data, _meta} = Builder.undo(user, like)
182 {:ok, like_undo, _meta} = ActivityPub.persist(undo_data, local: true)
184 {:ok, undo_data, _meta} = Builder.undo(user, reaction)
185 {:ok, reaction_undo, _meta} = ActivityPub.persist(undo_data, local: true)
187 {:ok, undo_data, _meta} = Builder.undo(user, announce)
188 {:ok, announce_undo, _meta} = ActivityPub.persist(undo_data, local: true)
190 {:ok, undo_data, _meta} = Builder.undo(user, block)
191 {:ok, block_undo, _meta} = ActivityPub.persist(undo_data, local: true)
194 like_undo: like_undo,
197 reaction_undo: reaction_undo,
199 announce_undo: announce_undo,
201 block_undo: block_undo,
208 test "deletes the original block", %{block_undo: block_undo, block: block} do
209 {:ok, _block_undo, _} = SideEffects.handle(block_undo)
210 refute Activity.get_by_id(block.id)
213 test "unblocks the blocked user", %{block_undo: block_undo, block: block} do
214 blocker = User.get_by_ap_id(block.data["actor"])
215 blocked = User.get_by_ap_id(block.data["object"])
217 {:ok, _block_undo, _} = SideEffects.handle(block_undo)
218 refute User.blocks?(blocker, blocked)
221 test "an announce undo removes the announce from the object", %{
222 announce_undo: announce_undo,
225 {:ok, _announce_undo, _} = SideEffects.handle(announce_undo)
227 object = Object.get_by_ap_id(post.data["object"])
229 assert object.data["announcement_count"] == 0
230 assert object.data["announcements"] == []
233 test "deletes the original announce", %{announce_undo: announce_undo, announce: announce} do
234 {:ok, _announce_undo, _} = SideEffects.handle(announce_undo)
235 refute Activity.get_by_id(announce.id)
238 test "a reaction undo removes the reaction from the object", %{
239 reaction_undo: reaction_undo,
242 {:ok, _reaction_undo, _} = SideEffects.handle(reaction_undo)
244 object = Object.get_by_ap_id(post.data["object"])
246 assert object.data["reaction_count"] == 0
247 assert object.data["reactions"] == []
250 test "deletes the original reaction", %{reaction_undo: reaction_undo, reaction: reaction} do
251 {:ok, _reaction_undo, _} = SideEffects.handle(reaction_undo)
252 refute Activity.get_by_id(reaction.id)
255 test "a like undo removes the like from the object", %{like_undo: like_undo, post: post} do
256 {:ok, _like_undo, _} = SideEffects.handle(like_undo)
258 object = Object.get_by_ap_id(post.data["object"])
260 assert object.data["like_count"] == 0
261 assert object.data["likes"] == []
264 test "deletes the original like", %{like_undo: like_undo, like: like} do
265 {:ok, _like_undo, _} = SideEffects.handle(like_undo)
266 refute Activity.get_by_id(like.id)
270 describe "like objects" do
272 poster = insert(:user)
274 {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
276 {:ok, like_data, _meta} = Builder.like(user, post.object)
277 {:ok, like, _meta} = ActivityPub.persist(like_data, local: true)
279 %{like: like, user: user, poster: poster}
282 test "add the like to the original object", %{like: like, user: user} do
283 {:ok, like, _} = SideEffects.handle(like)
284 object = Object.get_by_ap_id(like.data["object"])
285 assert object.data["like_count"] == 1
286 assert user.ap_id in object.data["likes"]
289 test "creates a notification", %{like: like, poster: poster} do
290 {:ok, like, _} = SideEffects.handle(like)
291 assert Repo.get_by(Notification, user_id: poster.id, activity_id: like.id)
295 describe "creation of ChatMessages" do
296 test "notifies the recipient" do
297 author = insert(:user, local: false)
298 recipient = insert(:user, local: true)
300 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
302 {:ok, create_activity_data, _meta} =
303 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
305 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
307 {:ok, _create_activity, _meta} =
308 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
310 assert Repo.get_by(Notification, user_id: recipient.id, activity_id: create_activity.id)
313 test "it streams the created ChatMessage" do
314 author = insert(:user, local: true)
315 recipient = insert(:user, local: true)
317 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
319 {:ok, create_activity_data, _meta} =
320 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
322 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
324 with_mock Pleroma.Web.Streamer, [], stream: fn _, _ -> nil end do
325 {:ok, _create_activity, _meta} =
326 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
328 object = Object.normalize(create_activity, false)
330 assert called(Pleroma.Web.Streamer.stream(["user", "user:pleroma_chat"], object))
334 test "it creates a Chat and ChatMessageReferences for the local users and bumps the unread count, except for the author" do
335 author = insert(:user, local: true)
336 recipient = insert(:user, local: true)
338 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
340 {:ok, create_activity_data, _meta} =
341 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
343 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
345 {:ok, _create_activity, _meta} =
346 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
348 chat = Chat.get(author.id, recipient.ap_id)
350 [cm_ref] = ChatMessageReference.for_chat_query(chat) |> Repo.all()
352 assert cm_ref.object.data["content"] == "hey"
353 assert cm_ref.seen == true
355 chat = Chat.get(recipient.id, author.ap_id)
357 [cm_ref] = ChatMessageReference.for_chat_query(chat) |> Repo.all()
359 assert cm_ref.object.data["content"] == "hey"
360 assert cm_ref.seen == false
363 test "it creates a Chat for the local users and bumps the unread count" do
364 author = insert(:user, local: false)
365 recipient = insert(:user, local: true)
367 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
369 {:ok, create_activity_data, _meta} =
370 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
372 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
374 {:ok, _create_activity, _meta} =
375 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
377 # An object is created
378 assert Object.get_by_ap_id(chat_message_data["id"])
380 # The remote user won't get a chat
381 chat = Chat.get(author.id, recipient.ap_id)
384 # The local user will get a chat
385 chat = Chat.get(recipient.id, author.ap_id)
388 author = insert(:user, local: true)
389 recipient = insert(:user, local: true)
391 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
393 {:ok, create_activity_data, _meta} =
394 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
396 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
398 {:ok, _create_activity, _meta} =
399 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
401 # Both users are local and get the chat
402 chat = Chat.get(author.id, recipient.ap_id)
405 chat = Chat.get(recipient.id, author.ap_id)
410 describe "announce objects" do
412 poster = insert(:user)
414 {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
415 {:ok, private_post} = CommonAPI.post(poster, %{status: "hey", visibility: "private"})
417 {:ok, announce_data, _meta} = Builder.announce(user, post.object, public: true)
419 {:ok, private_announce_data, _meta} =
420 Builder.announce(user, private_post.object, public: false)
422 {:ok, relay_announce_data, _meta} =
423 Builder.announce(Pleroma.Web.ActivityPub.Relay.get_actor(), post.object, public: true)
425 {:ok, announce, _meta} = ActivityPub.persist(announce_data, local: true)
426 {:ok, private_announce, _meta} = ActivityPub.persist(private_announce_data, local: true)
427 {:ok, relay_announce, _meta} = ActivityPub.persist(relay_announce_data, local: true)
433 private_announce: private_announce,
434 relay_announce: relay_announce
438 test "adds the announce to the original object", %{announce: announce, user: user} do
439 {:ok, announce, _} = SideEffects.handle(announce)
440 object = Object.get_by_ap_id(announce.data["object"])
441 assert object.data["announcement_count"] == 1
442 assert user.ap_id in object.data["announcements"]
445 test "does not add the announce to the original object if the actor is a service actor", %{
446 relay_announce: announce
448 {:ok, announce, _} = SideEffects.handle(announce)
449 object = Object.get_by_ap_id(announce.data["object"])
450 assert object.data["announcement_count"] == nil
453 test "creates a notification", %{announce: announce, poster: poster} do
454 {:ok, announce, _} = SideEffects.handle(announce)
455 assert Repo.get_by(Notification, user_id: poster.id, activity_id: announce.id)
458 test "it streams out the announce", %{announce: announce} do
459 with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough], stream_out: fn _ -> nil end do
460 {:ok, announce, _} = SideEffects.handle(announce)
462 assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(announce))