Merge remote-tracking branch 'remotes/origin/develop' into restricted-relations-embedding
[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} = CommonAPI.post(user, %{status: "foobar", visibility: "list:#{list.id}"})
331
332 assert activity.data["bcc"] == [list.ap_id]
333 assert activity.recipients == [list.ap_id, user.ap_id]
334 assert activity.data["listMessage"] == list.ap_id
335 end
336
337 test "it returns error when status is empty and no attachments" do
338 user = insert(:user)
339
340 assert {:error, "Cannot post an empty status without attachments"} =
341 CommonAPI.post(user, %{status: ""})
342 end
343
344 test "it validates character limits are correctly enforced" do
345 Pleroma.Config.put([:instance, :limit], 5)
346
347 user = insert(:user)
348
349 assert {:error, "The status is over the character limit"} =
350 CommonAPI.post(user, %{status: "foobar"})
351
352 assert {:ok, activity} = CommonAPI.post(user, %{status: "12345"})
353 end
354
355 test "it can handle activities that expire" do
356 user = insert(:user)
357
358 expires_at =
359 NaiveDateTime.utc_now()
360 |> NaiveDateTime.truncate(:second)
361 |> NaiveDateTime.add(1_000_000, :second)
362
363 assert {:ok, activity} = CommonAPI.post(user, %{status: "chai", expires_in: 1_000_000})
364
365 assert expiration = Pleroma.ActivityExpiration.get_by_activity_id(activity.id)
366 assert expiration.scheduled_at == expires_at
367 end
368 end
369
370 describe "reactions" do
371 test "reacting to a status with an emoji" do
372 user = insert(:user)
373 other_user = insert(:user)
374
375 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
376
377 {:ok, reaction} = CommonAPI.react_with_emoji(activity.id, user, "👍")
378
379 assert reaction.data["actor"] == user.ap_id
380 assert reaction.data["content"] == "👍"
381
382 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
383
384 {:error, _} = CommonAPI.react_with_emoji(activity.id, user, ".")
385 end
386
387 test "unreacting to a status with an emoji" do
388 user = insert(:user)
389 other_user = insert(:user)
390
391 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
392 {:ok, reaction} = CommonAPI.react_with_emoji(activity.id, user, "👍")
393
394 {:ok, unreaction} = CommonAPI.unreact_with_emoji(activity.id, user, "👍")
395
396 assert unreaction.data["type"] == "Undo"
397 assert unreaction.data["object"] == reaction.data["id"]
398 assert unreaction.local
399 end
400
401 test "repeating a status" do
402 user = insert(:user)
403 other_user = insert(:user)
404
405 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
406
407 {:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, user)
408 end
409
410 test "can't repeat a repeat" do
411 user = insert(:user)
412 other_user = insert(:user)
413 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
414
415 {:ok, %Activity{} = announce, _} = CommonAPI.repeat(activity.id, other_user)
416
417 refute match?({:ok, %Activity{}, _}, CommonAPI.repeat(announce.id, user))
418 end
419
420 test "repeating a status privately" do
421 user = insert(:user)
422 other_user = insert(:user)
423
424 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
425
426 {:ok, %Activity{} = announce_activity, _} =
427 CommonAPI.repeat(activity.id, user, %{visibility: "private"})
428
429 assert Visibility.is_private?(announce_activity)
430 end
431
432 test "favoriting a status" do
433 user = insert(:user)
434 other_user = insert(:user)
435
436 {:ok, post_activity} = CommonAPI.post(other_user, %{status: "cofe"})
437
438 {:ok, %Activity{data: data}} = CommonAPI.favorite(user, post_activity.id)
439 assert data["type"] == "Like"
440 assert data["actor"] == user.ap_id
441 assert data["object"] == post_activity.data["object"]
442 end
443
444 test "retweeting a status twice returns the status" do
445 user = insert(:user)
446 other_user = insert(:user)
447
448 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
449 {:ok, %Activity{} = announce, object} = CommonAPI.repeat(activity.id, user)
450 {:ok, ^announce, ^object} = CommonAPI.repeat(activity.id, user)
451 end
452
453 test "favoriting a status twice returns ok, but without the like activity" do
454 user = insert(:user)
455 other_user = insert(:user)
456
457 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
458 {:ok, %Activity{}} = CommonAPI.favorite(user, activity.id)
459 assert {:ok, :already_liked} = CommonAPI.favorite(user, activity.id)
460 end
461 end
462
463 describe "pinned statuses" do
464 setup do
465 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
466
467 user = insert(:user)
468 {:ok, activity} = CommonAPI.post(user, %{status: "HI!!!"})
469
470 [user: user, activity: activity]
471 end
472
473 test "pin status", %{user: user, activity: activity} do
474 assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
475
476 id = activity.id
477 user = refresh_record(user)
478
479 assert %User{pinned_activities: [^id]} = user
480 end
481
482 test "pin poll", %{user: user} do
483 {:ok, activity} =
484 CommonAPI.post(user, %{
485 status: "How is fediverse today?",
486 poll: %{options: ["Absolutely outstanding", "Not good"], expires_in: 20}
487 })
488
489 assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
490
491 id = activity.id
492 user = refresh_record(user)
493
494 assert %User{pinned_activities: [^id]} = user
495 end
496
497 test "unlisted statuses can be pinned", %{user: user} do
498 {:ok, activity} = CommonAPI.post(user, %{status: "HI!!!", visibility: "unlisted"})
499 assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
500 end
501
502 test "only self-authored can be pinned", %{activity: activity} do
503 user = insert(:user)
504
505 assert {:error, "Could not pin"} = CommonAPI.pin(activity.id, user)
506 end
507
508 test "max pinned statuses", %{user: user, activity: activity_one} do
509 {:ok, activity_two} = CommonAPI.post(user, %{status: "HI!!!"})
510
511 assert {:ok, ^activity_one} = CommonAPI.pin(activity_one.id, user)
512
513 user = refresh_record(user)
514
515 assert {:error, "You have already pinned the maximum number of statuses"} =
516 CommonAPI.pin(activity_two.id, user)
517 end
518
519 test "unpin status", %{user: user, activity: activity} do
520 {:ok, activity} = CommonAPI.pin(activity.id, user)
521
522 user = refresh_record(user)
523
524 id = activity.id
525
526 assert match?({:ok, %{id: ^id}}, CommonAPI.unpin(activity.id, user))
527
528 user = refresh_record(user)
529
530 assert %User{pinned_activities: []} = user
531 end
532
533 test "should unpin when deleting a status", %{user: user, activity: activity} do
534 {:ok, activity} = CommonAPI.pin(activity.id, user)
535
536 user = refresh_record(user)
537
538 assert {:ok, _} = CommonAPI.delete(activity.id, user)
539
540 user = refresh_record(user)
541
542 assert %User{pinned_activities: []} = user
543 end
544 end
545
546 describe "mute tests" do
547 setup do
548 user = insert(:user)
549
550 activity = insert(:note_activity)
551
552 [user: user, activity: activity]
553 end
554
555 test "add mute", %{user: user, activity: activity} do
556 {:ok, _} = CommonAPI.add_mute(user, activity)
557 assert CommonAPI.thread_muted?(user, activity)
558 end
559
560 test "remove mute", %{user: user, activity: activity} do
561 CommonAPI.add_mute(user, activity)
562 {:ok, _} = CommonAPI.remove_mute(user, activity)
563 refute CommonAPI.thread_muted?(user, activity)
564 end
565
566 test "check that mutes can't be duplicate", %{user: user, activity: activity} do
567 CommonAPI.add_mute(user, activity)
568 {:error, _} = CommonAPI.add_mute(user, activity)
569 end
570 end
571
572 describe "reports" do
573 test "creates a report" do
574 reporter = insert(:user)
575 target_user = insert(:user)
576
577 {:ok, activity} = CommonAPI.post(target_user, %{status: "foobar"})
578
579 reporter_ap_id = reporter.ap_id
580 target_ap_id = target_user.ap_id
581 activity_ap_id = activity.data["id"]
582 comment = "foobar"
583
584 report_data = %{
585 account_id: target_user.id,
586 comment: comment,
587 status_ids: [activity.id]
588 }
589
590 note_obj = %{
591 "type" => "Note",
592 "id" => activity_ap_id,
593 "content" => "foobar",
594 "published" => activity.object.data["published"],
595 "actor" => AccountView.render("show.json", %{user: target_user})
596 }
597
598 assert {:ok, flag_activity} = CommonAPI.report(reporter, report_data)
599
600 assert %Activity{
601 actor: ^reporter_ap_id,
602 data: %{
603 "type" => "Flag",
604 "content" => ^comment,
605 "object" => [^target_ap_id, ^note_obj],
606 "state" => "open"
607 }
608 } = flag_activity
609 end
610
611 test "updates report state" do
612 [reporter, target_user] = insert_pair(:user)
613 activity = insert(:note_activity, user: target_user)
614
615 {:ok, %Activity{id: report_id}} =
616 CommonAPI.report(reporter, %{
617 account_id: target_user.id,
618 comment: "I feel offended",
619 status_ids: [activity.id]
620 })
621
622 {:ok, report} = CommonAPI.update_report_state(report_id, "resolved")
623
624 assert report.data["state"] == "resolved"
625
626 [reported_user, activity_id] = report.data["object"]
627
628 assert reported_user == target_user.ap_id
629 assert activity_id == activity.data["id"]
630 end
631
632 test "does not update report state when state is unsupported" do
633 [reporter, target_user] = insert_pair(:user)
634 activity = insert(:note_activity, user: target_user)
635
636 {:ok, %Activity{id: report_id}} =
637 CommonAPI.report(reporter, %{
638 account_id: target_user.id,
639 comment: "I feel offended",
640 status_ids: [activity.id]
641 })
642
643 assert CommonAPI.update_report_state(report_id, "test") == {:error, "Unsupported state"}
644 end
645
646 test "updates state of multiple reports" do
647 [reporter, target_user] = insert_pair(:user)
648 activity = insert(:note_activity, user: target_user)
649
650 {:ok, %Activity{id: first_report_id}} =
651 CommonAPI.report(reporter, %{
652 account_id: target_user.id,
653 comment: "I feel offended",
654 status_ids: [activity.id]
655 })
656
657 {:ok, %Activity{id: second_report_id}} =
658 CommonAPI.report(reporter, %{
659 account_id: target_user.id,
660 comment: "I feel very offended!",
661 status_ids: [activity.id]
662 })
663
664 {:ok, report_ids} =
665 CommonAPI.update_report_state([first_report_id, second_report_id], "resolved")
666
667 first_report = Activity.get_by_id(first_report_id)
668 second_report = Activity.get_by_id(second_report_id)
669
670 assert report_ids -- [first_report_id, second_report_id] == []
671 assert first_report.data["state"] == "resolved"
672 assert second_report.data["state"] == "resolved"
673 end
674 end
675
676 describe "reblog muting" do
677 setup do
678 muter = insert(:user)
679
680 muted = insert(:user)
681
682 [muter: muter, muted: muted]
683 end
684
685 test "add a reblog mute", %{muter: muter, muted: muted} do
686 {:ok, _reblog_mute} = CommonAPI.hide_reblogs(muter, muted)
687
688 assert User.showing_reblogs?(muter, muted) == false
689 end
690
691 test "remove a reblog mute", %{muter: muter, muted: muted} do
692 {:ok, _reblog_mute} = CommonAPI.hide_reblogs(muter, muted)
693 {:ok, _reblog_mute} = CommonAPI.show_reblogs(muter, muted)
694
695 assert User.showing_reblogs?(muter, muted) == true
696 end
697 end
698
699 describe "unfollow/2" do
700 test "also unsubscribes a user" do
701 [follower, followed] = insert_pair(:user)
702 {:ok, follower, followed, _} = CommonAPI.follow(follower, followed)
703 {:ok, _subscription} = User.subscribe(follower, followed)
704
705 assert User.subscribed_to?(follower, followed)
706
707 {:ok, follower} = CommonAPI.unfollow(follower, followed)
708
709 refute User.subscribed_to?(follower, followed)
710 end
711
712 test "cancels a pending follow for a local user" do
713 follower = insert(:user)
714 followed = insert(:user, locked: true)
715
716 assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} =
717 CommonAPI.follow(follower, followed)
718
719 assert User.get_follow_state(follower, followed) == :follow_pending
720 assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
721 assert User.get_follow_state(follower, followed) == nil
722
723 assert %{id: ^activity_id, data: %{"state" => "cancelled"}} =
724 Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed)
725
726 assert %{
727 data: %{
728 "type" => "Undo",
729 "object" => %{"type" => "Follow", "state" => "cancelled"}
730 }
731 } = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower)
732 end
733
734 test "cancels a pending follow for a remote user" do
735 follower = insert(:user)
736 followed = insert(:user, locked: true, local: false, ap_enabled: true)
737
738 assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} =
739 CommonAPI.follow(follower, followed)
740
741 assert User.get_follow_state(follower, followed) == :follow_pending
742 assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
743 assert User.get_follow_state(follower, followed) == nil
744
745 assert %{id: ^activity_id, data: %{"state" => "cancelled"}} =
746 Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed)
747
748 assert %{
749 data: %{
750 "type" => "Undo",
751 "object" => %{"type" => "Follow", "state" => "cancelled"}
752 }
753 } = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower)
754 end
755 end
756
757 describe "accept_follow_request/2" do
758 test "after acceptance, it sets all existing pending follow request states to 'accept'" do
759 user = insert(:user, locked: true)
760 follower = insert(:user)
761 follower_two = insert(:user)
762
763 {:ok, follow_activity} = ActivityPub.follow(follower, user)
764 {:ok, follow_activity_two} = ActivityPub.follow(follower, user)
765 {:ok, follow_activity_three} = ActivityPub.follow(follower_two, user)
766
767 assert follow_activity.data["state"] == "pending"
768 assert follow_activity_two.data["state"] == "pending"
769 assert follow_activity_three.data["state"] == "pending"
770
771 {:ok, _follower} = CommonAPI.accept_follow_request(follower, user)
772
773 assert Repo.get(Activity, follow_activity.id).data["state"] == "accept"
774 assert Repo.get(Activity, follow_activity_two.id).data["state"] == "accept"
775 assert Repo.get(Activity, follow_activity_three.id).data["state"] == "pending"
776 end
777
778 test "after rejection, it sets all existing pending follow request states to 'reject'" do
779 user = insert(:user, locked: true)
780 follower = insert(:user)
781 follower_two = insert(:user)
782
783 {:ok, follow_activity} = ActivityPub.follow(follower, user)
784 {:ok, follow_activity_two} = ActivityPub.follow(follower, user)
785 {:ok, follow_activity_three} = ActivityPub.follow(follower_two, user)
786
787 assert follow_activity.data["state"] == "pending"
788 assert follow_activity_two.data["state"] == "pending"
789 assert follow_activity_three.data["state"] == "pending"
790
791 {:ok, _follower} = CommonAPI.reject_follow_request(follower, user)
792
793 assert Repo.get(Activity, follow_activity.id).data["state"] == "reject"
794 assert Repo.get(Activity, follow_activity_two.id).data["state"] == "reject"
795 assert Repo.get(Activity, follow_activity_three.id).data["state"] == "pending"
796 end
797
798 test "doesn't create a following relationship if the corresponding follow request doesn't exist" do
799 user = insert(:user, locked: true)
800 not_follower = insert(:user)
801 CommonAPI.accept_follow_request(not_follower, user)
802
803 assert Pleroma.FollowingRelationship.following?(not_follower, user) == false
804 end
805 end
806
807 describe "vote/3" do
808 test "does not allow to vote twice" do
809 user = insert(:user)
810 other_user = insert(:user)
811
812 {:ok, activity} =
813 CommonAPI.post(user, %{
814 status: "Am I cute?",
815 poll: %{options: ["Yes", "No"], expires_in: 20}
816 })
817
818 object = Object.normalize(activity)
819
820 {:ok, _, object} = CommonAPI.vote(other_user, object, [0])
821
822 assert {:error, "Already voted"} == CommonAPI.vote(other_user, object, [1])
823 end
824 end
825
826 describe "listen/2" do
827 test "returns a valid activity" do
828 user = insert(:user)
829
830 {:ok, activity} =
831 CommonAPI.listen(user, %{
832 "title" => "lain radio episode 1",
833 "album" => "lain radio",
834 "artist" => "lain",
835 "length" => 180_000
836 })
837
838 object = Object.normalize(activity)
839
840 assert object.data["title"] == "lain radio episode 1"
841
842 assert Visibility.get_visibility(activity) == "public"
843 end
844
845 test "respects visibility=private" do
846 user = insert(:user)
847
848 {:ok, activity} =
849 CommonAPI.listen(user, %{
850 "title" => "lain radio episode 1",
851 "album" => "lain radio",
852 "artist" => "lain",
853 "length" => 180_000,
854 "visibility" => "private"
855 })
856
857 object = Object.normalize(activity)
858
859 assert object.data["title"] == "lain radio episode 1"
860
861 assert Visibility.get_visibility(activity) == "private"
862 end
863 end
864 end