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