Announcements: Fix all tests.
[akkoma] / test / web / common_api / common_api_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.CommonAPITest do
6 use Pleroma.DataCase
7 alias Pleroma.Activity
8 alias Pleroma.Conversation.Participation
9 alias Pleroma.Object
10 alias Pleroma.User
11 alias Pleroma.Web.ActivityPub.ActivityPub
12 alias Pleroma.Web.ActivityPub.Transmogrifier
13 alias Pleroma.Web.ActivityPub.Visibility
14 alias Pleroma.Web.AdminAPI.AccountView
15 alias Pleroma.Web.CommonAPI
16
17 import Pleroma.Factory
18 import Mock
19
20 require Pleroma.Constants
21
22 setup do: clear_config([:instance, :safe_dm_mentions])
23 setup do: clear_config([:instance, :limit])
24 setup do: clear_config([:instance, :max_pinned_statuses])
25
26 describe "unblocking" do
27 test "it works even without an existing block activity" do
28 blocked = insert(:user)
29 blocker = insert(:user)
30 User.block(blocker, blocked)
31
32 assert User.blocks?(blocker, blocked)
33 assert {:ok, :no_activity} == CommonAPI.unblock(blocker, blocked)
34 refute User.blocks?(blocker, blocked)
35 end
36 end
37
38 describe "deletion" do
39 test "it works with pruned objects" do
40 user = insert(:user)
41
42 {:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"})
43
44 clear_config([:instance, :federating], true)
45
46 Object.normalize(post, false)
47 |> Object.prune()
48
49 with_mock Pleroma.Web.Federator,
50 publish: fn _ -> nil end do
51 assert {:ok, delete} = CommonAPI.delete(post.id, user)
52 assert delete.local
53 assert called(Pleroma.Web.Federator.publish(delete))
54 end
55
56 refute Activity.get_by_id(post.id)
57 end
58
59 test "it allows users to delete their posts" do
60 user = insert(:user)
61
62 {:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"})
63
64 clear_config([:instance, :federating], true)
65
66 with_mock Pleroma.Web.Federator,
67 publish: fn _ -> nil end do
68 assert {:ok, delete} = CommonAPI.delete(post.id, user)
69 assert delete.local
70 assert called(Pleroma.Web.Federator.publish(delete))
71 end
72
73 refute Activity.get_by_id(post.id)
74 end
75
76 test "it does not allow a user to delete their posts" do
77 user = insert(:user)
78 other_user = insert(:user)
79
80 {:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"})
81
82 assert {:error, "Could not delete"} = CommonAPI.delete(post.id, other_user)
83 assert Activity.get_by_id(post.id)
84 end
85
86 test "it allows moderators to delete other user's posts" do
87 user = insert(:user)
88 moderator = insert(:user, is_moderator: true)
89
90 {:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"})
91
92 assert {:ok, delete} = CommonAPI.delete(post.id, moderator)
93 assert delete.local
94
95 refute Activity.get_by_id(post.id)
96 end
97
98 test "it allows admins to delete other user's posts" do
99 user = insert(:user)
100 moderator = insert(:user, is_admin: true)
101
102 {:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"})
103
104 assert {:ok, delete} = CommonAPI.delete(post.id, moderator)
105 assert delete.local
106
107 refute Activity.get_by_id(post.id)
108 end
109
110 test "superusers deleting non-local posts won't federate the delete" do
111 # This is the user of the ingested activity
112 _user =
113 insert(:user,
114 local: false,
115 ap_id: "http://mastodon.example.org/users/admin",
116 last_refreshed_at: NaiveDateTime.utc_now()
117 )
118
119 moderator = insert(:user, is_admin: true)
120
121 data =
122 File.read!("test/fixtures/mastodon-post-activity.json")
123 |> Jason.decode!()
124
125 {:ok, post} = Transmogrifier.handle_incoming(data)
126
127 with_mock Pleroma.Web.Federator,
128 publish: fn _ -> nil end do
129 assert {:ok, delete} = CommonAPI.delete(post.id, moderator)
130 assert delete.local
131 refute called(Pleroma.Web.Federator.publish(:_))
132 end
133
134 refute Activity.get_by_id(post.id)
135 end
136 end
137
138 test "favoriting race condition" do
139 user = insert(:user)
140 users_serial = insert_list(10, :user)
141 users = insert_list(10, :user)
142
143 {:ok, activity} = CommonAPI.post(user, %{status: "."})
144
145 users_serial
146 |> Enum.map(fn user ->
147 CommonAPI.favorite(user, activity.id)
148 end)
149
150 object = Object.get_by_ap_id(activity.data["object"])
151 assert object.data["like_count"] == 10
152
153 users
154 |> Enum.map(fn user ->
155 Task.async(fn ->
156 CommonAPI.favorite(user, activity.id)
157 end)
158 end)
159 |> Enum.map(&Task.await/1)
160
161 object = Object.get_by_ap_id(activity.data["object"])
162 assert object.data["like_count"] == 20
163 end
164
165 test "repeating race condition" do
166 user = insert(:user)
167 users_serial = insert_list(10, :user)
168 users = insert_list(10, :user)
169
170 {:ok, activity} = CommonAPI.post(user, %{status: "."})
171
172 users_serial
173 |> Enum.map(fn user ->
174 CommonAPI.repeat(activity.id, user)
175 end)
176
177 object = Object.get_by_ap_id(activity.data["object"])
178 assert object.data["announcement_count"] == 10
179
180 users
181 |> Enum.map(fn user ->
182 Task.async(fn ->
183 CommonAPI.repeat(activity.id, user)
184 end)
185 end)
186 |> Enum.map(&Task.await/1)
187
188 object = Object.get_by_ap_id(activity.data["object"])
189 assert object.data["announcement_count"] == 20
190 end
191
192 test "when replying to a conversation / participation, it will set the correct context id even if no explicit reply_to is given" do
193 user = insert(:user)
194 {:ok, activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"})
195
196 [participation] = Participation.for_user(user)
197
198 {:ok, convo_reply} =
199 CommonAPI.post(user, %{status: ".", in_reply_to_conversation_id: participation.id})
200
201 assert Visibility.is_direct?(convo_reply)
202
203 assert activity.data["context"] == convo_reply.data["context"]
204 end
205
206 test "when replying to a conversation / participation, it only mentions the recipients explicitly declared in the participation" do
207 har = insert(:user)
208 jafnhar = insert(:user)
209 tridi = insert(:user)
210
211 {:ok, activity} =
212 CommonAPI.post(har, %{
213 status: "@#{jafnhar.nickname} hey",
214 visibility: "direct"
215 })
216
217 assert har.ap_id in activity.recipients
218 assert jafnhar.ap_id in activity.recipients
219
220 [participation] = Participation.for_user(har)
221
222 {:ok, activity} =
223 CommonAPI.post(har, %{
224 status: "I don't really like @#{tridi.nickname}",
225 visibility: "direct",
226 in_reply_to_status_id: activity.id,
227 in_reply_to_conversation_id: participation.id
228 })
229
230 assert har.ap_id in activity.recipients
231 assert jafnhar.ap_id in activity.recipients
232 refute tridi.ap_id in activity.recipients
233 end
234
235 test "with the safe_dm_mention option set, it does not mention people beyond the initial tags" do
236 har = insert(:user)
237 jafnhar = insert(:user)
238 tridi = insert(:user)
239
240 Pleroma.Config.put([:instance, :safe_dm_mentions], true)
241
242 {:ok, activity} =
243 CommonAPI.post(har, %{
244 status: "@#{jafnhar.nickname} hey, i never want to see @#{tridi.nickname} again",
245 visibility: "direct"
246 })
247
248 refute tridi.ap_id in activity.recipients
249 assert jafnhar.ap_id in activity.recipients
250 end
251
252 test "it de-duplicates tags" do
253 user = insert(:user)
254 {:ok, activity} = CommonAPI.post(user, %{status: "#2hu #2HU"})
255
256 object = Object.normalize(activity)
257
258 assert object.data["tag"] == ["2hu"]
259 end
260
261 test "it adds emoji in the object" do
262 user = insert(:user)
263 {:ok, activity} = CommonAPI.post(user, %{status: ":firefox:"})
264
265 assert Object.normalize(activity).data["emoji"]["firefox"]
266 end
267
268 describe "posting" do
269 test "it supports explicit addressing" do
270 user = insert(:user)
271 user_two = insert(:user)
272 user_three = insert(:user)
273 user_four = insert(:user)
274
275 {:ok, activity} =
276 CommonAPI.post(user, %{
277 status:
278 "Hey, I think @#{user_three.nickname} is ugly. @#{user_four.nickname} is alright though.",
279 to: [user_two.nickname, user_four.nickname, "nonexistent"]
280 })
281
282 assert user.ap_id in activity.recipients
283 assert user_two.ap_id in activity.recipients
284 assert user_four.ap_id in activity.recipients
285 refute user_three.ap_id in activity.recipients
286 end
287
288 test "it filters out obviously bad tags when accepting a post as HTML" do
289 user = insert(:user)
290
291 post = "<p><b>2hu</b></p><script>alert('xss')</script>"
292
293 {:ok, activity} =
294 CommonAPI.post(user, %{
295 status: post,
296 content_type: "text/html"
297 })
298
299 object = Object.normalize(activity)
300
301 assert object.data["content"] == "<p><b>2hu</b></p>alert(&#39;xss&#39;)"
302 end
303
304 test "it filters out obviously bad tags when accepting a post as Markdown" do
305 user = insert(:user)
306
307 post = "<p><b>2hu</b></p><script>alert('xss')</script>"
308
309 {:ok, activity} =
310 CommonAPI.post(user, %{
311 status: post,
312 content_type: "text/markdown"
313 })
314
315 object = Object.normalize(activity)
316
317 assert object.data["content"] == "<p><b>2hu</b></p>alert(&#39;xss&#39;)"
318 end
319
320 test "it does not allow replies to direct messages that are not direct messages themselves" do
321 user = insert(:user)
322
323 {:ok, activity} = CommonAPI.post(user, %{status: "suya..", visibility: "direct"})
324
325 assert {:ok, _} =
326 CommonAPI.post(user, %{
327 status: "suya..",
328 visibility: "direct",
329 in_reply_to_status_id: activity.id
330 })
331
332 Enum.each(["public", "private", "unlisted"], fn visibility ->
333 assert {:error, "The message visibility must be direct"} =
334 CommonAPI.post(user, %{
335 status: "suya..",
336 visibility: visibility,
337 in_reply_to_status_id: activity.id
338 })
339 end)
340 end
341
342 test "it allows to address a list" do
343 user = insert(:user)
344 {:ok, list} = Pleroma.List.create("foo", user)
345
346 {:ok, activity} = CommonAPI.post(user, %{status: "foobar", visibility: "list:#{list.id}"})
347
348 assert activity.data["bcc"] == [list.ap_id]
349 assert activity.recipients == [list.ap_id, user.ap_id]
350 assert activity.data["listMessage"] == list.ap_id
351 end
352
353 test "it returns error when status is empty and no attachments" do
354 user = insert(:user)
355
356 assert {:error, "Cannot post an empty status without attachments"} =
357 CommonAPI.post(user, %{status: ""})
358 end
359
360 test "it validates character limits are correctly enforced" do
361 Pleroma.Config.put([:instance, :limit], 5)
362
363 user = insert(:user)
364
365 assert {:error, "The status is over the character limit"} =
366 CommonAPI.post(user, %{status: "foobar"})
367
368 assert {:ok, activity} = CommonAPI.post(user, %{status: "12345"})
369 end
370
371 test "it can handle activities that expire" do
372 user = insert(:user)
373
374 expires_at =
375 NaiveDateTime.utc_now()
376 |> NaiveDateTime.truncate(:second)
377 |> NaiveDateTime.add(1_000_000, :second)
378
379 assert {:ok, activity} = CommonAPI.post(user, %{status: "chai", expires_in: 1_000_000})
380
381 assert expiration = Pleroma.ActivityExpiration.get_by_activity_id(activity.id)
382 assert expiration.scheduled_at == expires_at
383 end
384 end
385
386 describe "reactions" do
387 test "reacting to a status with an emoji" do
388 user = insert(:user)
389 other_user = insert(:user)
390
391 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
392
393 {:ok, reaction} = CommonAPI.react_with_emoji(activity.id, user, "👍")
394
395 assert reaction.data["actor"] == user.ap_id
396 assert reaction.data["content"] == "👍"
397
398 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
399
400 {:error, _} = CommonAPI.react_with_emoji(activity.id, user, ".")
401 end
402
403 test "unreacting to a status with an emoji" do
404 user = insert(:user)
405 other_user = insert(:user)
406
407 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
408 {:ok, reaction} = CommonAPI.react_with_emoji(activity.id, user, "👍")
409
410 {:ok, unreaction} = CommonAPI.unreact_with_emoji(activity.id, user, "👍")
411
412 assert unreaction.data["type"] == "Undo"
413 assert unreaction.data["object"] == reaction.data["id"]
414 assert unreaction.local
415 end
416
417 test "repeating a status" do
418 user = insert(:user)
419 other_user = insert(:user)
420
421 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
422
423 {:ok, %Activity{} = announce_activity} = CommonAPI.repeat(activity.id, user)
424 assert Visibility.is_public?(announce_activity)
425 end
426
427 test "can't repeat a repeat" do
428 user = insert(:user)
429 other_user = insert(:user)
430 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
431
432 {:ok, %Activity{} = announce} = CommonAPI.repeat(activity.id, other_user)
433
434 refute match?({:ok, %Activity{}}, CommonAPI.repeat(announce.id, user))
435 end
436
437 test "repeating a status privately" do
438 user = insert(:user)
439 other_user = insert(:user)
440
441 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
442
443 {:ok, %Activity{} = announce_activity} =
444 CommonAPI.repeat(activity.id, user, %{visibility: "private"})
445
446 assert Visibility.is_private?(announce_activity)
447 refute Visibility.visible_for_user?(announce_activity, nil)
448 end
449
450 test "favoriting a status" do
451 user = insert(:user)
452 other_user = insert(:user)
453
454 {:ok, post_activity} = CommonAPI.post(other_user, %{status: "cofe"})
455
456 {:ok, %Activity{data: data}} = CommonAPI.favorite(user, post_activity.id)
457 assert data["type"] == "Like"
458 assert data["actor"] == user.ap_id
459 assert data["object"] == post_activity.data["object"]
460 end
461
462 test "retweeting a status twice returns the status" do
463 user = insert(:user)
464 other_user = insert(:user)
465
466 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
467 {:ok, %Activity{} = announce} = CommonAPI.repeat(activity.id, user)
468 {:ok, ^announce} = CommonAPI.repeat(activity.id, user)
469 end
470
471 test "favoriting a status twice returns ok, but without the like activity" do
472 user = insert(:user)
473 other_user = insert(:user)
474
475 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
476 {:ok, %Activity{}} = CommonAPI.favorite(user, activity.id)
477 assert {:ok, :already_liked} = CommonAPI.favorite(user, activity.id)
478 end
479 end
480
481 describe "pinned statuses" do
482 setup do
483 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
484
485 user = insert(:user)
486 {:ok, activity} = CommonAPI.post(user, %{status: "HI!!!"})
487
488 [user: user, activity: activity]
489 end
490
491 test "pin status", %{user: user, activity: activity} do
492 assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
493
494 id = activity.id
495 user = refresh_record(user)
496
497 assert %User{pinned_activities: [^id]} = user
498 end
499
500 test "pin poll", %{user: user} do
501 {:ok, activity} =
502 CommonAPI.post(user, %{
503 status: "How is fediverse today?",
504 poll: %{options: ["Absolutely outstanding", "Not good"], expires_in: 20}
505 })
506
507 assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
508
509 id = activity.id
510 user = refresh_record(user)
511
512 assert %User{pinned_activities: [^id]} = user
513 end
514
515 test "unlisted statuses can be pinned", %{user: user} do
516 {:ok, activity} = CommonAPI.post(user, %{status: "HI!!!", visibility: "unlisted"})
517 assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
518 end
519
520 test "only self-authored can be pinned", %{activity: activity} do
521 user = insert(:user)
522
523 assert {:error, "Could not pin"} = CommonAPI.pin(activity.id, user)
524 end
525
526 test "max pinned statuses", %{user: user, activity: activity_one} do
527 {:ok, activity_two} = CommonAPI.post(user, %{status: "HI!!!"})
528
529 assert {:ok, ^activity_one} = CommonAPI.pin(activity_one.id, user)
530
531 user = refresh_record(user)
532
533 assert {:error, "You have already pinned the maximum number of statuses"} =
534 CommonAPI.pin(activity_two.id, user)
535 end
536
537 test "unpin status", %{user: user, activity: activity} do
538 {:ok, activity} = CommonAPI.pin(activity.id, user)
539
540 user = refresh_record(user)
541
542 id = activity.id
543
544 assert match?({:ok, %{id: ^id}}, CommonAPI.unpin(activity.id, user))
545
546 user = refresh_record(user)
547
548 assert %User{pinned_activities: []} = user
549 end
550
551 test "should unpin when deleting a status", %{user: user, activity: activity} do
552 {:ok, activity} = CommonAPI.pin(activity.id, user)
553
554 user = refresh_record(user)
555
556 assert {:ok, _} = CommonAPI.delete(activity.id, user)
557
558 user = refresh_record(user)
559
560 assert %User{pinned_activities: []} = user
561 end
562 end
563
564 describe "mute tests" do
565 setup do
566 user = insert(:user)
567
568 activity = insert(:note_activity)
569
570 [user: user, activity: activity]
571 end
572
573 test "add mute", %{user: user, activity: activity} do
574 {:ok, _} = CommonAPI.add_mute(user, activity)
575 assert CommonAPI.thread_muted?(user, activity)
576 end
577
578 test "remove mute", %{user: user, activity: activity} do
579 CommonAPI.add_mute(user, activity)
580 {:ok, _} = CommonAPI.remove_mute(user, activity)
581 refute CommonAPI.thread_muted?(user, activity)
582 end
583
584 test "check that mutes can't be duplicate", %{user: user, activity: activity} do
585 CommonAPI.add_mute(user, activity)
586 {:error, _} = CommonAPI.add_mute(user, activity)
587 end
588 end
589
590 describe "reports" do
591 test "creates a report" do
592 reporter = insert(:user)
593 target_user = insert(:user)
594
595 {:ok, activity} = CommonAPI.post(target_user, %{status: "foobar"})
596
597 reporter_ap_id = reporter.ap_id
598 target_ap_id = target_user.ap_id
599 activity_ap_id = activity.data["id"]
600 comment = "foobar"
601
602 report_data = %{
603 account_id: target_user.id,
604 comment: comment,
605 status_ids: [activity.id]
606 }
607
608 note_obj = %{
609 "type" => "Note",
610 "id" => activity_ap_id,
611 "content" => "foobar",
612 "published" => activity.object.data["published"],
613 "actor" => AccountView.render("show.json", %{user: target_user})
614 }
615
616 assert {:ok, flag_activity} = CommonAPI.report(reporter, report_data)
617
618 assert %Activity{
619 actor: ^reporter_ap_id,
620 data: %{
621 "type" => "Flag",
622 "content" => ^comment,
623 "object" => [^target_ap_id, ^note_obj],
624 "state" => "open"
625 }
626 } = flag_activity
627 end
628
629 test "updates report state" do
630 [reporter, target_user] = insert_pair(:user)
631 activity = insert(:note_activity, user: target_user)
632
633 {:ok, %Activity{id: report_id}} =
634 CommonAPI.report(reporter, %{
635 account_id: target_user.id,
636 comment: "I feel offended",
637 status_ids: [activity.id]
638 })
639
640 {:ok, report} = CommonAPI.update_report_state(report_id, "resolved")
641
642 assert report.data["state"] == "resolved"
643
644 [reported_user, activity_id] = report.data["object"]
645
646 assert reported_user == target_user.ap_id
647 assert activity_id == activity.data["id"]
648 end
649
650 test "does not update report state when state is unsupported" do
651 [reporter, target_user] = insert_pair(:user)
652 activity = insert(:note_activity, user: target_user)
653
654 {:ok, %Activity{id: report_id}} =
655 CommonAPI.report(reporter, %{
656 account_id: target_user.id,
657 comment: "I feel offended",
658 status_ids: [activity.id]
659 })
660
661 assert CommonAPI.update_report_state(report_id, "test") == {:error, "Unsupported state"}
662 end
663
664 test "updates state of multiple reports" do
665 [reporter, target_user] = insert_pair(:user)
666 activity = insert(:note_activity, user: target_user)
667
668 {:ok, %Activity{id: first_report_id}} =
669 CommonAPI.report(reporter, %{
670 account_id: target_user.id,
671 comment: "I feel offended",
672 status_ids: [activity.id]
673 })
674
675 {:ok, %Activity{id: second_report_id}} =
676 CommonAPI.report(reporter, %{
677 account_id: target_user.id,
678 comment: "I feel very offended!",
679 status_ids: [activity.id]
680 })
681
682 {:ok, report_ids} =
683 CommonAPI.update_report_state([first_report_id, second_report_id], "resolved")
684
685 first_report = Activity.get_by_id(first_report_id)
686 second_report = Activity.get_by_id(second_report_id)
687
688 assert report_ids -- [first_report_id, second_report_id] == []
689 assert first_report.data["state"] == "resolved"
690 assert second_report.data["state"] == "resolved"
691 end
692 end
693
694 describe "reblog muting" do
695 setup do
696 muter = insert(:user)
697
698 muted = insert(:user)
699
700 [muter: muter, muted: muted]
701 end
702
703 test "add a reblog mute", %{muter: muter, muted: muted} do
704 {:ok, _reblog_mute} = CommonAPI.hide_reblogs(muter, muted)
705
706 assert User.showing_reblogs?(muter, muted) == false
707 end
708
709 test "remove a reblog mute", %{muter: muter, muted: muted} do
710 {:ok, _reblog_mute} = CommonAPI.hide_reblogs(muter, muted)
711 {:ok, _reblog_mute} = CommonAPI.show_reblogs(muter, muted)
712
713 assert User.showing_reblogs?(muter, muted) == true
714 end
715 end
716
717 describe "unfollow/2" do
718 test "also unsubscribes a user" do
719 [follower, followed] = insert_pair(:user)
720 {:ok, follower, followed, _} = CommonAPI.follow(follower, followed)
721 {:ok, _subscription} = User.subscribe(follower, followed)
722
723 assert User.subscribed_to?(follower, followed)
724
725 {:ok, follower} = CommonAPI.unfollow(follower, followed)
726
727 refute User.subscribed_to?(follower, followed)
728 end
729
730 test "cancels a pending follow for a local user" do
731 follower = insert(:user)
732 followed = insert(:user, locked: true)
733
734 assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} =
735 CommonAPI.follow(follower, followed)
736
737 assert User.get_follow_state(follower, followed) == :follow_pending
738 assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
739 assert User.get_follow_state(follower, followed) == nil
740
741 assert %{id: ^activity_id, data: %{"state" => "cancelled"}} =
742 Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed)
743
744 assert %{
745 data: %{
746 "type" => "Undo",
747 "object" => %{"type" => "Follow", "state" => "cancelled"}
748 }
749 } = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower)
750 end
751
752 test "cancels a pending follow for a remote user" do
753 follower = insert(:user)
754 followed = insert(:user, locked: true, local: false, ap_enabled: true)
755
756 assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} =
757 CommonAPI.follow(follower, followed)
758
759 assert User.get_follow_state(follower, followed) == :follow_pending
760 assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
761 assert User.get_follow_state(follower, followed) == nil
762
763 assert %{id: ^activity_id, data: %{"state" => "cancelled"}} =
764 Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed)
765
766 assert %{
767 data: %{
768 "type" => "Undo",
769 "object" => %{"type" => "Follow", "state" => "cancelled"}
770 }
771 } = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower)
772 end
773 end
774
775 describe "accept_follow_request/2" do
776 test "after acceptance, it sets all existing pending follow request states to 'accept'" do
777 user = insert(:user, locked: true)
778 follower = insert(:user)
779 follower_two = insert(:user)
780
781 {:ok, follow_activity} = ActivityPub.follow(follower, user)
782 {:ok, follow_activity_two} = ActivityPub.follow(follower, user)
783 {:ok, follow_activity_three} = ActivityPub.follow(follower_two, user)
784
785 assert follow_activity.data["state"] == "pending"
786 assert follow_activity_two.data["state"] == "pending"
787 assert follow_activity_three.data["state"] == "pending"
788
789 {:ok, _follower} = CommonAPI.accept_follow_request(follower, user)
790
791 assert Repo.get(Activity, follow_activity.id).data["state"] == "accept"
792 assert Repo.get(Activity, follow_activity_two.id).data["state"] == "accept"
793 assert Repo.get(Activity, follow_activity_three.id).data["state"] == "pending"
794 end
795
796 test "after rejection, it sets all existing pending follow request states to 'reject'" do
797 user = insert(:user, locked: true)
798 follower = insert(:user)
799 follower_two = insert(:user)
800
801 {:ok, follow_activity} = ActivityPub.follow(follower, user)
802 {:ok, follow_activity_two} = ActivityPub.follow(follower, user)
803 {:ok, follow_activity_three} = ActivityPub.follow(follower_two, user)
804
805 assert follow_activity.data["state"] == "pending"
806 assert follow_activity_two.data["state"] == "pending"
807 assert follow_activity_three.data["state"] == "pending"
808
809 {:ok, _follower} = CommonAPI.reject_follow_request(follower, user)
810
811 assert Repo.get(Activity, follow_activity.id).data["state"] == "reject"
812 assert Repo.get(Activity, follow_activity_two.id).data["state"] == "reject"
813 assert Repo.get(Activity, follow_activity_three.id).data["state"] == "pending"
814 end
815
816 test "doesn't create a following relationship if the corresponding follow request doesn't exist" do
817 user = insert(:user, locked: true)
818 not_follower = insert(:user)
819 CommonAPI.accept_follow_request(not_follower, user)
820
821 assert Pleroma.FollowingRelationship.following?(not_follower, user) == false
822 end
823 end
824
825 describe "vote/3" do
826 test "does not allow to vote twice" do
827 user = insert(:user)
828 other_user = insert(:user)
829
830 {:ok, activity} =
831 CommonAPI.post(user, %{
832 status: "Am I cute?",
833 poll: %{options: ["Yes", "No"], expires_in: 20}
834 })
835
836 object = Object.normalize(activity)
837
838 {:ok, _, object} = CommonAPI.vote(other_user, object, [0])
839
840 assert {:error, "Already voted"} == CommonAPI.vote(other_user, object, [1])
841 end
842 end
843
844 describe "listen/2" do
845 test "returns a valid activity" do
846 user = insert(:user)
847
848 {:ok, activity} =
849 CommonAPI.listen(user, %{
850 title: "lain radio episode 1",
851 album: "lain radio",
852 artist: "lain",
853 length: 180_000
854 })
855
856 object = Object.normalize(activity)
857
858 assert object.data["title"] == "lain radio episode 1"
859
860 assert Visibility.get_visibility(activity) == "public"
861 end
862
863 test "respects visibility=private" do
864 user = insert(:user)
865
866 {:ok, activity} =
867 CommonAPI.listen(user, %{
868 title: "lain radio episode 1",
869 album: "lain radio",
870 artist: "lain",
871 length: 180_000,
872 visibility: "private"
873 })
874
875 object = Object.normalize(activity)
876
877 assert object.data["title"] == "lain radio episode 1"
878
879 assert Visibility.get_visibility(activity) == "private"
880 end
881 end
882 end