diff options
Diffstat (limited to 'test')
40 files changed, 1876 insertions, 96 deletions
diff --git a/test/fixtures/image_with_caption-abstract.jpg b/test/fixtures/image_with_caption-abstract.jpg Binary files differnew file mode 100644 index 000000000..f982ffa81 --- /dev/null +++ b/test/fixtures/image_with_caption-abstract.jpg diff --git a/test/fixtures/image_with_imagedescription_and_caption-abstract.jpg b/test/fixtures/image_with_imagedescription_and_caption-abstract.jpg Binary files differnew file mode 100644 index 000000000..c82a269ef --- /dev/null +++ b/test/fixtures/image_with_imagedescription_and_caption-abstract.jpg diff --git a/test/fixtures/image_with_imagedescription_and_caption-abstract_whitespaces.jpg b/test/fixtures/image_with_imagedescription_and_caption-abstract_whitespaces.jpg Binary files differnew file mode 100644 index 000000000..a232fd2a1 --- /dev/null +++ b/test/fixtures/image_with_imagedescription_and_caption-abstract_whitespaces.jpg diff --git a/test/fixtures/image_with_no_description.jpg b/test/fixtures/image_with_no_description.jpg Binary files differnew file mode 100644 index 000000000..ec6fc4be8 --- /dev/null +++ b/test/fixtures/image_with_no_description.jpg diff --git a/test/fixtures/owncast-note-with-attachment.json b/test/fixtures/owncast-note-with-attachment.json new file mode 100644 index 000000000..68cb6bbf7 --- /dev/null +++ b/test/fixtures/owncast-note-with-attachment.json @@ -0,0 +1,31 @@ +{ + "attachment": { + "content": "Live stream preview", + "type": "Image", + "url": "https://owncast.localhost.localdomain/preview.gif?us=KjfNX387gm" + }, + "attributedTo": "https://owncast.localhost.localdomain/federation/user/streamer", + "audience": "https://www.w3.org/ns/activitystreams#Public", + "content": "<p>I've gone live!</p><p></p><p><a class=\"hashtag\" href=\"https://directory.owncast.online/tags/owncast\">#owncast</a> <a class=\"hashtag\" href=\"https://directory.owncast.online/tags/streaming\">#streaming</a></p><a href=\"https://owncast.localhost.localdomain\">https://owncast.localhost.localdomain</a>", + "id": "https://owncast.localhost.localdomain/federation/KjBNuq8ng", + "published": "2022-04-17T15:42:03Z", + "tag": [ + { + "href": "https://directory.owncast.online/tags/owncast", + "name": "#owncast", + "type": "Hashtag" + }, + { + "href": "https://directory.owncast.online/tags/streaming", + "name": "#streaming", + "type": "Hashtag" + }, + { + "href": "https://directory.owncast.online/tags/owncast", + "name": "#owncast", + "type": "Hashtag" + } + ], + "to": "https://www.w3.org/ns/activitystreams#Public", + "type": "Note" +} diff --git a/test/fixtures/tesla_mock/https___lm.kazv.moe_users_mewmew.xml b/test/fixtures/tesla_mock/https___lm.kazv.moe_users_mewmew.xml new file mode 100644 index 000000000..b9e8dbbf5 --- /dev/null +++ b/test/fixtures/tesla_mock/https___lm.kazv.moe_users_mewmew.xml @@ -0,0 +1 @@ +<?xml version="1.0" encoding="UTF-8"?><XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"><Subject>acct:mewmew@lm.kazv.moe</Subject><Alias>https://lm.kazv.moe/users/mewmew</Alias><Alias>https://lm.kazv.moe/users/tester</Alias><Alias>https://lm.kazv.moe/users/testuser</Alias><Link href="https://lm.kazv.moe/users/mewmew" rel="http://webfinger.net/rel/profile-page" type="text/html" /><Link href="https://lm.kazv.moe/users/mewmew" rel="self" type="application/activity+json" /><Link href="https://lm.kazv.moe/users/mewmew" rel="self" type="application/ld+json; profile="https://www.w3.org/ns/activitystreams"" /><Link rel="http://ostatus.org/schema/1.0/subscribe" template="https://lm.kazv.moe/ostatus_subscribe?acct={uri}" /></XRD> diff --git a/test/fixtures/tesla_mock/lm.kazv.moe_host_meta b/test/fixtures/tesla_mock/lm.kazv.moe_host_meta new file mode 100644 index 000000000..02e6f055e --- /dev/null +++ b/test/fixtures/tesla_mock/lm.kazv.moe_host_meta @@ -0,0 +1 @@ +<?xml version="1.0" encoding="UTF-8"?><XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"><Link rel="lrdd" template="https://lm.kazv.moe/.well-known/webfinger?resource={uri}" type="application/xrd+xml" /></XRD> diff --git a/test/fixtures/tesla_mock/mewmew@lm.kazv.moe.json b/test/fixtures/tesla_mock/mewmew@lm.kazv.moe.json new file mode 100644 index 000000000..8d2c3e1e7 --- /dev/null +++ b/test/fixtures/tesla_mock/mewmew@lm.kazv.moe.json @@ -0,0 +1 @@ +{"@context":["https://www.w3.org/ns/activitystreams","https://lm.kazv.moe/schemas/litepub-0.1.jsonld",{"@language":"und"}],"alsoKnownAs":["https://lm.kazv.moe/users/tester","https://lm.kazv.moe/users/testuser"],"attachment":[],"capabilities":{"acceptsChatMessages":true},"discoverable":false,"endpoints":{"oauthAuthorizationEndpoint":"https://lm.kazv.moe/oauth/authorize","oauthRegistrationEndpoint":"https://lm.kazv.moe/api/v1/apps","oauthTokenEndpoint":"https://lm.kazv.moe/oauth/token","sharedInbox":"https://lm.kazv.moe/inbox","uploadMedia":"https://lm.kazv.moe/api/ap/upload_media"},"featured":"https://lm.kazv.moe/users/mewmew/collections/featured","followers":"https://lm.kazv.moe/users/mewmew/followers","following":"https://lm.kazv.moe/users/mewmew/following","id":"https://lm.kazv.moe/users/mewmew","inbox":"https://lm.kazv.moe/users/mewmew/inbox","manuallyApprovesFollowers":false,"name":"mew","outbox":"https://lm.kazv.moe/users/mewmew/outbox","preferredUsername":"mewmew","publicKey":{"id":"https://lm.kazv.moe/users/mewmew#main-key","owner":"https://lm.kazv.moe/users/mewmew","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0nT3IVUwx799FSJyJEOY\n5D2c5zgtt2Z+BD9417eVLmVQF5fJlWgcKS4pbFc76zkYoBkZtV7XbzvN9KTNulpa\nUGNOM0/UdEoQLB8xbVCMm0ABUU8vbTWoMTxp93bfVHBz+33FPYdH1JHX4TCU/mJF\nX4UJMvFmMn5BFjSQm9GG6Eq2j6SAUsaTa8+Rrd8FzS6zb/dk3N/Llz0tfsZYS0sq\nEy9OYhsKOQ6eegULFJOF3Hz04vzwftmeXFsbb3aO2zKz3uAMYZglWHNBYJAePBtJ\ng362kqdJwgT14TFnZ0K2ziDPbkRULG1Kke/lsqw2rPF6Q6P4PeO1shCEDthoDoID\newIDAQAB\n-----END PUBLIC KEY-----\n\n"},"summary":"","tag":[],"type":"Person","url":"https://lm.kazv.moe/users/mewmew"} diff --git a/test/mix/tasks/pleroma/instance_test.exs b/test/mix/tasks/pleroma/instance_test.exs index 249689ec6..b1c10e03c 100644 --- a/test/mix/tasks/pleroma/instance_test.exs +++ b/test/mix/tasks/pleroma/instance_test.exs @@ -67,7 +67,9 @@ defmodule Mix.Tasks.Pleroma.InstanceTest do "test/uploads", "--static-dir", "./test/../test/instance/static/", - "--strip-uploads", + "--strip-uploads-location", + "y", + "--read-uploads-description", "y", "--dedupe-uploads", "n", @@ -91,7 +93,10 @@ defmodule Mix.Tasks.Pleroma.InstanceTest do assert generated_config =~ "password: \"dbpass\"" assert generated_config =~ "configurable_from_database: true" assert generated_config =~ "http: [ip: {127, 0, 0, 1}, port: 4000]" - assert generated_config =~ "filters: [Pleroma.Upload.Filter.Exiftool]" + + assert generated_config =~ + "filters: [Pleroma.Upload.Filter.Exiftool.StripLocation, Pleroma.Upload.Filter.Exiftool.ReadDescription]" + assert File.read!(tmp_path() <> "setup.psql") == generated_setup_psql() assert File.exists?(Path.expand("./test/instance/static/robots.txt")) end diff --git a/test/pleroma/announcement_read_relationship_test.exs b/test/pleroma/announcement_read_relationship_test.exs new file mode 100644 index 000000000..5fd4ffbef --- /dev/null +++ b/test/pleroma/announcement_read_relationship_test.exs @@ -0,0 +1,40 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.AnnouncementReadRelationshipTest do + alias Pleroma.AnnouncementReadRelationship + + use Pleroma.DataCase, async: true + + import Pleroma.Factory + + setup do + {:ok, user: insert(:user), announcement: insert(:announcement)} + end + + describe "mark_read/2" do + test "should insert relationship", %{user: user, announcement: announcement} do + {:ok, _} = AnnouncementReadRelationship.mark_read(user, announcement) + + assert AnnouncementReadRelationship.exists?(user, announcement) + end + end + + describe "mark_unread/2" do + test "should delete relationship", %{user: user, announcement: announcement} do + {:ok, _} = AnnouncementReadRelationship.mark_read(user, announcement) + + assert :ok = AnnouncementReadRelationship.mark_unread(user, announcement) + refute AnnouncementReadRelationship.exists?(user, announcement) + end + + test "should not fail if relationship does not exist", %{ + user: user, + announcement: announcement + } do + assert :ok = AnnouncementReadRelationship.mark_unread(user, announcement) + refute AnnouncementReadRelationship.exists?(user, announcement) + end + end +end diff --git a/test/pleroma/announcement_test.exs b/test/pleroma/announcement_test.exs new file mode 100644 index 000000000..a007c3718 --- /dev/null +++ b/test/pleroma/announcement_test.exs @@ -0,0 +1,98 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.AnnouncementTest do + alias Pleroma.Announcement + + use Pleroma.DataCase, async: true + + import Pleroma.Factory + + describe "list_all_visible_when/1" do + setup do: {:ok, time: NaiveDateTime.utc_now()} + + test "with no start or end time", %{time: time} do + _announcement = insert(:announcement) + + assert [_] = Announcement.list_all_visible_when(time) + end + + test "with start time before current", %{time: time} do + before_now = NaiveDateTime.add(time, -10, :second) + + _announcement = insert(:announcement, %{starts_at: before_now}) + + assert [_] = Announcement.list_all_visible_when(time) + end + + test "with start time after current", %{time: time} do + after_now = NaiveDateTime.add(time, 10, :second) + + _announcement = insert(:announcement, %{starts_at: after_now}) + + assert [] = Announcement.list_all_visible_when(time) + end + + test "with end time after current", %{time: time} do + after_now = NaiveDateTime.add(time, 10, :second) + + _announcement = insert(:announcement, %{ends_at: after_now}) + + assert [_] = Announcement.list_all_visible_when(time) + end + + test "with end time before current", %{time: time} do + before_now = NaiveDateTime.add(time, -10, :second) + + _announcement = insert(:announcement, %{ends_at: before_now}) + + assert [] = Announcement.list_all_visible_when(time) + end + + test "with both start and end time", %{time: time} do + before_now = NaiveDateTime.add(time, -10, :second) + after_now = NaiveDateTime.add(time, 10, :second) + + _announcement = insert(:announcement, %{starts_at: before_now, ends_at: after_now}) + + assert [_] = Announcement.list_all_visible_when(time) + end + + test "with both start and end time, current not in the range", %{time: time} do + before_now = NaiveDateTime.add(time, -10, :second) + after_now = NaiveDateTime.add(time, 10, :second) + + _announcement = insert(:announcement, %{starts_at: after_now, ends_at: before_now}) + + assert [] = Announcement.list_all_visible_when(time) + end + end + + describe "announcements formatting" do + test "it formats links" do + raw = "something on https://pleroma.social ." + announcement = insert(:announcement, %{data: %{"content" => raw}}) + + assert announcement.rendered["content"] =~ ~r(<a.+?https://pleroma.social) + assert announcement.data["content"] == raw + end + + test "it formats mentions" do + user = insert(:user) + raw = "something on @#{user.nickname} ." + announcement = insert(:announcement, %{data: %{"content" => raw}}) + + assert announcement.rendered["content"] =~ ~r(<a.+?#{user.nickname}) + assert announcement.data["content"] == raw + end + + test "it formats tags" do + raw = "something on #mew ." + announcement = insert(:announcement, %{data: %{"content" => raw}}) + + assert announcement.rendered["content"] =~ ~r(<a.+?#mew) + assert announcement.data["content"] == raw + end + end +end diff --git a/test/pleroma/config/deprecation_warnings_test.exs b/test/pleroma/config/deprecation_warnings_test.exs index 202ec4b90..f3453ddb0 100644 --- a/test/pleroma/config/deprecation_warnings_test.exs +++ b/test/pleroma/config/deprecation_warnings_test.exs @@ -11,6 +11,62 @@ defmodule Pleroma.Config.DeprecationWarningsTest do alias Pleroma.Config alias Pleroma.Config.DeprecationWarnings + describe "filter exiftool" do + test "gives warning when still used" do + clear_config( + [Pleroma.Upload, :filters], + [Pleroma.Upload.Filter.Exiftool] + ) + + assert capture_log(fn -> DeprecationWarnings.check_exiftool_filter() end) =~ + """ + !!!DEPRECATION WARNING!!! + Your config is using Exiftool as a filter instead of Exiftool.StripLocation. This should work for now, but you are advised to change to the new configuration to prevent possible issues later: + + ``` + config :pleroma, Pleroma.Upload, + filters: [Pleroma.Upload.Filter.Exiftool] + ``` + + Is now + + + ``` + config :pleroma, Pleroma.Upload, + filters: [Pleroma.Upload.Filter.Exiftool.StripLocation] + ``` + """ + end + + test "changes setting to exiftool strip location" do + clear_config( + [Pleroma.Upload, :filters], + [Pleroma.Upload.Filter.Exiftool, Pleroma.Upload.Filter.Exiftool.ReadDescription] + ) + + expected_config = [ + Pleroma.Upload.Filter.Exiftool.StripLocation, + Pleroma.Upload.Filter.Exiftool.ReadDescription + ] + + capture_log(fn -> DeprecationWarnings.warn() end) + + assert Config.get([Pleroma.Upload]) |> Keyword.get(:filters, []) == expected_config + end + + test "doesn't give a warning with correct config" do + clear_config( + [Pleroma.Upload, :filters], + [ + Pleroma.Upload.Filter.Exiftool.StripLocation, + Pleroma.Upload.Filter.Exiftool.ReadDescription + ] + ) + + assert capture_log(fn -> DeprecationWarnings.check_exiftool_filter() end) == "" + end + end + describe "simple policy tuples" do test "gives warning when there are still strings" do clear_config([:mrf_simple], diff --git a/test/pleroma/config_db_test.exs b/test/pleroma/config_db_test.exs index ea44b716f..ba7c615e2 100644 --- a/test/pleroma/config_db_test.exs +++ b/test/pleroma/config_db_test.exs @@ -238,10 +238,11 @@ defmodule Pleroma.ConfigDBTest do end test "ssl options" do - assert ConfigDB.to_elixir_types([":tlsv1", ":tlsv1.1", ":tlsv1.2"]) == [ + assert ConfigDB.to_elixir_types([":tlsv1", ":tlsv1.1", ":tlsv1.2", ":tlsv1.3"]) == [ :tlsv1, :"tlsv1.1", - :"tlsv1.2" + :"tlsv1.2", + :"tlsv1.3" ] end diff --git a/test/pleroma/docs/generator_test.exs b/test/pleroma/docs/generator_test.exs index 92b4d13e4..5e41d6ccb 100644 --- a/test/pleroma/docs/generator_test.exs +++ b/test/pleroma/docs/generator_test.exs @@ -86,7 +86,7 @@ defmodule Pleroma.Docs.GeneratorTest do key: :versions, type: {:list, :atom}, description: "List of TLS version to use", - suggestions: [:tlsv1, ":tlsv1.1", ":tlsv1.2"] + suggestions: [:tlsv1, ":tlsv1.1", ":tlsv1.2", ":tlsv1.3"] } ] }, @@ -213,7 +213,7 @@ defmodule Pleroma.Docs.GeneratorTest do test "suggestion for tls versions" do [%{children: children} | _] = Generator.convert_to_strings(@descriptions) child = Enum.at(children, 8) - assert child[:suggestions] == [":tlsv1", ":tlsv1.1", ":tlsv1.2"] + assert child[:suggestions] == [":tlsv1", ":tlsv1.1", ":tlsv1.2", ":tlsv1.3"] end test "subgroup with module name" do diff --git a/test/pleroma/docs/translator/compiler_test.exs b/test/pleroma/docs/translator/compiler_test.exs new file mode 100644 index 000000000..d6c3cdd40 --- /dev/null +++ b/test/pleroma/docs/translator/compiler_test.exs @@ -0,0 +1,90 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Docs.Translator.CompilerTest do + use ExUnit.Case, async: true + + alias Pleroma.Docs.Translator.Compiler + + @descriptions [ + %{ + key: "1", + label: "1", + description: "2", + children: [ + %{ + key: "3", + label: "3", + description: "4" + }, + %{ + key: "5", + label: "5", + description: "6" + } + ] + }, + %{ + key: "7", + label: "7", + description: "8", + children: [ + %{ + key: "9", + description: "9", + children: [ + %{ + key: "10", + description: "10", + children: [ + %{key: "11", description: "11"}, + %{description: "12"} + ] + } + ] + }, + %{ + label: "13" + } + ] + }, + %{ + group: "14", + label: "14" + }, + %{ + group: "15", + key: "15", + label: "15" + }, + %{ + group: {":subgroup", "16"}, + label: "16" + } + ] + + describe "extract_strings/1" do + test "it extracts all labels and descriptions" do + strings = Compiler.extract_strings(@descriptions) + assert length(strings) == 16 + + assert {["1"], "label", "1"} in strings + assert {["1"], "description", "2"} in strings + assert {["1", "3"], "label", "3"} in strings + assert {["1", "3"], "description", "4"} in strings + assert {["1", "5"], "label", "5"} in strings + assert {["1", "5"], "description", "6"} in strings + assert {["7"], "label", "7"} in strings + assert {["7"], "description", "8"} in strings + assert {["7", "9"], "description", "9"} in strings + assert {["7", "9", "10"], "description", "10"} in strings + assert {["7", "9", "10", "11"], "description", "11"} in strings + assert {["7", "9", "10", nil], "description", "12"} in strings + assert {["7", nil], "label", "13"} in strings + assert {["14"], "label", "14"} in strings + assert {["15-15"], "label", "15"} in strings + assert {["16"], "label", "16"} in strings + end + end +end diff --git a/test/pleroma/report_note_test.exs b/test/pleroma/report_note_test.exs index 136ad9a40..e2028a3ba 100644 --- a/test/pleroma/report_note_test.exs +++ b/test/pleroma/report_note_test.exs @@ -13,4 +13,27 @@ defmodule Pleroma.ReportNoteTest do assert {:ok, note} = ReportNote.create(user.id, report.id, "naughty boy") assert note.content == "naughty boy" end + + test "create/3 with very long content" do + user = insert(:user) + report = insert(:report_activity) + + very_long_content = """ + ] pwgen 25 15 + eJ9eeceiquoolei2queeLeimi aiN9ie2iokie8chush7aiph5N ulaNgaighoPiequaipuzoog8F + Ohphei0hee6hoo0wah4Aasah9 ziel3Yo3eew4neiy3ekiesh8u ue9ShahTh7oongoPheeneijah + ohGheeCh6aloque0Neviopou3 ush2oobohxeec4aequeich3Oo Ze3eighoowiojadohch8iCa1n + Yu4yieBie9eengoich8fae4th chohqu6exooSiibogh3iefeez peephahtaik9quie5mohD9nee + eeQuur3rie5mei8ieng6iesie wei1meinguv0Heidoov8Ibaed deemo2Poh6ohc3eiBeez1uox2 + ] pwgen 25 15 + eJ9eeceiquoolei2queeLeimi aiN9ie2iokie8chush7aiph5N ulaNgaighoPiequaipuzoog8F + Ohphei0hee6hoo0wah4Aasah9 ziel3Yo3eew4neiy3ekiesh8u ue9ShahTh7oongoPheeneijah + ohGheeCh6aloque0Neviopou3 ush2oobohxeec4aequeich3Oo Ze3eighoowiojadohch8iCa1n + Yu4yieBie9eengoich8fae4th chohqu6exooSiibogh3iefeez peephahtaik9quie5mohD9nee + eeQuur3rie5mei8ieng6iesie wei1meinguv0Heidoov8Ibaed deemo2Poh6ohc3eiBeez1uox2 + """ + + assert {:ok, note} = ReportNote.create(user.id, report.id, very_long_content) + assert note.content == very_long_content + end end diff --git a/test/pleroma/upload/filter/exiftool/read_description_test.exs b/test/pleroma/upload/filter/exiftool/read_description_test.exs new file mode 100644 index 000000000..7389fda47 --- /dev/null +++ b/test/pleroma/upload/filter/exiftool/read_description_test.exs @@ -0,0 +1,117 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Upload.Filter.Exiftool.ReadDescriptionTest do + use Pleroma.DataCase, async: true + alias Pleroma.Upload.Filter + + @uploads %Pleroma.Upload{ + name: "image_with_imagedescription_and_caption-abstract.jpg", + content_type: "image/jpeg", + path: Path.absname("test/fixtures/image_with_imagedescription_and_caption-abstract.jpg"), + tempfile: Path.absname("test/fixtures/image_with_imagedescription_and_caption-abstract.jpg"), + description: nil + } + + test "keeps description when not empty" do + uploads = %Pleroma.Upload{ + name: "image_with_imagedescription_and_caption-abstract.jpg", + content_type: "image/jpeg", + path: Path.absname("test/fixtures/image_with_imagedescription_and_caption-abstract.jpg"), + tempfile: + Path.absname("test/fixtures/image_with_imagedescription_and_caption-abstract.jpg"), + description: "Some description" + } + + assert Filter.Exiftool.ReadDescription.filter(uploads) == + {:ok, :noop} + end + + test "otherwise returns ImageDescription when present" do + uploads_after = %Pleroma.Upload{ + name: "image_with_imagedescription_and_caption-abstract.jpg", + content_type: "image/jpeg", + path: Path.absname("test/fixtures/image_with_imagedescription_and_caption-abstract.jpg"), + tempfile: + Path.absname("test/fixtures/image_with_imagedescription_and_caption-abstract.jpg"), + description: "a descriptive white pixel" + } + + assert Filter.Exiftool.ReadDescription.filter(@uploads) == + {:ok, :filtered, uploads_after} + end + + test "otherwise returns iptc:Caption-Abstract when present" do + upload = %Pleroma.Upload{ + name: "image_with_caption-abstract.jpg", + content_type: "image/jpeg", + path: Path.absname("test/fixtures/image_with_caption-abstract.jpg"), + tempfile: Path.absname("test/fixtures/image_with_caption-abstract.jpg"), + description: nil + } + + upload_after = %Pleroma.Upload{ + name: "image_with_caption-abstract.jpg", + content_type: "image/jpeg", + path: Path.absname("test/fixtures/image_with_caption-abstract.jpg"), + tempfile: Path.absname("test/fixtures/image_with_caption-abstract.jpg"), + description: "an abstract white pixel" + } + + assert Filter.Exiftool.ReadDescription.filter(upload) == + {:ok, :filtered, upload_after} + end + + test "otherwise returns nil" do + uploads = %Pleroma.Upload{ + name: "image_with_no_description.jpg", + content_type: "image/jpeg", + path: Path.absname("test/fixtures/image_with_no_description.jpg"), + tempfile: Path.absname("test/fixtures/image_with_no_description.jpg"), + description: nil + } + + assert Filter.Exiftool.ReadDescription.filter(uploads) == + {:ok, :filtered, uploads} + end + + test "Return nil when image description from EXIF data exceeds the maximum length" do + clear_config([:instance, :description_limit], 5) + + assert Filter.Exiftool.ReadDescription.filter(@uploads) == + {:ok, :filtered, @uploads} + end + + test "Ignores content with only whitespace" do + uploads = %Pleroma.Upload{ + name: "non-existant.jpg", + content_type: "image/jpeg", + path: + Path.absname( + "test/fixtures/image_with_imagedescription_and_caption-abstract_whitespaces.jpg" + ), + tempfile: + Path.absname( + "test/fixtures/image_with_imagedescription_and_caption-abstract_whitespaces.jpg" + ), + description: nil + } + + assert Filter.Exiftool.ReadDescription.filter(uploads) == + {:ok, :filtered, uploads} + end + + test "Return nil when image description from EXIF data can't be read" do + uploads = %Pleroma.Upload{ + name: "non-existant.jpg", + content_type: "image/jpeg", + path: Path.absname("test/fixtures/non-existant.jpg"), + tempfile: Path.absname("test/fixtures/non-existant_tmp.jpg"), + description: nil + } + + assert Filter.Exiftool.ReadDescription.filter(uploads) == + {:ok, :filtered, uploads} + end +end diff --git a/test/pleroma/upload/filter/exiftool_test.exs b/test/pleroma/upload/filter/exiftool/strip_location_test.exs index 0a0ef2bdf..7e1541f60 100644 --- a/test/pleroma/upload/filter/exiftool_test.exs +++ b/test/pleroma/upload/filter/exiftool/strip_location_test.exs @@ -2,7 +2,7 @@ # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.Upload.Filter.ExiftoolTest do +defmodule Pleroma.Upload.Filter.Exiftool.StripLocationTest do use Pleroma.DataCase, async: true alias Pleroma.Upload.Filter @@ -21,7 +21,7 @@ defmodule Pleroma.Upload.Filter.ExiftoolTest do tempfile: Path.absname("test/fixtures/DSCN0010_tmp.jpg") } - assert Filter.Exiftool.filter(upload) == {:ok, :filtered} + assert Filter.Exiftool.StripLocation.filter(upload) == {:ok, :filtered} {exif_original, 0} = System.cmd("exiftool", ["test/fixtures/DSCN0010.jpg"]) {exif_filtered, 0} = System.cmd("exiftool", ["test/fixtures/DSCN0010_tmp.jpg"]) @@ -37,6 +37,6 @@ defmodule Pleroma.Upload.Filter.ExiftoolTest do content_type: "image/webp" } - assert Filter.Exiftool.filter(upload) == {:ok, :noop} + assert Filter.Exiftool.StripLocation.filter(upload) == {:ok, :noop} end end diff --git a/test/pleroma/user/backup_test.exs b/test/pleroma/user/backup_test.exs index 6441c5ba8..5c9b94000 100644 --- a/test/pleroma/user/backup_test.exs +++ b/test/pleroma/user/backup_test.exs @@ -22,15 +22,15 @@ defmodule Pleroma.User.BackupTest do clear_config([Pleroma.Emails.Mailer, :enabled], true) end - test "it requries enabled email" do + test "it does not requrie enabled email" do clear_config([Pleroma.Emails.Mailer, :enabled], false) user = insert(:user) - assert {:error, "Backups require enabled email"} == Backup.create(user) + assert {:ok, _} = Backup.create(user) end - test "it requries user's email" do + test "it does not require user's email" do user = insert(:user, %{email: nil}) - assert {:error, "Email is required"} == Backup.create(user) + assert {:ok, _} = Backup.create(user) end test "it creates a backup record and an Oban job" do @@ -75,6 +75,43 @@ defmodule Pleroma.User.BackupTest do ) end + test "it does not send an email if the user does not have an email" do + clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local) + %{id: user_id} = user = insert(:user, %{email: nil}) + + assert {:ok, %Oban.Job{args: %{"backup_id" => backup_id} = args}} = Backup.create(user) + assert {:ok, backup} = perform_job(BackupWorker, args) + assert backup.file_size > 0 + assert %Backup{id: ^backup_id, processed: true, user_id: ^user_id} = backup + + assert_no_email_sent() + end + + test "it does not send an email if mailer is not on" do + clear_config([Pleroma.Emails.Mailer, :enabled], false) + clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local) + %{id: user_id} = user = insert(:user) + + assert {:ok, %Oban.Job{args: %{"backup_id" => backup_id} = args}} = Backup.create(user) + assert {:ok, backup} = perform_job(BackupWorker, args) + assert backup.file_size > 0 + assert %Backup{id: ^backup_id, processed: true, user_id: ^user_id} = backup + + assert_no_email_sent() + end + + test "it does not send an email if the user has an empty email" do + clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local) + %{id: user_id} = user = insert(:user, %{email: ""}) + + assert {:ok, %Oban.Job{args: %{"backup_id" => backup_id} = args}} = Backup.create(user) + assert {:ok, backup} = perform_job(BackupWorker, args) + assert backup.file_size > 0 + assert %Backup{id: ^backup_id, processed: true, user_id: ^user_id} = backup + + assert_no_email_sent() + end + test "it removes outdated backups after creating a fresh one" do clear_config([Backup, :limit_days], -1) clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local) diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index 884b846ae..b4a49624a 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -618,9 +618,10 @@ defmodule Pleroma.UserTest do end test "it restricts certain nicknames" do + clear_config([User, :restricted_nicknames], ["about"]) [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames]) - assert is_bitstring(restricted_name) + assert is_binary(restricted_name) params = @full_user_data @@ -631,6 +632,23 @@ defmodule Pleroma.UserTest do refute changeset.valid? end + test "it is case-insensitive when restricting nicknames" do + clear_config([User, :restricted_nicknames], ["about"]) + [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames]) + + assert is_binary(restricted_name) + + restricted_upcase_name = String.upcase(restricted_name) + + params = + @full_user_data + |> Map.put(:nickname, restricted_upcase_name) + + changeset = User.register_changeset(%User{}, params) + + refute changeset.valid? + end + test "it blocks blacklisted email domains" do clear_config([User, :email_blacklist], ["trolling.world"]) @@ -639,6 +657,11 @@ defmodule Pleroma.UserTest do changeset = User.register_changeset(%User{}, params) refute changeset.valid? + # Block with case-insensitive match + params = Map.put(@full_user_data, :email, "troll@TrOlLing.wOrld") + changeset = User.register_changeset(%User{}, params) + refute changeset.valid? + # Block with subdomain match params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world") changeset = User.register_changeset(%User{}, params) @@ -1123,7 +1146,7 @@ defmodule Pleroma.UserTest do user = insert(:user) muted_user = insert(:user) - {:ok, _user_relationships} = User.mute(user, muted_user, %{expires_in: 60}) + {:ok, _user_relationships} = User.mute(user, muted_user, %{duration: 60}) assert User.mutes?(user, muted_user) worker = Pleroma.Workers.MuteExpireWorker @@ -2579,6 +2602,82 @@ defmodule Pleroma.UserTest do object_id end + describe "add_alias/2" do + test "should add alias for another user" do + user = insert(:user) + user2 = insert(:user) + + assert {:ok, user_updated} = user |> User.add_alias(user2) + + assert user_updated.also_known_as |> length() == 1 + assert user2.ap_id in user_updated.also_known_as + end + + test "should add multiple aliases" do + user = insert(:user) + user2 = insert(:user) + user3 = insert(:user) + + assert {:ok, user} = user |> User.add_alias(user2) + assert {:ok, user_updated} = user |> User.add_alias(user3) + + assert user_updated.also_known_as |> length() == 2 + assert user2.ap_id in user_updated.also_known_as + assert user3.ap_id in user_updated.also_known_as + end + + test "should not add duplicate aliases" do + user = insert(:user) + user2 = insert(:user) + + assert {:ok, user} = user |> User.add_alias(user2) + + assert {:ok, user_updated} = user |> User.add_alias(user2) + + assert user_updated.also_known_as |> length() == 1 + assert user2.ap_id in user_updated.also_known_as + end + end + + describe "alias_users/1" do + test "should get aliases for a user" do + user = insert(:user) + user2 = insert(:user, also_known_as: [user.ap_id]) + + aliases = user2 |> User.alias_users() + + assert aliases |> length() == 1 + + alias_user = aliases |> Enum.at(0) + + assert alias_user.ap_id == user.ap_id + end + end + + describe "delete_alias/2" do + test "should delete existing alias" do + user = insert(:user) + user2 = insert(:user, also_known_as: [user.ap_id]) + + assert {:ok, user_updated} = user2 |> User.delete_alias(user) + + assert user_updated.also_known_as == [] + end + + test "should report error on non-existing alias" do + user = insert(:user) + user2 = insert(:user) + user3 = insert(:user, also_known_as: [user.ap_id]) + + assert {:error, :no_such_alias} = user3 |> User.delete_alias(user2) + + user3_updated = User.get_cached_by_ap_id(user3.ap_id) + + assert user3_updated.also_known_as |> length() == 1 + assert user.ap_id in user3_updated.also_known_as + end + end + describe "account endorsements" do test "it pins people" do user = insert(:user) diff --git a/test/pleroma/web/activity_pub/activity_pub_test.exs b/test/pleroma/web/activity_pub/activity_pub_test.exs index 8aa586f40..4d7e76266 100644 --- a/test/pleroma/web/activity_pub/activity_pub_test.exs +++ b/test/pleroma/web/activity_pub/activity_pub_test.exs @@ -1836,9 +1836,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do "target" => ^new_ap_id, "type" => "Move" }, - local: true + local: true, + recipients: recipients } = activity + assert old_user.follower_address in recipients + params = %{ "op" => "move_following", "origin_id" => old_user.id, @@ -1869,6 +1872,42 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do assert {:error, "Target account must have the origin in `alsoKnownAs`"} = ActivityPub.move(old_user, new_user) end + + test "do not move remote user following relationships" do + %{ap_id: old_ap_id} = old_user = insert(:user) + %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id]) + follower_remote = insert(:user, local: false) + + User.follow(follower_remote, old_user) + + assert User.following?(follower_remote, old_user) + + assert {:ok, activity} = ActivityPub.move(old_user, new_user) + + assert %Activity{ + actor: ^old_ap_id, + data: %{ + "actor" => ^old_ap_id, + "object" => ^old_ap_id, + "target" => ^new_ap_id, + "type" => "Move" + }, + local: true + } = activity + + params = %{ + "op" => "move_following", + "origin_id" => old_user.id, + "target_id" => new_user.id + } + + assert_enqueued(worker: Pleroma.Workers.BackgroundWorker, args: params) + + Pleroma.Workers.BackgroundWorker.perform(%Oban.Job{args: params}) + + assert User.following?(follower_remote, old_user) + refute User.following?(follower_remote, new_user) + end end test "doesn't retrieve replies activities with exclude_replies" do diff --git a/test/pleroma/web/activity_pub/mrf/anti_followbot_policy_test.exs b/test/pleroma/web/activity_pub/mrf/anti_followbot_policy_test.exs index 8192629c6..732a5a7f3 100644 --- a/test/pleroma/web/activity_pub/mrf/anti_followbot_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/anti_followbot_policy_test.exs @@ -6,6 +6,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicyTest do use Pleroma.DataCase, async: true import Pleroma.Factory + alias Pleroma.User alias Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy describe "blocking based on attributes" do @@ -38,21 +39,55 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicyTest do assert {:reject, "[AntiFollowbotPolicy]" <> _} = AntiFollowbotPolicy.filter(message) end + + test "matches followbots by actor_type" do + actor = insert(:user, %{actor_type: "Service"}) + target = insert(:user) + + message = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "type" => "Follow", + "actor" => actor.ap_id, + "object" => target.ap_id, + "id" => "https://example.com/activities/1234" + } + + assert {:reject, "[AntiFollowbotPolicy]" <> _} = AntiFollowbotPolicy.filter(message) + end end - test "it allows non-followbots" do - actor = insert(:user) - target = insert(:user) + describe "it allows" do + test "non-followbots" do + actor = insert(:user) + target = insert(:user) - message = %{ - "@context" => "https://www.w3.org/ns/activitystreams", - "type" => "Follow", - "actor" => actor.ap_id, - "object" => target.ap_id, - "id" => "https://example.com/activities/1234" - } + message = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "type" => "Follow", + "actor" => actor.ap_id, + "object" => target.ap_id, + "id" => "https://example.com/activities/1234" + } - {:ok, _} = AntiFollowbotPolicy.filter(message) + {:ok, _} = AntiFollowbotPolicy.filter(message) + end + + test "bots if the target follows the bots" do + actor = insert(:user, %{actor_type: "Service"}) + target = insert(:user) + + User.follow(target, actor) + + message = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "type" => "Follow", + "actor" => actor.ap_id, + "object" => target.ap_id, + "id" => "https://example.com/activities/1234" + } + + {:ok, _} = AntiFollowbotPolicy.filter(message) + end end test "it gracefully handles nil display names" do diff --git a/test/pleroma/web/activity_pub/mrf/steal_emoji_policy_test.exs b/test/pleroma/web/activity_pub/mrf/steal_emoji_policy_test.exs index c537670f2..89d32352f 100644 --- a/test/pleroma/web/activity_pub/mrf/steal_emoji_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/steal_emoji_policy_test.exs @@ -60,7 +60,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicyTest do |> File.exists?() end - test "reject shortcode", %{message: message} do + test "reject regex shortcode", %{message: message} do refute "firedfox" in installed() clear_config(:mrf_steal_emoji, @@ -74,6 +74,20 @@ defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicyTest do refute "firedfox" in installed() end + test "reject string shortcode", %{message: message} do + refute "firedfox" in installed() + + clear_config(:mrf_steal_emoji, + hosts: ["example.org"], + size_limit: 284_468, + rejected_shortcodes: ["firedfox"] + ) + + assert {:ok, _message} = StealEmojiPolicy.filter(message) + + refute "firedfox" in installed() + end + test "reject if size is above the limit", %{message: message} do refute "firedfox" in installed() diff --git a/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs b/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs index f93537ed8..e59bf6787 100644 --- a/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs @@ -43,4 +43,15 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidatorTest %{valid?: true} = ArticleNotePageValidator.cast_and_validate(note) end + + test "a note with an attachment should work", _ do + insert(:user, %{ap_id: "https://owncast.localhost.localdomain/federation/user/streamer"}) + + note = + "test/fixtures/owncast-note-with-attachment.json" + |> File.read!() + |> Jason.decode!() + + %{valid?: true} = ArticleNotePageValidator.cast_and_validate(note) + end end diff --git a/test/pleroma/web/activity_pub/object_validators/attachment_validator_test.exs b/test/pleroma/web/activity_pub/object_validators/attachment_validator_test.exs index b07011b76..9a17e277e 100644 --- a/test/pleroma/web/activity_pub/object_validators/attachment_validator_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/attachment_validator_test.exs @@ -27,6 +27,46 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidatorTest do assert attachment.mediaType == "application/octet-stream" end + test "works with an unknown but valid mime type" do + attachment = %{ + "mediaType" => "x-custom/x-type", + "type" => "Document", + "url" => "https://example.org" + } + + assert {:ok, attachment} = + AttachmentValidator.cast_and_validate(attachment) + |> Ecto.Changeset.apply_action(:insert) + + assert attachment.mediaType == "x-custom/x-type" + end + + test "works with invalid mime types" do + attachment = %{ + "mediaType" => "x-customx-type", + "type" => "Document", + "url" => "https://example.org" + } + + assert {:ok, attachment} = + AttachmentValidator.cast_and_validate(attachment) + |> Ecto.Changeset.apply_action(:insert) + + assert attachment.mediaType == "application/octet-stream" + + attachment = %{ + "mediaType" => "https://example.org", + "type" => "Document", + "url" => "https://example.org" + } + + assert {:ok, attachment} = + AttachmentValidator.cast_and_validate(attachment) + |> Ecto.Changeset.apply_action(:insert) + + assert attachment.mediaType == "application/octet-stream" + end + test "it turns mastodon attachments into our attachments" do attachment = %{ "url" => diff --git a/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs index ceedb185f..9d99df27c 100644 --- a/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs @@ -37,6 +37,37 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiReactHandlingTest do assert match?([["👌", _]], object.data["reactions"]) end + test "it works for incoming unqualified emoji reactions" do + user = insert(:user) + other_user = insert(:user, local: false) + {:ok, activity} = CommonAPI.post(user, %{status: "hello"}) + + # woman detective emoji, unqualified + unqualified_emoji = [0x1F575, 0x200D, 0x2640] |> List.to_string() + + data = + File.read!("test/fixtures/emoji-reaction.json") + |> Jason.decode!() + |> Map.put("object", activity.data["object"]) + |> Map.put("actor", other_user.ap_id) + |> Map.put("content", unqualified_emoji) + + {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + + assert data["actor"] == other_user.ap_id + assert data["type"] == "EmojiReact" + assert data["id"] == "http://mastodon.example.org/users/admin#reactions/2" + assert data["object"] == activity.data["object"] + # woman detective emoji, fully qualified + emoji = [0x1F575, 0xFE0F, 0x200D, 0x2640, 0xFE0F] |> List.to_string() + assert data["content"] == emoji + + object = Object.get_by_ap_id(data["object"]) + + assert object.data["reaction_count"] == 1 + assert match?([[emoji, _]], object.data["reactions"]) + end + test "it reject invalid emoji reactions" do user = insert(:user) other_user = insert(:user, local: false) diff --git a/test/pleroma/web/admin_api/controllers/announcement_controller_test.exs b/test/pleroma/web/admin_api/controllers/announcement_controller_test.exs new file mode 100644 index 000000000..5b8148c05 --- /dev/null +++ b/test/pleroma/web/admin_api/controllers/announcement_controller_test.exs @@ -0,0 +1,281 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.AnnouncementControllerTest do + use Pleroma.Web.ConnCase + + import Pleroma.Factory + + setup do + admin = insert(:user, is_admin: true) + token = insert(:oauth_admin_token, user: admin) + + conn = + build_conn() + |> assign(:user, admin) + |> assign(:token, token) + + {:ok, %{admin: admin, token: token, conn: conn}} + end + + describe "GET /api/v1/pleroma/admin/announcements" do + test "it lists all announcements", %{conn: conn} do + %{id: id} = insert(:announcement) + + response = + conn + |> get("/api/v1/pleroma/admin/announcements") + |> json_response_and_validate_schema(:ok) + + assert [%{"id" => ^id}] = response + end + + test "it paginates announcements", %{conn: conn} do + _announcements = Enum.map(0..20, fn _ -> insert(:announcement) end) + + response = + conn + |> get("/api/v1/pleroma/admin/announcements") + |> json_response_and_validate_schema(:ok) + + assert length(response) == 20 + end + + test "it paginates announcements with custom params", %{conn: conn} do + announcements = Enum.map(0..20, fn _ -> insert(:announcement) end) + + response = + conn + |> get("/api/v1/pleroma/admin/announcements", limit: 5, offset: 7) + |> json_response_and_validate_schema(:ok) + + assert length(response) == 5 + assert Enum.at(response, 0)["id"] == Enum.at(announcements, 7).id + end + + test "it returns empty list with out-of-bounds offset", %{conn: conn} do + _announcements = Enum.map(0..20, fn _ -> insert(:announcement) end) + + response = + conn + |> get("/api/v1/pleroma/admin/announcements", offset: 21) + |> json_response_and_validate_schema(:ok) + + assert [] = response + end + + test "it rejects invalid pagination params", %{conn: conn} do + conn + |> get("/api/v1/pleroma/admin/announcements", limit: 0) + |> json_response_and_validate_schema(400) + + conn + |> get("/api/v1/pleroma/admin/announcements", limit: -1) + |> json_response_and_validate_schema(400) + + conn + |> get("/api/v1/pleroma/admin/announcements", offset: -1) + |> json_response_and_validate_schema(400) + end + end + + describe "GET /api/v1/pleroma/admin/announcements/:id" do + test "it displays one announcement", %{conn: conn} do + %{id: id} = insert(:announcement) + + response = + conn + |> get("/api/v1/pleroma/admin/announcements/#{id}") + |> json_response_and_validate_schema(:ok) + + assert %{"id" => ^id} = response + end + + test "it returns not found for non-existent id", %{conn: conn} do + %{id: id} = insert(:announcement) + + _response = + conn + |> get("/api/v1/pleroma/admin/announcements/#{id}xxx") + |> json_response_and_validate_schema(:not_found) + end + end + + describe "DELETE /api/v1/pleroma/admin/announcements/:id" do + test "it deletes specified announcement", %{conn: conn} do + %{id: id} = insert(:announcement) + + _response = + conn + |> delete("/api/v1/pleroma/admin/announcements/#{id}") + |> json_response_and_validate_schema(:ok) + end + + test "it returns not found for non-existent id", %{conn: conn} do + %{id: id} = insert(:announcement) + + _response = + conn + |> delete("/api/v1/pleroma/admin/announcements/#{id}xxx") + |> json_response_and_validate_schema(:not_found) + + assert %{id: ^id} = Pleroma.Announcement.get_by_id(id) + end + end + + describe "PATCH /api/v1/pleroma/admin/announcements/:id" do + test "it returns not found for non-existent id", %{conn: conn} do + %{id: id} = insert(:announcement) + + _response = + conn + |> put_req_header("content-type", "application/json") + |> patch("/api/v1/pleroma/admin/announcements/#{id}xxx", %{}) + |> json_response_and_validate_schema(:not_found) + + assert %{id: ^id} = Pleroma.Announcement.get_by_id(id) + end + + test "it updates a field", %{conn: conn} do + %{id: id} = insert(:announcement) + + now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second) + starts_at = NaiveDateTime.add(now, -10, :second) + + _response = + conn + |> put_req_header("content-type", "application/json") + |> patch("/api/v1/pleroma/admin/announcements/#{id}", %{ + starts_at: NaiveDateTime.to_iso8601(starts_at) + }) + |> json_response_and_validate_schema(:ok) + + new = Pleroma.Announcement.get_by_id(id) + + assert NaiveDateTime.compare(new.starts_at, starts_at) == :eq + end + + test "it updates with time with utc timezone", %{conn: conn} do + %{id: id} = insert(:announcement) + + now = DateTime.now("Etc/UTC") |> elem(1) |> DateTime.truncate(:second) + starts_at = DateTime.add(now, -10, :second) + + _response = + conn + |> put_req_header("content-type", "application/json") + |> patch("/api/v1/pleroma/admin/announcements/#{id}", %{ + starts_at: DateTime.to_iso8601(starts_at) + }) + |> json_response_and_validate_schema(:ok) + + new = Pleroma.Announcement.get_by_id(id) + + assert DateTime.compare(new.starts_at, starts_at) == :eq + end + + test "it updates a data field", %{conn: conn} do + %{id: id} = announcement = insert(:announcement, data: %{"all_day" => true}) + + assert announcement.data["all_day"] == true + + new_content = "new content" + + response = + conn + |> put_req_header("content-type", "application/json") + |> patch("/api/v1/pleroma/admin/announcements/#{id}", %{ + content: new_content + }) + |> json_response_and_validate_schema(:ok) + + assert response["content"] == new_content + assert response["all_day"] == true + + new = Pleroma.Announcement.get_by_id(id) + + assert new.data["content"] == new_content + assert new.data["all_day"] == true + end + + test "it nullifies a nullable field", %{conn: conn} do + now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second) + starts_at = NaiveDateTime.add(now, -10, :second) + + %{id: id} = insert(:announcement, starts_at: starts_at) + + response = + conn + |> put_req_header("content-type", "application/json") + |> patch("/api/v1/pleroma/admin/announcements/#{id}", %{ + starts_at: nil + }) + |> json_response_and_validate_schema(:ok) + + assert response["starts_at"] == nil + + new = Pleroma.Announcement.get_by_id(id) + + assert new.starts_at == nil + end + end + + describe "POST /api/v1/pleroma/admin/announcements" do + test "it creates an announcement", %{conn: conn} do + content = "test post announcement api" + + now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second) + starts_at = NaiveDateTime.add(now, -10, :second) + ends_at = NaiveDateTime.add(now, 10, :second) + + response = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/pleroma/admin/announcements", %{ + "content" => content, + "starts_at" => NaiveDateTime.to_iso8601(starts_at), + "ends_at" => NaiveDateTime.to_iso8601(ends_at), + "all_day" => true + }) + |> json_response_and_validate_schema(:ok) + + assert %{"content" => ^content, "all_day" => true} = response + + announcement = Pleroma.Announcement.get_by_id(response["id"]) + + assert not is_nil(announcement) + + assert NaiveDateTime.compare(announcement.starts_at, starts_at) == :eq + assert NaiveDateTime.compare(announcement.ends_at, ends_at) == :eq + end + + test "creating with time with utc timezones", %{conn: conn} do + content = "test post announcement api" + + now = DateTime.now("Etc/UTC") |> elem(1) |> DateTime.truncate(:second) + starts_at = DateTime.add(now, -10, :second) + ends_at = DateTime.add(now, 10, :second) + + response = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/pleroma/admin/announcements", %{ + "content" => content, + "starts_at" => DateTime.to_iso8601(starts_at), + "ends_at" => DateTime.to_iso8601(ends_at), + "all_day" => true + }) + |> json_response_and_validate_schema(:ok) + + assert %{"content" => ^content, "all_day" => true} = response + + announcement = Pleroma.Announcement.get_by_id(response["id"]) + + assert not is_nil(announcement) + + assert DateTime.compare(announcement.starts_at, starts_at) == :eq + assert DateTime.compare(announcement.ends_at, ends_at) == :eq + end + end +end diff --git a/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs index bf737a9fc..ba7293d36 100644 --- a/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs @@ -9,6 +9,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do alias Pleroma.Repo alias Pleroma.Tests.ObanHelpers alias Pleroma.User + alias Pleroma.UserRelationship alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.InternalFetchActor alias Pleroma.Web.CommonAPI @@ -1025,6 +1026,40 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = json_response_and_validate_schema(conn, 200) end + + test "expiring", %{conn: conn, user: user} do + other_user = insert(:user) + + conn = + conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/v1/accounts/#{other_user.id}/mute", %{"duration" => "86400"}) + + assert %{"id" => _id, "muting" => true} = json_response_and_validate_schema(conn, 200) + + mute_expires_at = UserRelationship.get_mute_expire_date(user, other_user) + + assert DateTime.diff( + mute_expires_at, + DateTime.utc_now() |> DateTime.add(24 * 60 * 60) + ) in -3..3 + end + + test "falls back to expires_in", %{conn: conn, user: user} do + other_user = insert(:user) + + conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/v1/accounts/#{other_user.id}/mute", %{"expires_in" => "86400"}) + |> json_response_and_validate_schema(200) + + mute_expires_at = UserRelationship.get_mute_expire_date(user, other_user) + + assert DateTime.diff( + mute_expires_at, + DateTime.utc_now() |> DateTime.add(24 * 60 * 60) + ) in -3..3 + end end describe "pinned statuses" do @@ -1843,21 +1878,21 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do |> get("/api/v1/mutes") |> json_response_and_validate_schema(200) - assert [id1, id2, id3] == Enum.map(result, & &1["id"]) + assert [id3, id2, id1] == Enum.map(result, & &1["id"]) result = conn |> get("/api/v1/mutes?limit=1") |> json_response_and_validate_schema(200) - assert [%{"id" => ^id1}] = result + assert [%{"id" => ^id3}] = result result = conn |> get("/api/v1/mutes?since_id=#{id1}") |> json_response_and_validate_schema(200) - assert [%{"id" => ^id2}, %{"id" => ^id3}] = result + assert [%{"id" => ^id3}, %{"id" => ^id2}] = result result = conn @@ -1871,7 +1906,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do |> get("/api/v1/mutes?since_id=#{id1}&limit=1") |> json_response_and_validate_schema(200) - assert [%{"id" => ^id2}] = result + assert [%{"id" => ^id3}] = result end test "list of mutes with with_relationships parameter" do @@ -1890,7 +1925,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do assert [ %{ - "id" => ^id1, + "id" => ^id3, "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}} }, %{ @@ -1898,7 +1933,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}} }, %{ - "id" => ^id3, + "id" => ^id1, "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}} } ] = @@ -1923,7 +1958,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do |> get("/api/v1/blocks") |> json_response_and_validate_schema(200) - assert [id1, id2, id3] == Enum.map(result, & &1["id"]) + assert [id3, id2, id1] == Enum.map(result, & &1["id"]) result = conn @@ -1931,7 +1966,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do |> get("/api/v1/blocks?limit=1") |> json_response_and_validate_schema(200) - assert [%{"id" => ^id1}] = result + assert [%{"id" => ^id3}] = result result = conn @@ -1939,7 +1974,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do |> get("/api/v1/blocks?since_id=#{id1}") |> json_response_and_validate_schema(200) - assert [%{"id" => ^id2}, %{"id" => ^id3}] = result + assert [%{"id" => ^id3}, %{"id" => ^id2}] = result result = conn @@ -1955,7 +1990,31 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do |> get("/api/v1/blocks?since_id=#{id1}&limit=1") |> json_response_and_validate_schema(200) - assert [%{"id" => ^id2}] = result + assert [%{"id" => ^id3}] = result + + conn_res = + conn + |> assign(:user, user) + |> get("/api/v1/blocks?limit=2") + + next_url = + ~r{<.+?(?<link>/api[^>]+)>; rel=\"next\"} + |> Regex.named_captures(get_resp_header(conn_res, "link") |> Enum.at(0)) + |> Map.get("link") + + result = + conn_res + |> json_response_and_validate_schema(200) + + assert [%{"id" => ^id3}, %{"id" => ^id2}] = result + + result = + conn + |> assign(:user, user) + |> get(next_url) + |> json_response_and_validate_schema(200) + + assert [%{"id" => ^id1}] = result end test "account lookup", %{conn: conn} do diff --git a/test/pleroma/web/mastodon_api/controllers/announcement_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/announcement_controller_test.exs new file mode 100644 index 000000000..60c9978c2 --- /dev/null +++ b/test/pleroma/web/mastodon_api/controllers/announcement_controller_test.exs @@ -0,0 +1,169 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.AnnouncementControllerTest do + use Pleroma.Web.ConnCase + + import Pleroma.Factory + + alias Pleroma.Announcement + alias Pleroma.AnnouncementReadRelationship + + describe "GET /api/v1/announcements" do + setup do + %{conn: conn} = oauth_access([]) + {:ok, conn: conn} + end + + test "it does not allow guests", %{conn: conn} do + _response = + conn + |> assign(:token, nil) + |> get("/api/v1/announcements") + |> json_response_and_validate_schema(:forbidden) + end + + test "it allows users with scopes" do + %{conn: conn} = oauth_access(["read:accounts"]) + + _response = + conn + |> get("/api/v1/announcements") + |> json_response_and_validate_schema(:ok) + end + + test "it lists all announcements", %{conn: conn} do + %{id: id} = insert(:announcement) + + response = + conn + |> get("/api/v1/announcements") + |> json_response_and_validate_schema(:ok) + + assert [%{"id" => ^id}] = response + end + + test "it returns time with utc timezone", %{conn: conn} do + start_time = + NaiveDateTime.utc_now() + |> NaiveDateTime.add(-999_999, :second) + |> NaiveDateTime.truncate(:second) + + end_time = + NaiveDateTime.utc_now() + |> NaiveDateTime.add(999_999, :second) + |> NaiveDateTime.truncate(:second) + + %{id: id} = insert(:announcement, %{starts_at: start_time, ends_at: end_time}) + + response = + conn + |> get("/api/v1/announcements") + |> json_response_and_validate_schema(:ok) + + assert [%{"id" => ^id}] = [announcement] = response + + assert String.ends_with?(announcement["starts_at"], "Z") + assert String.ends_with?(announcement["ends_at"], "Z") + end + + test "it does not list announcements starting after current time", %{conn: conn} do + time = NaiveDateTime.utc_now() |> NaiveDateTime.add(999_999, :second) + insert(:announcement, starts_at: time) + + response = + conn + |> get("/api/v1/announcements") + |> json_response_and_validate_schema(:ok) + + assert [] = response + end + + test "it does not list announcements ending before current time", %{conn: conn} do + time = NaiveDateTime.utc_now() |> NaiveDateTime.add(-999_999, :second) + insert(:announcement, ends_at: time) + + response = + conn + |> get("/api/v1/announcements") + |> json_response_and_validate_schema(:ok) + + assert [] = response + end + + test "when authenticated, also expose read property", %{conn: conn} do + %{id: id} = insert(:announcement) + + response = + conn + |> get("/api/v1/announcements") + |> json_response_and_validate_schema(:ok) + + assert [%{"id" => ^id, "read" => false}] = response + end + + test "when authenticated and announcement is read by user" do + %{id: id} = announcement = insert(:announcement) + user = insert(:user) + + AnnouncementReadRelationship.mark_read(user, announcement) + + %{conn: conn} = oauth_access(["read:accounts"], user: user) + + response = + conn + |> get("/api/v1/announcements") + |> json_response_and_validate_schema(:ok) + + assert [%{"id" => ^id, "read" => true}] = response + end + end + + describe "POST /api/v1/announcements/:id/dismiss" do + setup do: oauth_access(["write:accounts"]) + + test "it requires auth", %{conn: conn} do + %{id: id} = insert(:announcement) + + _response = + conn + |> assign(:token, nil) + |> post("/api/v1/announcements/#{id}/dismiss") + |> json_response_and_validate_schema(:forbidden) + end + + test "it requires write:accounts oauth scope" do + %{id: id} = insert(:announcement) + + %{conn: conn} = oauth_access(["read:accounts"]) + + _response = + conn + |> post("/api/v1/announcements/#{id}/dismiss") + |> json_response_and_validate_schema(:forbidden) + end + + test "it gives 404 for non-existent announcements", %{conn: conn} do + %{id: id} = insert(:announcement) + + _response = + conn + |> post("/api/v1/announcements/#{id}xxx/dismiss") + |> json_response_and_validate_schema(:not_found) + end + + test "it marks announcement as read", %{user: user, conn: conn} do + %{id: id} = announcement = insert(:announcement) + + refute Announcement.read_by?(announcement, user) + + _response = + conn + |> post("/api/v1/announcements/#{id}/dismiss") + |> json_response_and_validate_schema(:ok) + + assert Announcement.read_by?(announcement, user) + end + end +end diff --git a/test/pleroma/web/mastodon_api/controllers/instance_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/instance_controller_test.exs index 9845408d6..13e3ffc0a 100644 --- a/test/pleroma/web/mastodon_api/controllers/instance_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/instance_controller_test.exs @@ -22,6 +22,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do "uri" => _, "title" => _, "description" => _, + "short_description" => _, "version" => _, "email" => from_config_email, "urls" => %{ diff --git a/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs index 2b7a95635..403628488 100644 --- a/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs @@ -423,7 +423,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do assert [%{"id" => ^reblog_notification_id}] = json_response_and_validate_schema(conn_res, 200) end - test "filters notifications using include_types" do + test "filters notifications using types" do %{user: user, conn: conn} = oauth_access(["read:notifications"]) other_user = insert(:user) @@ -438,21 +438,21 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do reblog_notification_id = get_notification_id_by_activity(reblog_activity) follow_notification_id = get_notification_id_by_activity(follow_activity) - conn_res = get(conn, "/api/v1/notifications?include_types[]=follow") + conn_res = get(conn, "/api/v1/notifications?types[]=follow") assert [%{"id" => ^follow_notification_id}] = json_response_and_validate_schema(conn_res, 200) - conn_res = get(conn, "/api/v1/notifications?include_types[]=mention") + conn_res = get(conn, "/api/v1/notifications?types[]=mention") assert [%{"id" => ^mention_notification_id}] = json_response_and_validate_schema(conn_res, 200) - conn_res = get(conn, "/api/v1/notifications?include_types[]=favourite") + conn_res = get(conn, "/api/v1/notifications?types[]=favourite") assert [%{"id" => ^favorite_notification_id}] = json_response_and_validate_schema(conn_res, 200) - conn_res = get(conn, "/api/v1/notifications?include_types[]=reblog") + conn_res = get(conn, "/api/v1/notifications?types[]=reblog") assert [%{"id" => ^reblog_notification_id}] = json_response_and_validate_schema(conn_res, 200) @@ -460,7 +460,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do assert length(result) == 4 - query = params_to_query(%{include_types: ["follow", "mention", "favourite", "reblog"]}) + query = params_to_query(%{types: ["follow", "mention", "favourite", "reblog"]}) result = conn @@ -470,6 +470,23 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do assert length(result) == 4 end + test "filtering falls back to include_types" do + %{user: user, conn: conn} = oauth_access(["read:notifications"]) + other_user = insert(:user) + + {:ok, _activity} = CommonAPI.post(other_user, %{status: "hey @#{user.nickname}"}) + {:ok, create_activity} = CommonAPI.post(user, %{status: "hey"}) + {:ok, _activity} = CommonAPI.favorite(other_user, create_activity.id) + {:ok, _activity} = CommonAPI.repeat(create_activity.id, other_user) + {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user) + + follow_notification_id = get_notification_id_by_activity(follow_activity) + + conn_res = get(conn, "/api/v1/notifications?include_types[]=follow") + + assert [%{"id" => ^follow_notification_id}] = json_response_and_validate_schema(conn_res, 200) + end + test "destroy multiple" do %{user: user, conn: conn} = oauth_access(["read:notifications", "write:notifications"]) other_user = insert(:user) diff --git a/test/pleroma/web/mastodon_api/update_credentials_test.exs b/test/pleroma/web/mastodon_api/update_credentials_test.exs index c2e4debc8..f5211a60e 100644 --- a/test/pleroma/web/mastodon_api/update_credentials_test.exs +++ b/test/pleroma/web/mastodon_api/update_credentials_test.exs @@ -390,6 +390,20 @@ defmodule Pleroma.Web.MastodonAPI.UpdateCredentialsTest do assert user_data["source"]["pleroma"]["show_birthday"] == true end + test "unsets birth date", %{conn: conn} do + patch(conn, "/api/v1/accounts/update_credentials", %{ + "birthday" => "2001-02-12" + }) + + res = + patch(conn, "/api/v1/accounts/update_credentials", %{ + "birthday" => "" + }) + + assert user_data = json_response_and_validate_schema(res, 200) + assert user_data["pleroma"]["birthday"] == nil + end + test "emojis in fields labels", %{conn: conn} do fields = [ %{"name" => ":firefox:", "value" => "is best 2hu"}, diff --git a/test/pleroma/web/mastodon_api/views/account_view_test.exs b/test/pleroma/web/mastodon_api/views/account_view_test.exs index 8ed37fe58..692ec8c92 100644 --- a/test/pleroma/web/mastodon_api/views/account_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/account_view_test.exs @@ -634,4 +634,21 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do |> assert() end end + + test "renders mute expiration date" do + user = insert(:user) + other_user = insert(:user) + + {:ok, _user_relationships} = + User.mute(user, other_user, %{notifications: true, duration: 24 * 60 * 60}) + + %{ + mute_expires_at: mute_expires_at + } = AccountView.render("show.json", %{user: other_user, for: user, mutes: true}) + + assert DateTime.diff( + mute_expires_at, + DateTime.utc_now() |> DateTime.add(24 * 60 * 60) + ) in -3..3 + end end diff --git a/test/pleroma/web/o_status/o_status_controller_test.exs b/test/pleroma/web/o_status/o_status_controller_test.exs index 5abbcfbdc..36e581f5e 100644 --- a/test/pleroma/web/o_status/o_status_controller_test.exs +++ b/test/pleroma/web/o_status/o_status_controller_test.exs @@ -343,54 +343,4 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do |> response(200) end end - - describe "notice compatibility routes" do - test "Soapbox FE", %{conn: conn} do - user = insert(:user) - note_activity = insert(:note_activity, user: user) - - resp = - conn - |> put_req_header("accept", "text/html") - |> get("/@#{user.nickname}/posts/#{note_activity.id}") - |> response(200) - - expected = - "<meta content=\"#{Endpoint.url()}/notice/#{note_activity.id}\" property=\"og:url\">" - - assert resp =~ expected - end - - test "Mastodon", %{conn: conn} do - user = insert(:user) - note_activity = insert(:note_activity, user: user) - - resp = - conn - |> put_req_header("accept", "text/html") - |> get("/@#{user.nickname}/#{note_activity.id}") - |> response(200) - - expected = - "<meta content=\"#{Endpoint.url()}/notice/#{note_activity.id}\" property=\"og:url\">" - - assert resp =~ expected - end - - test "Twitter", %{conn: conn} do - user = insert(:user) - note_activity = insert(:note_activity, user: user) - - resp = - conn - |> put_req_header("accept", "text/html") - |> get("/#{user.nickname}/status/#{note_activity.id}") - |> response(200) - - expected = - "<meta content=\"#{Endpoint.url()}/notice/#{note_activity.id}\" property=\"og:url\">" - - assert resp =~ expected - end - end end diff --git a/test/pleroma/web/pleroma_api/controllers/backup_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/backup_controller_test.exs index 650f3d80d..3b4b1bfff 100644 --- a/test/pleroma/web/pleroma_api/controllers/backup_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/backup_controller_test.exs @@ -82,4 +82,24 @@ defmodule Pleroma.Web.PleromaAPI.BackupControllerTest do |> post("/api/v1/pleroma/backups") |> json_response_and_validate_schema(400) end + + test "Backup without email address" do + user = Pleroma.Factory.insert(:user, email: nil) + %{conn: conn} = oauth_access(["read:accounts"], user: user) + + assert is_nil(user.email) + + assert [ + %{ + "content_type" => "application/zip", + "url" => _url, + "file_size" => 0, + "processed" => false, + "inserted_at" => _ + } + ] = + conn + |> post("/api/v1/pleroma/backups") + |> json_response_and_validate_schema(:ok) + end end diff --git a/test/pleroma/web/plugs/frontend_static_plug_test.exs b/test/pleroma/web/plugs/frontend_static_plug_test.exs index a91e24c49..ab31c5f22 100644 --- a/test/pleroma/web/plugs/frontend_static_plug_test.exs +++ b/test/pleroma/web/plugs/frontend_static_plug_test.exs @@ -86,8 +86,6 @@ defmodule Pleroma.Web.Plugs.FrontendStaticPlugTest do "objects", "activities", "notice", - "@:nickname", - ":nickname", "users", "tags", "mailer", diff --git a/test/pleroma/web/twitter_api/remote_follow_controller_test.exs b/test/pleroma/web/twitter_api/remote_follow_controller_test.exs index a493dc9f6..2b57a42a4 100644 --- a/test/pleroma/web/twitter_api/remote_follow_controller_test.exs +++ b/test/pleroma/web/twitter_api/remote_follow_controller_test.exs @@ -410,4 +410,49 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do assert response =~ "Error following account" end end + + describe "avatar url" do + test "without media proxy" do + clear_config([:media_proxy, :enabled], false) + + user = + insert(:user, %{ + local: false, + avatar: %{"url" => [%{"href" => "https://remote.org/avatar.png"}]} + }) + + avatar_url = Pleroma.Web.TwitterAPI.RemoteFollowView.avatar_url(user) + + assert avatar_url == "https://remote.org/avatar.png" + end + + test "with media proxy" do + clear_config([:media_proxy, :enabled], true) + + user = + insert(:user, %{ + local: false, + avatar: %{"url" => [%{"href" => "https://remote.org/avatar.png"}]} + }) + + avatar_url = Pleroma.Web.TwitterAPI.RemoteFollowView.avatar_url(user) + url = Pleroma.Web.Endpoint.url() + + assert String.starts_with?(avatar_url, url) + end + + test "local avatar is not proxied" do + clear_config([:media_proxy, :enabled], true) + + user = + insert(:user, %{ + local: true, + avatar: %{"url" => [%{"href" => "#{Pleroma.Web.Endpoint.url()}/localuser/avatar.png"}]} + }) + + avatar_url = Pleroma.Web.TwitterAPI.RemoteFollowView.avatar_url(user) + + assert avatar_url == "#{Pleroma.Web.Endpoint.url()}/localuser/avatar.png" + end + end end diff --git a/test/pleroma/web/twitter_api/util_controller_test.exs b/test/pleroma/web/twitter_api/util_controller_test.exs index c795fd501..5dc72b177 100644 --- a/test/pleroma/web/twitter_api/util_controller_test.exs +++ b/test/pleroma/web/twitter_api/util_controller_test.exs @@ -516,4 +516,371 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do assert user.password_hash == nil end end + + describe "POST /api/pleroma/move_account" do + setup do: oauth_access(["write:accounts"]) + + test "without permissions", %{conn: conn} do + target_user = insert(:user) + target_nick = target_user |> User.full_nickname() + + conn = + conn + |> assign(:token, nil) + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/move_account", %{ + "password" => "hi", + "target_account" => target_nick + }) + + assert json_response_and_validate_schema(conn, 403) == %{ + "error" => "Insufficient permissions: write:accounts." + } + end + + test "with proper permissions and invalid password", %{conn: conn} do + target_user = insert(:user) + target_nick = target_user |> User.full_nickname() + + conn = + conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/move_account", %{ + "password" => "hi", + "target_account" => target_nick + }) + + assert json_response_and_validate_schema(conn, 200) == %{"error" => "Invalid password."} + end + + test "with proper permissions, valid password and target account does not alias it", + %{ + conn: conn + } do + target_user = insert(:user) + target_nick = target_user |> User.full_nickname() + + conn = + conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/move_account", %{ + "password" => "test", + "target_account" => target_nick + }) + + assert json_response_and_validate_schema(conn, 200) == %{ + "error" => "Target account must have the origin in `alsoKnownAs`" + } + end + + test "with proper permissions, valid password and target account does not exist", + %{ + conn: conn + } do + target_nick = "not_found@mastodon.social" + + conn = + conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/move_account", %{ + "password" => "test", + "target_account" => target_nick + }) + + assert json_response_and_validate_schema(conn, 404) == %{ + "error" => "Target account not found." + } + end + + test "with proper permissions, valid password, remote target account aliases it and local cache does not exist", + %{} do + user = insert(:user, ap_id: "https://lm.kazv.moe/users/testuser") + %{user: _user, conn: conn} = oauth_access(["write:accounts"], user: user) + + target_nick = "mewmew@lm.kazv.moe" + + conn = + conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/move_account", %{ + "password" => "test", + "target_account" => target_nick + }) + + assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"} + end + + test "with proper permissions, valid password, remote target account aliases it and local cache does not aliases it", + %{} do + user = insert(:user, ap_id: "https://lm.kazv.moe/users/testuser") + %{user: _user, conn: conn} = oauth_access(["write:accounts"], user: user) + + target_user = + insert( + :user, + ap_id: "https://lm.kazv.moe/users/mewmew", + nickname: "mewmew@lm.kazv.moe", + local: false + ) + + target_nick = target_user |> User.full_nickname() + + conn = + conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/move_account", %{ + "password" => "test", + "target_account" => target_nick + }) + + assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"} + end + + test "with proper permissions, valid password, remote target account does not aliases it and local cache aliases it", + %{ + user: user, + conn: conn + } do + target_user = + insert( + :user, + ap_id: "https://lm.kazv.moe/users/mewmew", + nickname: "mewmew@lm.kazv.moe", + local: false, + also_known_as: [user.ap_id] + ) + + target_nick = target_user |> User.full_nickname() + + conn = + conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/move_account", %{ + "password" => "test", + "target_account" => target_nick + }) + + assert json_response_and_validate_schema(conn, 200) == %{ + "error" => "Target account must have the origin in `alsoKnownAs`" + } + end + + test "with proper permissions, valid password and target account aliases it", %{ + conn: conn, + user: user + } do + target_user = insert(:user, also_known_as: [user.ap_id]) + target_nick = target_user |> User.full_nickname() + follower = insert(:user) + + User.follow(follower, user) + + assert User.following?(follower, user) + + conn = + conn + |> put_req_header("content-type", "multipart/form-data") + |> post( + "/api/pleroma/move_account", + %{ + password: "test", + target_account: target_nick + } + ) + + assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"} + + params = %{ + "op" => "move_following", + "origin_id" => user.id, + "target_id" => target_user.id + } + + assert_enqueued(worker: Pleroma.Workers.BackgroundWorker, args: params) + + Pleroma.Workers.BackgroundWorker.perform(%Oban.Job{args: params}) + + refute User.following?(follower, user) + assert User.following?(follower, target_user) + end + + test "prefix nickname by @ should work", %{ + conn: conn, + user: user + } do + target_user = insert(:user, also_known_as: [user.ap_id]) + target_nick = target_user |> User.full_nickname() + follower = insert(:user) + + User.follow(follower, user) + + assert User.following?(follower, user) + + conn = + conn + |> put_req_header("content-type", "multipart/form-data") + |> post( + "/api/pleroma/move_account", + %{ + password: "test", + target_account: "@" <> target_nick + } + ) + + assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"} + + params = %{ + "op" => "move_following", + "origin_id" => user.id, + "target_id" => target_user.id + } + + assert_enqueued(worker: Pleroma.Workers.BackgroundWorker, args: params) + + Pleroma.Workers.BackgroundWorker.perform(%Oban.Job{args: params}) + + refute User.following?(follower, user) + assert User.following?(follower, target_user) + end + end + + describe "GET /api/pleroma/aliases" do + setup do: oauth_access(["read:accounts"]) + + test "without permissions", %{conn: conn} do + conn = + conn + |> assign(:token, nil) + |> get("/api/pleroma/aliases") + + assert json_response_and_validate_schema(conn, 403) == %{ + "error" => "Insufficient permissions: read:accounts." + } + end + + test "with permissions", %{ + conn: conn + } do + assert %{"aliases" => []} = + conn + |> get("/api/pleroma/aliases") + |> json_response_and_validate_schema(200) + end + + test "with permissions and aliases", %{} do + user = insert(:user) + user2 = insert(:user) + + assert {:ok, user} = user |> User.add_alias(user2) + + %{user: _user, conn: conn} = oauth_access(["read:accounts"], user: user) + + assert %{"aliases" => aliases} = + conn + |> get("/api/pleroma/aliases") + |> json_response_and_validate_schema(200) + + assert aliases == [user2 |> User.full_nickname()] + end + end + + describe "PUT /api/pleroma/aliases" do + setup do: oauth_access(["write:accounts"]) + + test "without permissions", %{conn: conn} do + conn = + conn + |> assign(:token, nil) + |> put_req_header("content-type", "application/json") + |> put("/api/pleroma/aliases", %{alias: "none"}) + + assert json_response_and_validate_schema(conn, 403) == %{ + "error" => "Insufficient permissions: write:accounts." + } + end + + test "with permissions, no alias param", %{ + conn: conn + } do + conn = + conn + |> put_req_header("content-type", "application/json") + |> put("/api/pleroma/aliases", %{}) + + assert %{"error" => "Missing field: alias."} = json_response_and_validate_schema(conn, 400) + end + + test "with permissions, with alias param", %{ + conn: conn + } do + user2 = insert(:user) + + conn = + conn + |> put_req_header("content-type", "application/json") + |> put("/api/pleroma/aliases", %{alias: user2 |> User.full_nickname()}) + + assert json_response_and_validate_schema(conn, 200) == %{ + "status" => "success" + } + end + end + + describe "DELETE /api/pleroma/aliases" do + setup do + alias_user = insert(:user) + non_alias_user = insert(:user) + user = insert(:user, also_known_as: [alias_user.ap_id]) + + oauth_access(["write:accounts"], user: user) + |> Map.put(:alias_user, alias_user) + |> Map.put(:non_alias_user, non_alias_user) + end + + test "without permissions", %{conn: conn} do + conn = + conn + |> assign(:token, nil) + |> put_req_header("content-type", "application/json") + |> delete("/api/pleroma/aliases", %{alias: "none"}) + + assert json_response_and_validate_schema(conn, 403) == %{ + "error" => "Insufficient permissions: write:accounts." + } + end + + test "with permissions, no alias param", %{conn: conn} do + conn = + conn + |> put_req_header("content-type", "application/json") + |> delete("/api/pleroma/aliases", %{}) + + assert %{"error" => "Missing field: alias."} = json_response_and_validate_schema(conn, 400) + end + + test "with permissions, account does not have such alias", %{ + conn: conn, + non_alias_user: non_alias_user + } do + conn = + conn + |> put_req_header("content-type", "application/json") + |> delete("/api/pleroma/aliases", %{alias: non_alias_user |> User.full_nickname()}) + + assert %{"error" => "Account has no such alias."} = + json_response_and_validate_schema(conn, 404) + end + + test "with permissions, account does have such alias", %{ + conn: conn, + alias_user: alias_user + } do + conn = + conn + |> put_req_header("content-type", "application/json") + |> delete("/api/pleroma/aliases", %{alias: alias_user |> User.full_nickname()}) + + assert %{"status" => "success"} = json_response_and_validate_schema(conn, 200) + end + end end diff --git a/test/support/factory.ex b/test/support/factory.ex index 09456debf..efbf3df2e 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -627,4 +627,16 @@ defmodule Pleroma.Factory do context: ["home"] } end + + def announcement_factory(params \\ %{}) do + data = Map.get(params, :data, %{}) + + {_, params} = Map.pop(params, :data) + + %Pleroma.Announcement{ + data: Map.merge(%{"content" => "test announcement", "all_day" => false}, data) + } + |> Map.merge(params) + |> Pleroma.Announcement.add_rendered_properties() + end end diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index ad4925a5c..eb844e469 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -725,6 +725,15 @@ defmodule HttpRequestMock do }} end + def get( + "https://mastodon.social/.well-known/webfinger?resource=acct:not_found@mastodon.social", + _, + _, + [{"accept", "application/xrd+xml,application/jrd+json"}] + ) do + {:ok, %Tesla.Env{status: 404}} + end + def get("http://gs.example.org/.well-known/host-meta", _, _, _) do {:ok, %Tesla.Env{ @@ -1124,6 +1133,57 @@ defmodule HttpRequestMock do }} end + def get("http://lm.kazv.moe/.well-known/host-meta", _, _, _) do + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/lm.kazv.moe_host_meta") + }} + end + + def get("https://lm.kazv.moe/.well-known/host-meta", _, _, _) do + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/lm.kazv.moe_host_meta") + }} + end + + def get( + "https://lm.kazv.moe/.well-known/webfinger?resource=acct:mewmew@lm.kazv.moe", + _, + _, + [{"accept", "application/xrd+xml,application/jrd+json"}] + ) do + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/https___lm.kazv.moe_users_mewmew.xml"), + headers: [{"content-type", "application/xrd+xml"}] + }} + end + + def get("https://lm.kazv.moe/users/mewmew", _, _, _) do + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/mewmew@lm.kazv.moe.json"), + headers: activitypub_object_headers() + }} + end + + def get("https://lm.kazv.moe/users/mewmew/collections/featured", _, _, _) do + {:ok, + %Tesla.Env{ + status: 200, + body: + File.read!("test/fixtures/users_mock/masto_featured.json") + |> String.replace("{{domain}}", "lm.kazv.moe") + |> String.replace("{{nickname}}", "mewmew"), + headers: [{"content-type", "application/activity+json"}] + }} + end + def get("https://info.pleroma.site/activity.json", _, _, [ {"accept", "application/activity+json"} ]) do |