3eeae40042c76f7dacef8ef9ffbc252d85d9c7b0
[akkoma] / test / pleroma / web / activity_pub / transmogrifier / note_handling_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.ActivityPub.Transmogrifier.NoteHandlingTest do
6 use Oban.Testing, repo: Pleroma.Repo
7 use Pleroma.DataCase
8
9 alias Pleroma.Activity
10 alias Pleroma.Object
11 alias Pleroma.User
12 alias Pleroma.Web.ActivityPub.Transmogrifier
13 alias Pleroma.Web.CommonAPI
14
15 import Mock
16 import Pleroma.Factory
17
18 setup_all do
19 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
20 :ok
21 end
22
23 setup do: clear_config([:instance, :max_remote_account_fields])
24
25 describe "handle_incoming" do
26 test "it works for incoming notices with tag not being an array (kroeg)" do
27 data = File.read!("test/fixtures/kroeg-array-less-emoji.json") |> Jason.decode!()
28
29 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
30 object = Object.normalize(data["object"], fetch: false)
31
32 assert object.data["emoji"] == %{
33 "icon_e_smile" => "https://puckipedia.com/forum/images/smilies/icon_e_smile.png"
34 }
35
36 data = File.read!("test/fixtures/kroeg-array-less-hashtag.json") |> Jason.decode!()
37
38 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
39 object = Object.normalize(data["object"], fetch: false)
40
41 assert "test" in Object.tags(object)
42 assert Object.hashtags(object) == ["test"]
43 end
44
45 test "it cleans up incoming notices which are not really DMs" do
46 user = insert(:user)
47 other_user = insert(:user)
48
49 to = [user.ap_id, other_user.ap_id]
50
51 data =
52 File.read!("test/fixtures/mastodon-post-activity.json")
53 |> Jason.decode!()
54 |> Map.put("to", to)
55 |> Map.put("cc", [])
56
57 object =
58 data["object"]
59 |> Map.put("to", to)
60 |> Map.put("cc", [])
61
62 data = Map.put(data, "object", object)
63
64 {:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data)
65
66 assert data["to"] == []
67 assert data["cc"] == to
68
69 object_data = Object.normalize(activity, fetch: false).data
70
71 assert object_data["to"] == []
72 assert object_data["cc"] == to
73 end
74
75 test "it ignores an incoming notice if we already have it" do
76 activity = insert(:note_activity)
77
78 data =
79 File.read!("test/fixtures/mastodon-post-activity.json")
80 |> Jason.decode!()
81 |> Map.put("object", Object.normalize(activity, fetch: false).data)
82
83 {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
84
85 assert activity == returned_activity
86 end
87
88 @tag capture_log: true
89 test "it fetches reply-to activities if we don't have them" do
90 data =
91 File.read!("test/fixtures/mastodon-post-activity.json")
92 |> Jason.decode!()
93
94 object =
95 data["object"]
96 |> Map.put("inReplyTo", "https://mstdn.io/users/mayuutann/statuses/99568293732299394")
97
98 data = Map.put(data, "object", object)
99 {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
100 returned_object = Object.normalize(returned_activity, fetch: false)
101
102 assert %Activity{} =
103 Activity.get_create_by_object_ap_id(
104 "https://mstdn.io/users/mayuutann/statuses/99568293732299394"
105 )
106
107 assert returned_object.data["inReplyTo"] ==
108 "https://mstdn.io/users/mayuutann/statuses/99568293732299394"
109 end
110
111 test "it does not fetch reply-to activities beyond max replies depth limit" do
112 data =
113 File.read!("test/fixtures/mastodon-post-activity.json")
114 |> Jason.decode!()
115
116 object =
117 data["object"]
118 |> Map.put("inReplyTo", "https://shitposter.club/notice/2827873")
119
120 data = Map.put(data, "object", object)
121
122 with_mock Pleroma.Web.Federator,
123 allowed_thread_distance?: fn _ -> false end do
124 {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
125
126 returned_object = Object.normalize(returned_activity, fetch: false)
127
128 refute Activity.get_create_by_object_ap_id(
129 "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
130 )
131
132 assert returned_object.data["inReplyTo"] == "https://shitposter.club/notice/2827873"
133 end
134 end
135
136 test "it does not crash if the object in inReplyTo can't be fetched" do
137 data =
138 File.read!("test/fixtures/mastodon-post-activity.json")
139 |> Jason.decode!()
140
141 object =
142 data["object"]
143 |> Map.put("inReplyTo", "https://404.site/whatever")
144
145 data =
146 data
147 |> Map.put("object", object)
148
149 assert {:ok, _returned_activity} = Transmogrifier.handle_incoming(data)
150 end
151
152 test "it does not work for deactivated users" do
153 data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
154
155 insert(:user, ap_id: data["actor"], is_active: false)
156
157 assert {:error, _} = Transmogrifier.handle_incoming(data)
158 end
159
160 test "it works for incoming notices" do
161 data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
162
163 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
164
165 assert data["id"] ==
166 "http://mastodon.example.org/users/admin/statuses/99512778738411822/activity"
167
168 assert data["context"] ==
169 "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation"
170
171 assert data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
172
173 assert data["cc"] == [
174 "http://mastodon.example.org/users/admin/followers",
175 "http://localtesting.pleroma.lol/users/lain"
176 ]
177
178 assert data["actor"] == "http://mastodon.example.org/users/admin"
179
180 object_data = Object.normalize(data["object"], fetch: false).data
181
182 assert object_data["id"] ==
183 "http://mastodon.example.org/users/admin/statuses/99512778738411822"
184
185 assert object_data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
186
187 assert object_data["cc"] == [
188 "http://mastodon.example.org/users/admin/followers",
189 "http://localtesting.pleroma.lol/users/lain"
190 ]
191
192 assert object_data["actor"] == "http://mastodon.example.org/users/admin"
193 assert object_data["attributedTo"] == "http://mastodon.example.org/users/admin"
194
195 assert object_data["context"] ==
196 "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation"
197
198 assert object_data["sensitive"] == true
199
200 user = User.get_cached_by_ap_id(object_data["actor"])
201
202 assert user.note_count == 1
203 end
204
205 test "it works for incoming notices without the sensitive property but an nsfw hashtag" do
206 data = File.read!("test/fixtures/mastodon-post-activity-nsfw.json") |> Jason.decode!()
207
208 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
209
210 object_data = Object.normalize(data["object"], fetch: false).data
211
212 assert object_data["sensitive"] == true
213 end
214
215 test "it works for incoming notices with hashtags" do
216 data = File.read!("test/fixtures/mastodon-post-activity-hashtag.json") |> Jason.decode!()
217
218 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
219 object = Object.normalize(data["object"], fetch: false)
220
221 assert match?(
222 %{
223 "href" => "http://localtesting.pleroma.lol/users/lain",
224 "name" => "@lain@localtesting.pleroma.lol",
225 "type" => "Mention"
226 },
227 Enum.at(object.data["tag"], 0)
228 )
229
230 assert match?(
231 %{
232 "href" => "http://mastodon.example.org/tags/moo",
233 "name" => "#moo",
234 "type" => "Hashtag"
235 },
236 Enum.at(object.data["tag"], 1)
237 )
238
239 assert "moo" == Enum.at(object.data["tag"], 2)
240 end
241
242 test "it works for incoming notices with contentMap" do
243 data = File.read!("test/fixtures/mastodon-post-activity-contentmap.json") |> Jason.decode!()
244
245 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
246 object = Object.normalize(data["object"], fetch: false)
247
248 assert object.data["content"] ==
249 "<p><span class=\"h-card\"><a href=\"http://localtesting.pleroma.lol/users/lain\" class=\"u-url mention\">@<span>lain</span></a></span></p>"
250 end
251
252 test "it works for incoming notices with to/cc not being an array (kroeg)" do
253 data = File.read!("test/fixtures/kroeg-post-activity.json") |> Jason.decode!()
254
255 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
256 object = Object.normalize(data["object"], fetch: false)
257
258 assert object.data["content"] ==
259 "<p>henlo from my Psion netBook</p><p>message sent from my Psion netBook</p>"
260 end
261
262 test "it ensures that as:Public activities make it to their followers collection" do
263 user = insert(:user)
264
265 data =
266 File.read!("test/fixtures/mastodon-post-activity.json")
267 |> Jason.decode!()
268 |> Map.put("actor", user.ap_id)
269 |> Map.put("to", ["https://www.w3.org/ns/activitystreams#Public"])
270 |> Map.put("cc", [])
271
272 object =
273 data["object"]
274 |> Map.put("attributedTo", user.ap_id)
275 |> Map.put("to", ["https://www.w3.org/ns/activitystreams#Public"])
276 |> Map.put("cc", [])
277 |> Map.put("id", user.ap_id <> "/activities/12345678")
278
279 data = Map.put(data, "object", object)
280
281 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
282
283 assert data["cc"] == [User.ap_followers(user)]
284 end
285
286 test "it ensures that address fields become lists" do
287 user = insert(:user)
288
289 data =
290 File.read!("test/fixtures/mastodon-post-activity.json")
291 |> Jason.decode!()
292 |> Map.put("actor", user.ap_id)
293 |> Map.put("cc", nil)
294
295 object =
296 data["object"]
297 |> Map.put("attributedTo", user.ap_id)
298 |> Map.put("cc", nil)
299 |> Map.put("id", user.ap_id <> "/activities/12345678")
300
301 data = Map.put(data, "object", object)
302
303 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
304
305 refute is_nil(data["cc"])
306 end
307
308 test "it strips internal likes" do
309 data =
310 File.read!("test/fixtures/mastodon-post-activity.json")
311 |> Jason.decode!()
312
313 likes = %{
314 "first" =>
315 "http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes?page=1",
316 "id" => "http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes",
317 "totalItems" => 3,
318 "type" => "OrderedCollection"
319 }
320
321 object = Map.put(data["object"], "likes", likes)
322 data = Map.put(data, "object", object)
323
324 {:ok, %Activity{object: object}} = Transmogrifier.handle_incoming(data)
325
326 refute Map.has_key?(object.data, "likes")
327 end
328
329 test "it strips internal reactions" do
330 user = insert(:user)
331 {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"})
332 {:ok, _} = CommonAPI.react_with_emoji(activity.id, user, "📢")
333
334 %{object: object} = Activity.get_by_id_with_object(activity.id)
335 assert Map.has_key?(object.data, "reactions")
336 assert Map.has_key?(object.data, "reaction_count")
337
338 object_data = Transmogrifier.strip_internal_fields(object.data)
339 refute Map.has_key?(object_data, "reactions")
340 refute Map.has_key?(object_data, "reaction_count")
341 end
342
343 test "it correctly processes messages with non-array to field" do
344 data =
345 File.read!("test/fixtures/mastodon-post-activity.json")
346 |> Poison.decode!()
347 |> Map.put("to", "https://www.w3.org/ns/activitystreams#Public")
348 |> put_in(["object", "to"], "https://www.w3.org/ns/activitystreams#Public")
349
350 assert {:ok, activity} = Transmogrifier.handle_incoming(data)
351
352 assert [
353 "http://mastodon.example.org/users/admin/followers",
354 "http://localtesting.pleroma.lol/users/lain"
355 ] == activity.data["cc"]
356
357 assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["to"]
358 end
359
360 test "it correctly processes messages with non-array cc field" do
361 data =
362 File.read!("test/fixtures/mastodon-post-activity.json")
363 |> Poison.decode!()
364 |> Map.put("cc", "http://mastodon.example.org/users/admin/followers")
365 |> put_in(["object", "cc"], "http://mastodon.example.org/users/admin/followers")
366
367 assert {:ok, activity} = Transmogrifier.handle_incoming(data)
368
369 assert ["http://mastodon.example.org/users/admin/followers"] == activity.data["cc"]
370 assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["to"]
371 end
372
373 test "it correctly processes messages with weirdness in address fields" do
374 data =
375 File.read!("test/fixtures/mastodon-post-activity.json")
376 |> Poison.decode!()
377 |> Map.put("cc", ["http://mastodon.example.org/users/admin/followers", ["¿"]])
378 |> put_in(["object", "cc"], ["http://mastodon.example.org/users/admin/followers", ["¿"]])
379
380 assert {:ok, activity} = Transmogrifier.handle_incoming(data)
381
382 assert ["http://mastodon.example.org/users/admin/followers"] == activity.data["cc"]
383 assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["to"]
384 end
385 end
386
387 describe "`handle_incoming/2`, Mastodon format `replies` handling" do
388 setup do: clear_config([:activitypub, :note_replies_output_limit], 5)
389 setup do: clear_config([:instance, :federation_incoming_replies_max_depth])
390
391 setup do
392 data =
393 "test/fixtures/mastodon-post-activity.json"
394 |> File.read!()
395 |> Jason.decode!()
396
397 items = get_in(data, ["object", "replies", "first", "items"])
398 assert length(items) > 0
399
400 %{data: data, items: items}
401 end
402
403 test "schedules background fetching of `replies` items if max thread depth limit allows", %{
404 data: data,
405 items: items
406 } do
407 clear_config([:instance, :federation_incoming_replies_max_depth], 10)
408
409 {:ok, activity} = Transmogrifier.handle_incoming(data)
410
411 object = Object.normalize(activity.data["object"])
412
413 assert object.data["replies"] == items
414
415 for id <- items do
416 job_args = %{"op" => "fetch_remote", "id" => id, "depth" => 1}
417 assert_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker, args: job_args)
418 end
419 end
420
421 test "does NOT schedule background fetching of `replies` beyond max thread depth limit allows",
422 %{data: data} do
423 clear_config([:instance, :federation_incoming_replies_max_depth], 0)
424
425 {:ok, _activity} = Transmogrifier.handle_incoming(data)
426
427 assert all_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker) == []
428 end
429 end
430
431 describe "`handle_incoming/2`, Pleroma format `replies` handling" do
432 setup do: clear_config([:activitypub, :note_replies_output_limit], 5)
433 setup do: clear_config([:instance, :federation_incoming_replies_max_depth])
434
435 setup do
436 replies = %{
437 "type" => "Collection",
438 "items" => [
439 Pleroma.Web.ActivityPub.Utils.generate_object_id(),
440 Pleroma.Web.ActivityPub.Utils.generate_object_id()
441 ]
442 }
443
444 activity =
445 File.read!("test/fixtures/mastodon-post-activity.json")
446 |> Poison.decode!()
447 |> Kernel.put_in(["object", "replies"], replies)
448
449 %{activity: activity}
450 end
451
452 test "schedules background fetching of `replies` items if max thread depth limit allows", %{
453 activity: activity
454 } do
455 clear_config([:instance, :federation_incoming_replies_max_depth], 1)
456
457 assert {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(activity)
458 object = Object.normalize(data["object"])
459
460 for id <- object.data["replies"] do
461 job_args = %{"op" => "fetch_remote", "id" => id, "depth" => 1}
462 assert_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker, args: job_args)
463 end
464 end
465
466 test "does NOT schedule background fetching of `replies` beyond max thread depth limit allows",
467 %{activity: activity} do
468 clear_config([:instance, :federation_incoming_replies_max_depth], 0)
469
470 {:ok, _activity} = Transmogrifier.handle_incoming(activity)
471
472 assert all_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker) == []
473 end
474 end
475
476 describe "reserialization" do
477 test "successfully reserializes a message with inReplyTo == nil" do
478 user = insert(:user)
479
480 message = %{
481 "@context" => "https://www.w3.org/ns/activitystreams",
482 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
483 "cc" => [],
484 "type" => "Create",
485 "object" => %{
486 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
487 "cc" => [],
488 "id" => Utils.generate_object_id(),
489 "type" => "Note",
490 "content" => "Hi",
491 "inReplyTo" => nil,
492 "attributedTo" => user.ap_id
493 },
494 "actor" => user.ap_id
495 }
496
497 {:ok, activity} = Transmogrifier.handle_incoming(message)
498
499 {:ok, _} = Transmogrifier.prepare_outgoing(activity.data)
500 end
501
502 test "successfully reserializes a message with AS2 objects in IR" do
503 user = insert(:user)
504
505 message = %{
506 "@context" => "https://www.w3.org/ns/activitystreams",
507 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
508 "cc" => [],
509 "type" => "Create",
510 "object" => %{
511 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
512 "cc" => [],
513 "id" => Utils.generate_object_id(),
514 "type" => "Note",
515 "content" => "Hi",
516 "inReplyTo" => nil,
517 "attributedTo" => user.ap_id,
518 "tag" => [
519 %{"name" => "#2hu", "href" => "http://example.com/2hu", "type" => "Hashtag"},
520 %{"name" => "Bob", "href" => "http://example.com/bob", "type" => "Mention"}
521 ]
522 },
523 "actor" => user.ap_id
524 }
525
526 {:ok, activity} = Transmogrifier.handle_incoming(message)
527
528 {:ok, _} = Transmogrifier.prepare_outgoing(activity.data)
529 end
530 end
531
532 describe "fix_in_reply_to/2" do
533 setup do: clear_config([:instance, :federation_incoming_replies_max_depth])
534
535 setup do
536 data = Jason.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
537 [data: data]
538 end
539
540 test "returns not modified object when hasn't containts inReplyTo field", %{data: data} do
541 assert Transmogrifier.fix_in_reply_to(data) == data
542 end
543
544 test "returns object with inReplyTo when denied incoming reply", %{data: data} do
545 clear_config([:instance, :federation_incoming_replies_max_depth], 0)
546
547 object_with_reply =
548 Map.put(data["object"], "inReplyTo", "https://shitposter.club/notice/2827873")
549
550 modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
551 assert modified_object["inReplyTo"] == "https://shitposter.club/notice/2827873"
552
553 object_with_reply =
554 Map.put(data["object"], "inReplyTo", %{"id" => "https://shitposter.club/notice/2827873"})
555
556 modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
557 assert modified_object["inReplyTo"] == %{"id" => "https://shitposter.club/notice/2827873"}
558
559 object_with_reply =
560 Map.put(data["object"], "inReplyTo", ["https://shitposter.club/notice/2827873"])
561
562 modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
563 assert modified_object["inReplyTo"] == ["https://shitposter.club/notice/2827873"]
564
565 object_with_reply = Map.put(data["object"], "inReplyTo", [])
566 modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
567 assert modified_object["inReplyTo"] == []
568 end
569
570 @tag capture_log: true
571 test "returns modified object when allowed incoming reply", %{data: data} do
572 object_with_reply =
573 Map.put(
574 data["object"],
575 "inReplyTo",
576 "https://mstdn.io/users/mayuutann/statuses/99568293732299394"
577 )
578
579 clear_config([:instance, :federation_incoming_replies_max_depth], 5)
580 modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
581
582 assert modified_object["inReplyTo"] ==
583 "https://mstdn.io/users/mayuutann/statuses/99568293732299394"
584
585 assert modified_object["context"] ==
586 "tag:shitposter.club,2018-02-22:objectType=thread:nonce=e5a7c72d60a9c0e4"
587 end
588 end
589
590 describe "fix_attachments/1" do
591 test "returns not modified object" do
592 data = Jason.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
593 assert Transmogrifier.fix_attachments(data) == data
594 end
595
596 test "returns modified object when attachment is map" do
597 assert Transmogrifier.fix_attachments(%{
598 "attachment" => %{
599 "mediaType" => "video/mp4",
600 "url" => "https://peertube.moe/stat-480.mp4"
601 }
602 }) == %{
603 "attachment" => [
604 %{
605 "mediaType" => "video/mp4",
606 "type" => "Document",
607 "url" => [
608 %{
609 "href" => "https://peertube.moe/stat-480.mp4",
610 "mediaType" => "video/mp4",
611 "type" => "Link"
612 }
613 ]
614 }
615 ]
616 }
617 end
618
619 test "returns modified object when attachment is list" do
620 assert Transmogrifier.fix_attachments(%{
621 "attachment" => [
622 %{"mediaType" => "video/mp4", "url" => "https://pe.er/stat-480.mp4"},
623 %{"mimeType" => "video/mp4", "href" => "https://pe.er/stat-480.mp4"}
624 ]
625 }) == %{
626 "attachment" => [
627 %{
628 "mediaType" => "video/mp4",
629 "type" => "Document",
630 "url" => [
631 %{
632 "href" => "https://pe.er/stat-480.mp4",
633 "mediaType" => "video/mp4",
634 "type" => "Link"
635 }
636 ]
637 },
638 %{
639 "mediaType" => "video/mp4",
640 "type" => "Document",
641 "url" => [
642 %{
643 "href" => "https://pe.er/stat-480.mp4",
644 "mediaType" => "video/mp4",
645 "type" => "Link"
646 }
647 ]
648 }
649 ]
650 }
651 end
652 end
653
654 describe "fix_emoji/1" do
655 test "returns not modified object when object not contains tags" do
656 data = Jason.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
657 assert Transmogrifier.fix_emoji(data) == data
658 end
659
660 test "returns object with emoji when object contains list tags" do
661 assert Transmogrifier.fix_emoji(%{
662 "tag" => [
663 %{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}},
664 %{"type" => "Hashtag"}
665 ]
666 }) == %{
667 "emoji" => %{"bib" => "/test"},
668 "tag" => [
669 %{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"},
670 %{"type" => "Hashtag"}
671 ]
672 }
673 end
674
675 test "returns object with emoji when object contains map tag" do
676 assert Transmogrifier.fix_emoji(%{
677 "tag" => %{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}}
678 }) == %{
679 "emoji" => %{"bib" => "/test"},
680 "tag" => %{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"}
681 }
682 end
683 end
684
685 describe "set_replies/1" do
686 setup do: clear_config([:activitypub, :note_replies_output_limit], 2)
687
688 test "returns unmodified object if activity doesn't have self-replies" do
689 data = Jason.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
690 assert Transmogrifier.set_replies(data) == data
691 end
692
693 test "sets `replies` collection with a limited number of self-replies" do
694 [user, another_user] = insert_list(2, :user)
695
696 {:ok, %{id: id1} = activity} = CommonAPI.post(user, %{status: "1"})
697
698 {:ok, %{id: id2} = self_reply1} =
699 CommonAPI.post(user, %{status: "self-reply 1", in_reply_to_status_id: id1})
700
701 {:ok, self_reply2} =
702 CommonAPI.post(user, %{status: "self-reply 2", in_reply_to_status_id: id1})
703
704 # Assuming to _not_ be present in `replies` due to :note_replies_output_limit is set to 2
705 {:ok, _} = CommonAPI.post(user, %{status: "self-reply 3", in_reply_to_status_id: id1})
706
707 {:ok, _} =
708 CommonAPI.post(user, %{
709 status: "self-reply to self-reply",
710 in_reply_to_status_id: id2
711 })
712
713 {:ok, _} =
714 CommonAPI.post(another_user, %{
715 status: "another user's reply",
716 in_reply_to_status_id: id1
717 })
718
719 object = Object.normalize(activity, fetch: false)
720 replies_uris = Enum.map([self_reply1, self_reply2], fn a -> a.object.data["id"] end)
721
722 assert %{"type" => "Collection", "items" => ^replies_uris} =
723 Transmogrifier.set_replies(object.data)["replies"]
724 end
725 end
726
727 test "take_emoji_tags/1" do
728 user = insert(:user, %{emoji: %{"firefox" => "https://example.org/firefox.png"}})
729
730 assert Transmogrifier.take_emoji_tags(user) == [
731 %{
732 "icon" => %{"type" => "Image", "url" => "https://example.org/firefox.png"},
733 "id" => "https://example.org/firefox.png",
734 "name" => ":firefox:",
735 "type" => "Emoji",
736 "updated" => "1970-01-01T00:00:00Z"
737 }
738 ]
739 end
740 end