diff options
Diffstat (limited to 'test/web/twitter_api')
| -rw-r--r-- | test/web/twitter_api/representers/activity_representer_test.exs | 200 | ||||
| -rw-r--r-- | test/web/twitter_api/representers/object_representer_test.exs | 4 | ||||
| -rw-r--r-- | test/web/twitter_api/twitter_api_controller_test.exs | 971 | ||||
| -rw-r--r-- | test/web/twitter_api/twitter_api_test.exs | 462 | ||||
| -rw-r--r-- | test/web/twitter_api/util_controller_test.exs | 248 | ||||
| -rw-r--r-- | test/web/twitter_api/views/activity_view_test.exs | 158 | ||||
| -rw-r--r-- | test/web/twitter_api/views/notification_view_test.exs | 20 | ||||
| -rw-r--r-- | test/web/twitter_api/views/user_view_test.exs | 85 | 
8 files changed, 1759 insertions, 389 deletions
| diff --git a/test/web/twitter_api/representers/activity_representer_test.exs b/test/web/twitter_api/representers/activity_representer_test.exs deleted file mode 100644 index 314f2b51f..000000000 --- a/test/web/twitter_api/representers/activity_representer_test.exs +++ /dev/null @@ -1,200 +0,0 @@ -defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenterTest do -  use Pleroma.DataCase -  alias Pleroma.{User, Activity, Object} -  alias Pleroma.Web.TwitterAPI.Representers.{ActivityRepresenter, ObjectRepresenter} -  alias Pleroma.Web.ActivityPub.ActivityPub -  alias Pleroma.Builders.UserBuilder -  alias Pleroma.Web.TwitterAPI.UserView -  import Pleroma.Factory - -  test "an announce activity" do -    user = insert(:user) -    note_activity = insert(:note_activity) -    activity_actor = Repo.get_by(User, ap_id: note_activity.data["actor"]) -    object = Object.get_by_ap_id(note_activity.data["object"]["id"]) - -    {:ok, announce_activity, _object} = ActivityPub.announce(user, object) -    note_activity = Activity.get_by_ap_id(note_activity.data["id"]) - -    status = -      ActivityRepresenter.to_map(announce_activity, %{ -        users: [user, activity_actor], -        announced_activity: note_activity, -        for: user -      }) - -    assert status["id"] == announce_activity.id -    assert status["user"] == UserView.render("show.json", %{user: user, for: user}) - -    retweeted_status = -      ActivityRepresenter.to_map(note_activity, %{user: activity_actor, for: user}) - -    assert retweeted_status["repeated"] == true -    assert retweeted_status["id"] == note_activity.id -    assert status["statusnet_conversation_id"] == retweeted_status["statusnet_conversation_id"] - -    assert status["retweeted_status"] == retweeted_status -    assert status["activity_type"] == "repeat" -  end - -  test "a like activity" do -    user = insert(:user) -    note_activity = insert(:note_activity) -    object = Object.get_by_ap_id(note_activity.data["object"]["id"]) - -    {:ok, like_activity, _object} = ActivityPub.like(user, object) - -    status = -      ActivityRepresenter.to_map(like_activity, %{user: user, liked_activity: note_activity}) - -    assert status["id"] == like_activity.id -    assert status["in_reply_to_status_id"] == note_activity.id - -    note_activity = Activity.get_by_ap_id(note_activity.data["id"]) -    activity_actor = Repo.get_by(User, ap_id: note_activity.data["actor"]) -    liked_status = ActivityRepresenter.to_map(note_activity, %{user: activity_actor, for: user}) -    assert liked_status["favorited"] == true -    assert status["activity_type"] == "like" -  end - -  test "an activity" do -    user = insert(:user) -    #   {:ok, mentioned_user } = UserBuilder.insert(%{nickname: "shp", ap_id: "shp"}) -    mentioned_user = insert(:user, %{nickname: "shp"}) - -    # {:ok, follower} = UserBuilder.insert(%{following: [User.ap_followers(user)]}) -    follower = insert(:user, %{following: [User.ap_followers(user)]}) - -    object = %Object{ -      data: %{ -        "type" => "Image", -        "url" => [ -          %{ -            "type" => "Link", -            "mediaType" => "image/jpg", -            "href" => "http://example.org/image.jpg" -          } -        ], -        "uuid" => 1 -      } -    } - -    content_html = -      "<script>alert('YAY')</script>Some :2hu: content mentioning <a href='#{mentioned_user.ap_id}'>@shp</shp>" - -    content = HtmlSanitizeEx.strip_tags(content_html) -    date = DateTime.from_naive!(~N[2016-05-24 13:26:08.003], "Etc/UTC") |> DateTime.to_iso8601() - -    {:ok, convo_object} = Object.context_mapping("2hu") |> Repo.insert() - -    note_object = %{ -      "id" => "https://example.com/id/1", -      "published" => date, -      "type" => "Note", -      "content" => content_html, -      "summary" => "2hu", -      "inReplyToStatusId" => 213_123, -      "attachment" => [object.data], -      "external_url" => "some url", -      "like_count" => 5, -      "announcement_count" => 3, -      "context" => "2hu", -      "tag" => ["content", "mentioning", "nsfw"], -      "emoji" => %{ -        "2hu" => "corndog.png" -      } -    } - -    Object.create(note_object) - -    to = [ -      User.ap_followers(user), -      "https://www.w3.org/ns/activitystreams#Public", -      mentioned_user.ap_id -    ] - -    activity = %Activity{ -      id: 1, -      data: %{ -        "type" => "Create", -        "id" => "id", -        "to" => to, -        "actor" => User.ap_id(user), -        "object" => note_object["id"], -        "published" => date, -        "context" => "2hu" -      }, -      local: false, -      recipients: to -    } - -    expected_html = -      "<p>2hu</p>alert('YAY')Some <img height=\"32px\" width=\"32px\" alt=\"2hu\" title=\"2hu\" src=\"corndog.png\" /> content mentioning <a href=\"#{ -        mentioned_user.ap_id -      }\">@shp</a>" - -    expected_status = %{ -      "id" => activity.id, -      "user" => UserView.render("show.json", %{user: user, for: follower}), -      "is_local" => false, -      "statusnet_html" => expected_html, -      "text" => "2hu" <> content, -      "is_post_verb" => true, -      "created_at" => "Tue May 24 13:26:08 +0000 2016", -      "in_reply_to_status_id" => 213_123, -      "in_reply_to_screen_name" => nil, -      "in_reply_to_user_id" => nil, -      "in_reply_to_profileurl" => nil, -      "in_reply_to_ostatus_uri" => nil, -      "statusnet_conversation_id" => convo_object.id, -      "attachments" => [ -        ObjectRepresenter.to_map(object) -      ], -      "attentions" => [ -        UserView.render("show.json", %{user: mentioned_user, for: follower}) -      ], -      "fave_num" => 5, -      "repeat_num" => 3, -      "favorited" => false, -      "repeated" => false, -      "external_url" => "some url", -      "tags" => ["nsfw", "content", "mentioning"], -      "activity_type" => "post", -      "possibly_sensitive" => true, -      "uri" => note_object["id"], -      "visibility" => "direct", -      "summary" => "2hu" -    } - -    assert ActivityRepresenter.to_map(activity, %{ -             user: user, -             for: follower, -             mentioned: [mentioned_user] -           }) == expected_status -  end - -  test "an undo for a follow" do -    follower = insert(:user) -    followed = insert(:user) - -    {:ok, _follow} = ActivityPub.follow(follower, followed) -    {:ok, unfollow} = ActivityPub.unfollow(follower, followed) - -    map = ActivityRepresenter.to_map(unfollow, %{user: follower}) -    assert map["is_post_verb"] == false -    assert map["activity_type"] == "undo" -  end - -  test "a delete activity" do -    object = insert(:note) -    user = User.get_by_ap_id(object.data["actor"]) - -    {:ok, delete} = ActivityPub.delete(object) - -    map = ActivityRepresenter.to_map(delete, %{user: user}) - -    assert map["is_post_verb"] == false -    assert map["activity_type"] == "delete" -    assert map["uri"] == object.data["id"] -  end -end diff --git a/test/web/twitter_api/representers/object_representer_test.exs b/test/web/twitter_api/representers/object_representer_test.exs index 228b2ac42..c3cf330f1 100644 --- a/test/web/twitter_api/representers/object_representer_test.exs +++ b/test/web/twitter_api/representers/object_representer_test.exs @@ -1,3 +1,7 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only +  defmodule Pleroma.Web.TwitterAPI.Representers.ObjectReprenterTest do    use Pleroma.DataCase diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs index a6495ffc1..9a9630c19 100644 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ b/test/web/twitter_api/twitter_api_controller_test.exs @@ -1,31 +1,43 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only +  defmodule Pleroma.Web.TwitterAPI.ControllerTest do    use Pleroma.Web.ConnCase -  alias Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter -  alias Pleroma.Builders.{ActivityBuilder, UserBuilder} -  alias Pleroma.{Repo, Activity, User, Object, Notification} +  alias Comeonin.Pbkdf2 +  alias Ecto.Changeset +  alias Pleroma.Activity +  alias Pleroma.Builders.ActivityBuilder +  alias Pleroma.Builders.UserBuilder +  alias Pleroma.Notification +  alias Pleroma.Object +  alias Pleroma.Repo +  alias Pleroma.User    alias Pleroma.Web.ActivityPub.ActivityPub -  alias Pleroma.Web.TwitterAPI.UserView -  alias Pleroma.Web.TwitterAPI.NotificationView    alias Pleroma.Web.CommonAPI +  alias Pleroma.Web.OAuth.Token +  alias Pleroma.Web.TwitterAPI.ActivityView +  alias Pleroma.Web.TwitterAPI.Controller +  alias Pleroma.Web.TwitterAPI.NotificationView    alias Pleroma.Web.TwitterAPI.TwitterAPI -  alias Comeonin.Pbkdf2 +  alias Pleroma.Web.TwitterAPI.UserView +  import Mock    import Pleroma.Factory +  import Swoosh.TestAssertions + +  @banner "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7"    describe "POST /api/account/update_profile_banner" do      test "it updates the banner", %{conn: conn} do        user = insert(:user) -      new_banner = -        "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7" - -      response = -        conn -        |> assign(:user, user) -        |> post(authenticated_twitter_api__path(conn, :update_banner), %{"banner" => new_banner}) -        |> json_response(200) +      conn +      |> assign(:user, user) +      |> post(authenticated_twitter_api__path(conn, :update_banner), %{"banner" => @banner}) +      |> json_response(200) -      user = Repo.get(User, user.id) +      user = refresh_record(user)        assert user.info.banner["type"] == "Image"      end    end @@ -34,16 +46,12 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do      test "it updates the background", %{conn: conn} do        user = insert(:user) -      new_bg = -        "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7" - -      response = -        conn -        |> assign(:user, user) -        |> post(authenticated_twitter_api__path(conn, :update_background), %{"img" => new_bg}) -        |> json_response(200) +      conn +      |> assign(:user, user) +      |> post(authenticated_twitter_api__path(conn, :update_background), %{"img" => @banner}) +      |> json_response(200) -      user = Repo.get(User, user.id) +      user = refresh_record(user)        assert user.info.background["type"] == "Image"      end    end @@ -57,13 +65,14 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do      end      test "with credentials", %{conn: conn, user: user} do -      conn = +      response =          conn          |> with_credentials(user.nickname, "test")          |> post("/api/account/verify_credentials.json") +        |> json_response(200) -      assert response = json_response(conn, 200) -      assert response == UserView.render("show.json", %{user: user, token: response["token"]}) +      assert response == +               UserView.render("show.json", %{user: user, token: response["token"], for: user})      end    end @@ -84,24 +93,41 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do          "error" => "Client must provide a 'status' parameter with a value."        } -      conn = conn_with_creds |> post(request_path) +      conn = +        conn_with_creds +        |> post(request_path) +        assert json_response(conn, 400) == error_response -      conn = conn_with_creds |> post(request_path, %{status: ""}) +      conn = +        conn_with_creds +        |> post(request_path, %{status: ""}) +        assert json_response(conn, 400) == error_response -      conn = conn_with_creds |> post(request_path, %{status: " "}) +      conn = +        conn_with_creds +        |> post(request_path, %{status: " "}) +        assert json_response(conn, 400) == error_response        # we post with visibility private in order to avoid triggering relay -      conn = conn_with_creds |> post(request_path, %{status: "Nice meme.", visibility: "private"}) +      conn = +        conn_with_creds +        |> post(request_path, %{status: "Nice meme.", visibility: "private"})        assert json_response(conn, 200) == -               ActivityRepresenter.to_map(Repo.one(Activity), %{user: user}) +               ActivityView.render("activity.json", %{ +                 activity: Repo.one(Activity), +                 user: user, +                 for: user +               })      end    end    describe "GET /statuses/public_timeline.json" do +    setup [:valid_user] +      test "returns statuses", %{conn: conn} do        user = insert(:user)        activities = ActivityBuilder.insert_list(30, %{}, %{user: user}) @@ -117,7 +143,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        assert length(response) == 10      end -    test "returns 403 to unauthenticated request when the instance is not public" do +    test "returns 403 to unauthenticated request when the instance is not public", %{conn: conn} do        instance =          Application.get_env(:pleroma, :instance)          |> Keyword.put(:public, false) @@ -135,15 +161,59 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        Application.put_env(:pleroma, :instance, instance)      end -    test "returns 200 to unauthenticated request when the instance is public" do +    test "returns 200 to authenticated request when the instance is not public", +         %{conn: conn, user: user} do +      instance = +        Application.get_env(:pleroma, :instance) +        |> Keyword.put(:public, false) + +      Application.put_env(:pleroma, :instance, instance) + +      conn +      |> with_credentials(user.nickname, "test") +      |> get("/api/statuses/public_timeline.json") +      |> json_response(200) + +      instance = +        Application.get_env(:pleroma, :instance) +        |> Keyword.put(:public, true) + +      Application.put_env(:pleroma, :instance, instance) +    end + +    test "returns 200 to unauthenticated request when the instance is public", %{conn: conn} do        conn        |> get("/api/statuses/public_timeline.json")        |> json_response(200)      end + +    test "returns 200 to authenticated request when the instance is public", +         %{conn: conn, user: user} do +      conn +      |> with_credentials(user.nickname, "test") +      |> get("/api/statuses/public_timeline.json") +      |> json_response(200) +    end + +    test_with_mock "treats user as unauthenticated if `assigns[:token]` is present but lacks `read` permission", +                   Controller, +                   [:passthrough], +                   [] do +      token = insert(:oauth_token, scopes: ["write"]) + +      build_conn() +      |> put_req_header("authorization", "Bearer #{token.token}") +      |> get("/api/statuses/public_timeline.json") +      |> json_response(200) + +      assert called(Controller.public_timeline(%{assigns: %{user: nil}}, :_)) +    end    end    describe "GET /statuses/public_and_external_timeline.json" do -    test "returns 403 to unauthenticated request when the instance is not public" do +    setup [:valid_user] + +    test "returns 403 to unauthenticated request when the instance is not public", %{conn: conn} do        instance =          Application.get_env(:pleroma, :instance)          |> Keyword.put(:public, false) @@ -161,8 +231,36 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        Application.put_env(:pleroma, :instance, instance)      end -    test "returns 200 to unauthenticated request when the instance is public" do +    test "returns 200 to authenticated request when the instance is not public", +         %{conn: conn, user: user} do +      instance = +        Application.get_env(:pleroma, :instance) +        |> Keyword.put(:public, false) + +      Application.put_env(:pleroma, :instance, instance) + +      conn +      |> with_credentials(user.nickname, "test") +      |> get("/api/statuses/public_and_external_timeline.json") +      |> json_response(200) + +      instance = +        Application.get_env(:pleroma, :instance) +        |> Keyword.put(:public, true) + +      Application.put_env(:pleroma, :instance, instance) +    end + +    test "returns 200 to unauthenticated request when the instance is public", %{conn: conn} do +      conn +      |> get("/api/statuses/public_and_external_timeline.json") +      |> json_response(200) +    end + +    test "returns 200 to authenticated request when the instance is public", +         %{conn: conn, user: user} do        conn +      |> with_credentials(user.nickname, "test")        |> get("/api/statuses/public_and_external_timeline.json")        |> json_response(200)      end @@ -180,7 +278,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        response = json_response(conn, 200) -      assert response == ActivityRepresenter.to_map(activity, %{user: actor}) +      assert response == ActivityView.render("activity.json", %{activity: activity, user: actor})      end    end @@ -265,7 +363,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        since_id = List.last(activities).id        current_user = -        Ecto.Changeset.change(current_user, following: [User.ap_followers(user)]) +        Changeset.change(current_user, following: [User.ap_followers(user)])          |> Repo.update!()        conn = @@ -279,7 +377,8 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        assert response ==                 Enum.map(returned_activities, fn activity -> -                 ActivityRepresenter.to_map(activity, %{ +                 ActivityView.render("activity.json", %{ +                   activity: activity,                     user: User.get_cached_by_ap_id(activity.data["actor"]),                     for: current_user                   }) @@ -322,6 +421,33 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        assert status["id"] == direct_two.id        assert status_two["id"] == direct.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, blocker) +        |> get("/api/statuses/dm_timeline.json") + +      [status] = json_response(res_conn, 200) +      assert status["id"] == direct.id +    end    end    describe "GET /statuses/mentions.json" do @@ -334,7 +460,10 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do      test "with credentials", %{conn: conn, user: current_user} do        {:ok, activity} = -        ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: current_user}) +        CommonAPI.post(current_user, %{ +          "status" => "why is tenshi eating a corndog so cute?", +          "visibility" => "public" +        })        conn =          conn @@ -346,11 +475,29 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        assert length(response) == 1        assert Enum.at(response, 0) == -               ActivityRepresenter.to_map(activity, %{ +               ActivityView.render("activity.json", %{                   user: current_user, -                 mentioned: [current_user] +                 for: current_user, +                 activity: activity                 })      end + +    test "does not show DMs in mentions timeline", %{conn: conn, user: current_user} do +      {:ok, _activity} = +        CommonAPI.post(current_user, %{ +          "status" => "Have you guys ever seen how cute tenshi eating a corndog is?", +          "visibility" => "direct" +        }) + +      conn = +        conn +        |> with_credentials(current_user.nickname, "test") +        |> get("/api/statuses/mentions.json") + +      response = json_response(conn, 200) + +      assert Enum.empty?(response) +    end    end    describe "GET /api/qvitter/statuses/notifications.json" do @@ -453,7 +600,9 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        conn = get(conn, "/api/statuses/user_timeline.json", %{"user_id" => user.id})        response = json_response(conn, 200)        assert length(response) == 1 -      assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: user}) + +      assert Enum.at(response, 0) == +               ActivityView.render("activity.json", %{user: user, activity: activity})      end      test "with screen_name", %{conn: conn} do @@ -463,7 +612,9 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        conn = get(conn, "/api/statuses/user_timeline.json", %{"screen_name" => user.nickname})        response = json_response(conn, 200)        assert length(response) == 1 -      assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: user}) + +      assert Enum.at(response, 0) == +               ActivityView.render("activity.json", %{user: user, activity: activity})      end      test "with credentials", %{conn: conn, user: current_user} do @@ -477,7 +628,13 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        response = json_response(conn, 200)        assert length(response) == 1 -      assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: current_user}) + +      assert Enum.at(response, 0) == +               ActivityView.render("activity.json", %{ +                 user: current_user, +                 for: current_user, +                 activity: activity +               })      end      test "with credentials with user_id", %{conn: conn, user: current_user} do @@ -492,7 +649,9 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        response = json_response(conn, 200)        assert length(response) == 1 -      assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: user}) + +      assert Enum.at(response, 0) == +               ActivityView.render("activity.json", %{user: user, activity: activity})      end      test "with credentials screen_name", %{conn: conn, user: current_user} do @@ -507,7 +666,41 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        response = json_response(conn, 200)        assert length(response) == 1 -      assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: user}) + +      assert Enum.at(response, 0) == +               ActivityView.render("activity.json", %{user: user, activity: activity}) +    end + +    test "with credentials with user_id, excluding RTs", %{conn: conn, user: current_user} do +      user = insert(:user) +      {:ok, activity} = ActivityBuilder.insert(%{"id" => 1, "type" => "Create"}, %{user: user}) +      {:ok, _} = ActivityBuilder.insert(%{"id" => 2, "type" => "Announce"}, %{user: user}) + +      conn = +        conn +        |> with_credentials(current_user.nickname, "test") +        |> get("/api/statuses/user_timeline.json", %{ +          "user_id" => user.id, +          "include_rts" => "false" +        }) + +      response = json_response(conn, 200) + +      assert length(response) == 1 + +      assert Enum.at(response, 0) == +               ActivityView.render("activity.json", %{user: user, activity: activity}) + +      conn = +        conn +        |> get("/api/statuses/user_timeline.json", %{"user_id" => user.id, "include_rts" => "0"}) + +      response = json_response(conn, 200) + +      assert length(response) == 1 + +      assert Enum.at(response, 0) == +               ActivityView.render("activity.json", %{user: user, activity: activity})      end    end @@ -527,12 +720,29 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do          |> with_credentials(current_user.nickname, "test")          |> post("/api/friendships/create.json", %{user_id: followed.id}) -      current_user = Repo.get(User, current_user.id) +      current_user = User.get_by_id(current_user.id)        assert User.ap_followers(followed) in current_user.following        assert json_response(conn, 200) ==                 UserView.render("show.json", %{user: followed, for: current_user})      end + +    test "for restricted account", %{conn: conn, user: current_user} do +      followed = insert(:user, info: %User.Info{locked: true}) + +      conn = +        conn +        |> with_credentials(current_user.nickname, "test") +        |> post("/api/friendships/create.json", %{user_id: followed.id}) + +      current_user = User.get_by_id(current_user.id) +      followed = User.get_by_id(followed.id) + +      refute User.ap_followers(followed) in current_user.following + +      assert json_response(conn, 200) == +               UserView.render("show.json", %{user: followed, for: current_user}) +    end    end    describe "POST /friendships/destroy.json" do @@ -555,7 +765,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do          |> with_credentials(current_user.nickname, "test")          |> post("/api/friendships/destroy.json", %{user_id: followed.id}) -      current_user = Repo.get(User, current_user.id) +      current_user = User.get_by_id(current_user.id)        assert current_user.following == [current_user.ap_id]        assert json_response(conn, 200) == @@ -579,7 +789,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do          |> with_credentials(current_user.nickname, "test")          |> post("/api/blocks/create.json", %{user_id: blocked.id}) -      current_user = Repo.get(User, current_user.id) +      current_user = User.get_by_id(current_user.id)        assert User.blocks?(current_user, blocked)        assert json_response(conn, 200) == @@ -606,7 +816,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do          |> with_credentials(current_user.nickname, "test")          |> post("/api/blocks/destroy.json", %{user_id: blocked.id}) -      current_user = Repo.get(User, current_user.id) +      current_user = User.get_by_id(current_user.id)        assert current_user.info.blocks == []        assert json_response(conn, 200) == @@ -637,7 +847,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do          |> with_credentials(current_user.nickname, "test")          |> post("/api/qvitter/update_avatar.json", %{img: avatar_image}) -      current_user = Repo.get(User, current_user.id) +      current_user = User.get_by_id(current_user.id)        assert is_map(current_user.avatar)        assert json_response(conn, 200) == @@ -654,14 +864,13 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do      end      test "unimplemented mutes with credentials", %{conn: conn, user: current_user} do -      conn = +      response =          conn          |> with_credentials(current_user.nickname, "test")          |> get("/api/qvitter/mutes.json") +        |> json_response(200) -      current_user = Repo.get(User, current_user.id) - -      assert [] = json_response(conn, 200) +      assert [] = response      end    end @@ -700,7 +909,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do          |> with_credentials(current_user.nickname, "test")          |> post("/api/favorites/create/1.json") -      assert json_response(conn, 500) +      assert json_response(conn, 400)      end    end @@ -746,11 +955,15 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do          |> with_credentials(current_user.nickname, "test")          |> post(request_path) -      activity = Repo.get(Activity, note_activity.id) -      activity_user = Repo.get_by(User, ap_id: note_activity.data["actor"]) +      activity = Activity.get_by_id(note_activity.id) +      activity_user = User.get_by_ap_id(note_activity.data["actor"])        assert json_response(response, 200) == -               ActivityRepresenter.to_map(activity, %{user: activity_user, for: current_user}) +               ActivityView.render("activity.json", %{ +                 user: activity_user, +                 for: current_user, +                 activity: activity +               })      end    end @@ -780,11 +993,15 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do          |> with_credentials(current_user.nickname, "test")          |> post(request_path) -      activity = Repo.get(Activity, note_activity.id) -      activity_user = Repo.get_by(User, ap_id: note_activity.data["actor"]) +      activity = Activity.get_by_id(note_activity.id) +      activity_user = User.get_by_ap_id(note_activity.data["actor"])        assert json_response(response, 200) == -               ActivityRepresenter.to_map(activity, %{user: activity_user, for: current_user}) +               ActivityView.render("activity.json", %{ +                 user: activity_user, +                 for: current_user, +                 activity: activity +               })      end    end @@ -805,7 +1022,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        user = json_response(conn, 200) -      fetched_user = Repo.get_by(User, nickname: "lain") +      fetched_user = User.get_by_nickname("lain")        assert user == UserView.render("show.json", %{user: fetched_user})      end @@ -828,6 +1045,143 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do      end    end +  describe "POST /api/account/password_reset, with valid parameters" do +    setup %{conn: conn} do +      user = insert(:user) +      conn = post(conn, "/api/account/password_reset?email=#{user.email}") +      %{conn: conn, user: user} +    end + +    test "it returns 204", %{conn: conn} do +      assert json_response(conn, :no_content) +    end + +    test "it creates a PasswordResetToken record for user", %{user: user} do +      token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id) +      assert token_record +    end + +    test "it sends an email to user", %{user: user} do +      token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id) + +      email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token) +      notify_email = Pleroma.Config.get([:instance, :notify_email]) +      instance_name = Pleroma.Config.get([:instance, :name]) + +      assert_email_sent( +        from: {instance_name, notify_email}, +        to: {user.name, user.email}, +        html_body: email.html_body +      ) +    end +  end + +  describe "POST /api/account/password_reset, with invalid parameters" do +    setup [:valid_user] + +    test "it returns 500 when user is not found", %{conn: conn, user: user} do +      conn = post(conn, "/api/account/password_reset?email=nonexisting_#{user.email}") +      assert json_response(conn, :internal_server_error) +    end + +    test "it returns 500 when user is not local", %{conn: conn, user: user} do +      {:ok, user} = Repo.update(Changeset.change(user, local: false)) +      conn = post(conn, "/api/account/password_reset?email=#{user.email}") +      assert json_response(conn, :internal_server_error) +    end +  end + +  describe "GET /api/account/confirm_email/:id/:token" do +    setup do +      user = insert(:user) +      info_change = User.Info.confirmation_changeset(user.info, :unconfirmed) + +      {:ok, user} = +        user +        |> Changeset.change() +        |> Changeset.put_embed(:info, info_change) +        |> Repo.update() + +      assert user.info.confirmation_pending + +      [user: user] +    end + +    test "it redirects to root url", %{conn: conn, user: user} do +      conn = get(conn, "/api/account/confirm_email/#{user.id}/#{user.info.confirmation_token}") + +      assert 302 == conn.status +    end + +    test "it confirms the user account", %{conn: conn, user: user} do +      get(conn, "/api/account/confirm_email/#{user.id}/#{user.info.confirmation_token}") + +      user = User.get_by_id(user.id) + +      refute user.info.confirmation_pending +      refute user.info.confirmation_token +    end + +    test "it returns 500 if user cannot be found by id", %{conn: conn, user: user} do +      conn = get(conn, "/api/account/confirm_email/0/#{user.info.confirmation_token}") + +      assert 500 == conn.status +    end + +    test "it returns 500 if token is invalid", %{conn: conn, user: user} do +      conn = get(conn, "/api/account/confirm_email/#{user.id}/wrong_token") + +      assert 500 == conn.status +    end +  end + +  describe "POST /api/account/resend_confirmation_email" do +    setup do +      setting = Pleroma.Config.get([:instance, :account_activation_required]) + +      unless setting do +        Pleroma.Config.put([:instance, :account_activation_required], true) +        on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end) +      end + +      user = insert(:user) +      info_change = User.Info.confirmation_changeset(user.info, :unconfirmed) + +      {:ok, user} = +        user +        |> Changeset.change() +        |> Changeset.put_embed(:info, info_change) +        |> Repo.update() + +      assert user.info.confirmation_pending + +      [user: user] +    end + +    test "it returns 204 No Content", %{conn: conn, user: user} do +      conn +      |> assign(:user, user) +      |> post("/api/account/resend_confirmation_email?email=#{user.email}") +      |> json_response(:no_content) +    end + +    test "it sends confirmation email", %{conn: conn, user: user} do +      conn +      |> assign(:user, user) +      |> post("/api/account/resend_confirmation_email?email=#{user.email}") + +      email = Pleroma.Emails.UserEmail.account_confirmation_email(user) +      notify_email = Pleroma.Config.get([:instance, :notify_email]) +      instance_name = Pleroma.Config.get([:instance, :name]) + +      assert_email_sent( +        from: {instance_name, notify_email}, +        to: {user.name, user.email}, +        html_body: email.html_body +      ) +    end +  end +    describe "GET /api/externalprofile/show" do      test "it returns the user", %{conn: conn} do        user = insert(:user) @@ -861,6 +1215,112 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        result = json_response(conn, 200)        assert Enum.sort(expected) == Enum.sort(result)      end + +    test "it returns 20 followers per page", %{conn: conn} do +      user = insert(:user) +      followers = insert_list(21, :user) + +      Enum.each(followers, fn follower -> +        User.follow(follower, user) +      end) + +      res_conn = +        conn +        |> assign(:user, user) +        |> get("/api/statuses/followers") + +      result = json_response(res_conn, 200) +      assert length(result) == 20 + +      res_conn = +        conn +        |> assign(:user, user) +        |> get("/api/statuses/followers?page=2") + +      result = json_response(res_conn, 200) +      assert length(result) == 1 +    end + +    test "it returns a given user's followers with user_id", %{conn: conn} do +      user = insert(:user) +      follower_one = insert(:user) +      follower_two = insert(:user) +      not_follower = insert(:user) + +      {:ok, follower_one} = User.follow(follower_one, user) +      {:ok, follower_two} = User.follow(follower_two, user) + +      conn = +        conn +        |> assign(:user, not_follower) +        |> get("/api/statuses/followers", %{"user_id" => user.id}) + +      assert MapSet.equal?( +               MapSet.new(json_response(conn, 200)), +               MapSet.new( +                 UserView.render("index.json", %{ +                   users: [follower_one, follower_two], +                   for: not_follower +                 }) +               ) +             ) +    end + +    test "it returns empty when hide_followers is set to true", %{conn: conn} do +      user = insert(:user, %{info: %{hide_followers: true}}) +      follower_one = insert(:user) +      follower_two = insert(:user) +      not_follower = insert(:user) + +      {:ok, _follower_one} = User.follow(follower_one, user) +      {:ok, _follower_two} = User.follow(follower_two, user) + +      response = +        conn +        |> assign(:user, not_follower) +        |> get("/api/statuses/followers", %{"user_id" => user.id}) +        |> json_response(200) + +      assert [] == response +    end + +    test "it returns the followers when hide_followers is set to true if requested by the user themselves", +         %{ +           conn: conn +         } do +      user = insert(:user, %{info: %{hide_followers: true}}) +      follower_one = insert(:user) +      follower_two = insert(:user) +      _not_follower = insert(:user) + +      {:ok, _follower_one} = User.follow(follower_one, user) +      {:ok, _follower_two} = User.follow(follower_two, user) + +      conn = +        conn +        |> assign(:user, user) +        |> get("/api/statuses/followers", %{"user_id" => user.id}) + +      refute [] == json_response(conn, 200) +    end +  end + +  describe "GET /api/statuses/blocks" do +    test "it returns the list of users blocked by requester", %{conn: conn} do +      user = insert(:user) +      other_user = insert(:user) + +      {:ok, user} = User.block(user, other_user) + +      conn = +        conn +        |> assign(:user, user) +        |> get("/api/statuses/blocks") + +      expected = UserView.render("index.json", %{users: [other_user], for: user}) +      result = json_response(conn, 200) +      assert Enum.sort(expected) == Enum.sort(result) +    end    end    describe "GET /api/statuses/friends" do @@ -883,6 +1343,40 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        assert Enum.sort(expected) == Enum.sort(result)      end +    test "it returns 20 friends per page, except if 'export' is set to true", %{conn: conn} do +      user = insert(:user) +      followeds = insert_list(21, :user) + +      {:ok, user} = +        Enum.reduce(followeds, {:ok, user}, fn followed, {:ok, user} -> +          User.follow(user, followed) +        end) + +      res_conn = +        conn +        |> assign(:user, user) +        |> get("/api/statuses/friends") + +      result = json_response(res_conn, 200) +      assert length(result) == 20 + +      res_conn = +        conn +        |> assign(:user, user) +        |> get("/api/statuses/friends", %{page: 2}) + +      result = json_response(res_conn, 200) +      assert length(result) == 1 + +      res_conn = +        conn +        |> assign(:user, user) +        |> get("/api/statuses/friends", %{all: true}) + +      result = json_response(res_conn, 200) +      assert length(result) == 21 +    end +      test "it returns a given user's friends with user_id", %{conn: conn} do        user = insert(:user)        followed_one = insert(:user) @@ -905,6 +1399,44 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do               )      end +    test "it returns empty when hide_follows is set to true", %{conn: conn} do +      user = insert(:user, %{info: %{hide_follows: true}}) +      followed_one = insert(:user) +      followed_two = insert(:user) +      not_followed = insert(:user) + +      {:ok, user} = User.follow(user, followed_one) +      {:ok, user} = User.follow(user, followed_two) + +      conn = +        conn +        |> assign(:user, not_followed) +        |> get("/api/statuses/friends", %{"user_id" => user.id}) + +      assert [] == json_response(conn, 200) +    end + +    test "it returns friends when hide_follows is set to true if the user themselves request it", +         %{ +           conn: conn +         } do +      user = insert(:user, %{info: %{hide_follows: true}}) +      followed_one = insert(:user) +      followed_two = insert(:user) +      _not_followed = insert(:user) + +      {:ok, _user} = User.follow(user, followed_one) +      {:ok, _user} = User.follow(user, followed_two) + +      response = +        conn +        |> assign(:user, user) +        |> get("/api/statuses/friends", %{"user_id" => user.id}) +        |> json_response(200) + +      refute [] == response +    end +      test "it returns a given user's friends with screen_name", %{conn: conn} do        user = insert(:user)        followed_one = insert(:user) @@ -969,11 +1501,85 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        assert user.name == "new name"        assert user.bio == -               "hi <span><a class='mention' href='#{user2.ap_id}'>@<span>#{user2.nickname}</span></a></span>" +               "hi <span class='h-card'><a data-user='#{user2.id}' class='u-url mention' href='#{ +                 user2.ap_id +               }'>@<span>#{user2.nickname}</span></a></span>"        assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user})      end +    test "it sets and un-sets hide_follows", %{conn: conn} do +      user = insert(:user) + +      conn +      |> assign(:user, user) +      |> post("/api/account/update_profile.json", %{ +        "hide_follows" => "true" +      }) + +      user = Repo.get!(User, user.id) +      assert user.info.hide_follows == true + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/account/update_profile.json", %{ +          "hide_follows" => "false" +        }) + +      user = Repo.get!(User, user.id) +      assert user.info.hide_follows == false +      assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user}) +    end + +    test "it sets and un-sets hide_followers", %{conn: conn} do +      user = insert(:user) + +      conn +      |> assign(:user, user) +      |> post("/api/account/update_profile.json", %{ +        "hide_followers" => "true" +      }) + +      user = Repo.get!(User, user.id) +      assert user.info.hide_followers == true + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/account/update_profile.json", %{ +          "hide_followers" => "false" +        }) + +      user = Repo.get!(User, user.id) +      assert user.info.hide_followers == false +      assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user}) +    end + +    test "it sets and un-sets show_role", %{conn: conn} do +      user = insert(:user) + +      conn +      |> assign(:user, user) +      |> post("/api/account/update_profile.json", %{ +        "show_role" => "true" +      }) + +      user = Repo.get!(User, user.id) +      assert user.info.show_role == true + +      conn = +        conn +        |> assign(:user, user) +        |> post("/api/account/update_profile.json", %{ +          "show_role" => "false" +        }) + +      user = Repo.get!(User, user.id) +      assert user.info.show_role == false +      assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user}) +    end +      test "it locks an account", %{conn: conn} do        user = insert(:user) @@ -1136,7 +1742,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do          })        assert json_response(conn, 200) == %{"status" => "success"} -      fetched_user = Repo.get(User, current_user.id) +      fetched_user = User.get_by_id(current_user.id)        assert Pbkdf2.checkpw("newpass", fetched_user.password_hash) == true      end    end @@ -1177,8 +1783,8 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        {:ok, _activity} = ActivityPub.follow(other_user, user) -      user = Repo.get(User, user.id) -      other_user = Repo.get(User, other_user.id) +      user = User.get_by_id(user.id) +      other_user = User.get_by_id(other_user.id)        assert User.following?(other_user, user) == false @@ -1190,6 +1796,24 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        assert [relationship] = json_response(conn, 200)        assert other_user.id == relationship["id"]      end + +    test "requires 'read' permission", %{conn: conn} do +      token1 = insert(:oauth_token, scopes: ["write"]) +      token2 = insert(:oauth_token, scopes: ["read"]) + +      for token <- [token1, token2] do +        conn = +          conn +          |> put_req_header("authorization", "Bearer #{token.token}") +          |> get("/api/pleroma/friend_requests") + +        if token == token1 do +          assert %{"error" => "Insufficient permissions: read."} == json_response(conn, 403) +        else +          assert json_response(conn, 200) +        end +      end +    end    end    describe "POST /api/pleroma/friendships/approve" do @@ -1199,15 +1823,15 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        {:ok, _activity} = ActivityPub.follow(other_user, user) -      user = Repo.get(User, user.id) -      other_user = Repo.get(User, other_user.id) +      user = User.get_by_id(user.id) +      other_user = User.get_by_id(other_user.id)        assert User.following?(other_user, user) == false        conn =          build_conn()          |> assign(:user, user) -        |> post("/api/pleroma/friendships/approve", %{"user_id" => to_string(other_user.id)}) +        |> post("/api/pleroma/friendships/approve", %{"user_id" => other_user.id})        assert relationship = json_response(conn, 200)        assert other_user.id == relationship["id"] @@ -1222,15 +1846,15 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        {:ok, _activity} = ActivityPub.follow(other_user, user) -      user = Repo.get(User, user.id) -      other_user = Repo.get(User, other_user.id) +      user = User.get_by_id(user.id) +      other_user = User.get_by_id(other_user.id)        assert User.following?(other_user, user) == false        conn =          build_conn()          |> assign(:user, user) -        |> post("/api/pleroma/friendships/deny", %{"user_id" => to_string(other_user.id)}) +        |> post("/api/pleroma/friendships/deny", %{"user_id" => other_user.id})        assert relationship = json_response(conn, 200)        assert other_user.id == relationship["id"] @@ -1241,16 +1865,205 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do    describe "GET /api/pleroma/search_user" do      test "it returns users, ordered by similarity", %{conn: conn} do        user = insert(:user, %{name: "eal"}) -      user_two = insert(:user, %{name: "ean"}) -      user_three = insert(:user, %{name: "ebn"}) +      user_two = insert(:user, %{name: "eal me"}) +      _user_three = insert(:user, %{name: "zzz"}) + +      resp = +        conn +        |> get(twitter_api_search__path(conn, :search_user), query: "eal me") +        |> json_response(200) + +      assert length(resp) == 2 +      assert [user_two.id, user.id] == Enum.map(resp, fn %{"id" => id} -> id end) +    end +  end + +  describe "POST /api/media/upload" do +    setup context do +      Pleroma.DataCase.ensure_local_uploader(context) +    end + +    test "it performs the upload and sets `data[actor]` with AP id of uploader user", %{ +      conn: conn +    } do +      user = insert(:user) + +      upload_filename = "test/fixtures/image_tmp.jpg" +      File.cp!("test/fixtures/image.jpg", upload_filename) + +      file = %Plug.Upload{ +        content_type: "image/jpg", +        path: Path.absname(upload_filename), +        filename: "image.jpg" +      } + +      response = +        conn +        |> assign(:user, user) +        |> put_req_header("content-type", "application/octet-stream") +        |> post("/api/media/upload", %{ +          "media" => file +        }) +        |> json_response(:ok) + +      assert response["media_id"] +      object = Repo.get(Object, response["media_id"]) +      assert object +      assert object.data["actor"] == User.ap_id(user) +    end +  end + +  describe "POST /api/media/metadata/create" do +    setup do +      object = insert(:note) +      user = User.get_by_ap_id(object.data["actor"]) +      %{object: object, user: user} +    end + +    test "it returns :forbidden status on attempt to modify someone else's upload", %{ +      conn: conn, +      object: object +    } do +      initial_description = object.data["name"] +      another_user = insert(:user) + +      conn +      |> assign(:user, another_user) +      |> post("/api/media/metadata/create", %{"media_id" => object.id}) +      |> json_response(:forbidden) + +      object = Repo.get(Object, object.id) +      assert object.data["name"] == initial_description +    end + +    test "it updates `data[name]` of referenced Object with provided value", %{ +      conn: conn, +      object: object, +      user: user +    } do +      description = "Informative description of the image. Initial value: #{object.data["name"]}}" + +      conn +      |> assign(:user, user) +      |> post("/api/media/metadata/create", %{ +        "media_id" => object.id, +        "alt_text" => %{"text" => description} +      }) +      |> json_response(:no_content) + +      object = Repo.get(Object, object.id) +      assert object.data["name"] == description +    end +  end + +  describe "POST /api/statuses/user_timeline.json?user_id=:user_id&pinned=true" do +    test "it returns a list of pinned statuses", %{conn: conn} do +      Pleroma.Config.put([:instance, :max_pinned_statuses], 1) + +      user = insert(:user, %{name: "egor"}) +      {:ok, %{id: activity_id}} = CommonAPI.post(user, %{"status" => "HI!!!"}) +      {:ok, _} = CommonAPI.pin(activity_id, user)        resp =          conn -        |> get(twitter_api_search__path(conn, :search_user), query: "eal") +        |> get("/api/statuses/user_timeline.json", %{user_id: user.id, pinned: true})          |> json_response(200) -      assert length(resp) == 3 -      assert [user.id, user_two.id, user_three.id] == Enum.map(resp, fn %{"id" => id} -> id end) +      assert length(resp) == 1 +      assert [%{"id" => ^activity_id, "pinned" => true}] = resp +    end +  end + +  describe "POST /api/statuses/pin/:id" do +    setup do +      Pleroma.Config.put([:instance, :max_pinned_statuses], 1) +      [user: insert(:user)] +    end + +    test "without valid credentials", %{conn: conn} do +      note_activity = insert(:note_activity) +      conn = post(conn, "/api/statuses/pin/#{note_activity.id}.json") +      assert json_response(conn, 403) == %{"error" => "Invalid credentials."} +    end + +    test "with credentials", %{conn: conn, user: user} do +      {:ok, activity} = CommonAPI.post(user, %{"status" => "test!"}) + +      request_path = "/api/statuses/pin/#{activity.id}.json" + +      response = +        conn +        |> with_credentials(user.nickname, "test") +        |> post(request_path) + +      user = refresh_record(user) + +      assert json_response(response, 200) == +               ActivityView.render("activity.json", %{user: user, for: user, activity: activity}) +    end +  end + +  describe "POST /api/statuses/unpin/:id" do +    setup do +      Pleroma.Config.put([:instance, :max_pinned_statuses], 1) +      [user: insert(:user)] +    end + +    test "without valid credentials", %{conn: conn} do +      note_activity = insert(:note_activity) +      conn = post(conn, "/api/statuses/unpin/#{note_activity.id}.json") +      assert json_response(conn, 403) == %{"error" => "Invalid credentials."} +    end + +    test "with credentials", %{conn: conn, user: user} do +      {:ok, activity} = CommonAPI.post(user, %{"status" => "test!"}) +      {:ok, activity} = CommonAPI.pin(activity.id, user) + +      request_path = "/api/statuses/unpin/#{activity.id}.json" + +      response = +        conn +        |> with_credentials(user.nickname, "test") +        |> post(request_path) + +      user = refresh_record(user) + +      assert json_response(response, 200) == +               ActivityView.render("activity.json", %{user: user, for: user, activity: activity}) +    end +  end + +  describe "GET /api/oauth_tokens" do +    setup do +      token = insert(:oauth_token) |> Repo.preload(:user) + +      %{token: token} +    end + +    test "renders list", %{token: token} do +      response = +        build_conn() +        |> assign(:user, token.user) +        |> get("/api/oauth_tokens") + +      keys = +        json_response(response, 200) +        |> hd() +        |> Map.keys() + +      assert keys -- ["id", "app_name", "valid_until"] == [] +    end + +    test "revoke token", %{token: token} do +      response = +        build_conn() +        |> assign(:user, token.user) +        |> delete("/api/oauth_tokens/#{token.id}") + +      tokens = Token.get_user_tokens(token.user) + +      assert tokens == [] +      assert response.status == 201      end    end  end diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs index bc53fe68a..5bea1037a 100644 --- a/test/web/twitter_api/twitter_api_test.exs +++ b/test/web/twitter_api/twitter_api_test.exs @@ -1,16 +1,29 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only +  defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do    use Pleroma.DataCase -  alias Pleroma.Builders.UserBuilder -  alias Pleroma.Web.TwitterAPI.{TwitterAPI, UserView} -  alias Pleroma.{Activity, User, Object, Repo, UserInviteToken} +  alias Pleroma.Activity +  alias Pleroma.Object +  alias Pleroma.Repo +  alias Pleroma.User +  alias Pleroma.UserInviteToken    alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.TwitterAPI.ActivityView +  alias Pleroma.Web.TwitterAPI.TwitterAPI +  alias Pleroma.Web.TwitterAPI.UserView    import Pleroma.Factory +  setup_all do +    Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) +    :ok +  end +    test "create a status" do      user = insert(:user) -    _mentioned_user = insert(:user, %{nickname: "shp", ap_id: "shp"}) +    mentioned_user = insert(:user, %{nickname: "shp", ap_id: "shp"})      object_data = %{        "type" => "Image", @@ -36,7 +49,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do      object = Object.normalize(activity.data["object"])      expected_text = -      "Hello again, <span><a class='mention' href='shp'>@<span>shp</span></a></span>.<script></script><br>This is on another :moominmamma: line. <a href='http://localhost:4001/tag/2hu' rel='tag'>#2hu</a> <a href='http://localhost:4001/tag/epic' rel='tag'>#epic</a> <a href='http://localhost:4001/tag/phantasmagoric' rel='tag'>#phantasmagoric</a><br><a href=\"http://example.org/image.jpg\" class='attachment'>image.jpg</a>" +      "Hello again, <span class='h-card'><a data-user='#{mentioned_user.id}' class='u-url mention' href='shp'>@<span>shp</span></a></span>.<script></script><br>This is on another :moominmamma: line. <a class='hashtag' data-tag='2hu' href='http://localhost:4001/tag/2hu' rel='tag'>#2hu</a> <a class='hashtag' data-tag='epic' href='http://localhost:4001/tag/epic' rel='tag'>#epic</a> <a class='hashtag' data-tag='phantasmagoric' href='http://localhost:4001/tag/phantasmagoric' rel='tag'>#phantasmagoric</a><br><a href=\"http://example.org/image.jpg\" class='attachment'>image.jpg</a>"      assert get_in(object.data, ["content"]) == expected_text      assert get_in(object.data, ["type"]) == "Note" @@ -94,7 +107,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do      assert get_in(reply_object.data, ["context"]) == get_in(object.data, ["context"])      assert get_in(reply_object.data, ["inReplyTo"]) == get_in(activity.data, ["object"]) -    assert get_in(reply_object.data, ["inReplyToStatusId"]) == activity.id +    assert Activity.get_in_reply_to_activity(reply).id == activity.id    end    test "Follow another user using user_id" do @@ -184,25 +197,42 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do    end    test "upload a file" do +    user = insert(:user) +      file = %Plug.Upload{        content_type: "image/jpg",        path: Path.absname("test/fixtures/image.jpg"),        filename: "an_image.jpg"      } -    response = TwitterAPI.upload(file) +    response = TwitterAPI.upload(file, user)      assert is_binary(response)    end    test "it favorites a status, returns the updated activity" do      user = insert(:user) +    other_user = insert(:user)      note_activity = insert(:note_activity)      {:ok, status} = TwitterAPI.fav(user, note_activity.id)      updated_activity = Activity.get_by_ap_id(note_activity.data["id"]) +    assert ActivityView.render("activity.json", %{activity: updated_activity})["fave_num"] == 1 + +    object = Object.normalize(note_activity.data["object"]) + +    assert object.data["like_count"] == 1      assert status == updated_activity + +    {:ok, _status} = TwitterAPI.fav(other_user, note_activity.id) + +    object = Object.normalize(note_activity.data["object"]) + +    assert object.data["like_count"] == 2 + +    updated_activity = Activity.get_by_ap_id(note_activity.data["id"]) +    assert ActivityView.render("activity.json", %{activity: updated_activity})["fave_num"] == 2    end    test "it unfavorites a status, returns the updated activity" do @@ -246,19 +276,69 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do        "nickname" => "lain",        "email" => "lain@wired.jp",        "fullname" => "lain iwakura", -      "bio" => "close the world.",        "password" => "bear",        "confirm" => "bear"      }      {:ok, user} = TwitterAPI.register_user(data) -    fetched_user = Repo.get_by(User, nickname: "lain") +    fetched_user = User.get_by_nickname("lain")      assert UserView.render("show.json", %{user: user}) ==               UserView.render("show.json", %{user: fetched_user})    end +  test "it registers a new user with empty string in bio and returns the user." do +    data = %{ +      "nickname" => "lain", +      "email" => "lain@wired.jp", +      "fullname" => "lain iwakura", +      "bio" => "", +      "password" => "bear", +      "confirm" => "bear" +    } + +    {:ok, user} = TwitterAPI.register_user(data) + +    fetched_user = User.get_by_nickname("lain") + +    assert UserView.render("show.json", %{user: user}) == +             UserView.render("show.json", %{user: fetched_user}) +  end + +  test "it sends confirmation email if :account_activation_required is specified in instance config" do +    setting = Pleroma.Config.get([:instance, :account_activation_required]) + +    unless setting do +      Pleroma.Config.put([:instance, :account_activation_required], true) +      on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end) +    end + +    data = %{ +      "nickname" => "lain", +      "email" => "lain@wired.jp", +      "fullname" => "lain iwakura", +      "bio" => "", +      "password" => "bear", +      "confirm" => "bear" +    } + +    {:ok, user} = TwitterAPI.register_user(data) + +    assert user.info.confirmation_pending + +    email = Pleroma.Emails.UserEmail.account_confirmation_email(user) + +    notify_email = Pleroma.Config.get([:instance, :notify_email]) +    instance_name = Pleroma.Config.get([:instance, :name]) + +    Swoosh.TestAssertions.assert_email_sent( +      from: {instance_name, notify_email}, +      to: {user.name, user.email}, +      html_body: email.html_body +    ) +  end +    test "it registers a new user and parses mentions in the bio" do      data1 = %{        "nickname" => "john", @@ -283,73 +363,318 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do      {:ok, user2} = TwitterAPI.register_user(data2)      expected_text = -      "<span><a class='mention' href='#{user1.ap_id}'>@<span>john</span></a></span> test" +      "<span class='h-card'><a data-user='#{user1.id}' class='u-url mention' href='#{user1.ap_id}'>@<span>john</span></a></span> test"      assert user2.bio == expected_text    end -  @moduletag skip: "needs 'registrations_open: false' in config" -  test "it registers a new user via invite token and returns the user." do -    {:ok, token} = UserInviteToken.create_token() +  describe "register with one time token" do +    setup do +      setting = Pleroma.Config.get([:instance, :registrations_open]) -    data = %{ -      "nickname" => "vinny", -      "email" => "pasta@pizza.vs", -      "fullname" => "Vinny Vinesauce", -      "bio" => "streamer", -      "password" => "hiptofbees", -      "confirm" => "hiptofbees", -      "token" => token.token -    } +      if setting do +        Pleroma.Config.put([:instance, :registrations_open], false) +        on_exit(fn -> Pleroma.Config.put([:instance, :registrations_open], setting) end) +      end -    {:ok, user} = TwitterAPI.register_user(data) +      :ok +    end -    fetched_user = Repo.get_by(User, nickname: "vinny") -    token = Repo.get_by(UserInviteToken, token: token.token) +    test "returns user on success" do +      {:ok, invite} = UserInviteToken.create_invite() -    assert token.used == true +      data = %{ +        "nickname" => "vinny", +        "email" => "pasta@pizza.vs", +        "fullname" => "Vinny Vinesauce", +        "bio" => "streamer", +        "password" => "hiptofbees", +        "confirm" => "hiptofbees", +        "token" => invite.token +      } -    assert UserView.render("show.json", %{user: user}) == -             UserView.render("show.json", %{user: fetched_user}) +      {:ok, user} = TwitterAPI.register_user(data) + +      fetched_user = User.get_by_nickname("vinny") +      invite = Repo.get_by(UserInviteToken, token: invite.token) + +      assert invite.used == true + +      assert UserView.render("show.json", %{user: user}) == +               UserView.render("show.json", %{user: fetched_user}) +    end + +    test "returns error on invalid token" do +      data = %{ +        "nickname" => "GrimReaper", +        "email" => "death@reapers.afterlife", +        "fullname" => "Reaper Grim", +        "bio" => "Your time has come", +        "password" => "scythe", +        "confirm" => "scythe", +        "token" => "DudeLetMeInImAFairy" +      } + +      {:error, msg} = TwitterAPI.register_user(data) + +      assert msg == "Invalid token" +      refute User.get_by_nickname("GrimReaper") +    end + +    test "returns error on expired token" do +      {:ok, invite} = UserInviteToken.create_invite() +      UserInviteToken.update_invite!(invite, used: true) + +      data = %{ +        "nickname" => "GrimReaper", +        "email" => "death@reapers.afterlife", +        "fullname" => "Reaper Grim", +        "bio" => "Your time has come", +        "password" => "scythe", +        "confirm" => "scythe", +        "token" => invite.token +      } + +      {:error, msg} = TwitterAPI.register_user(data) + +      assert msg == "Expired token" +      refute User.get_by_nickname("GrimReaper") +    end    end -  @moduletag skip: "needs 'registrations_open: false' in config" -  test "it returns an error if invalid token submitted" do -    data = %{ -      "nickname" => "GrimReaper", -      "email" => "death@reapers.afterlife", -      "fullname" => "Reaper Grim", -      "bio" => "Your time has come", -      "password" => "scythe", -      "confirm" => "scythe", -      "token" => "DudeLetMeInImAFairy" -    } +  describe "registers with date limited token" do +    setup do +      setting = Pleroma.Config.get([:instance, :registrations_open]) + +      if setting do +        Pleroma.Config.put([:instance, :registrations_open], false) +        on_exit(fn -> Pleroma.Config.put([:instance, :registrations_open], setting) end) +      end + +      data = %{ +        "nickname" => "vinny", +        "email" => "pasta@pizza.vs", +        "fullname" => "Vinny Vinesauce", +        "bio" => "streamer", +        "password" => "hiptofbees", +        "confirm" => "hiptofbees" +      } + +      check_fn = fn invite -> +        data = Map.put(data, "token", invite.token) +        {:ok, user} = TwitterAPI.register_user(data) +        fetched_user = User.get_by_nickname("vinny") + +        assert UserView.render("show.json", %{user: user}) == +                 UserView.render("show.json", %{user: fetched_user}) +      end + +      {:ok, data: data, check_fn: check_fn} +    end + +    test "returns user on success", %{check_fn: check_fn} do +      {:ok, invite} = UserInviteToken.create_invite(%{expires_at: Date.utc_today()}) + +      check_fn.(invite) + +      invite = Repo.get_by(UserInviteToken, token: invite.token) + +      refute invite.used +    end + +    test "returns user on token which expired tomorrow", %{check_fn: check_fn} do +      {:ok, invite} = UserInviteToken.create_invite(%{expires_at: Date.add(Date.utc_today(), 1)}) + +      check_fn.(invite) + +      invite = Repo.get_by(UserInviteToken, token: invite.token) + +      refute invite.used +    end + +    test "returns an error on overdue date", %{data: data} do +      {:ok, invite} = UserInviteToken.create_invite(%{expires_at: Date.add(Date.utc_today(), -1)}) -    {:error, msg} = TwitterAPI.register_user(data) +      data = Map.put(data, "token", invite.token) -    assert msg == "Invalid token" -    refute Repo.get_by(User, nickname: "GrimReaper") +      {:error, msg} = TwitterAPI.register_user(data) + +      assert msg == "Expired token" +      refute User.get_by_nickname("vinny") +      invite = Repo.get_by(UserInviteToken, token: invite.token) + +      refute invite.used +    end    end -  @moduletag skip: "needs 'registrations_open: false' in config" -  test "it returns an error if expired token submitted" do -    {:ok, token} = UserInviteToken.create_token() -    UserInviteToken.mark_as_used(token.token) +  describe "registers with reusable token" do +    setup do +      setting = Pleroma.Config.get([:instance, :registrations_open]) -    data = %{ -      "nickname" => "GrimReaper", -      "email" => "death@reapers.afterlife", -      "fullname" => "Reaper Grim", -      "bio" => "Your time has come", -      "password" => "scythe", -      "confirm" => "scythe", -      "token" => token.token -    } +      if setting do +        Pleroma.Config.put([:instance, :registrations_open], false) +        on_exit(fn -> Pleroma.Config.put([:instance, :registrations_open], setting) end) +      end + +      :ok +    end + +    test "returns user on success, after him registration fails" do +      {:ok, invite} = UserInviteToken.create_invite(%{max_use: 100}) + +      UserInviteToken.update_invite!(invite, uses: 99) + +      data = %{ +        "nickname" => "vinny", +        "email" => "pasta@pizza.vs", +        "fullname" => "Vinny Vinesauce", +        "bio" => "streamer", +        "password" => "hiptofbees", +        "confirm" => "hiptofbees", +        "token" => invite.token +      } + +      {:ok, user} = TwitterAPI.register_user(data) +      fetched_user = User.get_by_nickname("vinny") +      invite = Repo.get_by(UserInviteToken, token: invite.token) + +      assert invite.used == true + +      assert UserView.render("show.json", %{user: user}) == +               UserView.render("show.json", %{user: fetched_user}) + +      data = %{ +        "nickname" => "GrimReaper", +        "email" => "death@reapers.afterlife", +        "fullname" => "Reaper Grim", +        "bio" => "Your time has come", +        "password" => "scythe", +        "confirm" => "scythe", +        "token" => invite.token +      } + +      {:error, msg} = TwitterAPI.register_user(data) -    {:error, msg} = TwitterAPI.register_user(data) +      assert msg == "Expired token" +      refute User.get_by_nickname("GrimReaper") +    end +  end + +  describe "registers with reusable date limited token" do +    setup do +      setting = Pleroma.Config.get([:instance, :registrations_open]) + +      if setting do +        Pleroma.Config.put([:instance, :registrations_open], false) +        on_exit(fn -> Pleroma.Config.put([:instance, :registrations_open], setting) end) +      end + +      :ok +    end + +    test "returns user on success" do +      {:ok, invite} = UserInviteToken.create_invite(%{expires_at: Date.utc_today(), max_use: 100}) + +      data = %{ +        "nickname" => "vinny", +        "email" => "pasta@pizza.vs", +        "fullname" => "Vinny Vinesauce", +        "bio" => "streamer", +        "password" => "hiptofbees", +        "confirm" => "hiptofbees", +        "token" => invite.token +      } + +      {:ok, user} = TwitterAPI.register_user(data) +      fetched_user = User.get_by_nickname("vinny") +      invite = Repo.get_by(UserInviteToken, token: invite.token) + +      refute invite.used + +      assert UserView.render("show.json", %{user: user}) == +               UserView.render("show.json", %{user: fetched_user}) +    end + +    test "error after max uses" do +      {:ok, invite} = UserInviteToken.create_invite(%{expires_at: Date.utc_today(), max_use: 100}) + +      UserInviteToken.update_invite!(invite, uses: 99) + +      data = %{ +        "nickname" => "vinny", +        "email" => "pasta@pizza.vs", +        "fullname" => "Vinny Vinesauce", +        "bio" => "streamer", +        "password" => "hiptofbees", +        "confirm" => "hiptofbees", +        "token" => invite.token +      } + +      {:ok, user} = TwitterAPI.register_user(data) +      fetched_user = User.get_by_nickname("vinny") +      invite = Repo.get_by(UserInviteToken, token: invite.token) +      assert invite.used == true + +      assert UserView.render("show.json", %{user: user}) == +               UserView.render("show.json", %{user: fetched_user}) + +      data = %{ +        "nickname" => "GrimReaper", +        "email" => "death@reapers.afterlife", +        "fullname" => "Reaper Grim", +        "bio" => "Your time has come", +        "password" => "scythe", +        "confirm" => "scythe", +        "token" => invite.token +      } + +      {:error, msg} = TwitterAPI.register_user(data) + +      assert msg == "Expired token" +      refute User.get_by_nickname("GrimReaper") +    end + +    test "returns error on overdue date" do +      {:ok, invite} = +        UserInviteToken.create_invite(%{expires_at: Date.add(Date.utc_today(), -1), max_use: 100}) + +      data = %{ +        "nickname" => "GrimReaper", +        "email" => "death@reapers.afterlife", +        "fullname" => "Reaper Grim", +        "bio" => "Your time has come", +        "password" => "scythe", +        "confirm" => "scythe", +        "token" => invite.token +      } -    assert msg == "Expired token" -    refute Repo.get_by(User, nickname: "GrimReaper") +      {:error, msg} = TwitterAPI.register_user(data) + +      assert msg == "Expired token" +      refute User.get_by_nickname("GrimReaper") +    end + +    test "returns error on with overdue date and after max" do +      {:ok, invite} = +        UserInviteToken.create_invite(%{expires_at: Date.add(Date.utc_today(), -1), max_use: 100}) + +      UserInviteToken.update_invite!(invite, uses: 100) + +      data = %{ +        "nickname" => "GrimReaper", +        "email" => "death@reapers.afterlife", +        "fullname" => "Reaper Grim", +        "bio" => "Your time has come", +        "password" => "scythe", +        "confirm" => "scythe", +        "token" => invite.token +      } + +      {:error, msg} = TwitterAPI.register_user(data) + +      assert msg == "Expired token" +      refute User.get_by_nickname("GrimReaper") +    end    end    test "it returns the error on registration problems" do @@ -364,7 +689,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do      {:error, error_object} = TwitterAPI.register_user(data)      assert is_binary(error_object[:error]) -    refute Repo.get_by(User, nickname: "lain") +    refute User.get_by_nickname("lain")    end    test "it assigns an integer conversation_id" do @@ -380,22 +705,6 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do      :ok    end -  describe "context_to_conversation_id" do -    test "creates a mapping object" do -      conversation_id = TwitterAPI.context_to_conversation_id("random context") -      object = Object.get_by_ap_id("random context") - -      assert conversation_id == object.id -    end - -    test "returns an existing mapping for an existing object" do -      {:ok, object} = Object.context_mapping("random context") |> Repo.insert() -      conversation_id = TwitterAPI.context_to_conversation_id("random context") - -      assert conversation_id == object.id -    end -  end -    describe "fetching a user by uri" do      test "fetches a user by uri" do        id = "https://mastodon.social/users/lambadalambda" @@ -406,7 +715,8 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do        assert represented["id"] == UserView.render("show.json", %{user: remote, for: user})["id"]        # Also fetches the feed. -      # assert Activity.get_create_activity_by_object_ap_id("tag:mastodon.social,2017-04-05:objectId=1641750:objectType=Status") +      # assert Activity.get_create_by_object_ap_id("tag:mastodon.social,2017-04-05:objectId=1641750:objectType=Status") +      # credo:disable-for-previous-line Credo.Check.Readability.MaxLineLength      end    end  end diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs new file mode 100644 index 000000000..c58b49ea4 --- /dev/null +++ b/test/web/twitter_api/util_controller_test.exs @@ -0,0 +1,248 @@ +defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do +  use Pleroma.Web.ConnCase + +  alias Pleroma.Notification +  alias Pleroma.Repo +  alias Pleroma.User +  alias Pleroma.Web.CommonAPI +  import Pleroma.Factory + +  setup do +    Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end) +    :ok +  end + +  describe "POST /api/pleroma/follow_import" do +    test "it returns HTTP 200", %{conn: conn} do +      user1 = insert(:user) +      user2 = insert(:user) + +      response = +        conn +        |> assign(:user, user1) +        |> post("/api/pleroma/follow_import", %{"list" => "#{user2.ap_id}"}) +        |> json_response(:ok) + +      assert response == "job started" +    end + +    test "it imports new-style mastodon follow lists", %{conn: conn} do +      user1 = insert(:user) +      user2 = insert(:user) + +      response = +        conn +        |> assign(:user, user1) +        |> post("/api/pleroma/follow_import", %{ +          "list" => "Account address,Show boosts\n#{user2.ap_id},true" +        }) +        |> json_response(:ok) + +      assert response == "job started" +    end + +    test "requires 'follow' permission", %{conn: conn} do +      token1 = insert(:oauth_token, scopes: ["read", "write"]) +      token2 = insert(:oauth_token, scopes: ["follow"]) +      another_user = insert(:user) + +      for token <- [token1, token2] do +        conn = +          conn +          |> put_req_header("authorization", "Bearer #{token.token}") +          |> post("/api/pleroma/follow_import", %{"list" => "#{another_user.ap_id}"}) + +        if token == token1 do +          assert %{"error" => "Insufficient permissions: follow."} == json_response(conn, 403) +        else +          assert json_response(conn, 200) +        end +      end +    end +  end + +  describe "POST /api/pleroma/blocks_import" do +    test "it returns HTTP 200", %{conn: conn} do +      user1 = insert(:user) +      user2 = insert(:user) + +      response = +        conn +        |> assign(:user, user1) +        |> post("/api/pleroma/blocks_import", %{"list" => "#{user2.ap_id}"}) +        |> json_response(:ok) + +      assert response == "job started" +    end +  end + +  describe "POST /api/pleroma/notifications/read" do +    test "it marks a single notification as read", %{conn: conn} do +      user1 = insert(:user) +      user2 = insert(:user) +      {:ok, activity1} = CommonAPI.post(user2, %{"status" => "hi @#{user1.nickname}"}) +      {:ok, activity2} = CommonAPI.post(user2, %{"status" => "hi @#{user1.nickname}"}) +      {:ok, [notification1]} = Notification.create_notifications(activity1) +      {:ok, [notification2]} = Notification.create_notifications(activity2) + +      conn +      |> assign(:user, user1) +      |> post("/api/pleroma/notifications/read", %{"id" => "#{notification1.id}"}) +      |> json_response(:ok) + +      assert Repo.get(Notification, notification1.id).seen +      refute Repo.get(Notification, notification2.id).seen +    end +  end + +  describe "PUT /api/pleroma/notification_settings" do +    test "it updates notification settings", %{conn: conn} do +      user = insert(:user) + +      conn +      |> assign(:user, user) +      |> put("/api/pleroma/notification_settings", %{ +        "remote" => false, +        "followers" => false, +        "bar" => 1 +      }) +      |> json_response(:ok) + +      user = Repo.get(User, user.id) + +      assert %{"remote" => false, "local" => true, "followers" => false, "follows" => true} == +               user.info.notification_settings +    end +  end + +  describe "GET /api/statusnet/config.json" do +    test "returns the state of safe_dm_mentions flag", %{conn: conn} do +      option = Pleroma.Config.get([:instance, :safe_dm_mentions]) +      Pleroma.Config.put([:instance, :safe_dm_mentions], true) + +      response = +        conn +        |> get("/api/statusnet/config.json") +        |> json_response(:ok) + +      assert response["site"]["safeDMMentionsEnabled"] == "1" + +      Pleroma.Config.put([:instance, :safe_dm_mentions], false) + +      response = +        conn +        |> get("/api/statusnet/config.json") +        |> json_response(:ok) + +      assert response["site"]["safeDMMentionsEnabled"] == "0" + +      Pleroma.Config.put([:instance, :safe_dm_mentions], option) +    end + +    test "it returns the managed config", %{conn: conn} do +      Pleroma.Config.put([:instance, :managed_config], false) +      Pleroma.Config.put([:fe], theme: "rei-ayanami-towel") + +      response = +        conn +        |> get("/api/statusnet/config.json") +        |> json_response(:ok) + +      refute response["site"]["pleromafe"] + +      Pleroma.Config.put([:instance, :managed_config], true) + +      response = +        conn +        |> get("/api/statusnet/config.json") +        |> json_response(:ok) + +      assert response["site"]["pleromafe"] +    end + +    test "if :pleroma, :fe is false, it returns the new style config settings", %{conn: conn} do +      Pleroma.Config.put([:instance, :managed_config], true) +      Pleroma.Config.put([:fe, :theme], "rei-ayanami-towel") +      Pleroma.Config.put([:frontend_configurations, :pleroma_fe], %{theme: "asuka-hospital"}) + +      response = +        conn +        |> get("/api/statusnet/config.json") +        |> json_response(:ok) + +      assert response["site"]["pleromafe"]["theme"] == "rei-ayanami-towel" + +      Pleroma.Config.put([:fe], false) + +      response = +        conn +        |> get("/api/statusnet/config.json") +        |> json_response(:ok) + +      assert response["site"]["pleromafe"]["theme"] == "asuka-hospital" +    end +  end + +  describe "GET /api/pleroma/frontend_configurations" do +    test "returns everything in :pleroma, :frontend_configurations", %{conn: conn} do +      config = [ +        frontend_a: %{ +          x: 1, +          y: 2 +        }, +        frontend_b: %{ +          z: 3 +        } +      ] + +      Pleroma.Config.put(:frontend_configurations, config) + +      response = +        conn +        |> get("/api/pleroma/frontend_configurations") +        |> json_response(:ok) + +      assert response == Jason.encode!(config |> Enum.into(%{})) |> Jason.decode!() +    end +  end + +  describe "/api/pleroma/emoji" do +    test "returns json with custom emoji with tags", %{conn: conn} do +      emoji = +        conn +        |> get("/api/pleroma/emoji") +        |> json_response(200) + +      assert Enum.all?(emoji, fn +               {_key, +                %{ +                  "image_url" => url, +                  "tags" => tags +                }} -> +                 is_binary(url) and is_list(tags) +             end) +    end +  end + +  describe "GET /ostatus_subscribe?acct=...." do +    test "adds status to pleroma instance if the `acct` is a status", %{conn: conn} do +      conn = +        get( +          conn, +          "/ostatus_subscribe?acct=https://mastodon.social/users/emelie/statuses/101849165031453009" +        ) + +      assert redirected_to(conn) =~ "/notice/" +    end + +    test "show follow account page if the `acct` is a account link", %{conn: conn} do +      response = +        get( +          conn, +          "/ostatus_subscribe?acct=https://mastodon.social/users/emelie" +        ) + +      assert html_response(response, 200) =~ "Log in to follow" +    end +  end +end diff --git a/test/web/twitter_api/views/activity_view_test.exs b/test/web/twitter_api/views/activity_view_test.exs index f4741cf24..7ef0270cc 100644 --- a/test/web/twitter_api/views/activity_view_test.exs +++ b/test/web/twitter_api/views/activity_view_test.exs @@ -1,19 +1,126 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only +  defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do    use Pleroma.DataCase +  alias Pleroma.Activity +  alias Pleroma.Object +  alias Pleroma.Repo +  alias Pleroma.User +  alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.CommonAPI    alias Pleroma.Web.CommonAPI.Utils    alias Pleroma.Web.TwitterAPI.ActivityView    alias Pleroma.Web.TwitterAPI.UserView -  alias Pleroma.Web.TwitterAPI.TwitterAPI -  alias Pleroma.Repo -  alias Pleroma.{Activity, Object} -  alias Pleroma.User -  alias Pleroma.Web.ActivityPub.ActivityPub    import Pleroma.Factory +  import Tesla.Mock + +  setup do +    mock(fn env -> apply(HttpRequestMock, :request, [env]) end) +    :ok +  end +    import Mock +  test "returns a temporary ap_id based user for activities missing db users" do +    user = insert(:user) + +    {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!", "visibility" => "direct"}) + +    Repo.delete(user) +    Cachex.clear(:user_cache) + +    %{"user" => tw_user} = ActivityView.render("activity.json", activity: activity) + +    assert tw_user["screen_name"] == "erroruser@example.com" +    assert tw_user["name"] == user.ap_id +    assert tw_user["statusnet_profile_url"] == user.ap_id +  end + +  test "tries to get a user by nickname if fetching by ap_id doesn't work" do +    user = insert(:user) + +    {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!", "visibility" => "direct"}) + +    {:ok, user} = +      user +      |> Ecto.Changeset.change(%{ap_id: "#{user.ap_id}/extension/#{user.nickname}"}) +      |> Repo.update() + +    Cachex.clear(:user_cache) + +    result = ActivityView.render("activity.json", activity: activity) +    assert result["user"]["id"] == user.id +  end + +  test "tells if the message is muted for some reason" do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, user} = User.mute(user, other_user) + +    {:ok, activity} = CommonAPI.post(other_user, %{"status" => "test"}) +    status = ActivityView.render("activity.json", %{activity: activity}) + +    assert status["muted"] == false + +    status = ActivityView.render("activity.json", %{activity: activity, for: user}) + +    assert status["muted"] == true +  end + +  test "a create activity with a html status" do +    text = """ +    #Bike log - Commute Tuesday\nhttps://pla.bike/posts/20181211/\n#cycling #CHScycling #commute\nMVIMG_20181211_054020.jpg +    """ + +    {:ok, activity} = CommonAPI.post(insert(:user), %{"status" => text}) + +    result = ActivityView.render("activity.json", activity: activity) + +    assert result["statusnet_html"] == +             "<a class=\"hashtag\" data-tag=\"bike\" href=\"http://localhost:4001/tag/bike\" rel=\"tag\">#Bike</a> log - Commute Tuesday<br /><a href=\"https://pla.bike/posts/20181211/\">https://pla.bike/posts/20181211/</a><br /><a class=\"hashtag\" data-tag=\"cycling\" href=\"http://localhost:4001/tag/cycling\" rel=\"tag\">#cycling</a> <a class=\"hashtag\" data-tag=\"chscycling\" href=\"http://localhost:4001/tag/chscycling\" rel=\"tag\">#CHScycling</a> <a class=\"hashtag\" data-tag=\"commute\" href=\"http://localhost:4001/tag/commute\" rel=\"tag\">#commute</a><br />MVIMG_20181211_054020.jpg" + +    assert result["text"] == +             "#Bike log - Commute Tuesday\nhttps://pla.bike/posts/20181211/\n#cycling #CHScycling #commute\nMVIMG_20181211_054020.jpg" +  end + +  test "a create activity with a summary containing emoji" do +    {:ok, activity} = +      CommonAPI.post(insert(:user), %{ +        "spoiler_text" => ":woollysocks: meow", +        "status" => "." +      }) + +    result = ActivityView.render("activity.json", activity: activity) + +    expected = ":woollysocks: meow" + +    expected_html = +      "<img height=\"32px\" width=\"32px\" alt=\"woollysocks\" title=\"woollysocks\" src=\"http://localhost:4001/finmoji/128px/woollysocks-128.png\" /> meow" + +    assert result["summary"] == expected +    assert result["summary_html"] == expected_html +  end + +  test "a create activity with a summary containing invalid HTML" do +    {:ok, activity} = +      CommonAPI.post(insert(:user), %{ +        "spoiler_text" => "<span style=\"color: magenta; font-size: 32px;\">meow</span>", +        "status" => "." +      }) + +    result = ActivityView.render("activity.json", activity: activity) + +    expected = "meow" + +    assert result["summary"] == expected +    assert result["summary_html"] == expected +  end +    test "a create activity with a note" do      user = insert(:user)      other_user = insert(:user, %{nickname: "shp"}) @@ -23,7 +130,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do      result = ActivityView.render("activity.json", activity: activity) -    convo_id = TwitterAPI.context_to_conversation_id(object.data["context"]) +    convo_id = Utils.context_to_conversation_id(object.data["context"])      expected = %{        "activity_type" => "post", @@ -46,15 +153,21 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do        "possibly_sensitive" => false,        "repeat_num" => 0,        "repeated" => false, +      "pinned" => false,        "statusnet_conversation_id" => convo_id, +      "summary" => "", +      "summary_html" => "",        "statusnet_html" => -        "Hey <span><a href=\"#{other_user.ap_id}\">@<span>shp</span></a></span>!", +        "Hey <span class=\"h-card\"><a data-user=\"#{other_user.id}\" class=\"u-url mention\" href=\"#{ +          other_user.ap_id +        }\">@<span>shp</span></a></span>!",        "tags" => [],        "text" => "Hey @shp!",        "uri" => object.data["id"],        "user" => UserView.render("show.json", %{user: user}),        "visibility" => "direct", -      "summary" => nil +      "card" => nil, +      "muted" => false      }      assert result == expected @@ -66,12 +179,12 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do      {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!"})      object = Object.normalize(activity.data["object"]) -    convo_id = TwitterAPI.context_to_conversation_id(object.data["context"]) +    convo_id = Utils.context_to_conversation_id(object.data["context"])      mocks = [        { -        TwitterAPI, -        [], +        Utils, +        [:passthrough],          [context_to_conversation_id: fn _ -> false end]        },        { @@ -86,7 +199,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do        assert result["statusnet_conversation_id"] == convo_id        assert result["user"] -      refute called(TwitterAPI.context_to_conversation_id(:_)) +      refute called(Utils.context_to_conversation_id(:_))        refute called(User.get_cached_by_ap_id(user.ap_id))        refute called(User.get_cached_by_ap_id(other_user.ap_id))      end @@ -114,6 +227,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do      {:ok, like, _object} = CommonAPI.favorite(activity.id, other_user)      result = ActivityView.render("activity.json", activity: like) +    activity = Pleroma.Activity.get_by_ap_id(activity.data["id"])      expected = %{        "activity_type" => "like", @@ -123,6 +237,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do        "in_reply_to_status_id" => activity.id,        "is_local" => true,        "is_post_verb" => false, +      "favorited_status" => ActivityView.render("activity.json", activity: activity),        "statusnet_html" => "shp favorited a status.",        "text" => "shp favorited a status.",        "uri" => "tag:#{like.data["id"]}:objectType=Favourite", @@ -150,6 +265,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do        "in_reply_to_status_id" => nil,        "is_local" => true,        "is_post_verb" => false, +      "favorited_status" => nil,        "statusnet_html" => "shp favorited a status.",        "text" => "shp favorited a status.",        "uri" => "tag:#{like.data["id"]}:objectType=Favourite", @@ -166,9 +282,9 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do      {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!"})      {:ok, announce, object} = CommonAPI.repeat(activity.id, other_user) -    convo_id = TwitterAPI.context_to_conversation_id(object.data["context"]) +    convo_id = Utils.context_to_conversation_id(object.data["context"]) -    activity = Repo.get(Activity, activity.id) +    activity = Activity.get_by_id(activity.id)      result = ActivityView.render("activity.json", activity: announce) @@ -241,4 +357,18 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do      assert result == expected    end + +  test "a peertube video" do +    {:ok, object} = +      ActivityPub.fetch_object_from_id( +        "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3" +      ) + +    %Activity{} = activity = Activity.get_create_by_object_ap_id(object.data["id"]) + +    result = ActivityView.render("activity.json", activity: activity) + +    assert length(result["attachments"]) == 1 +    assert result["summary"] == "Friday Night" +  end  end diff --git a/test/web/twitter_api/views/notification_view_test.exs b/test/web/twitter_api/views/notification_view_test.exs index 79eafda7d..6baeeaf63 100644 --- a/test/web/twitter_api/views/notification_view_test.exs +++ b/test/web/twitter_api/views/notification_view_test.exs @@ -1,14 +1,18 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only +  defmodule Pleroma.Web.TwitterAPI.NotificationViewTest do    use Pleroma.DataCase -  alias Pleroma.{User, Notification} -  alias Pleroma.Web.TwitterAPI.TwitterAPI +  alias Pleroma.Notification +  alias Pleroma.User +  alias Pleroma.Web.ActivityPub.ActivityPub +  alias Pleroma.Web.CommonAPI.Utils +  alias Pleroma.Web.TwitterAPI.ActivityView    alias Pleroma.Web.TwitterAPI.NotificationView +  alias Pleroma.Web.TwitterAPI.TwitterAPI    alias Pleroma.Web.TwitterAPI.UserView -  alias Pleroma.Web.TwitterAPI.ActivityView -  alias Pleroma.Web.CommonAPI.Utils -  alias Pleroma.Web.ActivityPub.ActivityPub -  alias Pleroma.Builders.UserBuilder    import Pleroma.Factory @@ -67,7 +71,7 @@ defmodule Pleroma.Web.TwitterAPI.NotificationViewTest do      user = User.get_cached_by_ap_id(note_activity.data["actor"])      repeater = insert(:user) -    {:ok, activity} = TwitterAPI.repeat(repeater, note_activity.id) +    {:ok, _activity} = TwitterAPI.repeat(repeater, note_activity.id)      [notification] = Notification.for_user(user)      represented = %{ @@ -89,7 +93,7 @@ defmodule Pleroma.Web.TwitterAPI.NotificationViewTest do      user = User.get_cached_by_ap_id(note_activity.data["actor"])      liker = insert(:user) -    {:ok, activity} = TwitterAPI.fav(liker, note_activity.id) +    {:ok, _activity} = TwitterAPI.fav(liker, note_activity.id)      [notification] = Notification.for_user(user)      represented = %{ diff --git a/test/web/twitter_api/views/user_view_test.exs b/test/web/twitter_api/views/user_view_test.exs index e69ca24a9..0feaf4b64 100644 --- a/test/web/twitter_api/views/user_view_test.exs +++ b/test/web/twitter_api/views/user_view_test.exs @@ -1,10 +1,13 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only +  defmodule Pleroma.Web.TwitterAPI.UserViewTest do    use Pleroma.DataCase    alias Pleroma.User -  alias Pleroma.Web.TwitterAPI.UserView    alias Pleroma.Web.CommonAPI.Utils -  alias Pleroma.Builders.UserBuilder +  alias Pleroma.Web.TwitterAPI.UserView    import Pleroma.Factory @@ -27,7 +30,7 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do      assert represented["profile_image_url"] == image    end -  test "A user with emoji in username", %{user: user} do +  test "A user with emoji in username" do      expected =        "<img height=\"32px\" width=\"32px\" alt=\"karjalanpiirakka\" title=\"karjalanpiirakka\" src=\"/file.png\" /> man" @@ -87,7 +90,8 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do        "follows_you" => false,        "statusnet_blocking" => false,        "rights" => %{ -        "delete_others_notice" => false +        "delete_others_notice" => false, +        "admin" => false        },        "statusnet_profile_url" => user.ap_id,        "cover_photo" => banner, @@ -96,7 +100,13 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do        "locked" => false,        "default_scope" => "public",        "no_rich_text" => false, -      "fields" => [] +      "hide_follows" => false, +      "hide_followers" => false, +      "fields" => [], +      "pleroma" => %{ +        "confirmation_pending" => false, +        "tags" => [] +      }      }      assert represented == UserView.render("show.json", %{user: user}) @@ -128,7 +138,8 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do        "follows_you" => false,        "statusnet_blocking" => false,        "rights" => %{ -        "delete_others_notice" => false +        "delete_others_notice" => false, +        "admin" => false        },        "statusnet_profile_url" => user.ap_id,        "cover_photo" => banner, @@ -137,7 +148,13 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do        "locked" => false,        "default_scope" => "public",        "no_rich_text" => false, -      "fields" => [] +      "hide_follows" => false, +      "hide_followers" => false, +      "fields" => [], +      "pleroma" => %{ +        "confirmation_pending" => false, +        "tags" => [] +      }      }      assert represented == UserView.render("show.json", %{user: user, for: follower}) @@ -170,7 +187,8 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do        "follows_you" => true,        "statusnet_blocking" => false,        "rights" => %{ -        "delete_others_notice" => false +        "delete_others_notice" => false, +        "admin" => false        },        "statusnet_profile_url" => follower.ap_id,        "cover_photo" => banner, @@ -179,7 +197,13 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do        "locked" => false,        "default_scope" => "public",        "no_rich_text" => false, -      "fields" => [] +      "hide_follows" => false, +      "hide_followers" => false, +      "fields" => [], +      "pleroma" => %{ +        "confirmation_pending" => false, +        "tags" => [] +      }      }      assert represented == UserView.render("show.json", %{user: follower, for: user}) @@ -190,6 +214,36 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do      represented = UserView.render("show.json", %{user: user, for: user})      assert represented["rights"]["delete_others_notice"] +    assert represented["role"] == "moderator" +  end + +  test "a user that is a admin" do +    user = insert(:user, %{info: %{is_admin: true}}) +    represented = UserView.render("show.json", %{user: user, for: user}) + +    assert represented["rights"]["admin"] +    assert represented["role"] == "admin" +  end + +  test "A moderator with hidden role for another user", %{user: user} do +    admin = insert(:user, %{info: %{is_moderator: true, show_role: false}}) +    represented = UserView.render("show.json", %{user: admin, for: user}) + +    assert represented["role"] == nil +  end + +  test "An admin with hidden role for another user", %{user: user} do +    admin = insert(:user, %{info: %{is_admin: true, show_role: false}}) +    represented = UserView.render("show.json", %{user: admin, for: user}) + +    assert represented["role"] == nil +  end + +  test "A regular user for the admin", %{user: user} do +    admin = insert(:user, %{info: %{is_admin: true}}) +    represented = UserView.render("show.json", %{user: user, for: admin}) + +    assert represented["pleroma"]["deactivated"] == false    end    test "A blocked user for the blocker" do @@ -219,7 +273,8 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do        "follows_you" => false,        "statusnet_blocking" => true,        "rights" => %{ -        "delete_others_notice" => false +        "delete_others_notice" => false, +        "admin" => false        },        "statusnet_profile_url" => user.ap_id,        "cover_photo" => banner, @@ -228,10 +283,16 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do        "locked" => false,        "default_scope" => "public",        "no_rich_text" => false, -      "fields" => [] +      "hide_follows" => false, +      "hide_followers" => false, +      "fields" => [], +      "pleroma" => %{ +        "confirmation_pending" => false, +        "tags" => [] +      }      } -    blocker = Repo.get(User, blocker.id) +    blocker = User.get_by_id(blocker.id)      assert represented == UserView.render("show.json", %{user: user, for: blocker})    end | 
