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