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" 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 assert unreaction.local
433 end
434
435 test "repeating a status" do
436 user = insert(:user)
437 other_user = insert(:user)
438
439 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
440
441 {:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, user)
442 end
443
444 test "can't repeat a repeat" do
445 user = insert(:user)
446 other_user = insert(:user)
447 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
448
449 {:ok, %Activity{} = announce, _} = CommonAPI.repeat(activity.id, other_user)
450
451 refute match?({:ok, %Activity{}, _}, CommonAPI.repeat(announce.id, user))
452 end
453
454 test "repeating a status privately" do
455 user = insert(:user)
456 other_user = insert(:user)
457
458 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
459
460 {:ok, %Activity{} = announce_activity, _} =
461 CommonAPI.repeat(activity.id, user, %{"visibility" => "private"})
462
463 assert Visibility.is_private?(announce_activity)
464 end
465
466 test "favoriting a status" do
467 user = insert(:user)
468 other_user = insert(:user)
469
470 {:ok, post_activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
471
472 {:ok, %Activity{data: data}} = CommonAPI.favorite(user, post_activity.id)
473 assert data["type"] == "Like"
474 assert data["actor"] == user.ap_id
475 assert data["object"] == post_activity.data["object"]
476 end
477
478 test "retweeting a status twice returns the status" do
479 user = insert(:user)
480 other_user = insert(:user)
481
482 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
483 {:ok, %Activity{} = announce, object} = CommonAPI.repeat(activity.id, user)
484 {:ok, ^announce, ^object} = CommonAPI.repeat(activity.id, user)
485 end
486
487 test "favoriting a status twice returns ok, but without the like activity" do
488 user = insert(:user)
489 other_user = insert(:user)
490
491 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
492 {:ok, %Activity{}} = CommonAPI.favorite(user, activity.id)
493 assert {:ok, :already_liked} = CommonAPI.favorite(user, activity.id)
494 end
495 end
496
497 describe "pinned statuses" do
498 setup do
499 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
500
501 user = insert(:user)
502 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
503
504 [user: user, activity: activity]
505 end
506
507 test "pin status", %{user: user, activity: activity} do
508 assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
509
510 id = activity.id
511 user = refresh_record(user)
512
513 assert %User{pinned_activities: [^id]} = user
514 end
515
516 test "pin poll", %{user: user} do
517 {:ok, activity} =
518 CommonAPI.post(user, %{
519 "status" => "How is fediverse today?",
520 "poll" => %{"options" => ["Absolutely outstanding", "Not good"], "expires_in" => 20}
521 })
522
523 assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
524
525 id = activity.id
526 user = refresh_record(user)
527
528 assert %User{pinned_activities: [^id]} = user
529 end
530
531 test "unlisted statuses can be pinned", %{user: user} do
532 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!", "visibility" => "unlisted"})
533 assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
534 end
535
536 test "only self-authored can be pinned", %{activity: activity} do
537 user = insert(:user)
538
539 assert {:error, "Could not pin"} = CommonAPI.pin(activity.id, user)
540 end
541
542 test "max pinned statuses", %{user: user, activity: activity_one} do
543 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
544
545 assert {:ok, ^activity_one} = CommonAPI.pin(activity_one.id, user)
546
547 user = refresh_record(user)
548
549 assert {:error, "You have already pinned the maximum number of statuses"} =
550 CommonAPI.pin(activity_two.id, user)
551 end
552
553 test "unpin status", %{user: user, activity: activity} do
554 {:ok, activity} = CommonAPI.pin(activity.id, user)
555
556 user = refresh_record(user)
557
558 id = activity.id
559
560 assert match?({:ok, %{id: ^id}}, CommonAPI.unpin(activity.id, user))
561
562 user = refresh_record(user)
563
564 assert %User{pinned_activities: []} = user
565 end
566
567 test "should unpin when deleting a status", %{user: user, activity: activity} do
568 {:ok, activity} = CommonAPI.pin(activity.id, user)
569
570 user = refresh_record(user)
571
572 assert {:ok, _} = CommonAPI.delete(activity.id, user)
573
574 user = refresh_record(user)
575
576 assert %User{pinned_activities: []} = user
577 end
578 end
579
580 describe "mute tests" do
581 setup do
582 user = insert(:user)
583
584 activity = insert(:note_activity)
585
586 [user: user, activity: activity]
587 end
588
589 test "add mute", %{user: user, activity: activity} do
590 {:ok, _} = CommonAPI.add_mute(user, activity)
591 assert CommonAPI.thread_muted?(user, activity)
592 end
593
594 test "remove mute", %{user: user, activity: activity} do
595 CommonAPI.add_mute(user, activity)
596 {:ok, _} = CommonAPI.remove_mute(user, activity)
597 refute CommonAPI.thread_muted?(user, activity)
598 end
599
600 test "check that mutes can't be duplicate", %{user: user, activity: activity} do
601 CommonAPI.add_mute(user, activity)
602 {:error, _} = CommonAPI.add_mute(user, activity)
603 end
604 end
605
606 describe "reports" do
607 test "creates a report" do
608 reporter = insert(:user)
609 target_user = insert(:user)
610
611 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
612
613 reporter_ap_id = reporter.ap_id
614 target_ap_id = target_user.ap_id
615 activity_ap_id = activity.data["id"]
616 comment = "foobar"
617
618 report_data = %{
619 account_id: target_user.id,
620 comment: comment,
621 status_ids: [activity.id]
622 }
623
624 note_obj = %{
625 "type" => "Note",
626 "id" => activity_ap_id,
627 "content" => "foobar",
628 "published" => activity.object.data["published"],
629 "actor" => AccountView.render("show.json", %{user: target_user})
630 }
631
632 assert {:ok, flag_activity} = CommonAPI.report(reporter, report_data)
633
634 assert %Activity{
635 actor: ^reporter_ap_id,
636 data: %{
637 "type" => "Flag",
638 "content" => ^comment,
639 "object" => [^target_ap_id, ^note_obj],
640 "state" => "open"
641 }
642 } = flag_activity
643 end
644
645 test "updates report state" do
646 [reporter, target_user] = insert_pair(:user)
647 activity = insert(:note_activity, user: target_user)
648
649 {:ok, %Activity{id: report_id}} =
650 CommonAPI.report(reporter, %{
651 account_id: target_user.id,
652 comment: "I feel offended",
653 status_ids: [activity.id]
654 })
655
656 {:ok, report} = CommonAPI.update_report_state(report_id, "resolved")
657
658 assert report.data["state"] == "resolved"
659
660 [reported_user, activity_id] = report.data["object"]
661
662 assert reported_user == target_user.ap_id
663 assert activity_id == activity.data["id"]
664 end
665
666 test "does not update report state when state is unsupported" do
667 [reporter, target_user] = insert_pair(:user)
668 activity = insert(:note_activity, user: target_user)
669
670 {:ok, %Activity{id: report_id}} =
671 CommonAPI.report(reporter, %{
672 account_id: target_user.id,
673 comment: "I feel offended",
674 status_ids: [activity.id]
675 })
676
677 assert CommonAPI.update_report_state(report_id, "test") == {:error, "Unsupported state"}
678 end
679
680 test "updates state of multiple reports" do
681 [reporter, target_user] = insert_pair(:user)
682 activity = insert(:note_activity, user: target_user)
683
684 {:ok, %Activity{id: first_report_id}} =
685 CommonAPI.report(reporter, %{
686 account_id: target_user.id,
687 comment: "I feel offended",
688 status_ids: [activity.id]
689 })
690
691 {:ok, %Activity{id: second_report_id}} =
692 CommonAPI.report(reporter, %{
693 account_id: target_user.id,
694 comment: "I feel very offended!",
695 status_ids: [activity.id]
696 })
697
698 {:ok, report_ids} =
699 CommonAPI.update_report_state([first_report_id, second_report_id], "resolved")
700
701 first_report = Activity.get_by_id(first_report_id)
702 second_report = Activity.get_by_id(second_report_id)
703
704 assert report_ids -- [first_report_id, second_report_id] == []
705 assert first_report.data["state"] == "resolved"
706 assert second_report.data["state"] == "resolved"
707 end
708 end
709
710 describe "reblog muting" do
711 setup do
712 muter = insert(:user)
713
714 muted = insert(:user)
715
716 [muter: muter, muted: muted]
717 end
718
719 test "add a reblog mute", %{muter: muter, muted: muted} do
720 {:ok, _reblog_mute} = CommonAPI.hide_reblogs(muter, muted)
721
722 assert User.showing_reblogs?(muter, muted) == false
723 end
724
725 test "remove a reblog mute", %{muter: muter, muted: muted} do
726 {:ok, _reblog_mute} = CommonAPI.hide_reblogs(muter, muted)
727 {:ok, _reblog_mute} = CommonAPI.show_reblogs(muter, muted)
728
729 assert User.showing_reblogs?(muter, muted) == true
730 end
731 end
732
733 describe "unfollow/2" do
734 test "also unsubscribes a user" do
735 [follower, followed] = insert_pair(:user)
736 {:ok, follower, followed, _} = CommonAPI.follow(follower, followed)
737 {:ok, _subscription} = User.subscribe(follower, followed)
738
739 assert User.subscribed_to?(follower, followed)
740
741 {:ok, follower} = CommonAPI.unfollow(follower, followed)
742
743 refute User.subscribed_to?(follower, followed)
744 end
745
746 test "cancels a pending follow for a local user" do
747 follower = insert(:user)
748 followed = insert(:user, locked: true)
749
750 assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} =
751 CommonAPI.follow(follower, followed)
752
753 assert User.get_follow_state(follower, followed) == :follow_pending
754 assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
755 assert User.get_follow_state(follower, followed) == nil
756
757 assert %{id: ^activity_id, data: %{"state" => "cancelled"}} =
758 Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed)
759
760 assert %{
761 data: %{
762 "type" => "Undo",
763 "object" => %{"type" => "Follow", "state" => "cancelled"}
764 }
765 } = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower)
766 end
767
768 test "cancels a pending follow for a remote user" do
769 follower = insert(:user)
770 followed = insert(:user, locked: true, local: false, ap_enabled: true)
771
772 assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} =
773 CommonAPI.follow(follower, followed)
774
775 assert User.get_follow_state(follower, followed) == :follow_pending
776 assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
777 assert User.get_follow_state(follower, followed) == nil
778
779 assert %{id: ^activity_id, data: %{"state" => "cancelled"}} =
780 Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed)
781
782 assert %{
783 data: %{
784 "type" => "Undo",
785 "object" => %{"type" => "Follow", "state" => "cancelled"}
786 }
787 } = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower)
788 end
789 end
790
791 describe "accept_follow_request/2" do
792 test "after acceptance, it sets all existing pending follow request states to 'accept'" do
793 user = insert(:user, locked: true)
794 follower = insert(:user)
795 follower_two = insert(:user)
796
797 {:ok, follow_activity} = ActivityPub.follow(follower, user)
798 {:ok, follow_activity_two} = ActivityPub.follow(follower, user)
799 {:ok, follow_activity_three} = ActivityPub.follow(follower_two, user)
800
801 assert follow_activity.data["state"] == "pending"
802 assert follow_activity_two.data["state"] == "pending"
803 assert follow_activity_three.data["state"] == "pending"
804
805 {:ok, _follower} = CommonAPI.accept_follow_request(follower, user)
806
807 assert Repo.get(Activity, follow_activity.id).data["state"] == "accept"
808 assert Repo.get(Activity, follow_activity_two.id).data["state"] == "accept"
809 assert Repo.get(Activity, follow_activity_three.id).data["state"] == "pending"
810 end
811
812 test "after rejection, it sets all existing pending follow request states to 'reject'" do
813 user = insert(:user, locked: true)
814 follower = insert(:user)
815 follower_two = insert(:user)
816
817 {:ok, follow_activity} = ActivityPub.follow(follower, user)
818 {:ok, follow_activity_two} = ActivityPub.follow(follower, user)
819 {:ok, follow_activity_three} = ActivityPub.follow(follower_two, user)
820
821 assert follow_activity.data["state"] == "pending"
822 assert follow_activity_two.data["state"] == "pending"
823 assert follow_activity_three.data["state"] == "pending"
824
825 {:ok, _follower} = CommonAPI.reject_follow_request(follower, user)
826
827 assert Repo.get(Activity, follow_activity.id).data["state"] == "reject"
828 assert Repo.get(Activity, follow_activity_two.id).data["state"] == "reject"
829 assert Repo.get(Activity, follow_activity_three.id).data["state"] == "pending"
830 end
831
832 test "doesn't create a following relationship if the corresponding follow request doesn't exist" do
833 user = insert(:user, locked: true)
834 not_follower = insert(:user)
835 CommonAPI.accept_follow_request(not_follower, user)
836
837 assert Pleroma.FollowingRelationship.following?(not_follower, user) == false
838 end
839 end
840
841 describe "vote/3" do
842 test "does not allow to vote twice" do
843 user = insert(:user)
844 other_user = insert(:user)
845
846 {:ok, activity} =
847 CommonAPI.post(user, %{
848 "status" => "Am I cute?",
849 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
850 })
851
852 object = Object.normalize(activity)
853
854 {:ok, _, object} = CommonAPI.vote(other_user, object, [0])
855
856 assert {:error, "Already voted"} == CommonAPI.vote(other_user, object, [1])
857 end
858 end
859
860 describe "listen/2" do
861 test "returns a valid activity" do
862 user = insert(:user)
863
864 {:ok, activity} =
865 CommonAPI.listen(user, %{
866 "title" => "lain radio episode 1",
867 "album" => "lain radio",
868 "artist" => "lain",
869 "length" => 180_000
870 })
871
872 object = Object.normalize(activity)
873
874 assert object.data["title"] == "lain radio episode 1"
875
876 assert Visibility.get_visibility(activity) == "public"
877 end
878
879 test "respects visibility=private" do
880 user = insert(:user)
881
882 {:ok, activity} =
883 CommonAPI.listen(user, %{
884 "title" => "lain radio episode 1",
885 "album" => "lain radio",
886 "artist" => "lain",
887 "length" => 180_000,
888 "visibility" => "private"
889 })
890
891 object = Object.normalize(activity)
892
893 assert object.data["title"] == "lain radio episode 1"
894
895 assert Visibility.get_visibility(activity) == "private"
896 end
897 end
898 end