Merge branch 'mastofe-content-types' into 'develop'
[akkoma] / test / notification_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.NotificationTest do
6 use Pleroma.DataCase
7 alias Pleroma.Notification
8 alias Pleroma.User
9 alias Pleroma.Web.ActivityPub.Transmogrifier
10 alias Pleroma.Web.CommonAPI
11 alias Pleroma.Web.TwitterAPI.TwitterAPI
12 import Pleroma.Factory
13
14 describe "create_notifications" do
15 test "notifies someone when they are directly addressed" do
16 user = insert(:user)
17 other_user = insert(:user)
18 third_user = insert(:user)
19
20 {:ok, activity} =
21 TwitterAPI.create_status(user, %{
22 "status" => "hey @#{other_user.nickname} and @#{third_user.nickname}"
23 })
24
25 {:ok, [notification, other_notification]} = Notification.create_notifications(activity)
26
27 notified_ids = Enum.sort([notification.user_id, other_notification.user_id])
28 assert notified_ids == [other_user.id, third_user.id]
29 assert notification.activity_id == activity.id
30 assert other_notification.activity_id == activity.id
31 end
32 end
33
34 describe "create_notification" do
35 test "it doesn't create a notification for user if the user blocks the activity author" do
36 activity = insert(:note_activity)
37 author = User.get_by_ap_id(activity.data["actor"])
38 user = insert(:user)
39 {:ok, user} = User.block(user, author)
40
41 assert nil == Notification.create_notification(activity, user)
42 end
43
44 test "it doesn't create a notification for user if he is the activity author" do
45 activity = insert(:note_activity)
46 author = User.get_by_ap_id(activity.data["actor"])
47
48 assert nil == Notification.create_notification(activity, author)
49 end
50
51 test "it doesn't create a notification for follow-unfollow-follow chains" do
52 user = insert(:user)
53 followed_user = insert(:user)
54 {:ok, _, _, activity} = TwitterAPI.follow(user, %{"user_id" => followed_user.id})
55 Notification.create_notification(activity, followed_user)
56 TwitterAPI.unfollow(user, %{"user_id" => followed_user.id})
57 {:ok, _, _, activity_dupe} = TwitterAPI.follow(user, %{"user_id" => followed_user.id})
58 assert nil == Notification.create_notification(activity_dupe, followed_user)
59 end
60
61 test "it doesn't create a notification for like-unlike-like chains" do
62 user = insert(:user)
63 liked_user = insert(:user)
64 {:ok, status} = TwitterAPI.create_status(liked_user, %{"status" => "Yui is best yuru"})
65 {:ok, fav_status} = TwitterAPI.fav(user, status.id)
66 Notification.create_notification(fav_status, liked_user)
67 TwitterAPI.unfav(user, status.id)
68 {:ok, dupe} = TwitterAPI.fav(user, status.id)
69 assert nil == Notification.create_notification(dupe, liked_user)
70 end
71
72 test "it doesn't create a notification for repeat-unrepeat-repeat chains" do
73 user = insert(:user)
74 retweeted_user = insert(:user)
75
76 {:ok, status} =
77 TwitterAPI.create_status(retweeted_user, %{
78 "status" => "Send dupe notifications to the shadow realm"
79 })
80
81 {:ok, retweeted_activity} = TwitterAPI.repeat(user, status.id)
82 Notification.create_notification(retweeted_activity, retweeted_user)
83 TwitterAPI.unrepeat(user, status.id)
84 {:ok, dupe} = TwitterAPI.repeat(user, status.id)
85 assert nil == Notification.create_notification(dupe, retweeted_user)
86 end
87 end
88
89 describe "get notification" do
90 test "it gets a notification that belongs to the user" do
91 user = insert(:user)
92 other_user = insert(:user)
93
94 {:ok, activity} =
95 TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
96
97 {:ok, [notification]} = Notification.create_notifications(activity)
98 {:ok, notification} = Notification.get(other_user, notification.id)
99
100 assert notification.user_id == other_user.id
101 end
102
103 test "it returns error if the notification doesn't belong to the user" do
104 user = insert(:user)
105 other_user = insert(:user)
106
107 {:ok, activity} =
108 TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
109
110 {:ok, [notification]} = Notification.create_notifications(activity)
111 {:error, _notification} = Notification.get(user, notification.id)
112 end
113 end
114
115 describe "dismiss notification" do
116 test "it dismisses a notification that belongs to the user" do
117 user = insert(:user)
118 other_user = insert(:user)
119
120 {:ok, activity} =
121 TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
122
123 {:ok, [notification]} = Notification.create_notifications(activity)
124 {:ok, notification} = Notification.dismiss(other_user, notification.id)
125
126 assert notification.user_id == other_user.id
127 end
128
129 test "it returns error if the notification doesn't belong to the user" do
130 user = insert(:user)
131 other_user = insert(:user)
132
133 {:ok, activity} =
134 TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
135
136 {:ok, [notification]} = Notification.create_notifications(activity)
137 {:error, _notification} = Notification.dismiss(user, notification.id)
138 end
139 end
140
141 describe "clear notification" do
142 test "it clears all notifications belonging to the user" do
143 user = insert(:user)
144 other_user = insert(:user)
145 third_user = insert(:user)
146
147 {:ok, activity} =
148 TwitterAPI.create_status(user, %{
149 "status" => "hey @#{other_user.nickname} and @#{third_user.nickname} !"
150 })
151
152 {:ok, _notifs} = Notification.create_notifications(activity)
153
154 {:ok, activity} =
155 TwitterAPI.create_status(user, %{
156 "status" => "hey again @#{other_user.nickname} and @#{third_user.nickname} !"
157 })
158
159 {:ok, _notifs} = Notification.create_notifications(activity)
160 Notification.clear(other_user)
161
162 assert Notification.for_user(other_user) == []
163 assert Notification.for_user(third_user) != []
164 end
165 end
166
167 describe "set_read_up_to()" do
168 test "it sets all notifications as read up to a specified notification ID" do
169 user = insert(:user)
170 other_user = insert(:user)
171
172 {:ok, _activity} =
173 TwitterAPI.create_status(user, %{
174 "status" => "hey @#{other_user.nickname}!"
175 })
176
177 {:ok, _activity} =
178 TwitterAPI.create_status(user, %{
179 "status" => "hey again @#{other_user.nickname}!"
180 })
181
182 [n2, n1] = notifs = Notification.for_user(other_user)
183 assert length(notifs) == 2
184
185 assert n2.id > n1.id
186
187 {:ok, _activity} =
188 TwitterAPI.create_status(user, %{
189 "status" => "hey yet again @#{other_user.nickname}!"
190 })
191
192 Notification.set_read_up_to(other_user, n2.id)
193
194 [n3, n2, n1] = Notification.for_user(other_user)
195
196 assert n1.seen == true
197 assert n2.seen == true
198 assert n3.seen == false
199 end
200 end
201
202 describe "notification target determination" do
203 test "it sends notifications to addressed users in new messages" do
204 user = insert(:user)
205 other_user = insert(:user)
206
207 {:ok, activity} =
208 CommonAPI.post(user, %{
209 "status" => "hey @#{other_user.nickname}!"
210 })
211
212 assert other_user in Notification.get_notified_from_activity(activity)
213 end
214
215 test "it sends notifications to mentioned users in new messages" do
216 user = insert(:user)
217 other_user = insert(:user)
218
219 create_activity = %{
220 "@context" => "https://www.w3.org/ns/activitystreams",
221 "type" => "Create",
222 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
223 "actor" => user.ap_id,
224 "object" => %{
225 "type" => "Note",
226 "content" => "message with a Mention tag, but no explicit tagging",
227 "tag" => [
228 %{
229 "type" => "Mention",
230 "href" => other_user.ap_id,
231 "name" => other_user.nickname
232 }
233 ],
234 "attributedTo" => user.ap_id
235 }
236 }
237
238 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
239
240 assert other_user in Notification.get_notified_from_activity(activity)
241 end
242
243 test "it does not send notifications to users who are only cc in new messages" do
244 user = insert(:user)
245 other_user = insert(:user)
246
247 create_activity = %{
248 "@context" => "https://www.w3.org/ns/activitystreams",
249 "type" => "Create",
250 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
251 "cc" => [other_user.ap_id],
252 "actor" => user.ap_id,
253 "object" => %{
254 "type" => "Note",
255 "content" => "hi everyone",
256 "attributedTo" => user.ap_id
257 }
258 }
259
260 {:ok, activity} = Transmogrifier.handle_incoming(create_activity)
261
262 assert other_user not in Notification.get_notified_from_activity(activity)
263 end
264
265 test "it does not send notification to mentioned users in likes" do
266 user = insert(:user)
267 other_user = insert(:user)
268 third_user = insert(:user)
269
270 {:ok, activity_one} =
271 CommonAPI.post(user, %{
272 "status" => "hey @#{other_user.nickname}!"
273 })
274
275 {:ok, activity_two, _} = CommonAPI.favorite(activity_one.id, third_user)
276
277 assert other_user not in Notification.get_notified_from_activity(activity_two)
278 end
279
280 test "it does not send notification to mentioned users in announces" do
281 user = insert(:user)
282 other_user = insert(:user)
283 third_user = insert(:user)
284
285 {:ok, activity_one} =
286 CommonAPI.post(user, %{
287 "status" => "hey @#{other_user.nickname}!"
288 })
289
290 {:ok, activity_two, _} = CommonAPI.repeat(activity_one.id, third_user)
291
292 assert other_user not in Notification.get_notified_from_activity(activity_two)
293 end
294 end
295
296 describe "notification lifecycle" do
297 test "liking an activity results in 1 notification, then 0 if the activity is deleted" do
298 user = insert(:user)
299 other_user = insert(:user)
300
301 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
302
303 assert Enum.empty?(Notification.for_user(user))
304
305 {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
306
307 assert length(Notification.for_user(user)) == 1
308
309 {:ok, _} = CommonAPI.delete(activity.id, user)
310
311 assert Enum.empty?(Notification.for_user(user))
312 end
313
314 test "liking an activity results in 1 notification, then 0 if the activity is unliked" do
315 user = insert(:user)
316 other_user = insert(:user)
317
318 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
319
320 assert Enum.empty?(Notification.for_user(user))
321
322 {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
323
324 assert length(Notification.for_user(user)) == 1
325
326 {:ok, _, _, _} = CommonAPI.unfavorite(activity.id, other_user)
327
328 assert Enum.empty?(Notification.for_user(user))
329 end
330
331 test "repeating an activity results in 1 notification, then 0 if the activity is deleted" do
332 user = insert(:user)
333 other_user = insert(:user)
334
335 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
336
337 assert Enum.empty?(Notification.for_user(user))
338
339 {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
340
341 assert length(Notification.for_user(user)) == 1
342
343 {:ok, _} = CommonAPI.delete(activity.id, user)
344
345 assert Enum.empty?(Notification.for_user(user))
346 end
347
348 test "repeating an activity results in 1 notification, then 0 if the activity is unrepeated" do
349 user = insert(:user)
350 other_user = insert(:user)
351
352 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
353
354 assert Enum.empty?(Notification.for_user(user))
355
356 {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
357
358 assert length(Notification.for_user(user)) == 1
359
360 {:ok, _, _} = CommonAPI.unrepeat(activity.id, other_user)
361
362 assert Enum.empty?(Notification.for_user(user))
363 end
364
365 test "liking an activity which is already deleted does not generate a notification" do
366 user = insert(:user)
367 other_user = insert(:user)
368
369 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
370
371 assert Enum.empty?(Notification.for_user(user))
372
373 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
374
375 assert Enum.empty?(Notification.for_user(user))
376
377 {:error, _} = CommonAPI.favorite(activity.id, other_user)
378
379 assert Enum.empty?(Notification.for_user(user))
380 end
381
382 test "repeating an activity which is already deleted does not generate a notification" do
383 user = insert(:user)
384 other_user = insert(:user)
385
386 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
387
388 assert Enum.empty?(Notification.for_user(user))
389
390 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
391
392 assert Enum.empty?(Notification.for_user(user))
393
394 {:error, _} = CommonAPI.repeat(activity.id, other_user)
395
396 assert Enum.empty?(Notification.for_user(user))
397 end
398
399 test "replying to a deleted post without tagging does not generate a notification" do
400 user = insert(:user)
401 other_user = insert(:user)
402
403 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
404 {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user)
405
406 {:ok, _reply_activity} =
407 CommonAPI.post(other_user, %{
408 "status" => "test reply",
409 "in_reply_to_status_id" => activity.id
410 })
411
412 assert Enum.empty?(Notification.for_user(user))
413 end
414 end
415 end