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