1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.CommonAPI.UtilsTest do
6 alias Pleroma.Builders.UserBuilder
8 alias Pleroma.Web.CommonAPI
9 alias Pleroma.Web.CommonAPI.ActivityDraft
10 alias Pleroma.Web.CommonAPI.Utils
13 import ExUnit.CaptureLog
14 import Pleroma.Factory
16 @public_address "https://www.w3.org/ns/activitystreams#Public"
18 describe "add_attachments/2" do
21 "Sakura Mana – Turned on by a Senior OL with a Temptating Tight Skirt-s Full Hipline and Panty Shot- Beautiful Thick Thighs- and Erotic Ass- -2015- -- Oppaitime 8-28-2017 6-50-33 PM.png"
24 "url" => [%{"href" => URI.encode(name)}]
27 %{name: name, attachment: attachment}
30 test "it adds attachment links to a given text and attachment set", %{
32 attachment: attachment
35 clear_config([Pleroma.Upload, :filename_display_max_length], len)
38 "<br><a href=\"#{URI.encode(name)}\" class='attachment'>#{String.slice(name, 0..len)}…</a>"
40 assert Utils.add_attachments("", [attachment]) == expected
43 test "doesn't truncate file name if config for truncate is set to 0", %{
45 attachment: attachment
47 clear_config([Pleroma.Upload, :filename_display_max_length], 0)
49 expected = "<br><a href=\"#{URI.encode(name)}\" class='attachment'>#{name}</a>"
51 assert Utils.add_attachments("", [attachment]) == expected
55 describe "it confirms the password given is the current users password" do
56 test "incorrect password given" do
57 {:ok, user} = UserBuilder.insert()
59 assert Utils.confirm_current_password(user, "") == {:error, "Invalid password."}
62 test "correct password given" do
63 {:ok, user} = UserBuilder.insert()
64 assert Utils.confirm_current_password(user, "test") == {:ok, user}
68 describe "format_input/3" do
69 test "works for bare text/plain" do
71 expected = "hello world!"
73 {output, [], []} = Utils.format_input(text, "text/plain")
75 assert output == expected
77 text = "hello world!\n\nsecond paragraph!"
78 expected = "hello world!<br><br>second paragraph!"
80 {output, [], []} = Utils.format_input(text, "text/plain")
82 assert output == expected
85 test "works for bare text/html" do
86 text = "<p>hello world!</p>"
87 expected = "<p>hello world!</p>"
89 {output, [], []} = Utils.format_input(text, "text/html")
91 assert output == expected
93 text = "<p>hello world!</p><br/>\n<p>second paragraph</p>"
94 expected = "<p>hello world!</p><br/>\n<p>second paragraph</p>"
96 {output, [], []} = Utils.format_input(text, "text/html")
98 assert output == expected
101 test "works for bare text/markdown" do
102 text = "**hello world**"
103 expected = "<p><strong>hello world</strong></p>"
105 {output, [], []} = Utils.format_input(text, "text/markdown")
107 assert output == expected
109 text = "**hello world**\n\n*another paragraph*"
110 expected = "<p><strong>hello world</strong></p><p><em>another paragraph</em></p>"
112 {output, [], []} = Utils.format_input(text, "text/markdown")
114 assert output == expected
122 expected = "<blockquote><p>cool quote</p></blockquote><p>by someone</p>"
124 {output, [], []} = Utils.format_input(text, "text/markdown")
126 assert output == expected
129 test "works for bare text/bbcode" do
130 text = "[b]hello world[/b]"
131 expected = "<strong>hello world</strong>"
133 {output, [], []} = Utils.format_input(text, "text/bbcode")
135 assert output == expected
137 text = "[b]hello world![/b]\n\nsecond paragraph!"
138 expected = "<strong>hello world!</strong><br><br>second paragraph!"
140 {output, [], []} = Utils.format_input(text, "text/bbcode")
142 assert output == expected
144 text = "[b]hello world![/b]\n\n<strong>second paragraph!</strong>"
147 "<strong>hello world!</strong><br><br><strong>second paragraph!</strong>"
149 {output, [], []} = Utils.format_input(text, "text/bbcode")
151 assert output == expected
154 test "works for text/markdown with mentions" do
156 UserBuilder.insert(%{nickname: "user__test", ap_id: "http://foo.com/user__test"})
158 text = "**hello world**\n\n*another @user__test and @user__test google.com paragraph*"
160 {output, _, _} = Utils.format_input(text, "text/markdown")
163 ~s(<p><strong>hello world</strong></p><p><em>another <span class="h-card"><a class="u-url mention" data-user="#{
165 }" href="http://foo.com/user__test" rel="ugc">@<span>user__test</span></a></span> and <span class="h-card"><a class="u-url mention" data-user="#{
167 }" href="http://foo.com/user__test" rel="ugc">@<span>user__test</span></a></span> <a href="http://google.com" rel="ugc">google.com</a> paragraph</em></p>)
171 describe "context_to_conversation_id" do
172 test "creates a mapping object" do
173 conversation_id = Utils.context_to_conversation_id("random context")
174 object = Object.get_by_ap_id("random context")
176 assert conversation_id == object.id
179 test "returns an existing mapping for an existing object" do
180 {:ok, object} = Object.context_mapping("random context") |> Repo.insert()
181 conversation_id = Utils.context_to_conversation_id("random context")
183 assert conversation_id == object.id
187 describe "formats date to asctime" do
188 test "when date is in ISO 8601 format" do
189 date = DateTime.utc_now() |> DateTime.to_iso8601()
193 |> DateTime.from_iso8601()
195 |> Calendar.Strftime.strftime!("%a %b %d %H:%M:%S %z %Y")
197 assert Utils.date_to_asctime(date) == expected
200 test "when date is a binary in wrong format" do
201 date = DateTime.utc_now()
205 assert capture_log(fn ->
206 assert Utils.date_to_asctime(date) == expected
207 end) =~ "[warn] Date #{date} in wrong format, must be ISO 8601"
210 test "when date is a Unix timestamp" do
211 date = DateTime.utc_now() |> DateTime.to_unix()
215 assert capture_log(fn ->
216 assert Utils.date_to_asctime(date) == expected
217 end) =~ "[warn] Date #{date} in wrong format, must be ISO 8601"
220 test "when date is nil" do
223 assert capture_log(fn ->
224 assert Utils.date_to_asctime(nil) == expected
225 end) =~ "[warn] Date in wrong format, must be ISO 8601"
228 test "when date is a random string" do
229 assert capture_log(fn ->
230 assert Utils.date_to_asctime("foo") == ""
231 end) =~ "[warn] Date foo in wrong format, must be ISO 8601"
235 describe "get_to_and_cc" do
236 test "for public posts, not a reply" do
238 mentioned_user = insert(:user)
239 draft = %ActivityDraft{user: user, mentions: [mentioned_user.ap_id], visibility: "public"}
241 {to, cc} = Utils.get_to_and_cc(draft)
243 assert length(to) == 2
244 assert length(cc) == 1
246 assert @public_address in to
247 assert mentioned_user.ap_id in to
248 assert user.follower_address in cc
251 test "for public posts, a reply" do
253 mentioned_user = insert(:user)
254 third_user = insert(:user)
255 {:ok, activity} = CommonAPI.post(third_user, %{status: "uguu"})
257 draft = %ActivityDraft{
259 mentions: [mentioned_user.ap_id],
260 visibility: "public",
261 in_reply_to: activity
264 {to, cc} = Utils.get_to_and_cc(draft)
266 assert length(to) == 3
267 assert length(cc) == 1
269 assert @public_address in to
270 assert mentioned_user.ap_id in to
271 assert third_user.ap_id in to
272 assert user.follower_address in cc
275 test "for unlisted posts, not a reply" do
277 mentioned_user = insert(:user)
278 draft = %ActivityDraft{user: user, mentions: [mentioned_user.ap_id], visibility: "unlisted"}
280 {to, cc} = Utils.get_to_and_cc(draft)
282 assert length(to) == 2
283 assert length(cc) == 1
285 assert @public_address in cc
286 assert mentioned_user.ap_id in to
287 assert user.follower_address in to
290 test "for unlisted posts, a reply" do
292 mentioned_user = insert(:user)
293 third_user = insert(:user)
294 {:ok, activity} = CommonAPI.post(third_user, %{status: "uguu"})
296 draft = %ActivityDraft{
298 mentions: [mentioned_user.ap_id],
299 visibility: "unlisted",
300 in_reply_to: activity
303 {to, cc} = Utils.get_to_and_cc(draft)
305 assert length(to) == 3
306 assert length(cc) == 1
308 assert @public_address in cc
309 assert mentioned_user.ap_id in to
310 assert third_user.ap_id in to
311 assert user.follower_address in to
314 test "for private posts, not a reply" do
316 mentioned_user = insert(:user)
317 draft = %ActivityDraft{user: user, mentions: [mentioned_user.ap_id], visibility: "private"}
319 {to, cc} = Utils.get_to_and_cc(draft)
320 assert length(to) == 2
321 assert Enum.empty?(cc)
323 assert mentioned_user.ap_id in to
324 assert user.follower_address in to
327 test "for private posts, a reply" do
329 mentioned_user = insert(:user)
330 third_user = insert(:user)
331 {:ok, activity} = CommonAPI.post(third_user, %{status: "uguu"})
333 draft = %ActivityDraft{
335 mentions: [mentioned_user.ap_id],
336 visibility: "private",
337 in_reply_to: activity
340 {to, cc} = Utils.get_to_and_cc(draft)
342 assert length(to) == 2
343 assert Enum.empty?(cc)
345 assert mentioned_user.ap_id in to
346 assert user.follower_address in to
349 test "for direct posts, not a reply" do
351 mentioned_user = insert(:user)
352 draft = %ActivityDraft{user: user, mentions: [mentioned_user.ap_id], visibility: "direct"}
354 {to, cc} = Utils.get_to_and_cc(draft)
356 assert length(to) == 1
357 assert Enum.empty?(cc)
359 assert mentioned_user.ap_id in to
362 test "for direct posts, a reply" do
364 mentioned_user = insert(:user)
365 third_user = insert(:user)
366 {:ok, activity} = CommonAPI.post(third_user, %{status: "uguu"})
368 draft = %ActivityDraft{
370 mentions: [mentioned_user.ap_id],
371 visibility: "direct",
372 in_reply_to: activity
375 {to, cc} = Utils.get_to_and_cc(draft)
377 assert length(to) == 1
378 assert Enum.empty?(cc)
380 assert mentioned_user.ap_id in to
382 {:ok, direct_activity} = CommonAPI.post(third_user, %{status: "uguu", visibility: "direct"})
384 draft = %ActivityDraft{
386 mentions: [mentioned_user.ap_id],
387 visibility: "direct",
388 in_reply_to: direct_activity
391 {to, cc} = Utils.get_to_and_cc(draft)
393 assert length(to) == 2
394 assert Enum.empty?(cc)
396 assert mentioned_user.ap_id in to
397 assert third_user.ap_id in to
401 describe "to_master_date/1" do
402 test "removes microseconds from date (NaiveDateTime)" do
403 assert Utils.to_masto_date(~N[2015-01-23 23:50:07.123]) == "2015-01-23T23:50:07.000Z"
406 test "removes microseconds from date (String)" do
407 assert Utils.to_masto_date("2015-01-23T23:50:07.123Z") == "2015-01-23T23:50:07.000Z"
410 test "returns empty string when date invalid" do
411 assert Utils.to_masto_date("2015-01?23T23:50:07.123Z") == ""
415 describe "conversation_id_to_context/1" do
417 object = insert(:note)
418 assert Utils.conversation_id_to_context(object.id) == object.data["id"]
421 test "returns error if object not found" do
422 assert Utils.conversation_id_to_context("123") == {:error, "No such conversation"}
426 describe "maybe_notify_mentioned_recipients/2" do
427 test "returns recipients when activity is not `Create`" do
428 activity = insert(:like_activity)
429 assert Utils.maybe_notify_mentioned_recipients(["test"], activity) == ["test"]
432 test "returns recipients from tag" do
440 %{"type" => "Hashtag"},
442 %{"type" => "Mention", "href" => "https://testing.pleroma.lol/users/lain"},
443 %{"type" => "Mention", "href" => "https://shitposter.club/user/5381"},
444 %{"type" => "Mention", "href" => "https://shitposter.club/user/5381"}
449 activity = insert(:note_activity, user: user, note: object)
451 assert Utils.maybe_notify_mentioned_recipients(["test"], activity) == [
453 "https://testing.pleroma.lol/users/lain",
454 "https://shitposter.club/user/5381"
458 test "returns recipients when object is map" do
460 object = insert(:note, user: user)
463 insert(:note_activity,
469 %{"type" => "Hashtag"},
471 %{"type" => "Mention", "href" => "https://testing.pleroma.lol/users/lain"},
472 %{"type" => "Mention", "href" => "https://shitposter.club/user/5381"},
473 %{"type" => "Mention", "href" => "https://shitposter.club/user/5381"}
479 Pleroma.Repo.delete(object)
481 assert Utils.maybe_notify_mentioned_recipients(["test"], activity) == [
483 "https://testing.pleroma.lol/users/lain",
484 "https://shitposter.club/user/5381"
488 test "returns recipients when object not found" do
490 object = insert(:note, user: user)
492 activity = insert(:note_activity, user: user, note: object)
493 Pleroma.Repo.delete(object)
495 obj_url = activity.data["object"]
498 %{method: :get, url: ^obj_url} ->
499 %Tesla.Env{status: 404, body: ""}
502 assert Utils.maybe_notify_mentioned_recipients(["test-test"], activity) == [
508 describe "attachments_from_ids_descs/2" do
509 test "returns [] when attachment ids is empty" do
510 assert Utils.attachments_from_ids_descs([], "{}") == []
513 test "returns list attachments with desc" do
514 object = insert(:note)
515 desc = Jason.encode!(%{object.id => "test-desc"})
517 assert Utils.attachments_from_ids_descs(["#{object.id}", "34"], desc) == [
518 Map.merge(object.data, %{"name" => "test-desc"})
523 describe "attachments_from_ids/1" do
524 test "returns attachments with descs" do
525 object = insert(:note)
526 desc = Jason.encode!(%{object.id => "test-desc"})
528 assert Utils.attachments_from_ids(%{
529 media_ids: ["#{object.id}"],
532 Map.merge(object.data, %{"name" => "test-desc"})
536 test "returns attachments without descs" do
537 object = insert(:note)
538 assert Utils.attachments_from_ids(%{media_ids: ["#{object.id}"]}) == [object.data]
541 test "returns [] when not pass media_ids" do
542 assert Utils.attachments_from_ids(%{}) == []
546 describe "maybe_add_list_data/3" do
547 test "adds list params when found user list" do
549 {:ok, %Pleroma.List{} = list} = Pleroma.List.create("title", user)
551 assert Utils.maybe_add_list_data(%{additional: %{}, object: %{}}, user, {:list, list.id}) ==
553 additional: %{"bcc" => [list.ap_id], "listMessage" => list.ap_id},
554 object: %{"listMessage" => list.ap_id}
558 test "returns original params when list not found" do
560 {:ok, %Pleroma.List{} = list} = Pleroma.List.create("title", insert(:user))
562 assert Utils.maybe_add_list_data(%{additional: %{}, object: %{}}, user, {:list, list.id}) ==
563 %{additional: %{}, object: %{}}
567 describe "make_note_data/1" do
568 test "returns note data" do
571 user2 = insert(:user)
572 user3 = insert(:user)
574 draft = %ActivityDraft{
578 content_html: "<h1>This is :moominmamma: note</h1>",
579 in_reply_to: note.id,
580 tags: [name: "jimm"],
581 summary: "test summary",
583 extra: %{"custom_tag" => "test"}
586 assert Utils.make_note_data(draft) == %{
587 "actor" => user.ap_id,
589 "cc" => [user3.ap_id],
590 "content" => "<h1>This is :moominmamma: note</h1>",
592 "sensitive" => false,
593 "summary" => "test summary",
595 "to" => [user2.ap_id],
597 "custom_tag" => "test"
602 describe "maybe_add_attachments/3" do
603 test "returns parsed results when attachment_links is false" do
604 assert Utils.maybe_add_attachments(
605 {"test", [], ["tags"]},
608 ) == {"test", [], ["tags"]}
611 test "adds attachments to parsed results" do
612 attachment = %{"url" => [%{"href" => "SakuraPM.png"}]}
614 assert Utils.maybe_add_attachments(
615 {"test", [], ["tags"]},
619 "test<br><a href=\"SakuraPM.png\" class='attachment'>SakuraPM.png</a>",