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