Merge branch 'develop' into 'remove-twitter-api'
[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 "Undo objects" do
144 setup do
145 poster = insert(:user)
146 user = insert(:user)
147 {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
148 {:ok, like} = CommonAPI.favorite(user, post.id)
149 {:ok, reaction} = CommonAPI.react_with_emoji(post.id, user, "👍")
150 {:ok, announce, _} = CommonAPI.repeat(post.id, user)
151 {:ok, block} = ActivityPub.block(user, poster)
152 User.block(user, poster)
153
154 {:ok, undo_data, _meta} = Builder.undo(user, like)
155 {:ok, like_undo, _meta} = ActivityPub.persist(undo_data, local: true)
156
157 {:ok, undo_data, _meta} = Builder.undo(user, reaction)
158 {:ok, reaction_undo, _meta} = ActivityPub.persist(undo_data, local: true)
159
160 {:ok, undo_data, _meta} = Builder.undo(user, announce)
161 {:ok, announce_undo, _meta} = ActivityPub.persist(undo_data, local: true)
162
163 {:ok, undo_data, _meta} = Builder.undo(user, block)
164 {:ok, block_undo, _meta} = ActivityPub.persist(undo_data, local: true)
165
166 %{
167 like_undo: like_undo,
168 post: post,
169 like: like,
170 reaction_undo: reaction_undo,
171 reaction: reaction,
172 announce_undo: announce_undo,
173 announce: announce,
174 block_undo: block_undo,
175 block: block,
176 poster: poster,
177 user: user
178 }
179 end
180
181 test "deletes the original block", %{block_undo: block_undo, block: block} do
182 {:ok, _block_undo, _} = SideEffects.handle(block_undo)
183 refute Activity.get_by_id(block.id)
184 end
185
186 test "unblocks the blocked user", %{block_undo: block_undo, block: block} do
187 blocker = User.get_by_ap_id(block.data["actor"])
188 blocked = User.get_by_ap_id(block.data["object"])
189
190 {:ok, _block_undo, _} = SideEffects.handle(block_undo)
191 refute User.blocks?(blocker, blocked)
192 end
193
194 test "an announce undo removes the announce from the object", %{
195 announce_undo: announce_undo,
196 post: post
197 } do
198 {:ok, _announce_undo, _} = SideEffects.handle(announce_undo)
199
200 object = Object.get_by_ap_id(post.data["object"])
201
202 assert object.data["announcement_count"] == 0
203 assert object.data["announcements"] == []
204 end
205
206 test "deletes the original announce", %{announce_undo: announce_undo, announce: announce} do
207 {:ok, _announce_undo, _} = SideEffects.handle(announce_undo)
208 refute Activity.get_by_id(announce.id)
209 end
210
211 test "a reaction undo removes the reaction from the object", %{
212 reaction_undo: reaction_undo,
213 post: post
214 } do
215 {:ok, _reaction_undo, _} = SideEffects.handle(reaction_undo)
216
217 object = Object.get_by_ap_id(post.data["object"])
218
219 assert object.data["reaction_count"] == 0
220 assert object.data["reactions"] == []
221 end
222
223 test "deletes the original reaction", %{reaction_undo: reaction_undo, reaction: reaction} do
224 {:ok, _reaction_undo, _} = SideEffects.handle(reaction_undo)
225 refute Activity.get_by_id(reaction.id)
226 end
227
228 test "a like undo removes the like from the object", %{like_undo: like_undo, post: post} do
229 {:ok, _like_undo, _} = SideEffects.handle(like_undo)
230
231 object = Object.get_by_ap_id(post.data["object"])
232
233 assert object.data["like_count"] == 0
234 assert object.data["likes"] == []
235 end
236
237 test "deletes the original like", %{like_undo: like_undo, like: like} do
238 {:ok, _like_undo, _} = SideEffects.handle(like_undo)
239 refute Activity.get_by_id(like.id)
240 end
241 end
242
243 describe "like objects" do
244 setup do
245 poster = insert(:user)
246 user = insert(:user)
247 {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
248
249 {:ok, like_data, _meta} = Builder.like(user, post.object)
250 {:ok, like, _meta} = ActivityPub.persist(like_data, local: true)
251
252 %{like: like, user: user, poster: poster}
253 end
254
255 test "add the like to the original object", %{like: like, user: user} do
256 {:ok, like, _} = SideEffects.handle(like)
257 object = Object.get_by_ap_id(like.data["object"])
258 assert object.data["like_count"] == 1
259 assert user.ap_id in object.data["likes"]
260 end
261
262 test "creates a notification", %{like: like, poster: poster} do
263 {:ok, like, _} = SideEffects.handle(like)
264 assert Repo.get_by(Notification, user_id: poster.id, activity_id: like.id)
265 end
266 end
267 end