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