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