paginate follow requests (#460)
[akkoma] / test / pleroma / web / common_api_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.CommonAPITest do
6 use Oban.Testing, repo: Pleroma.Repo
7 use Pleroma.DataCase
8
9 alias Pleroma.Activity
10 alias Pleroma.Conversation.Participation
11 alias Pleroma.Notification
12 alias Pleroma.Object
13 alias Pleroma.Repo
14 alias Pleroma.User
15 alias Pleroma.Web.ActivityPub.Transmogrifier
16 alias Pleroma.Web.ActivityPub.Visibility
17 alias Pleroma.Web.AdminAPI.AccountView
18 alias Pleroma.Web.CommonAPI
19 alias Pleroma.Workers.PollWorker
20
21 import Pleroma.Factory
22 import Mock
23 import Ecto.Query, only: [from: 2]
24
25 require Pleroma.Constants
26
27 setup_all do
28 clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
29 clear_config([Pleroma.Uploaders.Local, :uploads], "uploads")
30 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
31 :ok
32 end
33
34 setup do: clear_config([:instance, :safe_dm_mentions])
35 setup do: clear_config([:instance, :limit])
36 setup do: clear_config([:instance, :max_pinned_statuses])
37
38 describe "posting polls" do
39 test "it posts a poll" do
40 user = insert(:user)
41
42 {:ok, activity} =
43 CommonAPI.post(user, %{
44 status: "who is the best",
45 poll: %{expires_in: 600, options: ["reimu", "marisa"]}
46 })
47
48 object = Object.normalize(activity, fetch: false)
49
50 assert object.data["type"] == "Question"
51 assert object.data["oneOf"] |> length() == 2
52
53 assert_enqueued(
54 worker: PollWorker,
55 args: %{op: "poll_end", activity_id: activity.id},
56 scheduled_at: NaiveDateTime.from_iso8601!(object.data["closed"])
57 )
58 end
59 end
60
61 describe "blocking" do
62 setup do
63 blocker = insert(:user)
64 blocked = insert(:user, local: false)
65 CommonAPI.follow(blocker, blocked)
66 CommonAPI.follow(blocked, blocker)
67 CommonAPI.accept_follow_request(blocker, blocked)
68 CommonAPI.accept_follow_request(blocked, blocked)
69 %{blocker: blocker, blocked: blocked}
70 end
71
72 test "it blocks and federates", %{blocker: blocker, blocked: blocked} do
73 clear_config([:instance, :federating], true)
74 clear_config([:activitypub, :outgoing_blocks], true)
75
76 with_mock Pleroma.Web.Federator,
77 publish: fn _ -> nil end do
78 assert User.get_follow_state(blocker, blocked) == :follow_accept
79 refute is_nil(Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(blocker, blocked))
80
81 assert {:ok, block} = CommonAPI.block(blocker, blocked)
82
83 assert block.local
84 assert User.blocks?(blocker, blocked)
85 refute User.following?(blocker, blocked)
86 refute User.following?(blocked, blocker)
87
88 refute User.get_follow_state(blocker, blocked)
89
90 assert %{data: %{"state" => "reject"}} =
91 Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(blocker, blocked)
92
93 assert called(Pleroma.Web.Federator.publish(block))
94 end
95 end
96
97 test "it blocks and does not federate if outgoing blocks are disabled", %{
98 blocker: blocker,
99 blocked: blocked
100 } do
101 clear_config([:instance, :federating], true)
102 clear_config([:activitypub, :outgoing_blocks], false)
103
104 with_mock Pleroma.Web.Federator,
105 publish: fn _ -> nil end do
106 assert {:ok, block} = CommonAPI.block(blocker, blocked)
107
108 assert block.local
109 assert User.blocks?(blocker, blocked)
110 refute User.following?(blocker, blocked)
111 refute User.following?(blocked, blocker)
112
113 refute called(Pleroma.Web.Federator.publish(block))
114 end
115 end
116 end
117
118 describe "unblocking" do
119 test "it works even without an existing block activity" do
120 blocked = insert(:user)
121 blocker = insert(:user)
122 User.block(blocker, blocked)
123
124 assert User.blocks?(blocker, blocked)
125 assert {:ok, :no_activity} == CommonAPI.unblock(blocker, blocked)
126 refute User.blocks?(blocker, blocked)
127 end
128 end
129
130 describe "deletion" do
131 test "it works with pruned objects" do
132 user = insert(:user)
133
134 {:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"})
135
136 clear_config([:instance, :federating], true)
137
138 Object.normalize(post, fetch: false)
139 |> Object.prune()
140
141 with_mock Pleroma.Web.Federator,
142 publish: fn _ -> nil end do
143 assert {:ok, delete} = CommonAPI.delete(post.id, user)
144 assert delete.local
145 assert called(Pleroma.Web.Federator.publish(delete))
146 end
147
148 refute Activity.get_by_id(post.id)
149 end
150
151 test "it allows users to delete their posts" do
152 user = insert(:user)
153
154 {:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"})
155
156 clear_config([:instance, :federating], true)
157
158 with_mock Pleroma.Web.Federator,
159 publish: fn _ -> nil end do
160 assert {:ok, delete} = CommonAPI.delete(post.id, user)
161 assert delete.local
162 assert called(Pleroma.Web.Federator.publish(delete))
163 end
164
165 refute Activity.get_by_id(post.id)
166 end
167
168 test "it does not allow a user to delete their posts" do
169 user = insert(:user)
170 other_user = insert(:user)
171
172 {:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"})
173
174 assert {:error, "Could not delete"} = CommonAPI.delete(post.id, other_user)
175 assert Activity.get_by_id(post.id)
176 end
177
178 test "it allows moderators to delete other user's posts" do
179 user = insert(:user)
180 moderator = insert(:user, is_moderator: true)
181
182 {:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"})
183
184 assert {:ok, delete} = CommonAPI.delete(post.id, moderator)
185 assert delete.local
186
187 refute Activity.get_by_id(post.id)
188 end
189
190 test "it allows admins to delete other user's posts" do
191 user = insert(:user)
192 moderator = insert(:user, is_admin: true)
193
194 {:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"})
195
196 assert {:ok, delete} = CommonAPI.delete(post.id, moderator)
197 assert delete.local
198
199 refute Activity.get_by_id(post.id)
200 end
201
202 test "superusers deleting non-local posts won't federate the delete" do
203 # This is the user of the ingested activity
204 _user =
205 insert(:user,
206 local: false,
207 ap_id: "http://mastodon.example.org/users/admin",
208 last_refreshed_at: NaiveDateTime.utc_now()
209 )
210
211 moderator = insert(:user, is_admin: true)
212
213 data =
214 File.read!("test/fixtures/mastodon-post-activity.json")
215 |> Jason.decode!()
216
217 {:ok, post} = Transmogrifier.handle_incoming(data)
218
219 with_mock Pleroma.Web.Federator,
220 publish: fn _ -> nil end do
221 assert {:ok, delete} = CommonAPI.delete(post.id, moderator)
222 assert delete.local
223 refute called(Pleroma.Web.Federator.publish(:_))
224 end
225
226 refute Activity.get_by_id(post.id)
227 end
228 end
229
230 test "favoriting race condition" do
231 user = insert(:user)
232 users_serial = insert_list(10, :user)
233 users = insert_list(10, :user)
234
235 {:ok, activity} = CommonAPI.post(user, %{status: "."})
236
237 users_serial
238 |> Enum.map(fn user ->
239 CommonAPI.favorite(user, activity.id)
240 end)
241
242 object = Object.get_by_ap_id(activity.data["object"])
243 assert object.data["like_count"] == 10
244
245 users
246 |> Enum.map(fn user ->
247 Task.async(fn ->
248 CommonAPI.favorite(user, activity.id)
249 end)
250 end)
251 |> Enum.map(&Task.await/1)
252
253 object = Object.get_by_ap_id(activity.data["object"])
254 assert object.data["like_count"] == 20
255 end
256
257 test "repeating race condition" do
258 user = insert(:user)
259 users_serial = insert_list(10, :user)
260 users = insert_list(10, :user)
261
262 {:ok, activity} = CommonAPI.post(user, %{status: "."})
263
264 users_serial
265 |> Enum.map(fn user ->
266 CommonAPI.repeat(activity.id, user)
267 end)
268
269 object = Object.get_by_ap_id(activity.data["object"])
270 assert object.data["announcement_count"] == 10
271
272 users
273 |> Enum.map(fn user ->
274 Task.async(fn ->
275 CommonAPI.repeat(activity.id, user)
276 end)
277 end)
278 |> Enum.map(&Task.await/1)
279
280 object = Object.get_by_ap_id(activity.data["object"])
281 assert object.data["announcement_count"] == 20
282 end
283
284 test "when replying to a conversation / participation, it will set the correct context id even if no explicit reply_to is given" do
285 user = insert(:user)
286 {:ok, activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"})
287
288 [participation] = Participation.for_user(user)
289
290 {:ok, convo_reply} =
291 CommonAPI.post(user, %{status: ".", in_reply_to_conversation_id: participation.id})
292
293 assert Visibility.is_direct?(convo_reply)
294
295 assert activity.data["context"] == convo_reply.data["context"]
296 end
297
298 test "when replying to a conversation / participation, it only mentions the recipients explicitly declared in the participation" do
299 har = insert(:user)
300 jafnhar = insert(:user)
301 tridi = insert(:user)
302
303 {:ok, activity} =
304 CommonAPI.post(har, %{
305 status: "@#{jafnhar.nickname} hey",
306 visibility: "direct"
307 })
308
309 assert har.ap_id in activity.recipients
310 assert jafnhar.ap_id in activity.recipients
311
312 [participation] = Participation.for_user(har)
313
314 {:ok, activity} =
315 CommonAPI.post(har, %{
316 status: "I don't really like @#{tridi.nickname}",
317 visibility: "direct",
318 in_reply_to_status_id: activity.id,
319 in_reply_to_conversation_id: participation.id
320 })
321
322 assert har.ap_id in activity.recipients
323 assert jafnhar.ap_id in activity.recipients
324 refute tridi.ap_id in activity.recipients
325 end
326
327 test "with the safe_dm_mention option set, it does not mention people beyond the initial tags" do
328 har = insert(:user)
329 jafnhar = insert(:user)
330 tridi = insert(:user)
331
332 clear_config([:instance, :safe_dm_mentions], true)
333
334 {:ok, activity} =
335 CommonAPI.post(har, %{
336 status: "@#{jafnhar.nickname} hey, i never want to see @#{tridi.nickname} again",
337 visibility: "direct"
338 })
339
340 refute tridi.ap_id in activity.recipients
341 assert jafnhar.ap_id in activity.recipients
342 end
343
344 test "it de-duplicates tags" do
345 user = insert(:user)
346 {:ok, activity} = CommonAPI.post(user, %{status: "#2hu #2HU"})
347
348 object = Object.normalize(activity, fetch: false)
349
350 assert Object.tags(object) == ["2hu"]
351 end
352
353 test "it adds emoji in the object" do
354 user = insert(:user)
355 {:ok, activity} = CommonAPI.post(user, %{status: ":firefox:"})
356
357 assert Object.normalize(activity, fetch: false).data["emoji"]["firefox"]
358 end
359
360 describe "posting" do
361 test "it adds an emoji on an external site" do
362 user = insert(:user)
363 {:ok, activity} = CommonAPI.post(user, %{status: "hey :external_emoji:"})
364
365 assert %{"external_emoji" => url} = Object.normalize(activity).data["emoji"]
366 assert url == "https://example.com/emoji.png"
367
368 {:ok, activity} = CommonAPI.post(user, %{status: "hey :blank:"})
369
370 assert %{"blank" => url} = Object.normalize(activity).data["emoji"]
371 assert url == "#{Pleroma.Web.Endpoint.url()}/emoji/blank.png"
372 end
373
374 test "it copies emoji from the subject of the parent post" do
375 %Object{} =
376 object =
377 Object.normalize("https://patch.cx/objects/a399c28e-c821-4820-bc3e-4afeb044c16f",
378 fetch: true
379 )
380
381 activity = Activity.get_create_by_object_ap_id(object.data["id"])
382 user = insert(:user)
383
384 {:ok, reply_activity} =
385 CommonAPI.post(user, %{
386 in_reply_to_id: activity.id,
387 status: ":joker_disapprove:",
388 spoiler_text: ":joker_smile:"
389 })
390
391 assert Object.normalize(reply_activity).data["emoji"]["joker_smile"]
392 refute Object.normalize(reply_activity).data["emoji"]["joker_disapprove"]
393 end
394
395 test "deactivated users can't post" do
396 user = insert(:user, is_active: false)
397 assert {:error, _} = CommonAPI.post(user, %{status: "ye"})
398 end
399
400 test "it supports explicit addressing" do
401 user = insert(:user)
402 user_two = insert(:user)
403 user_three = insert(:user)
404 user_four = insert(:user)
405
406 {:ok, activity} =
407 CommonAPI.post(user, %{
408 status:
409 "Hey, I think @#{user_three.nickname} is ugly. @#{user_four.nickname} is alright though.",
410 to: [user_two.nickname, user_four.nickname, "nonexistent"]
411 })
412
413 assert user.ap_id in activity.recipients
414 assert user_two.ap_id in activity.recipients
415 assert user_four.ap_id in activity.recipients
416 refute user_three.ap_id in activity.recipients
417 end
418
419 test "it filters out obviously bad tags when accepting a post as HTML" do
420 user = insert(:user)
421
422 post = "<p><b>2hu</b></p><script>alert('xss')</script>"
423
424 {:ok, activity} =
425 CommonAPI.post(user, %{
426 status: post,
427 content_type: "text/html"
428 })
429
430 object = Object.normalize(activity, fetch: false)
431
432 assert object.data["content"] == "<p><b>2hu</b></p>alert(&#39;xss&#39;)"
433
434 assert object.data["source"] == %{
435 "mediaType" => "text/html",
436 "content" => post
437 }
438 end
439
440 test "it filters out obviously bad tags when accepting a post as Markdown" do
441 user = insert(:user)
442
443 post = "<p><b>2hu</b></p><script>alert('xss')</script>"
444
445 {:ok, activity} =
446 CommonAPI.post(user, %{
447 status: post,
448 content_type: "text/markdown"
449 })
450
451 object = Object.normalize(activity, fetch: false)
452
453 assert object.data["content"] == "<p><b>2hu</b></p>"
454
455 assert object.data["source"] == %{
456 "mediaType" => "text/markdown",
457 "content" => post
458 }
459 end
460
461 test "it does not allow replies to direct messages that are not direct messages themselves" do
462 user = insert(:user)
463
464 {:ok, activity} = CommonAPI.post(user, %{status: "suya..", visibility: "direct"})
465
466 assert {:ok, _} =
467 CommonAPI.post(user, %{
468 status: "suya..",
469 visibility: "direct",
470 in_reply_to_status_id: activity.id
471 })
472
473 Enum.each(["public", "private", "unlisted"], fn visibility ->
474 assert {:error, "The message visibility must be direct"} =
475 CommonAPI.post(user, %{
476 status: "suya..",
477 visibility: visibility,
478 in_reply_to_status_id: activity.id
479 })
480 end)
481 end
482
483 test "replying with a direct message will NOT auto-add the author of the reply to the recipient list" do
484 user = insert(:user)
485 other_user = insert(:user)
486 third_user = insert(:user)
487
488 {:ok, post} = CommonAPI.post(user, %{status: "I'm stupid"})
489
490 {:ok, open_answer} =
491 CommonAPI.post(other_user, %{status: "No ur smart", in_reply_to_status_id: post.id})
492
493 # The OP is implicitly added
494 assert user.ap_id in open_answer.recipients
495
496 {:ok, secret_answer} =
497 CommonAPI.post(other_user, %{
498 status: "lol, that guy really is stupid, right, @#{third_user.nickname}?",
499 in_reply_to_status_id: post.id,
500 visibility: "direct"
501 })
502
503 assert third_user.ap_id in secret_answer.recipients
504
505 # The OP is not added
506 refute user.ap_id in secret_answer.recipients
507 end
508
509 test "it allows to address a list" do
510 user = insert(:user)
511 {:ok, list} = Pleroma.List.create("foo", user)
512
513 {:ok, activity} = CommonAPI.post(user, %{status: "foobar", visibility: "list:#{list.id}"})
514
515 assert activity.data["bcc"] == [list.ap_id]
516 assert activity.recipients == [list.ap_id, user.ap_id]
517 assert activity.data["listMessage"] == list.ap_id
518 end
519
520 test "it returns error when status is empty and no attachments" do
521 user = insert(:user)
522
523 assert {:error, "Cannot post an empty status without attachments"} =
524 CommonAPI.post(user, %{status: ""})
525 end
526
527 test "it validates character limits are correctly enforced" do
528 clear_config([:instance, :limit], 5)
529
530 user = insert(:user)
531
532 assert {:error, "The status is over the character limit"} =
533 CommonAPI.post(user, %{status: "foobar"})
534
535 assert {:ok, _activity} = CommonAPI.post(user, %{status: "12345"})
536 end
537
538 test "it can handle activities that expire" do
539 user = insert(:user)
540
541 expires_at = DateTime.add(DateTime.utc_now(), 1_000_000)
542
543 assert {:ok, activity} = CommonAPI.post(user, %{status: "chai", expires_in: 1_000_000})
544
545 assert_enqueued(
546 worker: Pleroma.Workers.PurgeExpiredActivity,
547 args: %{activity_id: activity.id},
548 scheduled_at: expires_at
549 )
550 end
551 end
552
553 describe "reactions" do
554 test "reacting to a status with an emoji" do
555 user = insert(:user)
556 other_user = insert(:user)
557
558 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
559
560 {:ok, reaction} = CommonAPI.react_with_emoji(activity.id, user, "👍")
561
562 assert reaction.data["actor"] == user.ap_id
563 assert reaction.data["content"] == "👍"
564
565 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
566
567 {:error, _} = CommonAPI.react_with_emoji(activity.id, user, ".")
568 end
569
570 test "unreacting to a status with an emoji" do
571 user = insert(:user)
572 other_user = insert(:user)
573
574 clear_config([:instance, :federating], true)
575
576 with_mock Pleroma.Web.Federator,
577 publish: fn _ -> nil end do
578 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
579 {:ok, reaction} = CommonAPI.react_with_emoji(activity.id, user, "👍")
580
581 {:ok, unreaction} = CommonAPI.unreact_with_emoji(activity.id, user, "👍")
582
583 assert unreaction.data["type"] == "Undo"
584 assert unreaction.data["object"] == reaction.data["id"]
585 assert unreaction.local
586
587 # On federation, it contains the undone (and deleted) object
588 unreaction_with_object = %{
589 unreaction
590 | data: Map.put(unreaction.data, "object", reaction.data)
591 }
592
593 assert called(Pleroma.Web.Federator.publish(unreaction_with_object))
594 end
595 end
596
597 test "repeating a status" do
598 user = insert(:user)
599 other_user = insert(:user)
600
601 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
602
603 {:ok, %Activity{} = announce_activity} = CommonAPI.repeat(activity.id, user)
604 assert Visibility.is_public?(announce_activity)
605 end
606
607 test "can't repeat a repeat" do
608 user = insert(:user)
609 other_user = insert(:user)
610 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
611
612 {:ok, %Activity{} = announce} = CommonAPI.repeat(activity.id, other_user)
613
614 refute match?({:ok, %Activity{}}, CommonAPI.repeat(announce.id, user))
615 end
616
617 test "repeating a status privately" do
618 user = insert(:user)
619 other_user = insert(:user)
620
621 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
622
623 {:ok, %Activity{} = announce_activity} =
624 CommonAPI.repeat(activity.id, user, %{visibility: "private"})
625
626 assert Visibility.is_private?(announce_activity)
627 refute Visibility.visible_for_user?(announce_activity, nil)
628 end
629
630 test "author can repeat own private statuses" do
631 author = insert(:user)
632 follower = insert(:user)
633 CommonAPI.follow(follower, author)
634
635 {:ok, activity} = CommonAPI.post(author, %{status: "cofe", visibility: "private"})
636
637 {:ok, %Activity{} = announce_activity} = CommonAPI.repeat(activity.id, author)
638
639 assert Visibility.is_private?(announce_activity)
640 refute Visibility.visible_for_user?(announce_activity, nil)
641
642 assert Visibility.visible_for_user?(activity, follower)
643 assert {:error, :not_found} = CommonAPI.repeat(activity.id, follower)
644 end
645
646 test "favoriting a status" do
647 user = insert(:user)
648 other_user = insert(:user)
649
650 {:ok, post_activity} = CommonAPI.post(other_user, %{status: "cofe"})
651
652 {:ok, %Activity{data: data}} = CommonAPI.favorite(user, post_activity.id)
653 assert data["type"] == "Like"
654 assert data["actor"] == user.ap_id
655 assert data["object"] == post_activity.data["object"]
656 end
657
658 test "retweeting a status twice returns the status" do
659 user = insert(:user)
660 other_user = insert(:user)
661
662 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
663 {:ok, %Activity{} = announce} = CommonAPI.repeat(activity.id, user)
664 {:ok, ^announce} = CommonAPI.repeat(activity.id, user)
665 end
666
667 test "favoriting a status twice returns ok, but without the like activity" do
668 user = insert(:user)
669 other_user = insert(:user)
670
671 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
672 {:ok, %Activity{}} = CommonAPI.favorite(user, activity.id)
673 assert {:ok, :already_liked} = CommonAPI.favorite(user, activity.id)
674 end
675 end
676
677 describe "pinned statuses" do
678 setup do
679 clear_config([:instance, :max_pinned_statuses], 1)
680
681 user = insert(:user)
682 {:ok, activity} = CommonAPI.post(user, %{status: "HI!!!"})
683
684 [user: user, activity: activity]
685 end
686
687 test "activity not found error", %{user: user} do
688 assert {:error, :not_found} = CommonAPI.pin("id", user)
689 end
690
691 test "pin status", %{user: user, activity: activity} do
692 assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
693
694 %{data: %{"id" => object_id}} = Object.normalize(activity)
695 user = refresh_record(user)
696
697 assert user.pinned_objects |> Map.keys() == [object_id]
698 end
699
700 test "pin poll", %{user: user} do
701 {:ok, activity} =
702 CommonAPI.post(user, %{
703 status: "How is fediverse today?",
704 poll: %{options: ["Absolutely outstanding", "Not good"], expires_in: 20}
705 })
706
707 assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
708
709 %{data: %{"id" => object_id}} = Object.normalize(activity)
710
711 user = refresh_record(user)
712
713 assert user.pinned_objects |> Map.keys() == [object_id]
714 end
715
716 test "unlisted statuses can be pinned", %{user: user} do
717 {:ok, activity} = CommonAPI.post(user, %{status: "HI!!!", visibility: "unlisted"})
718 assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
719 end
720
721 test "only self-authored can be pinned", %{activity: activity} do
722 user = insert(:user)
723
724 assert {:error, :ownership_error} = CommonAPI.pin(activity.id, user)
725 end
726
727 test "max pinned statuses", %{user: user, activity: activity_one} do
728 {:ok, activity_two} = CommonAPI.post(user, %{status: "HI!!!"})
729
730 assert {:ok, ^activity_one} = CommonAPI.pin(activity_one.id, user)
731
732 user = refresh_record(user)
733
734 assert {:error, :pinned_statuses_limit_reached} = CommonAPI.pin(activity_two.id, user)
735 end
736
737 test "only public can be pinned", %{user: user} do
738 {:ok, activity} = CommonAPI.post(user, %{status: "private status", visibility: "private"})
739 {:error, :visibility_error} = CommonAPI.pin(activity.id, user)
740 end
741
742 test "unpin status", %{user: user, activity: activity} do
743 {:ok, activity} = CommonAPI.pin(activity.id, user)
744
745 user = refresh_record(user)
746
747 id = activity.id
748
749 assert match?({:ok, %{id: ^id}}, CommonAPI.unpin(activity.id, user))
750
751 user = refresh_record(user)
752
753 assert user.pinned_objects == %{}
754 end
755
756 test "should unpin when deleting a status", %{user: user, activity: activity} do
757 {:ok, activity} = CommonAPI.pin(activity.id, user)
758
759 user = refresh_record(user)
760
761 assert {:ok, _} = CommonAPI.delete(activity.id, user)
762
763 user = refresh_record(user)
764
765 assert user.pinned_objects == %{}
766 end
767
768 test "ephemeral activity won't be deleted if was pinned", %{user: user} do
769 {:ok, activity} = CommonAPI.post(user, %{status: "Hello!", expires_in: 601})
770
771 assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity.id)
772
773 {:ok, _activity} = CommonAPI.pin(activity.id, user)
774 refute Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity.id)
775
776 user = refresh_record(user)
777 {:ok, _} = CommonAPI.unpin(activity.id, user)
778
779 # recreates expiration job on unpin
780 assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity.id)
781 end
782
783 test "ephemeral activity deletion job won't be deleted on pinning error", %{
784 user: user,
785 activity: activity
786 } do
787 clear_config([:instance, :max_pinned_statuses], 1)
788
789 {:ok, _activity} = CommonAPI.pin(activity.id, user)
790
791 {:ok, activity2} = CommonAPI.post(user, %{status: "another status", expires_in: 601})
792
793 assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity2.id)
794
795 user = refresh_record(user)
796 {:error, :pinned_statuses_limit_reached} = CommonAPI.pin(activity2.id, user)
797
798 assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity2.id)
799 end
800 end
801
802 describe "mute tests" do
803 setup do
804 user = insert(:user)
805
806 activity = insert(:note_activity)
807
808 [user: user, activity: activity]
809 end
810
811 test "marks notifications as read after mute" do
812 author = insert(:user)
813 activity = insert(:note_activity, user: author)
814
815 friend1 = insert(:user)
816 friend2 = insert(:user)
817
818 {:ok, reply_activity} =
819 CommonAPI.post(
820 friend2,
821 %{
822 status: "@#{author.nickname} @#{friend1.nickname} test reply",
823 in_reply_to_status_id: activity.id
824 }
825 )
826
827 {:ok, favorite_activity} = CommonAPI.favorite(friend2, activity.id)
828 {:ok, repeat_activity} = CommonAPI.repeat(activity.id, friend1)
829
830 assert Repo.aggregate(
831 from(n in Notification, where: n.seen == false and n.user_id == ^friend1.id),
832 :count
833 ) == 1
834
835 unread_notifications =
836 Repo.all(from(n in Notification, where: n.seen == false, where: n.user_id == ^author.id))
837
838 assert Enum.any?(unread_notifications, fn n ->
839 n.type == "favourite" && n.activity_id == favorite_activity.id
840 end)
841
842 assert Enum.any?(unread_notifications, fn n ->
843 n.type == "reblog" && n.activity_id == repeat_activity.id
844 end)
845
846 assert Enum.any?(unread_notifications, fn n ->
847 n.type == "mention" && n.activity_id == reply_activity.id
848 end)
849
850 {:ok, _} = CommonAPI.add_mute(author, activity)
851 assert CommonAPI.thread_muted?(author, activity)
852
853 assert Repo.aggregate(
854 from(n in Notification, where: n.seen == false and n.user_id == ^friend1.id),
855 :count
856 ) == 1
857
858 read_notifications =
859 Repo.all(from(n in Notification, where: n.seen == true, where: n.user_id == ^author.id))
860
861 assert Enum.any?(read_notifications, fn n ->
862 n.type == "favourite" && n.activity_id == favorite_activity.id
863 end)
864
865 assert Enum.any?(read_notifications, fn n ->
866 n.type == "reblog" && n.activity_id == repeat_activity.id
867 end)
868
869 assert Enum.any?(read_notifications, fn n ->
870 n.type == "mention" && n.activity_id == reply_activity.id
871 end)
872 end
873
874 test "add mute", %{user: user, activity: activity} do
875 {:ok, _} = CommonAPI.add_mute(user, activity)
876 assert CommonAPI.thread_muted?(user, activity)
877 end
878
879 test "add expiring mute", %{user: user, activity: activity} do
880 {:ok, _} = CommonAPI.add_mute(user, activity, %{expires_in: 60})
881 assert CommonAPI.thread_muted?(user, activity)
882
883 worker = Pleroma.Workers.MuteExpireWorker
884 args = %{"op" => "unmute_conversation", "user_id" => user.id, "activity_id" => activity.id}
885
886 assert_enqueued(
887 worker: worker,
888 args: args
889 )
890
891 assert :ok = perform_job(worker, args)
892 refute CommonAPI.thread_muted?(user, activity)
893 end
894
895 test "remove mute", %{user: user, activity: activity} do
896 CommonAPI.add_mute(user, activity)
897 {:ok, _} = CommonAPI.remove_mute(user, activity)
898 refute CommonAPI.thread_muted?(user, activity)
899 end
900
901 test "remove mute by ids", %{user: user, activity: activity} do
902 CommonAPI.add_mute(user, activity)
903 {:ok, _} = CommonAPI.remove_mute(user.id, activity.id)
904 refute CommonAPI.thread_muted?(user, activity)
905 end
906
907 test "check that mutes can't be duplicate", %{user: user, activity: activity} do
908 CommonAPI.add_mute(user, activity)
909 {:error, _} = CommonAPI.add_mute(user, activity)
910 end
911 end
912
913 describe "reports" do
914 test "creates a report" do
915 reporter = insert(:user)
916 target_user = insert(:user)
917
918 {:ok, activity} = CommonAPI.post(target_user, %{status: "foobar"})
919
920 reporter_ap_id = reporter.ap_id
921 target_ap_id = target_user.ap_id
922 activity_ap_id = activity.data["id"]
923 comment = "foobar"
924
925 report_data = %{
926 account_id: target_user.id,
927 comment: comment,
928 status_ids: [activity.id]
929 }
930
931 note_obj = %{
932 "type" => "Note",
933 "id" => activity_ap_id,
934 "content" => "foobar",
935 "published" => activity.object.data["published"],
936 "actor" => AccountView.render("show.json", %{user: target_user})
937 }
938
939 assert {:ok, flag_activity} = CommonAPI.report(reporter, report_data)
940
941 assert %Activity{
942 actor: ^reporter_ap_id,
943 data: %{
944 "type" => "Flag",
945 "content" => ^comment,
946 "object" => [^target_ap_id, ^note_obj],
947 "state" => "open"
948 }
949 } = flag_activity
950 end
951
952 test "updates report state" do
953 [reporter, target_user] = insert_pair(:user)
954 activity = insert(:note_activity, user: target_user)
955
956 {:ok, %Activity{id: report_id}} =
957 CommonAPI.report(reporter, %{
958 account_id: target_user.id,
959 comment: "I feel offended",
960 status_ids: [activity.id]
961 })
962
963 {:ok, report} = CommonAPI.update_report_state(report_id, "resolved")
964
965 assert report.data["state"] == "resolved"
966
967 [reported_user, activity_id] = report.data["object"]
968
969 assert reported_user == target_user.ap_id
970 assert activity_id == activity.data["id"]
971 end
972
973 test "does not update report state when state is unsupported" do
974 [reporter, target_user] = insert_pair(:user)
975 activity = insert(:note_activity, user: target_user)
976
977 {:ok, %Activity{id: report_id}} =
978 CommonAPI.report(reporter, %{
979 account_id: target_user.id,
980 comment: "I feel offended",
981 status_ids: [activity.id]
982 })
983
984 assert CommonAPI.update_report_state(report_id, "test") == {:error, "Unsupported state"}
985 end
986
987 test "updates state of multiple reports" do
988 [reporter, target_user] = insert_pair(:user)
989 activity = insert(:note_activity, user: target_user)
990
991 {:ok, %Activity{id: first_report_id}} =
992 CommonAPI.report(reporter, %{
993 account_id: target_user.id,
994 comment: "I feel offended",
995 status_ids: [activity.id]
996 })
997
998 {:ok, %Activity{id: second_report_id}} =
999 CommonAPI.report(reporter, %{
1000 account_id: target_user.id,
1001 comment: "I feel very offended!",
1002 status_ids: [activity.id]
1003 })
1004
1005 {:ok, report_ids} =
1006 CommonAPI.update_report_state([first_report_id, second_report_id], "resolved")
1007
1008 first_report = Activity.get_by_id(first_report_id)
1009 second_report = Activity.get_by_id(second_report_id)
1010
1011 assert report_ids -- [first_report_id, second_report_id] == []
1012 assert first_report.data["state"] == "resolved"
1013 assert second_report.data["state"] == "resolved"
1014 end
1015 end
1016
1017 describe "reblog muting" do
1018 setup do
1019 muter = insert(:user)
1020
1021 muted = insert(:user)
1022
1023 [muter: muter, muted: muted]
1024 end
1025
1026 test "add a reblog mute", %{muter: muter, muted: muted} do
1027 {:ok, _reblog_mute} = CommonAPI.hide_reblogs(muter, muted)
1028
1029 assert User.showing_reblogs?(muter, muted) == false
1030 end
1031
1032 test "remove a reblog mute", %{muter: muter, muted: muted} do
1033 {:ok, _reblog_mute} = CommonAPI.hide_reblogs(muter, muted)
1034 {:ok, _reblog_mute} = CommonAPI.show_reblogs(muter, muted)
1035
1036 assert User.showing_reblogs?(muter, muted) == true
1037 end
1038 end
1039
1040 describe "follow/2" do
1041 test "directly follows a non-locked local user" do
1042 [follower, followed] = insert_pair(:user)
1043 {:ok, follower, followed, _} = CommonAPI.follow(follower, followed)
1044
1045 assert User.following?(follower, followed)
1046 end
1047 end
1048
1049 describe "unfollow/2" do
1050 test "also unsubscribes a user" do
1051 [follower, followed] = insert_pair(:user)
1052 {:ok, follower, followed, _} = CommonAPI.follow(follower, followed)
1053 {:ok, _subscription} = User.subscribe(follower, followed)
1054
1055 assert User.subscribed_to?(follower, followed)
1056
1057 {:ok, follower} = CommonAPI.unfollow(follower, followed)
1058
1059 refute User.subscribed_to?(follower, followed)
1060 end
1061
1062 test "removes a pending follow for a local user" do
1063 follower = insert(:user)
1064 followed = insert(:user, is_locked: true)
1065
1066 assert {:ok, follower, followed, %{id: _activity_id, data: %{"state" => "pending"}}} =
1067 CommonAPI.follow(follower, followed)
1068
1069 assert User.get_follow_state(follower, followed) == :follow_pending
1070 assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
1071 assert User.get_follow_state(follower, followed) == nil
1072
1073 assert is_nil(Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed))
1074
1075 assert %{
1076 data: %{
1077 "type" => "Undo",
1078 "object" => %{"type" => "Follow"}
1079 }
1080 } = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower)
1081 end
1082
1083 test "cancels a pending follow for a remote user" do
1084 follower = insert(:user)
1085 followed = insert(:user, is_locked: true, local: false, ap_enabled: true)
1086
1087 assert {:ok, follower, followed, %{id: _activity_id, data: %{"state" => "pending"}}} =
1088 CommonAPI.follow(follower, followed)
1089
1090 assert User.get_follow_state(follower, followed) == :follow_pending
1091 assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
1092 assert User.get_follow_state(follower, followed) == nil
1093
1094 assert is_nil(Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed))
1095
1096 assert %{
1097 data: %{
1098 "type" => "Undo",
1099 "object" => %{"type" => "Follow"}
1100 }
1101 } = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower)
1102 end
1103 end
1104
1105 describe "accept_follow_request/2" do
1106 test "after acceptance, it sets all existing pending follow request states to 'accept'" do
1107 user = insert(:user, is_locked: true)
1108 follower = insert(:user)
1109 follower_two = insert(:user)
1110
1111 {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user)
1112 {:ok, _, _, follow_activity_two} = CommonAPI.follow(follower, user)
1113 {:ok, _, _, follow_activity_three} = CommonAPI.follow(follower_two, user)
1114
1115 assert follow_activity.data["state"] == "pending"
1116 assert follow_activity_two.data["state"] == "pending"
1117 assert follow_activity_three.data["state"] == "pending"
1118
1119 {:ok, _follower} = CommonAPI.accept_follow_request(follower, user)
1120
1121 assert Repo.get(Activity, follow_activity.id).data["state"] == "accept"
1122 assert Repo.get(Activity, follow_activity_two.id).data["state"] == "accept"
1123 assert Repo.get(Activity, follow_activity_three.id).data["state"] == "pending"
1124 end
1125
1126 test "after rejection, it sets all existing pending follow request states to 'reject'" do
1127 user = insert(:user, is_locked: true)
1128 follower = insert(:user)
1129 follower_two = insert(:user)
1130
1131 {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user)
1132 {:ok, _, _, follow_activity_two} = CommonAPI.follow(follower, user)
1133 {:ok, _, _, follow_activity_three} = CommonAPI.follow(follower_two, user)
1134
1135 assert follow_activity.data["state"] == "pending"
1136 assert follow_activity_two.data["state"] == "pending"
1137 assert follow_activity_three.data["state"] == "pending"
1138
1139 {:ok, _follower} = CommonAPI.reject_follow_request(follower, user)
1140
1141 assert Repo.get(Activity, follow_activity.id).data["state"] == "reject"
1142 assert Repo.get(Activity, follow_activity_two.id).data["state"] == "reject"
1143 assert Repo.get(Activity, follow_activity_three.id).data["state"] == "pending"
1144 end
1145
1146 test "doesn't create a following relationship if the corresponding follow request doesn't exist" do
1147 user = insert(:user, is_locked: true)
1148 not_follower = insert(:user)
1149 CommonAPI.accept_follow_request(not_follower, user)
1150
1151 assert Pleroma.FollowingRelationship.following?(not_follower, user) == false
1152 end
1153 end
1154
1155 describe "vote/3" do
1156 test "does not allow to vote twice" do
1157 user = insert(:user)
1158 other_user = insert(:user)
1159
1160 {:ok, activity} =
1161 CommonAPI.post(user, %{
1162 status: "Am I cute?",
1163 poll: %{options: ["Yes", "No"], expires_in: 20}
1164 })
1165
1166 object = Object.normalize(activity, fetch: false)
1167
1168 {:ok, _, object} = CommonAPI.vote(other_user, object, [0])
1169
1170 assert {:error, "Already voted"} == CommonAPI.vote(other_user, object, [1])
1171 end
1172 end
1173
1174 describe "get_user/1" do
1175 test "gets user by ap_id" do
1176 user = insert(:user)
1177 assert CommonAPI.get_user(user.ap_id) == user
1178 end
1179
1180 test "gets user by guessed nickname" do
1181 user = insert(:user, ap_id: "", nickname: "mario@mushroom.kingdom")
1182 assert CommonAPI.get_user("https://mushroom.kingdom/users/mario") == user
1183 end
1184
1185 test "fallback" do
1186 assert %User{
1187 name: "",
1188 ap_id: "",
1189 nickname: "erroruser@example.com"
1190 } = CommonAPI.get_user("")
1191 end
1192 end
1193
1194 describe "with `local` visibility" do
1195 setup do: clear_config([:instance, :federating], true)
1196
1197 test "post" do
1198 user = insert(:user)
1199
1200 with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
1201 {:ok, activity} = CommonAPI.post(user, %{status: "#2hu #2HU", visibility: "local"})
1202
1203 assert Visibility.is_local_public?(activity)
1204 assert_not_called(Pleroma.Web.Federator.publish(activity))
1205 end
1206 end
1207
1208 test "delete" do
1209 user = insert(:user)
1210
1211 {:ok, %Activity{id: activity_id}} =
1212 CommonAPI.post(user, %{status: "#2hu #2HU", visibility: "local"})
1213
1214 with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
1215 assert {:ok, %Activity{data: %{"deleted_activity_id" => ^activity_id}} = activity} =
1216 CommonAPI.delete(activity_id, user)
1217
1218 assert Visibility.is_local_public?(activity)
1219 assert_not_called(Pleroma.Web.Federator.publish(activity))
1220 end
1221 end
1222
1223 test "repeat" do
1224 user = insert(:user)
1225 other_user = insert(:user)
1226
1227 {:ok, %Activity{id: activity_id}} =
1228 CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
1229
1230 with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
1231 assert {:ok, %Activity{data: %{"type" => "Announce"}} = activity} =
1232 CommonAPI.repeat(activity_id, user)
1233
1234 assert Visibility.is_local_public?(activity)
1235 refute called(Pleroma.Web.Federator.publish(activity))
1236 end
1237 end
1238
1239 test "unrepeat" do
1240 user = insert(:user)
1241 other_user = insert(:user)
1242
1243 {:ok, %Activity{id: activity_id}} =
1244 CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
1245
1246 assert {:ok, _} = CommonAPI.repeat(activity_id, user)
1247
1248 with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
1249 assert {:ok, %Activity{data: %{"type" => "Undo"}} = activity} =
1250 CommonAPI.unrepeat(activity_id, user)
1251
1252 assert Visibility.is_local_public?(activity)
1253 refute called(Pleroma.Web.Federator.publish(activity))
1254 end
1255 end
1256
1257 test "favorite" do
1258 user = insert(:user)
1259 other_user = insert(:user)
1260
1261 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
1262
1263 with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
1264 assert {:ok, %Activity{data: %{"type" => "Like"}} = activity} =
1265 CommonAPI.favorite(user, activity.id)
1266
1267 assert Visibility.is_local_public?(activity)
1268 refute called(Pleroma.Web.Federator.publish(activity))
1269 end
1270 end
1271
1272 test "unfavorite" do
1273 user = insert(:user)
1274 other_user = insert(:user)
1275
1276 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
1277
1278 {:ok, %Activity{}} = CommonAPI.favorite(user, activity.id)
1279
1280 with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
1281 assert {:ok, activity} = CommonAPI.unfavorite(activity.id, user)
1282 assert Visibility.is_local_public?(activity)
1283 refute called(Pleroma.Web.Federator.publish(activity))
1284 end
1285 end
1286
1287 test "react_with_emoji" do
1288 user = insert(:user)
1289 other_user = insert(:user)
1290 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
1291
1292 with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
1293 assert {:ok, %Activity{data: %{"type" => "EmojiReact"}} = activity} =
1294 CommonAPI.react_with_emoji(activity.id, user, "👍")
1295
1296 assert Visibility.is_local_public?(activity)
1297 refute called(Pleroma.Web.Federator.publish(activity))
1298 end
1299 end
1300
1301 test "unreact_with_emoji" do
1302 user = insert(:user)
1303 other_user = insert(:user)
1304 {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
1305
1306 {:ok, _reaction} = CommonAPI.react_with_emoji(activity.id, user, "👍")
1307
1308 with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
1309 assert {:ok, %Activity{data: %{"type" => "Undo"}} = activity} =
1310 CommonAPI.unreact_with_emoji(activity.id, user, "👍")
1311
1312 assert Visibility.is_local_public?(activity)
1313 refute called(Pleroma.Web.Federator.publish(activity))
1314 end
1315 end
1316 end
1317
1318 describe "update/3" do
1319 test "updates a post" do
1320 user = insert(:user)
1321 {:ok, activity} = CommonAPI.post(user, %{status: "foo1", spoiler_text: "title 1"})
1322
1323 {:ok, updated} = CommonAPI.update(user, activity, %{status: "updated 2"})
1324
1325 updated_object = Object.normalize(updated)
1326 assert updated_object.data["content"] == "updated 2"
1327 assert Map.get(updated_object.data, "summary", "") == ""
1328 assert Map.has_key?(updated_object.data, "updated")
1329 end
1330
1331 test "does not change visibility" do
1332 user = insert(:user)
1333
1334 {:ok, activity} =
1335 CommonAPI.post(user, %{status: "foo1", spoiler_text: "title 1", visibility: "private"})
1336
1337 {:ok, updated} = CommonAPI.update(user, activity, %{status: "updated 2"})
1338
1339 updated_object = Object.normalize(updated)
1340 assert updated_object.data["content"] == "updated 2"
1341 assert Map.get(updated_object.data, "summary", "") == ""
1342 assert Visibility.get_visibility(updated_object) == "private"
1343 assert Visibility.get_visibility(updated) == "private"
1344 end
1345
1346 test "updates a post with emoji" do
1347 [{emoji1, _}, {emoji2, _} | _] = Pleroma.Emoji.get_all()
1348
1349 user = insert(:user)
1350
1351 {:ok, activity} =
1352 CommonAPI.post(user, %{status: "foo1", spoiler_text: "title 1 :#{emoji1}:"})
1353
1354 {:ok, updated} = CommonAPI.update(user, activity, %{status: "updated 2 :#{emoji2}:"})
1355
1356 updated_object = Object.normalize(updated)
1357 assert updated_object.data["content"] == "updated 2 :#{emoji2}:"
1358 assert %{^emoji2 => _} = updated_object.data["emoji"]
1359 end
1360
1361 test "updates a post with emoji and federate properly" do
1362 [{emoji1, _}, {emoji2, _} | _] = Pleroma.Emoji.get_all()
1363
1364 user = insert(:user)
1365
1366 {:ok, activity} =
1367 CommonAPI.post(user, %{status: "foo1", spoiler_text: "title 1 :#{emoji1}:"})
1368
1369 clear_config([:instance, :federating], true)
1370
1371 with_mock Pleroma.Web.Federator,
1372 publish: fn _p -> nil end do
1373 {:ok, updated} = CommonAPI.update(user, activity, %{status: "updated 2 :#{emoji2}:"})
1374
1375 assert updated.data["object"]["content"] == "updated 2 :#{emoji2}:"
1376 assert %{^emoji2 => _} = updated.data["object"]["emoji"]
1377
1378 assert called(Pleroma.Web.Federator.publish(updated))
1379 end
1380 end
1381
1382 test "editing a post that copied a remote title with remote emoji should keep that emoji" do
1383 remote_emoji_uri = "https://remote.org/emoji.png"
1384
1385 note =
1386 insert(
1387 :note,
1388 data: %{
1389 "summary" => ":remoteemoji:",
1390 "emoji" => %{
1391 "remoteemoji" => remote_emoji_uri
1392 },
1393 "tag" => [
1394 %{
1395 "type" => "Emoji",
1396 "name" => "remoteemoji",
1397 "icon" => %{"url" => remote_emoji_uri}
1398 }
1399 ]
1400 }
1401 )
1402
1403 note_activity = insert(:note_activity, note: note)
1404
1405 user = insert(:user)
1406
1407 {:ok, reply} =
1408 CommonAPI.post(user, %{
1409 status: "reply",
1410 spoiler_text: ":remoteemoji:",
1411 in_reply_to_id: note_activity.id
1412 })
1413
1414 assert reply.object.data["emoji"]["remoteemoji"] == remote_emoji_uri
1415
1416 {:ok, edit} =
1417 CommonAPI.update(user, reply, %{status: "reply mew mew", spoiler_text: ":remoteemoji:"})
1418
1419 edited_note = Pleroma.Object.normalize(edit)
1420
1421 assert edited_note.data["emoji"]["remoteemoji"] == remote_emoji_uri
1422 end
1423
1424 test "respects MRF" do
1425 user = insert(:user)
1426
1427 clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.KeywordPolicy])
1428 clear_config([:mrf_keyword, :replace], [{"updated", "mewmew"}])
1429
1430 {:ok, activity} = CommonAPI.post(user, %{status: "foo1", spoiler_text: "updated 1"})
1431 assert Object.normalize(activity).data["summary"] == "mewmew 1"
1432
1433 {:ok, updated} = CommonAPI.update(user, activity, %{status: "updated 2"})
1434
1435 updated_object = Object.normalize(updated)
1436 assert updated_object.data["content"] == "mewmew 2"
1437 assert Map.get(updated_object.data, "summary", "") == ""
1438 assert Map.has_key?(updated_object.data, "updated")
1439 end
1440 end
1441 end