Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into remake-remodel-dms
[akkoma] / test / web / activity_pub / side_effects_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
6 use Oban.Testing, repo: Pleroma.Repo
7 use Pleroma.DataCase
8
9 alias Pleroma.Activity
10 alias Pleroma.Chat
11 alias Pleroma.Notification
12 alias Pleroma.Object
13 alias Pleroma.Repo
14 alias Pleroma.Tests.ObanHelpers
15 alias Pleroma.User
16 alias Pleroma.Web.ActivityPub.ActivityPub
17 alias Pleroma.Web.ActivityPub.Builder
18 alias Pleroma.Web.ActivityPub.SideEffects
19 alias Pleroma.Web.CommonAPI
20
21 import Pleroma.Factory
22 import Mock
23
24 describe "delete objects" do
25 setup do
26 user = insert(:user)
27 other_user = insert(:user)
28
29 {:ok, op} = CommonAPI.post(other_user, %{status: "big oof"})
30 {:ok, post} = CommonAPI.post(user, %{status: "hey", in_reply_to_id: op})
31 {:ok, favorite} = CommonAPI.favorite(user, post.id)
32 object = Object.normalize(post)
33 {:ok, delete_data, _meta} = Builder.delete(user, object.data["id"])
34 {:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id)
35 {:ok, delete, _meta} = ActivityPub.persist(delete_data, local: true)
36 {:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true)
37
38 %{
39 user: user,
40 delete: delete,
41 post: post,
42 object: object,
43 delete_user: delete_user,
44 op: op,
45 favorite: favorite
46 }
47 end
48
49 test "it handles object deletions", %{
50 delete: delete,
51 post: post,
52 object: object,
53 user: user,
54 op: op,
55 favorite: favorite
56 } do
57 with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough],
58 stream_out: fn _ -> nil end,
59 stream_out_participations: fn _, _ -> nil end do
60 {:ok, delete, _} = SideEffects.handle(delete)
61 user = User.get_cached_by_ap_id(object.data["actor"])
62
63 assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(delete))
64 assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out_participations(object, user))
65 end
66
67 object = Object.get_by_id(object.id)
68 assert object.data["type"] == "Tombstone"
69 refute Activity.get_by_id(post.id)
70 refute Activity.get_by_id(favorite.id)
71
72 user = User.get_by_id(user.id)
73 assert user.note_count == 0
74
75 object = Object.normalize(op.data["object"], false)
76
77 assert object.data["repliesCount"] == 0
78 end
79
80 test "it handles object deletions when the object itself has been pruned", %{
81 delete: delete,
82 post: post,
83 object: object,
84 user: user,
85 op: op
86 } do
87 with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough],
88 stream_out: fn _ -> nil end,
89 stream_out_participations: fn _, _ -> nil end do
90 {:ok, delete, _} = SideEffects.handle(delete)
91 user = User.get_cached_by_ap_id(object.data["actor"])
92
93 assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(delete))
94 assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out_participations(object, user))
95 end
96
97 object = Object.get_by_id(object.id)
98 assert object.data["type"] == "Tombstone"
99 refute Activity.get_by_id(post.id)
100
101 user = User.get_by_id(user.id)
102 assert user.note_count == 0
103
104 object = Object.normalize(op.data["object"], false)
105
106 assert object.data["repliesCount"] == 0
107 end
108
109 test "it handles user deletions", %{delete_user: delete, user: user} do
110 {:ok, _delete, _} = SideEffects.handle(delete)
111 ObanHelpers.perform_all()
112
113 assert User.get_cached_by_ap_id(user.ap_id).deactivated
114 end
115 end
116
117 describe "EmojiReact objects" do
118 setup do
119 poster = insert(:user)
120 user = insert(:user)
121
122 {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
123
124 {:ok, emoji_react_data, []} = Builder.emoji_react(user, post.object, "👌")
125 {:ok, emoji_react, _meta} = ActivityPub.persist(emoji_react_data, local: true)
126
127 %{emoji_react: emoji_react, user: user, poster: poster}
128 end
129
130 test "adds the reaction to the object", %{emoji_react: emoji_react, user: user} do
131 {:ok, emoji_react, _} = SideEffects.handle(emoji_react)
132 object = Object.get_by_ap_id(emoji_react.data["object"])
133
134 assert object.data["reaction_count"] == 1
135 assert ["👌", [user.ap_id]] in object.data["reactions"]
136 end
137
138 test "creates a notification", %{emoji_react: emoji_react, poster: poster} do
139 {:ok, emoji_react, _} = SideEffects.handle(emoji_react)
140 assert Repo.get_by(Notification, user_id: poster.id, activity_id: emoji_react.id)
141 end
142 end
143
144 describe "Undo objects" do
145 setup do
146 poster = insert(:user)
147 user = insert(:user)
148 {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
149 {:ok, like} = CommonAPI.favorite(user, post.id)
150 {:ok, reaction} = CommonAPI.react_with_emoji(post.id, user, "👍")
151 {:ok, announce, _} = CommonAPI.repeat(post.id, user)
152 {:ok, block} = ActivityPub.block(user, poster)
153 User.block(user, poster)
154
155 {:ok, undo_data, _meta} = Builder.undo(user, like)
156 {:ok, like_undo, _meta} = ActivityPub.persist(undo_data, local: true)
157
158 {:ok, undo_data, _meta} = Builder.undo(user, reaction)
159 {:ok, reaction_undo, _meta} = ActivityPub.persist(undo_data, local: true)
160
161 {:ok, undo_data, _meta} = Builder.undo(user, announce)
162 {:ok, announce_undo, _meta} = ActivityPub.persist(undo_data, local: true)
163
164 {:ok, undo_data, _meta} = Builder.undo(user, block)
165 {:ok, block_undo, _meta} = ActivityPub.persist(undo_data, local: true)
166
167 %{
168 like_undo: like_undo,
169 post: post,
170 like: like,
171 reaction_undo: reaction_undo,
172 reaction: reaction,
173 announce_undo: announce_undo,
174 announce: announce,
175 block_undo: block_undo,
176 block: block,
177 poster: poster,
178 user: user
179 }
180 end
181
182 test "deletes the original block", %{block_undo: block_undo, block: block} do
183 {:ok, _block_undo, _} = SideEffects.handle(block_undo)
184 refute Activity.get_by_id(block.id)
185 end
186
187 test "unblocks the blocked user", %{block_undo: block_undo, block: block} do
188 blocker = User.get_by_ap_id(block.data["actor"])
189 blocked = User.get_by_ap_id(block.data["object"])
190
191 {:ok, _block_undo, _} = SideEffects.handle(block_undo)
192 refute User.blocks?(blocker, blocked)
193 end
194
195 test "an announce undo removes the announce from the object", %{
196 announce_undo: announce_undo,
197 post: post
198 } do
199 {:ok, _announce_undo, _} = SideEffects.handle(announce_undo)
200
201 object = Object.get_by_ap_id(post.data["object"])
202
203 assert object.data["announcement_count"] == 0
204 assert object.data["announcements"] == []
205 end
206
207 test "deletes the original announce", %{announce_undo: announce_undo, announce: announce} do
208 {:ok, _announce_undo, _} = SideEffects.handle(announce_undo)
209 refute Activity.get_by_id(announce.id)
210 end
211
212 test "a reaction undo removes the reaction from the object", %{
213 reaction_undo: reaction_undo,
214 post: post
215 } do
216 {:ok, _reaction_undo, _} = SideEffects.handle(reaction_undo)
217
218 object = Object.get_by_ap_id(post.data["object"])
219
220 assert object.data["reaction_count"] == 0
221 assert object.data["reactions"] == []
222 end
223
224 test "deletes the original reaction", %{reaction_undo: reaction_undo, reaction: reaction} do
225 {:ok, _reaction_undo, _} = SideEffects.handle(reaction_undo)
226 refute Activity.get_by_id(reaction.id)
227 end
228
229 test "a like undo removes the like from the object", %{like_undo: like_undo, post: post} do
230 {:ok, _like_undo, _} = SideEffects.handle(like_undo)
231
232 object = Object.get_by_ap_id(post.data["object"])
233
234 assert object.data["like_count"] == 0
235 assert object.data["likes"] == []
236 end
237
238 test "deletes the original like", %{like_undo: like_undo, like: like} do
239 {:ok, _like_undo, _} = SideEffects.handle(like_undo)
240 refute Activity.get_by_id(like.id)
241 end
242 end
243
244 describe "like objects" do
245 setup do
246 poster = insert(:user)
247 user = insert(:user)
248 {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
249
250 {:ok, like_data, _meta} = Builder.like(user, post.object)
251 {:ok, like, _meta} = ActivityPub.persist(like_data, local: true)
252
253 %{like: like, user: user, poster: poster}
254 end
255
256 test "add the like to the original object", %{like: like, user: user} do
257 {:ok, like, _} = SideEffects.handle(like)
258 object = Object.get_by_ap_id(like.data["object"])
259 assert object.data["like_count"] == 1
260 assert user.ap_id in object.data["likes"]
261 end
262
263 test "creates a notification", %{like: like, poster: poster} do
264 {:ok, like, _} = SideEffects.handle(like)
265 assert Repo.get_by(Notification, user_id: poster.id, activity_id: like.id)
266 end
267 end
268
269 describe "creation of ChatMessages" do
270 test "notifies the recipient" do
271 author = insert(:user, local: false)
272 recipient = insert(:user, local: true)
273
274 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
275
276 {:ok, create_activity_data, _meta} =
277 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
278
279 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
280
281 {:ok, _create_activity, _meta} =
282 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
283
284 assert Repo.get_by(Notification, user_id: recipient.id, activity_id: create_activity.id)
285 end
286
287 test "it creates a Chat for the local users and bumps the unread count" do
288 author = insert(:user, local: false)
289 recipient = insert(:user, local: true)
290
291 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
292
293 {:ok, create_activity_data, _meta} =
294 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
295
296 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
297
298 {:ok, _create_activity, _meta} =
299 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
300
301 # An object is created
302 assert Object.get_by_ap_id(chat_message_data["id"])
303
304 # The remote user won't get a chat
305 chat = Chat.get(author.id, recipient.ap_id)
306 refute chat
307
308 # The local user will get a chat
309 chat = Chat.get(recipient.id, author.ap_id)
310 assert chat
311
312 author = insert(:user, local: true)
313 recipient = insert(:user, local: true)
314
315 {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
316
317 {:ok, create_activity_data, _meta} =
318 Builder.create(author, chat_message_data["id"], [recipient.ap_id])
319
320 {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
321
322 {:ok, _create_activity, _meta} =
323 SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
324
325 # Both users are local and get the chat
326 chat = Chat.get(author.id, recipient.ap_id)
327 assert chat
328
329 chat = Chat.get(recipient.id, author.ap_id)
330 assert chat
331 end
332 end
333 end