Mastdon API: Add ability to get a remote account by nickname to
authorrinpatch <rinpatch@sdf.org>
Tue, 3 Sep 2019 14:54:21 +0000 (17:54 +0300)
committerrinpatch <rinpatch@sdf.org>
Tue, 3 Sep 2019 16:26:10 +0000 (19:26 +0300)
`/api/v1/accounts/:id`

lib/pleroma/plugs/trailing_format_plug.ex [new file with mode: 0644]
lib/pleroma/user.ex
lib/pleroma/web/endpoint.ex
lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex
test/web/mastodon_api/mastodon_api_controller_test.exs

diff --git a/lib/pleroma/plugs/trailing_format_plug.ex b/lib/pleroma/plugs/trailing_format_plug.ex
new file mode 100644 (file)
index 0000000..2473e07
--- /dev/null
@@ -0,0 +1,40 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Plugs.TrailingFormatPlug do
+  @moduledoc "Calls TrailingFormatPlug for specific paths. Ideally we would just do this in the router, but TrailingFormatPlug needs to be called before Plug.Parsers."
+
+  @behaviour Plug
+  @paths [
+    "/api/statusnet",
+    "/api/statuses",
+    "/api/qvitter",
+    "/api/search",
+    "/api/account",
+    "/api/friends",
+    "/api/mutes",
+    "/api/media",
+    "/api/favorites",
+    "/api/blocks",
+    "/api/friendships",
+    "/api/users",
+    "/users",
+    "/nodeinfo",
+    "/api/help",
+    "/api/externalprofile",
+    "/notice"
+  ]
+
+  def init(opts) do
+    TrailingFormatPlug.init(opts)
+  end
+
+  for path <- @paths do
+    def call(%{request_path: unquote(path) <> _} = conn, opts) do
+      TrailingFormatPlug.call(conn, opts)
+    end
+  end
+
+  def call(conn, _opts), do: conn
+end
index 29fd6d2ea1cba4d4343e88548d648a29e36f45f6..d68015a8079179b6cb5361a14236b53c22d60111 100644 (file)
@@ -569,8 +569,12 @@ defmodule Pleroma.User do
     end)
   end
 
-  def get_cached_by_nickname_or_id(nickname_or_id) do
-    get_cached_by_id(nickname_or_id) || get_cached_by_nickname(nickname_or_id)
+  def get_cached_by_nickname_or_id(nickname_or_id, opts \\ []) do
+    if is_integer(nickname_or_id) or Pleroma.FlakeId.is_flake_id?(nickname_or_id) do
+      get_cached_by_id(nickname_or_id) || get_cached_by_nickname(nickname_or_id)
+    else
+      unless opts[:restrict_remote_nicknames], do: get_cached_by_nickname(nickname_or_id)
+    end
   end
 
   def get_by_nickname(nickname) do
index c123530dcf961c10a2dfd5179404c3a43c53613f..eb805e853b3fdb349a0c3c4485336451192b1485 100644 (file)
@@ -57,7 +57,7 @@ defmodule Pleroma.Web.Endpoint do
     plug(Phoenix.CodeReloader)
   end
 
-  plug(TrailingFormatPlug)
+  plug(Pleroma.Plugs.TrailingFormatPlug)
   plug(Plug.RequestId)
   plug(Plug.Logger)
 
index 83e877c0e79e352022b6df5df528b59618e3d58f..c5f2819764e1498f67224362bc3c46800f87e399 100644 (file)
@@ -290,7 +290,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def user(%{assigns: %{user: for_user}} = conn, %{"id" => nickname_or_id}) do
-    with %User{} = user <- User.get_cached_by_nickname_or_id(nickname_or_id),
+    with %User{} = user <- get_user_by_nickname_or_id(for_user, nickname_or_id),
          true <- User.auth_active?(user) || user.id == for_user.id || User.superuser?(for_user) do
       account = AccountView.render("account.json", %{user: user, for: for_user})
       json(conn, account)
