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