Merge branch 'feature/1734-user-deletion' into 'develop'
[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.Notification
11 alias Pleroma.Object
12 alias Pleroma.Repo
13 alias Pleroma.Tests.ObanHelpers
14 alias Pleroma.User
15 alias Pleroma.Web.ActivityPub.ActivityPub
16 alias Pleroma.Web.ActivityPub.Builder
17 alias Pleroma.Web.ActivityPub.SideEffects
18 alias Pleroma.Web.CommonAPI
19
20 import Pleroma.Factory
21 import Mock
22
23 describe "delete objects" do
24 setup do
25 user = insert(:user)
26 other_user = insert(:user)
27
28 {:ok, op} = CommonAPI.post(other_user, %{status: "big oof"})
29 {:ok, post} = CommonAPI.post(user, %{status: "hey", in_reply_to_id: op})
30 {:ok, favorite} = CommonAPI.favorite(user, post.id)
31 object = Object.normalize(post)
32 {:ok, delete_data, _meta} = Builder.delete(user, object.data["id"])
33 {:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id)
34 {:ok, delete, _meta} = ActivityPub.persist(delete_data, local: true)
35 {:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true)
36
37 %{
38 user: user,
39 delete: delete,
40 post: post,
41 object: object,
42 delete_user: delete_user,
43 op: op,
44 favorite: favorite
45 }
46 end
47
48 test "it handles object deletions", %{
49 delete: delete,
50 post: post,
51 object: object,
52 user: user,
53 op: op,
54 favorite: favorite
55 } do
56 with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough],
57 stream_out: fn _ -> nil end,
58 stream_out_participations: fn _, _ -> nil end do
59 {:ok, delete, _} = SideEffects.handle(delete)
60 user = User.get_cached_by_ap_id(object.data["actor"])
61
62 assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(delete))
63 assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out_participations(object, user))
64 end
65
66 object = Object.get_by_id(object.id)
67 assert object.data["type"] == "Tombstone"
68 refute Activity.get_by_id(post.id)
69 refute Activity.get_by_id(favorite.id)
70
71 user = User.get_by_id(user.id)
72 assert user.note_count == 0
73
74 object = Object.normalize(op.data["object"], false)
75
76 assert object.data["repliesCount"] == 0
77 end
78
79 test "it handles object deletions when the object itself has been pruned", %{
80 delete: delete,
81 post: post,
82 object: object,
83 user: user,
84 op: op
85 } do
86 with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough],
87 stream_out: fn _ -> nil end,
88 stream_out_participations: fn _, _ -> nil end do
89 {:ok, delete, _} = SideEffects.handle(delete)
90 user = User.get_cached_by_ap_id(object.data["actor"])
91
92 assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(delete))
93 assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out_participations(object, user))
94 end
95
96 object = Object.get_by_id(object.id)
97 assert object.data["type"] == "Tombstone"
98 refute Activity.get_by_id(post.id)
99
100 user = User.get_by_id(user.id)
101 assert user.note_count == 0
102
103 object = Object.normalize(op.data["object"], false)
104
105 assert object.data["repliesCount"] == 0
106 end
107
108 test "it handles user deletions", %{delete_user: delete, user: user} do
109 {:ok, _delete, _} = SideEffects.handle(delete)
110 ObanHelpers.perform_all()
111
112 assert User.get_cached_by_ap_id(user.ap_id).deactivated
113 end
114 end
115
116 describe "EmojiReact objects" do
117 setup do
118 poster = insert(:user)
119 user = insert(:user)
120
121 {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
122
123 {:ok, emoji_react_data, []} = Builder.emoji_react(user, post.object, "👌")
124 {:ok, emoji_react, _meta} = ActivityPub.persist(emoji_react_data, local: true)
125
126 %{emoji_react: emoji_react, user: user, poster: poster}
127 end
128
129 test "adds the reaction to the object", %{emoji_react: emoji_react, user: user} do
130 {:ok, emoji_react, _} = SideEffects.handle(emoji_react)
131 object = Object.get_by_ap_id(emoji_react.data["object"])
132
133 assert object.data["reaction_count"] == 1
134 assert ["👌", [user.ap_id]] in object.data["reactions"]
135 end
136
137 test "creates a notification", %{emoji_react: emoji_react, poster: poster} do
138 {:ok, emoji_react, _} = SideEffects.handle(emoji_react)
139 assert Repo.get_by(Notification, user_id: poster.id, activity_id: emoji_react.id)
140 end
141 end
142
143 describe "delete users with confirmation pending" do
144 setup do
145 user = insert(:user, confirmation_pending: true)
146 {:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id)
147 {:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true)
148 {:ok, delete: delete_user, user: user}
149 end
150
151 test "when activation is not required", %{delete: delete, user: user} do
152 clear_config([:instance, :account_activation_required], false)
153 {:ok, _, _} = SideEffects.handle(delete)
154 ObanHelpers.perform_all()
155
156 assert User.get_cached_by_id(user.id).deactivated
157 end
158
159 test "when activation is required", %{delete: delete, user: user} do
160 clear_config([:instance, :account_activation_required], true)
161 {:ok, _, _} = SideEffects.handle(delete)
162 ObanHelpers.perform_all()
163
164 refute User.get_cached_by_id(user.id)
165 end
166 end
167
168 describe "Undo objects" do
169 setup do
170 poster = insert(:user)
171 user = insert(:user)
172 {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
173 {:ok, like} = CommonAPI.favorite(user, post.id)
174 {:ok, reaction} = CommonAPI.react_with_emoji(post.id, user, "👍")
175 {:ok, announce, _} = CommonAPI.repeat(post.id, user)
176 {:ok, block} = ActivityPub.block(user, poster)
177 User.block(user, poster)
178
179 {:ok, undo_data, _meta} = Builder.undo(user, like)
180 {:ok, like_undo, _meta} = ActivityPub.persist(undo_data, local: true)
181
182 {:ok, undo_data, _meta} = Builder.undo(user, reaction)
183 {:ok, reaction_undo, _meta} = ActivityPub.persist(undo_data, local: true)
184
185 {:ok, undo_data, _meta} = Builder.undo(user, announce)
186 {:ok, announce_undo, _meta} = ActivityPub.persist(undo_data, local: true)
187
188 {:ok, undo_data, _meta} = Builder.undo(user, block)
189 {:ok, block_undo, _meta} = ActivityPub.persist(undo_data, local: true)
190
191 %{
192 like_undo: like_undo,
193 post: post,
194 like: like,
195 reaction_undo: reaction_undo,
196 reaction: reaction,
197 announce_undo: announce_undo,
198 announce: announce,
199 block_undo: block_undo,
200 block: block,
201 poster: poster,
202 user: user
203 }
204 end
205
206 test "deletes the original block", %{block_undo: block_undo, block: block} do
207 {:ok, _block_undo, _} = SideEffects.handle(block_undo)
208 refute Activity.get_by_id(block.id)
209 end
210
211 test "unblocks the blocked user", %{block_undo: block_undo, block: block} do
212 blocker = User.get_by_ap_id(block.data["actor"])
213 blocked = User.get_by_ap_id(block.data["object"])
214
215 {:ok, _block_undo, _} = SideEffects.handle(block_undo)
216 refute User.blocks?(blocker, blocked)
217 end
218
219 test "an announce undo removes the announce from the object", %{
220 announce_undo: announce_undo,
221 post: post
222 } do
223 {:ok, _announce_undo, _} = SideEffects.handle(announce_undo)
224
225 object = Object.get_by_ap_id(post.data["object"])
226
227 assert object.data["announcement_count"] == 0
228 assert object.data["announcements"] == []
229 end
230
231 test "deletes the original announce", %{announce_undo: announce_undo, announce: announce} do
232 {:ok, _announce_undo, _} = SideEffects.handle(announce_undo)
233 refute Activity.get_by_id(announce.id)
234 end
235
236 test "a reaction undo removes the reaction from the object", %{
237 reaction_undo: reaction_undo,
238 post: post
239 } do
240 {:ok, _reaction_undo, _} = SideEffects.handle(reaction_undo)
241
242 object = Object.get_by_ap_id(post.data["object"])
243
244 assert object.data["reaction_count"] == 0
245 assert object.data["reactions"] == []
246 end
247
248 test "deletes the original reaction", %{reaction_undo: reaction_undo, reaction: reaction} do
249 {:ok, _reaction_undo, _} = SideEffects.handle(reaction_undo)
250 refute Activity.get_by_id(reaction.id)
251 end
252
253 test "a like undo removes the like from the object", %{like_undo: like_undo, post: post} do
254 {:ok, _like_undo, _} = SideEffects.handle(like_undo)
255
256 object = Object.get_by_ap_id(post.data["object"])
257
258 assert object.data["like_count"] == 0
259 assert object.data["likes"] == []
260 end
261
262 test "deletes the original like", %{like_undo: like_undo, like: like} do
263 {:ok, _like_undo, _} = SideEffects.handle(like_undo)
264 refute Activity.get_by_id(like.id)
265 end
266 end
267
268 describe "like objects" do
269 setup do
270 poster = insert(:user)
271 user = insert(:user)
272 {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
273
274 {:ok, like_data, _meta} = Builder.like(user, post.object)
275 {:ok, like, _meta} = ActivityPub.persist(like_data, local: true)
276
277 %{like: like, user: user, poster: poster}
278 end
279
280 test "add the like to the original object", %{like: like, user: user} do
281 {:ok, like, _} = SideEffects.handle(like)
282 object = Object.get_by_ap_id(like.data["object"])
283 assert object.data["like_count"] == 1
284 assert user.ap_id in object.data["likes"]
285 end
286
287 test "creates a notification", %{like: like, poster: poster} do
288 {:ok, like, _} = SideEffects.handle(like)
289 assert Repo.get_by(Notification, user_id: poster.id, activity_id: like.id)
290 end
291 end
292 end