Fork of Pleroma with site-specific changes and feature branches https://git.pleroma.social/pleroma/pleroma
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

601 lines
18KB

  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Web.CommonAPI.UtilsTest do
  5. alias Pleroma.Builders.UserBuilder
  6. alias Pleroma.Object
  7. alias Pleroma.Web.CommonAPI
  8. alias Pleroma.Web.CommonAPI.Utils
  9. alias Pleroma.Web.Endpoint
  10. use Pleroma.DataCase
  11. import ExUnit.CaptureLog
  12. import Pleroma.Factory
  13. @public_address "https://www.w3.org/ns/activitystreams#Public"
  14. test "it adds attachment links to a given text and attachment set" do
  15. name =
  16. "Sakura%20Mana%20%E2%80%93%20Turned%20on%20by%20a%20Senior%20OL%20with%20a%20Temptating%20Tight%20Skirt-s%20Full%20Hipline%20and%20Panty%20Shot-%20Beautiful%20Thick%20Thighs-%20and%20Erotic%20Ass-%20-2015-%20--%20Oppaitime%208-28-2017%206-50-33%20PM.png"
  17. attachment = %{
  18. "url" => [%{"href" => name}]
  19. }
  20. res = Utils.add_attachments("", [attachment])
  21. assert res ==
  22. "<br><a href=\"#{name}\" class='attachment'>Sakura Mana – Turned on by a Se…</a>"
  23. end
  24. describe "it confirms the password given is the current users password" do
  25. test "incorrect password given" do
  26. {:ok, user} = UserBuilder.insert()
  27. assert Utils.confirm_current_password(user, "") == {:error, "Invalid password."}
  28. end
  29. test "correct password given" do
  30. {:ok, user} = UserBuilder.insert()
  31. assert Utils.confirm_current_password(user, "test") == {:ok, user}
  32. end
  33. end
  34. test "parses emoji from name and bio" do
  35. {:ok, user} = UserBuilder.insert(%{name: ":blank:", bio: ":firefox:"})
  36. expected = [
  37. %{
  38. "type" => "Emoji",
  39. "icon" => %{"type" => "Image", "url" => "#{Endpoint.url()}/emoji/Firefox.gif"},
  40. "name" => ":firefox:"
  41. },
  42. %{
  43. "type" => "Emoji",
  44. "icon" => %{
  45. "type" => "Image",
  46. "url" => "#{Endpoint.url()}/emoji/blank.png"
  47. },
  48. "name" => ":blank:"
  49. }
  50. ]
  51. assert expected == Utils.emoji_from_profile(user)
  52. end
  53. describe "format_input/3" do
  54. test "works for bare text/plain" do
  55. text = "hello world!"
  56. expected = "hello world!"
  57. {output, [], []} = Utils.format_input(text, "text/plain")
  58. assert output == expected
  59. text = "hello world!\n\nsecond paragraph!"
  60. expected = "hello world!<br><br>second paragraph!"
  61. {output, [], []} = Utils.format_input(text, "text/plain")
  62. assert output == expected
  63. end
  64. test "works for bare text/html" do
  65. text = "<p>hello world!</p>"
  66. expected = "<p>hello world!</p>"
  67. {output, [], []} = Utils.format_input(text, "text/html")
  68. assert output == expected
  69. text = "<p>hello world!</p>\n\n<p>second paragraph</p>"
  70. expected = "<p>hello world!</p>\n\n<p>second paragraph</p>"
  71. {output, [], []} = Utils.format_input(text, "text/html")
  72. assert output == expected
  73. end
  74. test "works for bare text/markdown" do
  75. text = "**hello world**"
  76. expected = "<p><strong>hello world</strong></p>\n"
  77. {output, [], []} = Utils.format_input(text, "text/markdown")
  78. assert output == expected
  79. text = "**hello world**\n\n*another paragraph*"
  80. expected = "<p><strong>hello world</strong></p>\n<p><em>another paragraph</em></p>\n"
  81. {output, [], []} = Utils.format_input(text, "text/markdown")
  82. assert output == expected
  83. text = """
  84. > cool quote
  85. by someone
  86. """
  87. expected = "<blockquote><p>cool quote</p>\n</blockquote>\n<p>by someone</p>\n"
  88. {output, [], []} = Utils.format_input(text, "text/markdown")
  89. assert output == expected
  90. end
  91. test "works for bare text/bbcode" do
  92. text = "[b]hello world[/b]"
  93. expected = "<strong>hello world</strong>"
  94. {output, [], []} = Utils.format_input(text, "text/bbcode")
  95. assert output == expected
  96. text = "[b]hello world![/b]\n\nsecond paragraph!"
  97. expected = "<strong>hello world!</strong><br>\n<br>\nsecond paragraph!"
  98. {output, [], []} = Utils.format_input(text, "text/bbcode")
  99. assert output == expected
  100. text = "[b]hello world![/b]\n\n<strong>second paragraph!</strong>"
  101. expected =
  102. "<strong>hello world!</strong><br>\n<br>\n&lt;strong&gt;second paragraph!&lt;/strong&gt;"
  103. {output, [], []} = Utils.format_input(text, "text/bbcode")
  104. assert output == expected
  105. end
  106. test "works for text/markdown with mentions" do
  107. {:ok, user} =
  108. UserBuilder.insert(%{nickname: "user__test", ap_id: "http://foo.com/user__test"})
  109. text = "**hello world**\n\n*another @user__test and @user__test google.com paragraph*"
  110. expected =
  111. "<p><strong>hello world</strong></p>\n<p><em>another <span class=\"h-card\"><a data-user=\"#{
  112. user.id
  113. }\" class=\"u-url mention\" href=\"http://foo.com/user__test\">@<span>user__test</span></a></span> and <span class=\"h-card\"><a data-user=\"#{
  114. user.id
  115. }\" class=\"u-url mention\" href=\"http://foo.com/user__test\">@<span>user__test</span></a></span> <a href=\"http://google.com\">google.com</a> paragraph</em></p>\n"
  116. {output, _, _} = Utils.format_input(text, "text/markdown")
  117. assert output == expected
  118. end
  119. end
  120. describe "context_to_conversation_id" do
  121. test "creates a mapping object" do
  122. conversation_id = Utils.context_to_conversation_id("random context")
  123. object = Object.get_by_ap_id("random context")
  124. assert conversation_id == object.id
  125. end
  126. test "returns an existing mapping for an existing object" do
  127. {:ok, object} = Object.context_mapping("random context") |> Repo.insert()
  128. conversation_id = Utils.context_to_conversation_id("random context")
  129. assert conversation_id == object.id
  130. end
  131. end
  132. describe "formats date to asctime" do
  133. test "when date is in ISO 8601 format" do
  134. date = DateTime.utc_now() |> DateTime.to_iso8601()
  135. expected =
  136. date
  137. |> DateTime.from_iso8601()
  138. |> elem(1)
  139. |> Calendar.Strftime.strftime!("%a %b %d %H:%M:%S %z %Y")
  140. assert Utils.date_to_asctime(date) == expected
  141. end
  142. test "when date is a binary in wrong format" do
  143. date = DateTime.utc_now()
  144. expected = ""
  145. assert capture_log(fn ->
  146. assert Utils.date_to_asctime(date) == expected
  147. end) =~ "[warn] Date #{date} in wrong format, must be ISO 8601"
  148. end
  149. test "when date is a Unix timestamp" do
  150. date = DateTime.utc_now() |> DateTime.to_unix()
  151. expected = ""
  152. assert capture_log(fn ->
  153. assert Utils.date_to_asctime(date) == expected
  154. end) =~ "[warn] Date #{date} in wrong format, must be ISO 8601"
  155. end
  156. test "when date is nil" do
  157. expected = ""
  158. assert capture_log(fn ->
  159. assert Utils.date_to_asctime(nil) == expected
  160. end) =~ "[warn] Date in wrong format, must be ISO 8601"
  161. end
  162. test "when date is a random string" do
  163. assert capture_log(fn ->
  164. assert Utils.date_to_asctime("foo") == ""
  165. end) =~ "[warn] Date foo in wrong format, must be ISO 8601"
  166. end
  167. end
  168. describe "get_to_and_cc" do
  169. test "for public posts, not a reply" do
  170. user = insert(:user)
  171. mentioned_user = insert(:user)
  172. mentions = [mentioned_user.ap_id]
  173. {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "public", nil)
  174. assert length(to) == 2
  175. assert length(cc) == 1
  176. assert @public_address in to
  177. assert mentioned_user.ap_id in to
  178. assert user.follower_address in cc
  179. end
  180. test "for public posts, a reply" do
  181. user = insert(:user)
  182. mentioned_user = insert(:user)
  183. third_user = insert(:user)
  184. {:ok, activity} = CommonAPI.post(third_user, %{"status" => "uguu"})
  185. mentions = [mentioned_user.ap_id]
  186. {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "public", nil)
  187. assert length(to) == 3
  188. assert length(cc) == 1
  189. assert @public_address in to
  190. assert mentioned_user.ap_id in to
  191. assert third_user.ap_id in to
  192. assert user.follower_address in cc
  193. end
  194. test "for unlisted posts, not a reply" do
  195. user = insert(:user)
  196. mentioned_user = insert(:user)
  197. mentions = [mentioned_user.ap_id]
  198. {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "unlisted", nil)
  199. assert length(to) == 2
  200. assert length(cc) == 1
  201. assert @public_address in cc
  202. assert mentioned_user.ap_id in to
  203. assert user.follower_address in to
  204. end
  205. test "for unlisted posts, a reply" do
  206. user = insert(:user)
  207. mentioned_user = insert(:user)
  208. third_user = insert(:user)
  209. {:ok, activity} = CommonAPI.post(third_user, %{"status" => "uguu"})
  210. mentions = [mentioned_user.ap_id]
  211. {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "unlisted", nil)
  212. assert length(to) == 3
  213. assert length(cc) == 1
  214. assert @public_address in cc
  215. assert mentioned_user.ap_id in to
  216. assert third_user.ap_id in to
  217. assert user.follower_address in to
  218. end
  219. test "for private posts, not a reply" do
  220. user = insert(:user)
  221. mentioned_user = insert(:user)
  222. mentions = [mentioned_user.ap_id]
  223. {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "private", nil)
  224. assert length(to) == 2
  225. assert length(cc) == 0
  226. assert mentioned_user.ap_id in to
  227. assert user.follower_address in to
  228. end
  229. test "for private posts, a reply" do
  230. user = insert(:user)
  231. mentioned_user = insert(:user)
  232. third_user = insert(:user)
  233. {:ok, activity} = CommonAPI.post(third_user, %{"status" => "uguu"})
  234. mentions = [mentioned_user.ap_id]
  235. {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "private", nil)
  236. assert length(to) == 3
  237. assert length(cc) == 0
  238. assert mentioned_user.ap_id in to
  239. assert third_user.ap_id in to
  240. assert user.follower_address in to
  241. end
  242. test "for direct posts, not a reply" do
  243. user = insert(:user)
  244. mentioned_user = insert(:user)
  245. mentions = [mentioned_user.ap_id]
  246. {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "direct", nil)
  247. assert length(to) == 1
  248. assert length(cc) == 0
  249. assert mentioned_user.ap_id in to
  250. end
  251. test "for direct posts, a reply" do
  252. user = insert(:user)
  253. mentioned_user = insert(:user)
  254. third_user = insert(:user)
  255. {:ok, activity} = CommonAPI.post(third_user, %{"status" => "uguu"})
  256. mentions = [mentioned_user.ap_id]
  257. {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "direct", nil)
  258. assert length(to) == 2
  259. assert length(cc) == 0
  260. assert mentioned_user.ap_id in to
  261. assert third_user.ap_id in to
  262. end
  263. end
  264. describe "get_by_id_or_ap_id/1" do
  265. test "get activity by id" do
  266. activity = insert(:note_activity)
  267. %Pleroma.Activity{} = note = Utils.get_by_id_or_ap_id(activity.id)
  268. assert note.id == activity.id
  269. end
  270. test "get activity by ap_id" do
  271. activity = insert(:note_activity)
  272. %Pleroma.Activity{} = note = Utils.get_by_id_or_ap_id(activity.data["object"])
  273. assert note.id == activity.id
  274. end
  275. test "get activity by object when type isn't `Create` " do
  276. activity = insert(:like_activity)
  277. %Pleroma.Activity{} = like = Utils.get_by_id_or_ap_id(activity.id)
  278. assert like.data["object"] == activity.data["object"]
  279. end
  280. end
  281. describe "to_master_date/1" do
  282. test "removes microseconds from date (NaiveDateTime)" do
  283. assert Utils.to_masto_date(~N[2015-01-23 23:50:07.123]) == "2015-01-23T23:50:07.000Z"
  284. end
  285. test "removes microseconds from date (String)" do
  286. assert Utils.to_masto_date("2015-01-23T23:50:07.123Z") == "2015-01-23T23:50:07.000Z"
  287. end
  288. test "returns empty string when date invalid" do
  289. assert Utils.to_masto_date("2015-01?23T23:50:07.123Z") == ""
  290. end
  291. end
  292. describe "conversation_id_to_context/1" do
  293. test "returns id" do
  294. object = insert(:note)
  295. assert Utils.conversation_id_to_context(object.id) == object.data["id"]
  296. end
  297. test "returns error if object not found" do
  298. assert Utils.conversation_id_to_context("123") == {:error, "No such conversation"}
  299. end
  300. end
  301. describe "maybe_notify_mentioned_recipients/2" do
  302. test "returns recipients when activity is not `Create`" do
  303. activity = insert(:like_activity)
  304. assert Utils.maybe_notify_mentioned_recipients(["test"], activity) == ["test"]
  305. end
  306. test "returns recipients from tag" do
  307. user = insert(:user)
  308. object =
  309. insert(:note,
  310. user: user,
  311. data: %{
  312. "tag" => [
  313. %{"type" => "Hashtag"},
  314. "",
  315. %{"type" => "Mention", "href" => "https://testing.pleroma.lol/users/lain"},
  316. %{"type" => "Mention", "href" => "https://shitposter.club/user/5381"},
  317. %{"type" => "Mention", "href" => "https://shitposter.club/user/5381"}
  318. ]
  319. }
  320. )
  321. activity = insert(:note_activity, user: user, note: object)
  322. assert Utils.maybe_notify_mentioned_recipients(["test"], activity) == [
  323. "test",
  324. "https://testing.pleroma.lol/users/lain",
  325. "https://shitposter.club/user/5381"
  326. ]
  327. end
  328. test "returns recipients when object is map" do
  329. user = insert(:user)
  330. object = insert(:note, user: user)
  331. activity =
  332. insert(:note_activity,
  333. user: user,
  334. note: object,
  335. data_attrs: %{
  336. "object" => %{
  337. "tag" => [
  338. %{"type" => "Hashtag"},
  339. "",
  340. %{"type" => "Mention", "href" => "https://testing.pleroma.lol/users/lain"},
  341. %{"type" => "Mention", "href" => "https://shitposter.club/user/5381"},
  342. %{"type" => "Mention", "href" => "https://shitposter.club/user/5381"}
  343. ]
  344. }
  345. }
  346. )
  347. Pleroma.Repo.delete(object)
  348. assert Utils.maybe_notify_mentioned_recipients(["test"], activity) == [
  349. "test",
  350. "https://testing.pleroma.lol/users/lain",
  351. "https://shitposter.club/user/5381"
  352. ]
  353. end
  354. test "returns recipients when object not found" do
  355. user = insert(:user)
  356. object = insert(:note, user: user)
  357. activity = insert(:note_activity, user: user, note: object)
  358. Pleroma.Repo.delete(object)
  359. assert Utils.maybe_notify_mentioned_recipients(["test-test"], activity) == [
  360. "test-test"
  361. ]
  362. end
  363. end
  364. describe "attachments_from_ids_descs/2" do
  365. test "returns [] when attachment ids is empty" do
  366. assert Utils.attachments_from_ids_descs([], "{}") == []
  367. end
  368. test "returns list attachments with desc" do
  369. object = insert(:note)
  370. desc = Jason.encode!(%{object.id => "test-desc"})
  371. assert Utils.attachments_from_ids_descs(["#{object.id}", "34"], desc) == [
  372. Map.merge(object.data, %{"name" => "test-desc"})
  373. ]
  374. end
  375. end
  376. describe "attachments_from_ids/1" do
  377. test "returns attachments with descs" do
  378. object = insert(:note)
  379. desc = Jason.encode!(%{object.id => "test-desc"})
  380. assert Utils.attachments_from_ids(%{
  381. "media_ids" => ["#{object.id}"],
  382. "descriptions" => desc
  383. }) == [
  384. Map.merge(object.data, %{"name" => "test-desc"})
  385. ]
  386. end
  387. test "returns attachments without descs" do
  388. object = insert(:note)
  389. assert Utils.attachments_from_ids(%{"media_ids" => ["#{object.id}"]}) == [object.data]
  390. end
  391. test "returns [] when not pass media_ids" do
  392. assert Utils.attachments_from_ids(%{}) == []
  393. end
  394. end
  395. describe "maybe_add_list_data/3" do
  396. test "adds list params when found user list" do
  397. user = insert(:user)
  398. {:ok, %Pleroma.List{} = list} = Pleroma.List.create("title", user)
  399. assert Utils.maybe_add_list_data(%{additional: %{}, object: %{}}, user, {:list, list.id}) ==
  400. %{
  401. additional: %{"bcc" => [list.ap_id], "listMessage" => list.ap_id},
  402. object: %{"listMessage" => list.ap_id}
  403. }
  404. end
  405. test "returns original params when list not found" do
  406. user = insert(:user)
  407. {:ok, %Pleroma.List{} = list} = Pleroma.List.create("title", insert(:user))
  408. assert Utils.maybe_add_list_data(%{additional: %{}, object: %{}}, user, {:list, list.id}) ==
  409. %{additional: %{}, object: %{}}
  410. end
  411. end
  412. describe "make_note_data/11" do
  413. test "returns note data" do
  414. user = insert(:user)
  415. note = insert(:note)
  416. user2 = insert(:user)
  417. user3 = insert(:user)
  418. assert Utils.make_note_data(
  419. user.ap_id,
  420. [user2.ap_id],
  421. "2hu",
  422. "<h1>This is :moominmamma: note</h1>",
  423. [],
  424. note.id,
  425. [name: "jimm"],
  426. "test summary",
  427. [user3.ap_id],
  428. false,
  429. %{"custom_tag" => "test"}
  430. ) == %{
  431. "actor" => user.ap_id,
  432. "attachment" => [],
  433. "cc" => [user3.ap_id],
  434. "content" => "<h1>This is :moominmamma: note</h1>",
  435. "context" => "2hu",
  436. "sensitive" => false,
  437. "summary" => "test summary",
  438. "tag" => ["jimm"],
  439. "to" => [user2.ap_id],
  440. "type" => "Note",
  441. "custom_tag" => "test"
  442. }
  443. end
  444. end
  445. describe "maybe_add_attachments/3" do
  446. test "returns parsed results when no_links is true" do
  447. assert Utils.maybe_add_attachments(
  448. {"test", [], ["tags"]},
  449. [],
  450. true
  451. ) == {"test", [], ["tags"]}
  452. end
  453. test "adds attachments to parsed results" do
  454. attachment = %{"url" => [%{"href" => "SakuraPM.png"}]}
  455. assert Utils.maybe_add_attachments(
  456. {"test", [], ["tags"]},
  457. [attachment],
  458. false
  459. ) == {
  460. "test<br><a href=\"SakuraPM.png\" class='attachment'>SakuraPM.png</a>",
  461. [],
  462. ["tags"]
  463. }
  464. end
  465. end
  466. end