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