logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma

transmogrifier_test.exs (26401B)


  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
  5. use Oban.Testing, repo: Pleroma.Repo
  6. use Pleroma.DataCase
  7. alias Pleroma.Activity
  8. alias Pleroma.Object
  9. alias Pleroma.Tests.ObanHelpers
  10. alias Pleroma.User
  11. alias Pleroma.Web.ActivityPub.Transmogrifier
  12. alias Pleroma.Web.ActivityPub.Utils
  13. alias Pleroma.Web.AdminAPI.AccountView
  14. alias Pleroma.Web.CommonAPI
  15. import Mock
  16. import Pleroma.Factory
  17. import ExUnit.CaptureLog
  18. setup_all do
  19. Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
  20. :ok
  21. end
  22. setup do: clear_config([:instance, :max_remote_account_fields])
  23. describe "handle_incoming" do
  24. test "it works for incoming unfollows with an existing follow" do
  25. user = insert(:user)
  26. follow_data =
  27. File.read!("test/fixtures/mastodon-follow-activity.json")
  28. |> Poison.decode!()
  29. |> Map.put("object", user.ap_id)
  30. {:ok, %Activity{data: _, local: false}} = Transmogrifier.handle_incoming(follow_data)
  31. data =
  32. File.read!("test/fixtures/mastodon-unfollow-activity.json")
  33. |> Poison.decode!()
  34. |> Map.put("object", follow_data)
  35. {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
  36. assert data["type"] == "Undo"
  37. assert data["object"]["type"] == "Follow"
  38. assert data["object"]["object"] == user.ap_id
  39. assert data["actor"] == "http://mastodon.example.org/users/admin"
  40. refute User.following?(User.get_cached_by_ap_id(data["actor"]), user)
  41. end
  42. test "it accepts Flag activities" do
  43. user = insert(:user)
  44. other_user = insert(:user)
  45. {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
  46. object = Object.normalize(activity)
  47. note_obj = %{
  48. "type" => "Note",
  49. "id" => activity.data["id"],
  50. "content" => "test post",
  51. "published" => object.data["published"],
  52. "actor" => AccountView.render("show.json", %{user: user, skip_visibility_check: true})
  53. }
  54. message = %{
  55. "@context" => "https://www.w3.org/ns/activitystreams",
  56. "cc" => [user.ap_id],
  57. "object" => [user.ap_id, activity.data["id"]],
  58. "type" => "Flag",
  59. "content" => "blocked AND reported!!!",
  60. "actor" => other_user.ap_id
  61. }
  62. assert {:ok, activity} = Transmogrifier.handle_incoming(message)
  63. assert activity.data["object"] == [user.ap_id, note_obj]
  64. assert activity.data["content"] == "blocked AND reported!!!"
  65. assert activity.data["actor"] == other_user.ap_id
  66. assert activity.data["cc"] == [user.ap_id]
  67. end
  68. test "it accepts Move activities" do
  69. old_user = insert(:user)
  70. new_user = insert(:user)
  71. message = %{
  72. "@context" => "https://www.w3.org/ns/activitystreams",
  73. "type" => "Move",
  74. "actor" => old_user.ap_id,
  75. "object" => old_user.ap_id,
  76. "target" => new_user.ap_id
  77. }
  78. assert :error = Transmogrifier.handle_incoming(message)
  79. {:ok, _new_user} = User.update_and_set_cache(new_user, %{also_known_as: [old_user.ap_id]})
  80. assert {:ok, %Activity{} = activity} = Transmogrifier.handle_incoming(message)
  81. assert activity.actor == old_user.ap_id
  82. assert activity.data["actor"] == old_user.ap_id
  83. assert activity.data["object"] == old_user.ap_id
  84. assert activity.data["target"] == new_user.ap_id
  85. assert activity.data["type"] == "Move"
  86. end
  87. end
  88. describe "prepare outgoing" do
  89. test "it inlines private announced objects" do
  90. user = insert(:user)
  91. {:ok, activity} = CommonAPI.post(user, %{status: "hey", visibility: "private"})
  92. {:ok, announce_activity} = CommonAPI.repeat(activity.id, user)
  93. {:ok, modified} = Transmogrifier.prepare_outgoing(announce_activity.data)
  94. assert modified["object"]["content"] == "hey"
  95. assert modified["object"]["actor"] == modified["object"]["attributedTo"]
  96. end
  97. test "it turns mentions into tags" do
  98. user = insert(:user)
  99. other_user = insert(:user)
  100. {:ok, activity} =
  101. CommonAPI.post(user, %{status: "hey, @#{other_user.nickname}, how are ya? #2hu"})
  102. with_mock Pleroma.Notification,
  103. get_notified_from_activity: fn _, _ -> [] end do
  104. {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
  105. object = modified["object"]
  106. expected_mention = %{
  107. "href" => other_user.ap_id,
  108. "name" => "@#{other_user.nickname}",
  109. "type" => "Mention"
  110. }
  111. expected_tag = %{
  112. "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu",
  113. "type" => "Hashtag",
  114. "name" => "#2hu"
  115. }
  116. refute called(Pleroma.Notification.get_notified_from_activity(:_, :_))
  117. assert Enum.member?(object["tag"], expected_tag)
  118. assert Enum.member?(object["tag"], expected_mention)
  119. end
  120. end
  121. test "it adds the sensitive property" do
  122. user = insert(:user)
  123. {:ok, activity} = CommonAPI.post(user, %{status: "#nsfw hey"})
  124. {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
  125. assert modified["object"]["sensitive"]
  126. end
  127. test "it adds the json-ld context and the conversation property" do
  128. user = insert(:user)
  129. {:ok, activity} = CommonAPI.post(user, %{status: "hey"})
  130. {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
  131. assert modified["@context"] == Utils.make_json_ld_header()["@context"]
  132. assert modified["object"]["conversation"] == modified["context"]
  133. end
  134. test "it sets the 'attributedTo' property to the actor of the object if it doesn't have one" do
  135. user = insert(:user)
  136. {:ok, activity} = CommonAPI.post(user, %{status: "hey"})
  137. {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
  138. assert modified["object"]["actor"] == modified["object"]["attributedTo"]
  139. end
  140. test "it strips internal hashtag data" do
  141. user = insert(:user)
  142. {:ok, activity} = CommonAPI.post(user, %{status: "#2hu"})
  143. expected_tag = %{
  144. "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu",
  145. "type" => "Hashtag",
  146. "name" => "#2hu"
  147. }
  148. {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
  149. assert modified["object"]["tag"] == [expected_tag]
  150. end
  151. test "it strips internal fields" do
  152. user = insert(:user)
  153. {:ok, activity} = CommonAPI.post(user, %{status: "#2hu :firefox:"})
  154. {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
  155. assert length(modified["object"]["tag"]) == 2
  156. assert is_nil(modified["object"]["emoji"])
  157. assert is_nil(modified["object"]["like_count"])
  158. assert is_nil(modified["object"]["announcements"])
  159. assert is_nil(modified["object"]["announcement_count"])
  160. assert is_nil(modified["object"]["context_id"])
  161. end
  162. test "it strips internal fields of article" do
  163. activity = insert(:article_activity)
  164. {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
  165. assert length(modified["object"]["tag"]) == 2
  166. assert is_nil(modified["object"]["emoji"])
  167. assert is_nil(modified["object"]["like_count"])
  168. assert is_nil(modified["object"]["announcements"])
  169. assert is_nil(modified["object"]["announcement_count"])
  170. assert is_nil(modified["object"]["context_id"])
  171. assert is_nil(modified["object"]["likes"])
  172. end
  173. test "the directMessage flag is present" do
  174. user = insert(:user)
  175. other_user = insert(:user)
  176. {:ok, activity} = CommonAPI.post(user, %{status: "2hu :moominmamma:"})
  177. {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
  178. assert modified["directMessage"] == false
  179. {:ok, activity} = CommonAPI.post(user, %{status: "@#{other_user.nickname} :moominmamma:"})
  180. {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
  181. assert modified["directMessage"] == false
  182. {:ok, activity} =
  183. CommonAPI.post(user, %{
  184. status: "@#{other_user.nickname} :moominmamma:",
  185. visibility: "direct"
  186. })
  187. {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
  188. assert modified["directMessage"] == true
  189. end
  190. test "it strips BCC field" do
  191. user = insert(:user)
  192. {:ok, list} = Pleroma.List.create("foo", user)
  193. {:ok, activity} = CommonAPI.post(user, %{status: "foobar", visibility: "list:#{list.id}"})
  194. {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
  195. assert is_nil(modified["bcc"])
  196. end
  197. test "it can handle Listen activities" do
  198. listen_activity = insert(:listen)
  199. {:ok, modified} = Transmogrifier.prepare_outgoing(listen_activity.data)
  200. assert modified["type"] == "Listen"
  201. user = insert(:user)
  202. {:ok, activity} = CommonAPI.listen(user, %{"title" => "lain radio episode 1"})
  203. {:ok, _modified} = Transmogrifier.prepare_outgoing(activity.data)
  204. end
  205. end
  206. describe "user upgrade" do
  207. test "it upgrades a user to activitypub" do
  208. user =
  209. insert(:user, %{
  210. nickname: "rye@niu.moe",
  211. local: false,
  212. ap_id: "https://niu.moe/users/rye",
  213. follower_address: User.ap_followers(%User{nickname: "rye@niu.moe"})
  214. })
  215. user_two = insert(:user)
  216. Pleroma.FollowingRelationship.follow(user_two, user, :follow_accept)
  217. {:ok, activity} = CommonAPI.post(user, %{status: "test"})
  218. {:ok, unrelated_activity} = CommonAPI.post(user_two, %{status: "test"})
  219. assert "http://localhost:4001/users/rye@niu.moe/followers" in activity.recipients
  220. user = User.get_cached_by_id(user.id)
  221. assert user.note_count == 1
  222. {:ok, user} = Transmogrifier.upgrade_user_from_ap_id("https://niu.moe/users/rye")
  223. ObanHelpers.perform_all()
  224. assert user.ap_enabled
  225. assert user.note_count == 1
  226. assert user.follower_address == "https://niu.moe/users/rye/followers"
  227. assert user.following_address == "https://niu.moe/users/rye/following"
  228. user = User.get_cached_by_id(user.id)
  229. assert user.note_count == 1
  230. activity = Activity.get_by_id(activity.id)
  231. assert user.follower_address in activity.recipients
  232. assert %{
  233. "url" => [
  234. %{
  235. "href" =>
  236. "https://cdn.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg"
  237. }
  238. ]
  239. } = user.avatar
  240. assert %{
  241. "url" => [
  242. %{
  243. "href" =>
  244. "https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"
  245. }
  246. ]
  247. } = user.banner
  248. refute "..." in activity.recipients
  249. unrelated_activity = Activity.get_by_id(unrelated_activity.id)
  250. refute user.follower_address in unrelated_activity.recipients
  251. user_two = User.get_cached_by_id(user_two.id)
  252. assert User.following?(user_two, user)
  253. refute "..." in User.following(user_two)
  254. end
  255. end
  256. describe "actor rewriting" do
  257. test "it fixes the actor URL property to be a proper URI" do
  258. data = %{
  259. "url" => %{"href" => "http://example.com"}
  260. }
  261. rewritten = Transmogrifier.maybe_fix_user_object(data)
  262. assert rewritten["url"] == "http://example.com"
  263. end
  264. end
  265. describe "actor origin containment" do
  266. test "it rejects activities which reference objects with bogus origins" do
  267. data = %{
  268. "@context" => "https://www.w3.org/ns/activitystreams",
  269. "id" => "http://mastodon.example.org/users/admin/activities/1234",
  270. "actor" => "http://mastodon.example.org/users/admin",
  271. "to" => ["https://www.w3.org/ns/activitystreams#Public"],
  272. "object" => "https://info.pleroma.site/activity.json",
  273. "type" => "Announce"
  274. }
  275. assert capture_log(fn ->
  276. {:error, _} = Transmogrifier.handle_incoming(data)
  277. end) =~ "Object containment failed"
  278. end
  279. test "it rejects activities which reference objects that have an incorrect attribution (variant 1)" do
  280. data = %{
  281. "@context" => "https://www.w3.org/ns/activitystreams",
  282. "id" => "http://mastodon.example.org/users/admin/activities/1234",
  283. "actor" => "http://mastodon.example.org/users/admin",
  284. "to" => ["https://www.w3.org/ns/activitystreams#Public"],
  285. "object" => "https://info.pleroma.site/activity2.json",
  286. "type" => "Announce"
  287. }
  288. assert capture_log(fn ->
  289. {:error, _} = Transmogrifier.handle_incoming(data)
  290. end) =~ "Object containment failed"
  291. end
  292. test "it rejects activities which reference objects that have an incorrect attribution (variant 2)" do
  293. data = %{
  294. "@context" => "https://www.w3.org/ns/activitystreams",
  295. "id" => "http://mastodon.example.org/users/admin/activities/1234",
  296. "actor" => "http://mastodon.example.org/users/admin",
  297. "to" => ["https://www.w3.org/ns/activitystreams#Public"],
  298. "object" => "https://info.pleroma.site/activity3.json",
  299. "type" => "Announce"
  300. }
  301. assert capture_log(fn ->
  302. {:error, _} = Transmogrifier.handle_incoming(data)
  303. end) =~ "Object containment failed"
  304. end
  305. end
  306. describe "reserialization" do
  307. test "successfully reserializes a message with inReplyTo == nil" do
  308. user = insert(:user)
  309. message = %{
  310. "@context" => "https://www.w3.org/ns/activitystreams",
  311. "to" => ["https://www.w3.org/ns/activitystreams#Public"],
  312. "cc" => [],
  313. "type" => "Create",
  314. "object" => %{
  315. "to" => ["https://www.w3.org/ns/activitystreams#Public"],
  316. "cc" => [],
  317. "id" => Utils.generate_object_id(),
  318. "type" => "Note",
  319. "content" => "Hi",
  320. "inReplyTo" => nil,
  321. "attributedTo" => user.ap_id
  322. },
  323. "actor" => user.ap_id
  324. }
  325. {:ok, activity} = Transmogrifier.handle_incoming(message)
  326. {:ok, _} = Transmogrifier.prepare_outgoing(activity.data)
  327. end
  328. test "successfully reserializes a message with AS2 objects in IR" do
  329. user = insert(:user)
  330. message = %{
  331. "@context" => "https://www.w3.org/ns/activitystreams",
  332. "to" => ["https://www.w3.org/ns/activitystreams#Public"],
  333. "cc" => [],
  334. "type" => "Create",
  335. "object" => %{
  336. "to" => ["https://www.w3.org/ns/activitystreams#Public"],
  337. "cc" => [],
  338. "id" => Utils.generate_object_id(),
  339. "type" => "Note",
  340. "content" => "Hi",
  341. "inReplyTo" => nil,
  342. "attributedTo" => user.ap_id,
  343. "tag" => [
  344. %{"name" => "#2hu", "href" => "http://example.com/2hu", "type" => "Hashtag"},
  345. %{"name" => "Bob", "href" => "http://example.com/bob", "type" => "Mention"}
  346. ]
  347. },
  348. "actor" => user.ap_id
  349. }
  350. {:ok, activity} = Transmogrifier.handle_incoming(message)
  351. {:ok, _} = Transmogrifier.prepare_outgoing(activity.data)
  352. end
  353. end
  354. describe "fix_explicit_addressing" do
  355. setup do
  356. user = insert(:user)
  357. [user: user]
  358. end
  359. test "moves non-explicitly mentioned actors to cc", %{user: user} do
  360. explicitly_mentioned_actors = [
  361. "https://pleroma.gold/users/user1",
  362. "https://pleroma.gold/user2"
  363. ]
  364. object = %{
  365. "actor" => user.ap_id,
  366. "to" => explicitly_mentioned_actors ++ ["https://social.beepboop.ga/users/dirb"],
  367. "cc" => [],
  368. "tag" =>
  369. Enum.map(explicitly_mentioned_actors, fn href ->
  370. %{"type" => "Mention", "href" => href}
  371. end)
  372. }
  373. fixed_object = Transmogrifier.fix_explicit_addressing(object, user.follower_address)
  374. assert Enum.all?(explicitly_mentioned_actors, &(&1 in fixed_object["to"]))
  375. refute "https://social.beepboop.ga/users/dirb" in fixed_object["to"]
  376. assert "https://social.beepboop.ga/users/dirb" in fixed_object["cc"]
  377. end
  378. test "does not move actor's follower collection to cc", %{user: user} do
  379. object = %{
  380. "actor" => user.ap_id,
  381. "to" => [user.follower_address],
  382. "cc" => []
  383. }
  384. fixed_object = Transmogrifier.fix_explicit_addressing(object, user.follower_address)
  385. assert user.follower_address in fixed_object["to"]
  386. refute user.follower_address in fixed_object["cc"]
  387. end
  388. test "removes recipient's follower collection from cc", %{user: user} do
  389. recipient = insert(:user)
  390. object = %{
  391. "actor" => user.ap_id,
  392. "to" => [recipient.ap_id, "https://www.w3.org/ns/activitystreams#Public"],
  393. "cc" => [user.follower_address, recipient.follower_address]
  394. }
  395. fixed_object = Transmogrifier.fix_explicit_addressing(object, user.follower_address)
  396. assert user.follower_address in fixed_object["cc"]
  397. refute recipient.follower_address in fixed_object["cc"]
  398. refute recipient.follower_address in fixed_object["to"]
  399. end
  400. end
  401. describe "fix_summary/1" do
  402. test "returns fixed object" do
  403. assert Transmogrifier.fix_summary(%{"summary" => nil}) == %{"summary" => ""}
  404. assert Transmogrifier.fix_summary(%{"summary" => "ok"}) == %{"summary" => "ok"}
  405. assert Transmogrifier.fix_summary(%{}) == %{"summary" => ""}
  406. end
  407. end
  408. describe "fix_in_reply_to/2" do
  409. setup do: clear_config([:instance, :federation_incoming_replies_max_depth])
  410. setup do
  411. data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
  412. [data: data]
  413. end
  414. test "returns not modified object when hasn't containts inReplyTo field", %{data: data} do
  415. assert Transmogrifier.fix_in_reply_to(data) == data
  416. end
  417. test "returns object with inReplyTo when denied incoming reply", %{data: data} do
  418. Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0)
  419. object_with_reply =
  420. Map.put(data["object"], "inReplyTo", "https://shitposter.club/notice/2827873")
  421. modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
  422. assert modified_object["inReplyTo"] == "https://shitposter.club/notice/2827873"
  423. object_with_reply =
  424. Map.put(data["object"], "inReplyTo", %{"id" => "https://shitposter.club/notice/2827873"})
  425. modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
  426. assert modified_object["inReplyTo"] == %{"id" => "https://shitposter.club/notice/2827873"}
  427. object_with_reply =
  428. Map.put(data["object"], "inReplyTo", ["https://shitposter.club/notice/2827873"])
  429. modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
  430. assert modified_object["inReplyTo"] == ["https://shitposter.club/notice/2827873"]
  431. object_with_reply = Map.put(data["object"], "inReplyTo", [])
  432. modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
  433. assert modified_object["inReplyTo"] == []
  434. end
  435. @tag capture_log: true
  436. test "returns modified object when allowed incoming reply", %{data: data} do
  437. object_with_reply =
  438. Map.put(
  439. data["object"],
  440. "inReplyTo",
  441. "https://mstdn.io/users/mayuutann/statuses/99568293732299394"
  442. )
  443. Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 5)
  444. modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
  445. assert modified_object["inReplyTo"] ==
  446. "https://mstdn.io/users/mayuutann/statuses/99568293732299394"
  447. assert modified_object["context"] ==
  448. "tag:shitposter.club,2018-02-22:objectType=thread:nonce=e5a7c72d60a9c0e4"
  449. end
  450. end
  451. describe "fix_url/1" do
  452. test "fixes data for object when url is map" do
  453. object = %{
  454. "url" => %{
  455. "type" => "Link",
  456. "mimeType" => "video/mp4",
  457. "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4"
  458. }
  459. }
  460. assert Transmogrifier.fix_url(object) == %{
  461. "url" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4"
  462. }
  463. end
  464. test "returns non-modified object" do
  465. assert Transmogrifier.fix_url(%{"type" => "Text"}) == %{"type" => "Text"}
  466. end
  467. end
  468. describe "get_obj_helper/2" do
  469. test "returns nil when cannot normalize object" do
  470. assert capture_log(fn ->
  471. refute Transmogrifier.get_obj_helper("test-obj-id")
  472. end) =~ "Unsupported URI scheme"
  473. end
  474. @tag capture_log: true
  475. test "returns {:ok, %Object{}} for success case" do
  476. assert {:ok, %Object{}} =
  477. Transmogrifier.get_obj_helper(
  478. "https://mstdn.io/users/mayuutann/statuses/99568293732299394"
  479. )
  480. end
  481. end
  482. describe "fix_attachments/1" do
  483. test "returns not modified object" do
  484. data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
  485. assert Transmogrifier.fix_attachments(data) == data
  486. end
  487. test "returns modified object when attachment is map" do
  488. assert Transmogrifier.fix_attachments(%{
  489. "attachment" => %{
  490. "mediaType" => "video/mp4",
  491. "url" => "https://peertube.moe/stat-480.mp4"
  492. }
  493. }) == %{
  494. "attachment" => [
  495. %{
  496. "mediaType" => "video/mp4",
  497. "type" => "Document",
  498. "url" => [
  499. %{
  500. "href" => "https://peertube.moe/stat-480.mp4",
  501. "mediaType" => "video/mp4",
  502. "type" => "Link"
  503. }
  504. ]
  505. }
  506. ]
  507. }
  508. end
  509. test "returns modified object when attachment is list" do
  510. assert Transmogrifier.fix_attachments(%{
  511. "attachment" => [
  512. %{"mediaType" => "video/mp4", "url" => "https://pe.er/stat-480.mp4"},
  513. %{"mimeType" => "video/mp4", "href" => "https://pe.er/stat-480.mp4"}
  514. ]
  515. }) == %{
  516. "attachment" => [
  517. %{
  518. "mediaType" => "video/mp4",
  519. "type" => "Document",
  520. "url" => [
  521. %{
  522. "href" => "https://pe.er/stat-480.mp4",
  523. "mediaType" => "video/mp4",
  524. "type" => "Link"
  525. }
  526. ]
  527. },
  528. %{
  529. "mediaType" => "video/mp4",
  530. "type" => "Document",
  531. "url" => [
  532. %{
  533. "href" => "https://pe.er/stat-480.mp4",
  534. "mediaType" => "video/mp4",
  535. "type" => "Link"
  536. }
  537. ]
  538. }
  539. ]
  540. }
  541. end
  542. end
  543. describe "fix_emoji/1" do
  544. test "returns not modified object when object not contains tags" do
  545. data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
  546. assert Transmogrifier.fix_emoji(data) == data
  547. end
  548. test "returns object with emoji when object contains list tags" do
  549. assert Transmogrifier.fix_emoji(%{
  550. "tag" => [
  551. %{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}},
  552. %{"type" => "Hashtag"}
  553. ]
  554. }) == %{
  555. "emoji" => %{"bib" => "/test"},
  556. "tag" => [
  557. %{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"},
  558. %{"type" => "Hashtag"}
  559. ]
  560. }
  561. end
  562. test "returns object with emoji when object contains map tag" do
  563. assert Transmogrifier.fix_emoji(%{
  564. "tag" => %{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}}
  565. }) == %{
  566. "emoji" => %{"bib" => "/test"},
  567. "tag" => %{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"}
  568. }
  569. end
  570. end
  571. describe "set_replies/1" do
  572. setup do: clear_config([:activitypub, :note_replies_output_limit], 2)
  573. test "returns unmodified object if activity doesn't have self-replies" do
  574. data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
  575. assert Transmogrifier.set_replies(data) == data
  576. end
  577. test "sets `replies` collection with a limited number of self-replies" do
  578. [user, another_user] = insert_list(2, :user)
  579. {:ok, %{id: id1} = activity} = CommonAPI.post(user, %{status: "1"})
  580. {:ok, %{id: id2} = self_reply1} =
  581. CommonAPI.post(user, %{status: "self-reply 1", in_reply_to_status_id: id1})
  582. {:ok, self_reply2} =
  583. CommonAPI.post(user, %{status: "self-reply 2", in_reply_to_status_id: id1})
  584. # Assuming to _not_ be present in `replies` due to :note_replies_output_limit is set to 2
  585. {:ok, _} = CommonAPI.post(user, %{status: "self-reply 3", in_reply_to_status_id: id1})
  586. {:ok, _} =
  587. CommonAPI.post(user, %{
  588. status: "self-reply to self-reply",
  589. in_reply_to_status_id: id2
  590. })
  591. {:ok, _} =
  592. CommonAPI.post(another_user, %{
  593. status: "another user's reply",
  594. in_reply_to_status_id: id1
  595. })
  596. object = Object.normalize(activity)
  597. replies_uris = Enum.map([self_reply1, self_reply2], fn a -> a.object.data["id"] end)
  598. assert %{"type" => "Collection", "items" => ^replies_uris} =
  599. Transmogrifier.set_replies(object.data)["replies"]
  600. end
  601. end
  602. test "take_emoji_tags/1" do
  603. user = insert(:user, %{emoji: %{"firefox" => "https://example.org/firefox.png"}})
  604. assert Transmogrifier.take_emoji_tags(user) == [
  605. %{
  606. "icon" => %{"type" => "Image", "url" => "https://example.org/firefox.png"},
  607. "id" => "https://example.org/firefox.png",
  608. "name" => ":firefox:",
  609. "type" => "Emoji",
  610. "updated" => "1970-01-01T00:00:00Z"
  611. }
  612. ]
  613. end
  614. end