@@ -390,7 +390,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def user_statuses(%{assigns: %{user: reading_user}} = conn, params) do
-    with %User{} = user <- User.get_cached_by_nickname_or_id(params["id"]) do
+    with %User{} = user <- get_user_by_nickname_or_id(reading_user, params["id"]) do
       params =
         params
         |> Map.put("tag", params["tagged"])
@@ -1697,4 +1697,25 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   defp present?(nil), do: false
   defp present?(false), do: false
   defp present?(_), do: true
+
+  defp get_user_by_nickname_or_id(for_user, nickname_or_id) do
+    restrict_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
+
+    opts =
+      cond do
+        restrict_to_local == :all ->
+          [restrict_remote_nicknames: true]
+
+        restrict_to_local == false ->
+          []
+
+        restrict_to_local == :unauthenticated and match?(%User{}, for_user) ->
+          []
+
+        true ->
+          [restrict_remote_nicknames: true]
+      end
+
+    User.get_cached_by_nickname_or_id(nickname_or_id, opts)
+  end
 end
index 4fd0a5aebff307d9dba2f570046051035d37f5c9..427ee6f634e00bb82344d8503f5f7fdd99035ac8 100644 (file)
@@ -1675,32 +1675,85 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     end
   end
 
-  test "account fetching", %{conn: conn} do
-    user = insert(:user)
+  describe "account fetching" do
+    test "works by id" do
+      user = insert(:user)
 
-    conn =
-      conn
-      |> get("/api/v1/accounts/#{user.id}")
+      conn =
+        build_conn()
+        |> get("/api/v1/accounts/#{user.id}")
 
-    assert %{"id" => id} = json_response(conn, 200)
-    assert id == to_string(user.id)
+      assert %{"id" => id} = json_response(conn, 200)
+      assert id == to_string(user.id)
 
-    conn =
-      build_conn()
-      |> get("/api/v1/accounts/-1")
+      conn =
+        build_conn()
+        |> get("/api/v1/accounts/-1")
 
-    assert %{"error" => "Can't find user"} = json_response(conn, 404)
-  end
+      assert %{"error" => "Can't find user"} = json_response(conn, 404)
+    end
 
-  test "account fetching also works nickname", %{conn: conn} do
-    user = insert(:user)
+    test "works by nickname" do
+      user = insert(:user)
 
-    conn =
-      conn
-      |> get("/api/v1/accounts/#{user.nickname}")
+      conn =
+        build_conn()
+        |> get("/api/v1/accounts/#{user.nickname}")
 
-    assert %{"id" => id} = json_response(conn, 200)
-    assert id == user.id
+      assert %{"id" => id} = json_response(conn, 200)
+      assert id == user.id
+    end
+
+    test "works by nickname for remote users" do
+      limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
+      Pleroma.Config.put([:instance, :limit_to_local_content], false)
+      user = insert(:user, nickname: "user@example.com", local: false)
+
+      conn =
+        build_conn()
+        |> get("/api/v1/accounts/#{user.nickname}")
+
+      Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
+      assert %{"id" => id} = json_response(conn, 200)
+      assert id == user.id
+    end
+
+    test "respects limit_to_local_content == :all for remote user nicknames" do
+      limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
+      Pleroma.Config.put([:instance, :limit_to_local_content], :all)
+
+      user = insert(:user, nickname: "user@example.com", local: false)
+
+      conn =
+        build_conn()
+        |> get("/api/v1/accounts/#{user.nickname}")
+
+      Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
+      assert json_response(conn, 404)
+    end
+
+    test "respects limit_to_local_content == :unauthenticated for remote user nicknames" do
+      limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
+      Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
+
+      user = insert(:user, nickname: "user@example.com", local: false)
+      reading_user = insert(:user)
+
+      conn =
+        build_conn()
+        |> get("/api/v1/accounts/#{user.nickname}")
+
+      assert json_response(conn, 404)
+
+      conn =
+        build_conn()
+        |> assign(:user, reading_user)
+        |> get("/api/v1/accounts/#{user.nickname}")
+
+      Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
+      assert %{"id" => id} = json_response(conn, 200)
+      assert id == user.id
+    end
   end
 
   test "mascot upload", %{conn: conn} do