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