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