logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma git clone https://anongit.hacktivis.me/git/pleroma.git/

status_view_test.exs (33090B)


  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
  5. use Pleroma.DataCase
  6. alias Pleroma.Activity
  7. alias Pleroma.Bookmark
  8. alias Pleroma.Conversation.Participation
  9. alias Pleroma.HTML
  10. alias Pleroma.Object
  11. alias Pleroma.Repo
  12. alias Pleroma.UnstubbedConfigMock, as: ConfigMock
  13. alias Pleroma.User
  14. alias Pleroma.UserRelationship
  15. alias Pleroma.Web.CommonAPI
  16. alias Pleroma.Web.MastodonAPI.AccountView
  17. alias Pleroma.Web.MastodonAPI.StatusView
  18. alias Pleroma.Web.RichMedia.Card
  19. require Bitwise
  20. import Mox
  21. import OpenApiSpex.TestAssertions
  22. import Pleroma.Factory
  23. import Tesla.Mock
  24. setup do
  25. mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
  26. :ok
  27. end
  28. test "has an emoji reaction list" do
  29. user = insert(:user)
  30. other_user = insert(:user)
  31. third_user = insert(:user)
  32. {:ok, activity} = CommonAPI.post(user, %{status: "dae cofe??"})
  33. {:ok, _} = CommonAPI.react_with_emoji(activity.id, user, "☕")
  34. {:ok, _} = CommonAPI.react_with_emoji(activity.id, user, ":dinosaur:")
  35. {:ok, _} = CommonAPI.react_with_emoji(activity.id, third_user, "🍵")
  36. {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
  37. {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, ":dinosaur:")
  38. activity = Repo.get(Activity, activity.id)
  39. status = StatusView.render("show.json", activity: activity)
  40. assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec())
  41. assert status[:pleroma][:emoji_reactions] == [
  42. %{name: "☕", count: 2, me: false, url: nil, account_ids: [other_user.id, user.id]},
  43. %{
  44. count: 2,
  45. me: false,
  46. name: "dinosaur",
  47. url: "http://localhost:4001/emoji/dino walking.gif",
  48. account_ids: [other_user.id, user.id]
  49. },
  50. %{name: "🍵", count: 1, me: false, url: nil, account_ids: [third_user.id]}
  51. ]
  52. status = StatusView.render("show.json", activity: activity, for: user)
  53. assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec())
  54. assert status[:pleroma][:emoji_reactions] == [
  55. %{name: "☕", count: 2, me: true, url: nil, account_ids: [other_user.id, user.id]},
  56. %{
  57. count: 2,
  58. me: true,
  59. name: "dinosaur",
  60. url: "http://localhost:4001/emoji/dino walking.gif",
  61. account_ids: [other_user.id, user.id]
  62. },
  63. %{name: "🍵", count: 1, me: false, url: nil, account_ids: [third_user.id]}
  64. ]
  65. end
  66. test "works with legacy-formatted reactions" do
  67. user = insert(:user)
  68. other_user = insert(:user)
  69. note =
  70. insert(:note,
  71. user: user,
  72. data: %{
  73. "reactions" => [["😿", [other_user.ap_id]]]
  74. }
  75. )
  76. activity = insert(:note_activity, user: user, note: note)
  77. status = StatusView.render("show.json", activity: activity, for: user)
  78. assert status[:pleroma][:emoji_reactions] == [
  79. %{name: "😿", count: 1, me: false, url: nil, account_ids: [other_user.id]}
  80. ]
  81. end
  82. test "works correctly with badly formatted emojis" do
  83. user = insert(:user)
  84. {:ok, activity} = CommonAPI.post(user, %{status: "yo"})
  85. activity
  86. |> Object.normalize(fetch: false)
  87. |> Object.update_data(%{"reactions" => %{"☕" => [user.ap_id], "x" => 1}})
  88. activity = Activity.get_by_id(activity.id)
  89. status = StatusView.render("show.json", activity: activity, for: user)
  90. assert status[:pleroma][:emoji_reactions] == [
  91. %{name: "☕", count: 1, me: true, url: nil, account_ids: [user.id]}
  92. ]
  93. end
  94. test "doesn't show reactions from muted and blocked users" do
  95. user = insert(:user)
  96. other_user = insert(:user)
  97. third_user = insert(:user)
  98. {:ok, activity} = CommonAPI.post(user, %{status: "dae cofe??"})
  99. {:ok, _} = User.mute(user, other_user)
  100. {:ok, _} = User.block(other_user, third_user)
  101. {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
  102. activity = Repo.get(Activity, activity.id)
  103. status = StatusView.render("show.json", activity: activity)
  104. assert status[:pleroma][:emoji_reactions] == [
  105. %{name: "☕", count: 1, me: false, url: nil, account_ids: [other_user.id]}
  106. ]
  107. status = StatusView.render("show.json", activity: activity, for: user)
  108. assert status[:pleroma][:emoji_reactions] == []
  109. {:ok, _} = CommonAPI.react_with_emoji(activity.id, third_user, "☕")
  110. status = StatusView.render("show.json", activity: activity)
  111. assert status[:pleroma][:emoji_reactions] == [
  112. %{
  113. name: "☕",
  114. count: 2,
  115. me: false,
  116. url: nil,
  117. account_ids: [third_user.id, other_user.id]
  118. }
  119. ]
  120. status = StatusView.render("show.json", activity: activity, for: user)
  121. assert status[:pleroma][:emoji_reactions] == [
  122. %{name: "☕", count: 1, me: false, url: nil, account_ids: [third_user.id]}
  123. ]
  124. status = StatusView.render("show.json", activity: activity, for: other_user)
  125. assert status[:pleroma][:emoji_reactions] == [
  126. %{name: "☕", count: 1, me: true, url: nil, account_ids: [other_user.id]}
  127. ]
  128. end
  129. test "loads and returns the direct conversation id when given the `with_direct_conversation_id` option" do
  130. user = insert(:user)
  131. {:ok, activity} = CommonAPI.post(user, %{status: "Hey @shp!", visibility: "direct"})
  132. [participation] = Participation.for_user(user)
  133. status =
  134. StatusView.render("show.json",
  135. activity: activity,
  136. with_direct_conversation_id: true,
  137. for: user
  138. )
  139. assert status[:pleroma][:direct_conversation_id] == participation.id
  140. status = StatusView.render("show.json", activity: activity, for: user)
  141. assert status[:pleroma][:direct_conversation_id] == nil
  142. assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec())
  143. end
  144. test "returns the direct conversation id when given the `direct_conversation_id` option" do
  145. user = insert(:user)
  146. {:ok, activity} = CommonAPI.post(user, %{status: "Hey @shp!", visibility: "direct"})
  147. [participation] = Participation.for_user(user)
  148. status =
  149. StatusView.render("show.json",
  150. activity: activity,
  151. direct_conversation_id: participation.id,
  152. for: user
  153. )
  154. assert status[:pleroma][:direct_conversation_id] == participation.id
  155. assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec())
  156. end
  157. test "returns a temporary ap_id based user for activities missing db users" do
  158. user = insert(:user)
  159. {:ok, activity} = CommonAPI.post(user, %{status: "Hey @shp!", visibility: "direct"})
  160. Repo.delete(user)
  161. User.invalidate_cache(user)
  162. finger_url =
  163. "https://localhost/.well-known/webfinger?resource=acct:#{user.nickname}@localhost"
  164. Tesla.Mock.mock_global(fn
  165. %{method: :get, url: "http://localhost/.well-known/host-meta"} ->
  166. %Tesla.Env{status: 404, body: ""}
  167. %{method: :get, url: "https://localhost/.well-known/host-meta"} ->
  168. %Tesla.Env{status: 404, body: ""}
  169. %{
  170. method: :get,
  171. url: ^finger_url
  172. } ->
  173. %Tesla.Env{status: 404, body: ""}
  174. end)
  175. %{account: ms_user} = StatusView.render("show.json", activity: activity)
  176. assert ms_user.acct == "erroruser@example.com"
  177. end
  178. test "tries to get a user by nickname if fetching by ap_id doesn't work" do
  179. user = insert(:user)
  180. {:ok, activity} = CommonAPI.post(user, %{status: "Hey @shp!", visibility: "direct"})
  181. {:ok, user} =
  182. user
  183. |> Ecto.Changeset.change(%{ap_id: "#{user.ap_id}/extension/#{user.nickname}"})
  184. |> Repo.update()
  185. User.invalidate_cache(user)
  186. result = StatusView.render("show.json", activity: activity)
  187. assert result[:account][:id] == to_string(user.id)
  188. assert_schema(result, "Status", Pleroma.Web.ApiSpec.spec())
  189. end
  190. test "a note with null content" do
  191. note = insert(:note_activity)
  192. note_object = Object.normalize(note, fetch: false)
  193. data =
  194. note_object.data
  195. |> Map.put("content", nil)
  196. Object.change(note_object, %{data: data})
  197. |> Object.update_and_set_cache()
  198. User.get_cached_by_ap_id(note.data["actor"])
  199. status = StatusView.render("show.json", %{activity: note})
  200. assert status.content == ""
  201. assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec())
  202. end
  203. test "a note activity" do
  204. note = insert(:note_activity)
  205. object_data = Object.normalize(note, fetch: false).data
  206. user = User.get_cached_by_ap_id(note.data["actor"])
  207. convo_id = :erlang.crc32(object_data["context"]) |> Bitwise.band(Bitwise.bnot(0x8000_0000))
  208. status = StatusView.render("show.json", %{activity: note})
  209. created_at =
  210. (object_data["published"] || "")
  211. |> String.replace(~r/\.\d+Z/, ".000Z")
  212. expected = %{
  213. id: to_string(note.id),
  214. uri: object_data["id"],
  215. url: Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, note),
  216. account: AccountView.render("show.json", %{user: user, skip_visibility_check: true}),
  217. in_reply_to_id: nil,
  218. in_reply_to_account_id: nil,
  219. card: nil,
  220. reblog: nil,
  221. content: HTML.filter_tags(object_data["content"]),
  222. text: nil,
  223. created_at: created_at,
  224. edited_at: nil,
  225. reblogs_count: 0,
  226. replies_count: 0,
  227. favourites_count: 0,
  228. reblogged: false,
  229. bookmarked: false,
  230. favourited: false,
  231. muted: false,
  232. pinned: false,
  233. sensitive: false,
  234. poll: nil,
  235. spoiler_text: HTML.filter_tags(object_data["summary"]),
  236. visibility: "public",
  237. media_attachments: [],
  238. mentions: [],
  239. tags: [
  240. %{
  241. name: "#{hd(object_data["tag"])}",
  242. url: "http://localhost:4001/tag/#{hd(object_data["tag"])}"
  243. }
  244. ],
  245. application: nil,
  246. language: nil,
  247. emojis: [
  248. %{
  249. shortcode: "2hu",
  250. url: "corndog.png",
  251. static_url: "corndog.png",
  252. visible_in_picker: false
  253. }
  254. ],
  255. pleroma: %{
  256. local: true,
  257. conversation_id: convo_id,
  258. context: object_data["context"],
  259. in_reply_to_account_acct: nil,
  260. quote: nil,
  261. quote_id: nil,
  262. quote_url: nil,
  263. quote_visible: false,
  264. content: %{"text/plain" => HTML.strip_tags(object_data["content"])},
  265. spoiler_text: %{"text/plain" => HTML.strip_tags(object_data["summary"])},
  266. expires_at: nil,
  267. direct_conversation_id: nil,
  268. thread_muted: false,
  269. emoji_reactions: [],
  270. parent_visible: false,
  271. pinned_at: nil,
  272. quotes_count: 0,
  273. bookmark_folder: nil,
  274. list_id: nil
  275. }
  276. }
  277. assert status == expected
  278. assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec())
  279. end
  280. test "tells if the message is muted for some reason" do
  281. user = insert(:user)
  282. other_user = insert(:user)
  283. {:ok, _user_relationships} = User.mute(user, other_user)
  284. {:ok, activity} = CommonAPI.post(other_user, %{status: "test"})
  285. relationships_opt = UserRelationship.view_relationships_option(user, [other_user])
  286. opts = %{activity: activity}
  287. status = StatusView.render("show.json", opts)
  288. assert status.muted == false
  289. assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec())
  290. status = StatusView.render("show.json", Map.put(opts, :relationships, relationships_opt))
  291. assert status.muted == false
  292. for_opts = %{activity: activity, for: user}
  293. status = StatusView.render("show.json", for_opts)
  294. assert status.muted == true
  295. status = StatusView.render("show.json", Map.put(for_opts, :relationships, relationships_opt))
  296. assert status.muted == true
  297. assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec())
  298. end
  299. test "tells if the message is thread muted" do
  300. user = insert(:user)
  301. other_user = insert(:user)
  302. {:ok, _user_relationships} = User.mute(user, other_user)
  303. {:ok, activity} = CommonAPI.post(other_user, %{status: "test"})
  304. status = StatusView.render("show.json", %{activity: activity, for: user})
  305. assert status.pleroma.thread_muted == false
  306. {:ok, activity} = CommonAPI.add_mute(activity, user)
  307. status = StatusView.render("show.json", %{activity: activity, for: user})
  308. assert status.pleroma.thread_muted == true
  309. end
  310. test "tells if the status is bookmarked" do
  311. user = insert(:user)
  312. {:ok, activity} = CommonAPI.post(user, %{status: "Cute girls doing cute things"})
  313. status = StatusView.render("show.json", %{activity: activity})
  314. assert status.bookmarked == false
  315. status = StatusView.render("show.json", %{activity: activity, for: user})
  316. assert status.bookmarked == false
  317. {:ok, _bookmark} = Bookmark.create(user.id, activity.id)
  318. activity = Activity.get_by_id_with_object(activity.id)
  319. status = StatusView.render("show.json", %{activity: activity, for: user})
  320. assert status.bookmarked == true
  321. end
  322. test "a reply" do
  323. note = insert(:note_activity)
  324. user = insert(:user)
  325. {:ok, activity} = CommonAPI.post(user, %{status: "he", in_reply_to_status_id: note.id})
  326. status = StatusView.render("show.json", %{activity: activity})
  327. assert status.in_reply_to_id == to_string(note.id)
  328. [status] = StatusView.render("index.json", %{activities: [activity], as: :activity})
  329. assert status.in_reply_to_id == to_string(note.id)
  330. end
  331. test "a quote post" do
  332. post = insert(:note_activity)
  333. user = insert(:user)
  334. {:ok, quote_post} = CommonAPI.post(user, %{status: "he", quote_id: post.id})
  335. {:ok, quoted_quote_post} = CommonAPI.post(user, %{status: "yo", quote_id: quote_post.id})
  336. status = StatusView.render("show.json", %{activity: quoted_quote_post})
  337. assert status.pleroma.quote.id == to_string(quote_post.id)
  338. assert status.pleroma.quote_id == to_string(quote_post.id)
  339. assert status.pleroma.quote_url == Object.normalize(quote_post).data["id"]
  340. assert status.pleroma.quote_visible
  341. # Quotes don't go more than one level deep
  342. refute status.pleroma.quote.pleroma.quote
  343. assert status.pleroma.quote.pleroma.quote_id == to_string(post.id)
  344. assert status.pleroma.quote.pleroma.quote_url == Object.normalize(post).data["id"]
  345. assert status.pleroma.quote.pleroma.quote_visible
  346. # In an index
  347. [status] = StatusView.render("index.json", %{activities: [quoted_quote_post], as: :activity})
  348. assert status.pleroma.quote.id == to_string(quote_post.id)
  349. end
  350. test "quoted private post" do
  351. user = insert(:user)
  352. # Insert a private post
  353. private = insert(:followers_only_note_activity, user: user)
  354. private_object = Object.normalize(private)
  355. # Create a public post quoting the private post
  356. quote_private =
  357. insert(:note_activity,
  358. note: insert(:note, data: %{"quoteUrl" => private_object.data["id"]})
  359. )
  360. status = StatusView.render("show.json", %{activity: quote_private})
  361. # The quote isn't rendered
  362. refute status.pleroma.quote
  363. assert status.pleroma.quote_url == private_object.data["id"]
  364. refute status.pleroma.quote_visible
  365. # After following the user, the quote is rendered
  366. follower = insert(:user)
  367. CommonAPI.follow(user, follower)
  368. status = StatusView.render("show.json", %{activity: quote_private, for: follower})
  369. assert status.pleroma.quote.id == to_string(private.id)
  370. assert status.pleroma.quote_visible
  371. end
  372. test "quoted direct message" do
  373. # Insert a direct message
  374. direct = insert(:direct_note_activity)
  375. direct_object = Object.normalize(direct)
  376. # Create a public post quoting the direct message
  377. quote_direct =
  378. insert(:note_activity, note: insert(:note, data: %{"quoteUrl" => direct_object.data["id"]}))
  379. status = StatusView.render("show.json", %{activity: quote_direct})
  380. # The quote isn't rendered
  381. refute status.pleroma.quote
  382. assert status.pleroma.quote_url == direct_object.data["id"]
  383. refute status.pleroma.quote_visible
  384. end
  385. test "repost of quote post" do
  386. post = insert(:note_activity)
  387. user = insert(:user)
  388. {:ok, quote_post} = CommonAPI.post(user, %{status: "he", quote_id: post.id})
  389. {:ok, repost} = CommonAPI.repeat(quote_post.id, user)
  390. [status] = StatusView.render("index.json", %{activities: [repost], as: :activity})
  391. assert status.reblog.pleroma.quote.id == to_string(post.id)
  392. end
  393. test "contains mentions" do
  394. user = insert(:user)
  395. mentioned = insert(:user)
  396. {:ok, activity} = CommonAPI.post(user, %{status: "hi @#{mentioned.nickname}"})
  397. status = StatusView.render("show.json", %{activity: activity})
  398. assert status.mentions ==
  399. Enum.map([mentioned], fn u -> AccountView.render("mention.json", %{user: u}) end)
  400. assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec())
  401. end
  402. test "create mentions from the 'to' field" do
  403. %User{ap_id: recipient_ap_id} = insert(:user)
  404. cc = insert_pair(:user) |> Enum.map(& &1.ap_id)
  405. object =
  406. insert(:note, %{
  407. data: %{
  408. "to" => [recipient_ap_id],
  409. "cc" => cc
  410. }
  411. })
  412. activity =
  413. insert(:note_activity, %{
  414. note: object,
  415. recipients: [recipient_ap_id | cc]
  416. })
  417. assert length(activity.recipients) == 3
  418. %{mentions: [mention] = mentions} = StatusView.render("show.json", %{activity: activity})
  419. assert length(mentions) == 1
  420. assert mention.url == recipient_ap_id
  421. end
  422. test "create mentions from the 'tag' field" do
  423. recipient = insert(:user)
  424. cc = insert_pair(:user) |> Enum.map(& &1.ap_id)
  425. object =
  426. insert(:note, %{
  427. data: %{
  428. "cc" => cc,
  429. "tag" => [
  430. %{
  431. "href" => recipient.ap_id,
  432. "name" => recipient.nickname,
  433. "type" => "Mention"
  434. },
  435. %{
  436. "href" => "https://example.com/search?tag=test",
  437. "name" => "#test",
  438. "type" => "Hashtag"
  439. }
  440. ]
  441. }
  442. })
  443. activity =
  444. insert(:note_activity, %{
  445. note: object,
  446. recipients: [recipient.ap_id | cc]
  447. })
  448. assert length(activity.recipients) == 3
  449. %{mentions: [mention] = mentions} = StatusView.render("show.json", %{activity: activity})
  450. assert length(mentions) == 1
  451. assert mention.url == recipient.ap_id
  452. end
  453. describe "attachments" do
  454. test "Complete Mastodon style" do
  455. object = %{
  456. "type" => "Image",
  457. "url" => [
  458. %{
  459. "mediaType" => "image/png",
  460. "href" => "someurl",
  461. "width" => 200,
  462. "height" => 100
  463. }
  464. ],
  465. "blurhash" => "UJJ8X[xYW,%Jtq%NNFbXB5j]IVM|9GV=WHRn",
  466. "uuid" => 6
  467. }
  468. expected = %{
  469. id: "1638338801",
  470. type: "image",
  471. url: "someurl",
  472. remote_url: "someurl",
  473. preview_url: "someurl",
  474. text_url: "someurl",
  475. description: nil,
  476. pleroma: %{mime_type: "image/png"},
  477. meta: %{original: %{width: 200, height: 100, aspect: 2}},
  478. blurhash: "UJJ8X[xYW,%Jtq%NNFbXB5j]IVM|9GV=WHRn"
  479. }
  480. api_spec = Pleroma.Web.ApiSpec.spec()
  481. assert expected == StatusView.render("attachment.json", %{attachment: object})
  482. assert_schema(expected, "Attachment", api_spec)
  483. # If theres a "id", use that instead of the generated one
  484. object = Map.put(object, "id", 2)
  485. result = StatusView.render("attachment.json", %{attachment: object})
  486. assert %{id: "2"} = result
  487. assert_schema(result, "Attachment", api_spec)
  488. end
  489. test "Honkerific" do
  490. object = %{
  491. "type" => "Image",
  492. "url" => [
  493. %{
  494. "mediaType" => "image/png",
  495. "href" => "someurl"
  496. }
  497. ],
  498. "name" => "fool.jpeg",
  499. "summary" => "they have played us for absolute fools."
  500. }
  501. expected = %{
  502. blurhash: nil,
  503. description: "they have played us for absolute fools.",
  504. id: "1638338801",
  505. pleroma: %{mime_type: "image/png", name: "fool.jpeg"},
  506. preview_url: "someurl",
  507. remote_url: "someurl",
  508. text_url: "someurl",
  509. type: "image",
  510. url: "someurl"
  511. }
  512. api_spec = Pleroma.Web.ApiSpec.spec()
  513. assert expected == StatusView.render("attachment.json", %{attachment: object})
  514. assert_schema(expected, "Attachment", api_spec)
  515. end
  516. end
  517. test "put the url advertised in the Activity in to the url attribute" do
  518. id = "https://wedistribute.org/wp-json/pterotype/v1/object/85810"
  519. [activity] = Activity.search(nil, id)
  520. status = StatusView.render("show.json", %{activity: activity})
  521. assert status.uri == id
  522. assert status.url == "https://wedistribute.org/2019/07/mastodon-drops-ostatus/"
  523. end
  524. test "a reblog" do
  525. user = insert(:user)
  526. activity = insert(:note_activity)
  527. {:ok, reblog} = CommonAPI.repeat(activity.id, user)
  528. represented = StatusView.render("show.json", %{for: user, activity: reblog})
  529. assert represented[:id] == to_string(reblog.id)
  530. assert represented[:reblog][:id] == to_string(activity.id)
  531. assert represented[:emojis] == []
  532. assert_schema(represented, "Status", Pleroma.Web.ApiSpec.spec())
  533. end
  534. test "a peertube video" do
  535. user = insert(:user)
  536. {:ok, object} =
  537. Pleroma.Object.Fetcher.fetch_object_from_id(
  538. "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"
  539. )
  540. %Activity{} = activity = Activity.get_create_by_object_ap_id(object.data["id"])
  541. represented = StatusView.render("show.json", %{for: user, activity: activity})
  542. assert represented[:id] == to_string(activity.id)
  543. assert length(represented[:media_attachments]) == 1
  544. assert_schema(represented, "Status", Pleroma.Web.ApiSpec.spec())
  545. end
  546. test "funkwhale audio" do
  547. user = insert(:user)
  548. {:ok, object} =
  549. Pleroma.Object.Fetcher.fetch_object_from_id(
  550. "https://channels.tests.funkwhale.audio/federation/music/uploads/42342395-0208-4fee-a38d-259a6dae0871"
  551. )
  552. %Activity{} = activity = Activity.get_create_by_object_ap_id(object.data["id"])
  553. represented = StatusView.render("show.json", %{for: user, activity: activity})
  554. assert represented[:id] == to_string(activity.id)
  555. assert length(represented[:media_attachments]) == 1
  556. end
  557. test "a Mobilizon event" do
  558. user = insert(:user)
  559. {:ok, object} =
  560. Pleroma.Object.Fetcher.fetch_object_from_id(
  561. "https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39"
  562. )
  563. %Activity{} = activity = Activity.get_create_by_object_ap_id(object.data["id"])
  564. represented = StatusView.render("show.json", %{for: user, activity: activity})
  565. assert represented[:id] == to_string(activity.id)
  566. assert represented[:url] ==
  567. "https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39"
  568. assert represented[:content] ==
  569. "<p><a href=\"https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39\">Mobilizon Launching Party</a></p><p>Mobilizon is now federated! 🎉</p><p></p><p>You can view this event from other instances if they are subscribed to mobilizon.org, and soon directly from Mastodon and Pleroma. It is possible that you may see some comments from other instances, including Mastodon ones, just below.</p><p></p><p>With a Mobilizon account on an instance, you may <strong>participate</strong> at events from other instances and <strong>add comments</strong> on events.</p><p></p><p>Of course, it&#39;s still <u>a work in progress</u>: if reports made from an instance on events and comments can be federated, you can&#39;t block people right now, and moderators actions are rather limited, but this <strong>will definitely get fixed over time</strong> until first stable version next year.</p><p></p><p>Anyway, if you want to come up with some feedback, head over to our forum or - if you feel you have technical skills and are familiar with it - on our Gitlab repository.</p><p></p><p>Also, to people that want to set Mobilizon themselves even though we really don&#39;t advise to do that for now, we have a little documentation but it&#39;s quite the early days and you&#39;ll probably need some help. No worries, you can chat with us on our Forum or though our Matrix channel.</p><p></p><p>Check our website for more informations and follow us on Twitter or Mastodon.</p>"
  570. end
  571. test "a Honk event" do
  572. user = insert(:user)
  573. {:ok, object} =
  574. Pleroma.Object.Fetcher.fetch_object_from_id(
  575. "https://honk.tedunangst.com/u/tedu/h/8dkPX284T8286Mm9HD"
  576. )
  577. %Activity{} = activity = Activity.get_create_by_object_ap_id(object.data["id"])
  578. represented = StatusView.render("show.json", %{for: user, activity: activity})
  579. assert represented[:id] == to_string(activity.id)
  580. end
  581. describe "build_tags/1" do
  582. test "it returns a a dictionary tags" do
  583. object_tags = [
  584. "fediverse",
  585. "mastodon",
  586. "nextcloud",
  587. %{
  588. "href" => "https://kawen.space/users/lain",
  589. "name" => "@lain@kawen.space",
  590. "type" => "Mention"
  591. }
  592. ]
  593. assert StatusView.build_tags(object_tags) == [
  594. %{name: "fediverse", url: "http://localhost:4001/tag/fediverse"},
  595. %{name: "mastodon", url: "http://localhost:4001/tag/mastodon"},
  596. %{name: "nextcloud", url: "http://localhost:4001/tag/nextcloud"}
  597. ]
  598. end
  599. end
  600. describe "rich media cards" do
  601. test "a rich media card without a site name renders correctly" do
  602. page_url = "https://example.com"
  603. {:ok, card} =
  604. Card.create(page_url, %{image: page_url <> "/example.jpg", title: "Example website"})
  605. assert match?(%{provider_name: "example.com"}, StatusView.render("card.json", card))
  606. end
  607. test "a rich media card without a site name or image renders correctly" do
  608. page_url = "https://example.com"
  609. fields = %{
  610. "url" => page_url,
  611. "title" => "Example website"
  612. }
  613. {:ok, card} = Card.create(page_url, fields)
  614. assert match?(%{provider_name: "example.com"}, StatusView.render("card.json", card))
  615. end
  616. test "a rich media card without an image renders correctly" do
  617. page_url = "https://example.com"
  618. fields = %{
  619. "url" => page_url,
  620. "site_name" => "Example site name",
  621. "title" => "Example website"
  622. }
  623. {:ok, card} = Card.create(page_url, fields)
  624. assert match?(%{provider_name: "example.com"}, StatusView.render("card.json", card))
  625. end
  626. test "a rich media card without descriptions returns the fields with empty strings" do
  627. page_url = "https://example.com"
  628. fields = %{
  629. "url" => page_url,
  630. "site_name" => "Example site name",
  631. "title" => "Example website"
  632. }
  633. {:ok, card} = Card.create(page_url, fields)
  634. assert match?(
  635. %{description: "", image_description: ""},
  636. StatusView.render("card.json", card)
  637. )
  638. end
  639. test "a rich media card with all relevant data renders correctly" do
  640. page_url = "https://example.com"
  641. fields = %{
  642. "url" => page_url,
  643. "site_name" => "Example site name",
  644. "title" => "Example website",
  645. "image" => page_url <> "/example.jpg",
  646. "description" => "Example description"
  647. }
  648. {:ok, card} = Card.create(page_url, fields)
  649. assert match?(%{provider_name: "example.com"}, StatusView.render("card.json", card))
  650. end
  651. test "a rich media card has all media proxied" do
  652. clear_config([:media_proxy, :enabled], true)
  653. clear_config([:media_preview_proxy, :enabled])
  654. ConfigMock
  655. |> stub_with(Pleroma.Test.StaticConfig)
  656. page_url = "https://example.com"
  657. fields = %{
  658. "url" => page_url,
  659. "site_name" => "Example site name",
  660. "title" => "Example website",
  661. "image" => page_url <> "/example.jpg",
  662. "audio" => page_url <> "/example.ogg",
  663. "video" => page_url <> "/example.mp4",
  664. "description" => "Example description"
  665. }
  666. {:ok, card} = Card.create(page_url, fields)
  667. %{
  668. provider_name: "example.com",
  669. image: image,
  670. pleroma: %{opengraph: og}
  671. } = StatusView.render("card.json", card)
  672. assert String.match?(image, ~r/\/proxy\//)
  673. assert String.match?(og["image"], ~r/\/proxy\//)
  674. assert String.match?(og["audio"], ~r/\/proxy\//)
  675. assert String.match?(og["video"], ~r/\/proxy\//)
  676. end
  677. end
  678. test "does not embed a relationship in the account" do
  679. user = insert(:user)
  680. other_user = insert(:user)
  681. {:ok, activity} =
  682. CommonAPI.post(user, %{
  683. status: "drink more water"
  684. })
  685. result = StatusView.render("show.json", %{activity: activity, for: other_user})
  686. assert result[:account][:pleroma][:relationship] == %{}
  687. assert_schema(result, "Status", Pleroma.Web.ApiSpec.spec())
  688. end
  689. test "does not embed a relationship in the account in reposts" do
  690. user = insert(:user)
  691. other_user = insert(:user)
  692. {:ok, activity} =
  693. CommonAPI.post(user, %{
  694. status: "˙˙ɐʎns"
  695. })
  696. {:ok, activity} = CommonAPI.repeat(activity.id, other_user)
  697. result = StatusView.render("show.json", %{activity: activity, for: user})
  698. assert result[:account][:pleroma][:relationship] == %{}
  699. assert result[:reblog][:account][:pleroma][:relationship] == %{}
  700. assert_schema(result, "Status", Pleroma.Web.ApiSpec.spec())
  701. end
  702. test "visibility/list" do
  703. user = insert(:user)
  704. {:ok, list} = Pleroma.List.create("foo", user)
  705. {:ok, activity} = CommonAPI.post(user, %{status: "foobar", visibility: "list:#{list.id}"})
  706. status = StatusView.render("show.json", activity: activity)
  707. assert status.visibility == "list"
  708. assert status.pleroma.list_id == nil
  709. status = StatusView.render("show.json", activity: activity, for: user)
  710. assert status.pleroma.list_id == list.id
  711. end
  712. test "has a field for parent visibility" do
  713. user = insert(:user)
  714. poster = insert(:user)
  715. {:ok, invisible} = CommonAPI.post(poster, %{status: "hey", visibility: "private"})
  716. {:ok, visible} =
  717. CommonAPI.post(poster, %{status: "hey", visibility: "private", in_reply_to_id: invisible.id})
  718. status = StatusView.render("show.json", activity: visible, for: user)
  719. refute status.pleroma.parent_visible
  720. status = StatusView.render("show.json", activity: visible, for: poster)
  721. assert status.pleroma.parent_visible
  722. end
  723. test "it shows edited_at" do
  724. poster = insert(:user)
  725. {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
  726. status = StatusView.render("show.json", activity: post)
  727. refute status.edited_at
  728. {:ok, _} = CommonAPI.update(post, poster, %{status: "mew mew"})
  729. edited = Pleroma.Activity.normalize(post)
  730. status = StatusView.render("show.json", activity: edited)
  731. assert status.edited_at
  732. end
  733. test "it shows post language" do
  734. user = insert(:user)
  735. {:ok, post} = CommonAPI.post(user, %{status: "Szczęść Boże", language: "pl"})
  736. status = StatusView.render("show.json", activity: post)
  737. assert status.language == "pl"
  738. end
  739. test "doesn't show post language if it's 'und'" do
  740. user = insert(:user)
  741. {:ok, post} = CommonAPI.post(user, %{status: "sdifjogijodfg", language: "und"})
  742. status = StatusView.render("show.json", activity: post)
  743. assert status.language == nil
  744. end
  745. test "with a source object" do
  746. note =
  747. insert(:note,
  748. data: %{"source" => %{"content" => "object source", "mediaType" => "text/markdown"}}
  749. )
  750. activity = insert(:note_activity, note: note)
  751. status = StatusView.render("show.json", activity: activity, with_source: true)
  752. assert status.text == "object source"
  753. end
  754. describe "source.json" do
  755. test "with a source object, renders both source and content type" do
  756. note =
  757. insert(:note,
  758. data: %{"source" => %{"content" => "object source", "mediaType" => "text/markdown"}}
  759. )
  760. activity = insert(:note_activity, note: note)
  761. status = StatusView.render("source.json", activity: activity)
  762. assert status.text == "object source"
  763. assert status.content_type == "text/markdown"
  764. end
  765. test "with a source string, renders source and put text/plain as the content type" do
  766. note = insert(:note, data: %{"source" => "string source"})
  767. activity = insert(:note_activity, note: note)
  768. status = StatusView.render("source.json", activity: activity)
  769. assert status.text == "string source"
  770. assert status.content_type == "text/plain"
  771. end
  772. end
  773. end