diff --git a/lib/mix/tasks/set_locked.ex b/lib/mix/tasks/set_locked.ex
new file mode 100644
index 000000000..2b3b18b09
--- /dev/null
+++ b/lib/mix/tasks/set_locked.ex
@@ -0,0 +1,30 @@
+defmodule Mix.Tasks.SetLocked do
+  use Mix.Task
+  import Mix.Ecto
+  alias Pleroma.{Repo, User}
+
+  @shortdoc "Set locked status"
+  def run([nickname | rest]) do
+    ensure_started(Repo, [])
+
+    locked =
+      case rest do
+        [locked] -> locked == "true"
+        _ -> true
+      end
+
+    with %User{local: true} = user <- User.get_by_nickname(nickname) do
+      info =
+        user.info
+        |> Map.put("locked", !!locked)
+
+      cng = User.info_changeset(user, %{info: info})
+      user = Repo.update!(cng)
+
+      IO.puts("locked status of #{nickname}: #{user.info["locked"]}")
+    else
+      _ ->
+        IO.puts("No local user #{nickname}")
+    end
+  end
+end
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 00cac153d..b27397e13 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -197,6 +197,14 @@ defmodule Pleroma.User do
     end
   end
 
+  def maybe_follow(%User{} = follower, %User{info: info} = followed) do
+    if not following?(follower, followed) do
+      follow(follower, followed)
+    else
+      {:ok, follower}
+    end
+  end
+
   def follow(%User{} = follower, %User{info: info} = followed) do
     ap_followers = followed.follower_address
 
@@ -252,6 +260,10 @@ defmodule Pleroma.User do
     Enum.member?(follower.following, followed.follower_address)
   end
 
+  def locked?(%User{} = user) do
+    user.info["locked"] || false
+  end
+
   def get_by_ap_id(ap_id) do
     Repo.get_by(User, ap_id: ap_id)
   end
@@ -349,6 +361,40 @@ defmodule Pleroma.User do
     {:ok, Repo.all(q)}
   end
 
+  def get_follow_requests_query(%User{} = user) do
+    from(
+      a in Activity,
+      where:
+        fragment(
+          "? ->> 'type' = 'Follow'",
+          a.data
+        ),
+      where:
+        fragment(
+          "? ->> 'state' = 'pending'",
+          a.data
+        ),
+      where:
+        fragment(
+          "? @> ?",
+          a.data,
+          ^%{"object" => user.ap_id}
+        )
+    )
+  end
+
+  def get_follow_requests(%User{} = user) do
+    q = get_follow_requests_query(user)
+    reqs = Repo.all(q)
+
+    users =
+      Enum.map(reqs, fn req -> req.actor end)
+      |> Enum.uniq()
+      |> Enum.map(fn ap_id -> get_by_ap_id(ap_id) end)
+
+    {:ok, users}
+  end
+
   def increase_note_count(%User{} = user) do
     note_count = (user.info["note_count"] || 0) + 1
     new_info = Map.put(user.info, "note_count", note_count)
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 43e96fe37..3c2875548 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -214,6 +214,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
 
   def unfollow(follower, followed, activity_id \\ nil, local \\ true) do
     with %Activity{} = follow_activity <- fetch_latest_follow(follower, followed),
+         {:ok, follow_activity} <- update_follow_state(follow_activity, "cancelled"),
          unfollow_data <- make_unfollow_data(follower, followed, follow_activity, activity_id),
          {:ok, activity} <- insert(unfollow_data, local),
          :ok <- maybe_federate(activity) do
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 75ba36729..e7a3420d2 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -137,9 +137,17 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
     with %User{local: true} = followed <- User.get_cached_by_ap_id(followed),
          %User{} = follower <- User.get_or_fetch_by_ap_id(follower),
          {:ok, activity} <- ActivityPub.follow(follower, followed, id, false) do
-      ActivityPub.accept(%{to: [follower.ap_id], actor: followed.ap_id, object: data, local: true})
+      if not User.locked?(followed) do
+        ActivityPub.accept(%{
+          to: [follower.ap_id],
+          actor: followed.ap_id,
+          object: data,
+          local: true
+        })
+
+        User.follow(follower, followed)
+      end
 
-      User.follow(follower, followed)
       {:ok, activity}
     else
       _e -> :error
@@ -252,7 +260,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
       {:ok, new_user_data} = ActivityPub.user_data_from_user_object(object)
 
       banner = new_user_data[:info]["banner"]
-      locked = new_user_data[:info]["locked"]
+      locked = new_user_data[:info]["locked"] || false
 
       update_data =
         new_user_data
@@ -432,6 +440,58 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
     {:ok, data}
   end
 
+  # Mastodon Accept/Reject requires a non-normalized object containing the actor URIs,
+  # because of course it does.
+  def prepare_outgoing(%{"type" => "Accept"} = data) do
+    follow_activity_id =
+      if is_binary(data["object"]) do
+        data["object"]
+      else
+        data["object"]["id"]
+      end
+
+    with follow_activity <- Activity.get_by_ap_id(follow_activity_id) do
+      object = %{
+        "actor" => follow_activity.actor,
+        "object" => follow_activity.data["object"],
+        "id" => follow_activity.data["id"],
+        "type" => "Follow"
+      }
+
+      data =
+        data
+        |> Map.put("object", object)
+        |> Map.put("@context", "https://www.w3.org/ns/activitystreams")
+
+      {:ok, data}
+    end
+  end
+
+  def prepare_outgoing(%{"type" => "Reject"} = data) do
+    follow_activity_id =
+      if is_binary(data["object"]) do
+        data["object"]
+      else
+        data["object"]["id"]
+      end
+
+    with follow_activity <- Activity.get_by_ap_id(follow_activity_id) do
+      object = %{
+        "actor" => follow_activity.actor,
+        "object" => follow_activity.data["object"],
+        "id" => follow_activity.data["id"],
+        "type" => "Follow"
+      }
+
+      data =
+        data
+        |> Map.put("object", object)
+        |> Map.put("@context", "https://www.w3.org/ns/activitystreams")
+
+      {:ok, data}
+    end
+  end
+
   def prepare_outgoing(%{"type" => _type} = data) do
     data =
       data
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index 56b80a8db..64329b710 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -4,6 +4,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
   alias Pleroma.Web.Endpoint
   alias Ecto.{Changeset, UUID}
   import Ecto.Query
+  require Logger
 
   # Some implementations send the actor URI as the actor field, others send the entire actor object,
   # so figure out what the actor's URI is based on what we have.
@@ -216,10 +217,27 @@ defmodule Pleroma.Web.ActivityPub.Utils do
 
   #### Follow-related helpers
 
+  @doc """
+  Updates a follow activity's state (for locked accounts).
+  """
+  def update_follow_state(%Activity{} = activity, state) do
+    with new_data <-
+           activity.data
+           |> Map.put("state", state),
+         changeset <- Changeset.change(activity, data: new_data),
+         {:ok, activity} <- Repo.update(changeset) do
+      {:ok, activity}
+    end
+  end
+
   @doc """
   Makes a follow activity data for the given follower and followed
   """
-  def make_follow_data(%User{ap_id: follower_id}, %User{ap_id: followed_id}, activity_id) do
+  def make_follow_data(
+        %User{ap_id: follower_id},
+        %User{ap_id: followed_id} = followed,
+        activity_id
+      ) do
     data = %{
       "type" => "Follow",
       "actor" => follower_id,
@@ -228,7 +246,10 @@ defmodule Pleroma.Web.ActivityPub.Utils do
       "object" => followed_id
     }
 
-    if activity_id, do: Map.put(data, "id", activity_id), else: data
+    data = if activity_id, do: Map.put(data, "id", activity_id), else: data
+    data = if User.locked?(followed), do: Map.put(data, "state", "pending"), else: data
+
+    data
   end
 
   def fetch_latest_follow(%User{ap_id: follower_id}, %User{ap_id: followed_id}) do
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index 0f7d4bb6d..922b83ed0 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -4,6 +4,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   alias Pleroma.Web
   alias Pleroma.Web.MastodonAPI.{StatusView, AccountView, MastodonView, ListView}
   alias Pleroma.Web.ActivityPub.ActivityPub
+  alias Pleroma.Web.ActivityPub.Utils
   alias Pleroma.Web.{CommonAPI, OStatus}
   alias Pleroma.Web.OAuth.{Authorization, Token, App}
   alias Comeonin.Pbkdf2
@@ -71,6 +72,20 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
         user
       end
 
+    user =
+      if locked = params["locked"] do
+        with locked <- locked == "true",
+             new_info <- Map.put(user.info, "locked", locked),
+             change <- User.info_changeset(user, %{info: new_info}),
+             {:ok, user} <- User.update_and_set_cache(change) do
+          user
+        else
+          _e -> user
+        end
+      else
+        user
+      end
+
     with changeset <- User.update_changeset(user, params),
          {:ok, user} <- User.update_and_set_cache(changeset) do
       if original_user != user do
@@ -476,6 +491,53 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     end
   end
 
+  def follow_requests(%{assigns: %{user: followed}} = conn, _params) do
+    with {:ok, follow_requests} <- User.get_follow_requests(followed) do
+      render(conn, AccountView, "accounts.json", %{users: follow_requests, as: :user})
+    end
+  end
+
+  def authorize_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do
+    with %User{} = follower <- Repo.get(User, id),
+         {:ok, follower} <- User.maybe_follow(follower, followed),
+         %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
+         {:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "accept"),
+         {:ok, _activity} <-
+           ActivityPub.accept(%{
+             to: [follower.ap_id],
+             actor: followed.ap_id,
+             object: follow_activity.data["id"],
+             type: "Accept"
+           }) do
+      render(conn, AccountView, "relationship.json", %{user: followed, target: follower})
+    else
+      {:error, message} ->
+        conn
+        |> put_resp_content_type("application/json")
+        |> send_resp(403, Jason.encode!(%{"error" => message}))
+    end
+  end
+
+  def reject_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do
+    with %User{} = follower <- Repo.get(User, id),
+         %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
+         {:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "reject"),
+         {:ok, _activity} <-
+           ActivityPub.reject(%{
+             to: [follower.ap_id],
+             actor: followed.ap_id,
+             object: follow_activity.data["id"],
+             type: "Reject"
+           }) do
+      render(conn, AccountView, "relationship.json", %{user: followed, target: follower})
+    else
+      {:error, message} ->
+        conn
+        |> put_resp_content_type("application/json")
+        |> send_resp(403, Jason.encode!(%{"error" => message}))
+    end
+  end
+
   def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
     with %User{} = followed <- Repo.get(User, id),
          {:ok, follower} <- User.maybe_direct_follow(follower, followed),
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 57b10bff1..ee6a373d3 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -97,11 +97,14 @@ defmodule Pleroma.Web.Router do
     post("/accounts/:id/mute", MastodonAPIController, :relationship_noop)
     post("/accounts/:id/unmute", MastodonAPIController, :relationship_noop)
 
+    get("/follow_requests", MastodonAPIController, :follow_requests)
+    post("/follow_requests/:id/authorize", MastodonAPIController, :authorize_follow_request)
+    post("/follow_requests/:id/reject", MastodonAPIController, :reject_follow_request)
+
     post("/follows", MastodonAPIController, :follow)
 
     get("/blocks", MastodonAPIController, :blocks)
 
-    get("/follow_requests", MastodonAPIController, :empty_array)
     get("/mutes", MastodonAPIController, :empty_array)
 
     get("/timelines/home", MastodonAPIController, :home_timeline)
@@ -243,6 +246,10 @@ defmodule Pleroma.Web.Router do
     post("/statuses/retweet/:id", TwitterAPI.Controller, :retweet)
     post("/statuses/destroy/:id", TwitterAPI.Controller, :delete_post)
 
+    get("/pleroma/friend_requests", TwitterAPI.Controller, :friend_requests)
+    post("/pleroma/friendships/approve", TwitterAPI.Controller, :approve_friend_request)
+    post("/pleroma/friendships/deny", TwitterAPI.Controller, :deny_friend_request)
+
     post("/friendships/create", TwitterAPI.Controller, :follow)
     post("/friendships/destroy", TwitterAPI.Controller, :unfollow)
     post("/blocks/create", TwitterAPI.Controller, :block)
diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
index d53dd0c44..b29687df5 100644
--- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
@@ -4,6 +4,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
   alias Pleroma.Web.CommonAPI
   alias Pleroma.{Repo, Activity, User, Notification}
   alias Pleroma.Web.ActivityPub.ActivityPub
+  alias Pleroma.Web.ActivityPub.Utils
   alias Ecto.Changeset
 
   require Logger
@@ -331,6 +332,54 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
     end
   end
 
+  def friend_requests(conn, params) do
+    with {:ok, user} <- TwitterAPI.get_user(conn.assigns[:user], params),
+         {:ok, friend_requests} <- User.get_follow_requests(user) do
+      render(conn, UserView, "index.json", %{users: friend_requests, for: conn.assigns[:user]})
+    else
+      _e -> bad_request_reply(conn, "Can't get friend requests")
+    end
+  end
+
+  def approve_friend_request(conn, %{"user_id" => uid} = params) do
+    with followed <- conn.assigns[:user],
+         uid when is_number(uid) <- String.to_integer(uid),
+         %User{} = follower <- Repo.get(User, uid),
+         {:ok, follower} <- User.maybe_follow(follower, followed),
+         %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
+         {:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "accept"),
+         {:ok, _activity} <-
+           ActivityPub.accept(%{
+             to: [follower.ap_id],
+             actor: followed.ap_id,
+             object: follow_activity.data["id"],
+             type: "Accept"
+           }) do
+      render(conn, UserView, "show.json", %{user: follower, for: followed})
+    else
+      e -> bad_request_reply(conn, "Can't approve user: #{inspect(e)}")
+    end
+  end
+
+  def deny_friend_request(conn, %{"user_id" => uid} = params) do
+    with followed <- conn.assigns[:user],
+         uid when is_number(uid) <- String.to_integer(uid),
+         %User{} = follower <- Repo.get(User, uid),
+         %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
+         {:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "reject"),
+         {:ok, _activity} <-
+           ActivityPub.reject(%{
+             to: [follower.ap_id],
+             actor: followed.ap_id,
+             object: follow_activity.data["id"],
+             type: "Reject"
+           }) do
+      render(conn, UserView, "show.json", %{user: follower, for: followed})
+    else
+      e -> bad_request_reply(conn, "Can't deny user: #{inspect(e)}")
+    end
+  end
+
   def friends_ids(%{assigns: %{user: user}} = conn, _params) do
     with {:ok, friends} <- User.get_friends(user) do
       ids =
@@ -357,6 +406,20 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
         params
       end
 
+    user =
+      if locked = params["locked"] do
+        with locked <- locked == "true",
+             new_info <- Map.put(user.info, "locked", locked),
+             change <- User.info_changeset(user, %{info: new_info}),
+             {:ok, user} <- User.update_and_set_cache(change) do
+          user
+        else
+          _e -> user
+        end
+      else
+        user
+      end
+
     with changeset <- User.update_changeset(user, params),
          {:ok, user} <- User.update_and_set_cache(changeset) do
       CommonAPI.update(user)
diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex
index 31527caae..711008973 100644
--- a/lib/pleroma/web/twitter_api/views/user_view.ex
+++ b/lib/pleroma/web/twitter_api/views/user_view.ex
@@ -51,7 +51,8 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
       "statusnet_profile_url" => user.ap_id,
       "cover_photo" => User.banner_url(user) |> MediaProxy.url(),
       "background_image" => image_url(user.info["background"]) |> MediaProxy.url(),
-      "is_local" => user.local
+      "is_local" => user.local,
+      "locked" => !!user.info["locked"]
     }
 
     if assigns[:token] do
diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs
index 566f5acfc..d1812457d 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -4,6 +4,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
   alias Pleroma.Web.TwitterAPI.TwitterAPI
   alias Pleroma.{Repo, User, Activity, Notification}
   alias Pleroma.Web.{OStatus, CommonAPI}
+  alias Pleroma.Web.ActivityPub.ActivityPub
 
   import Pleroma.Factory
   import ExUnit.CaptureLog
@@ -644,6 +645,73 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     end
   end
 
+  describe "locked accounts" do
+    test "/api/v1/follow_requests works" do
+      user = insert(:user, %{info: %{"locked" => true}})
+      other_user = insert(:user)
+
+      {:ok, activity} = ActivityPub.follow(other_user, user)
+
+      user = Repo.get(User, user.id)
+      other_user = Repo.get(User, other_user.id)
+
+      assert User.following?(other_user, user) == false
+
+      conn =
+        build_conn()
+        |> assign(:user, user)
+        |> get("/api/v1/follow_requests")
+
+      assert [relationship] = json_response(conn, 200)
+      assert to_string(other_user.id) == relationship["id"]
+    end
+
+    test "/api/v1/follow_requests/:id/authorize works" do
+      user = insert(:user, %{info: %{"locked" => true}})
+      other_user = insert(:user)
+
+      {:ok, activity} = ActivityPub.follow(other_user, user)
+
+      user = Repo.get(User, user.id)
+      other_user = Repo.get(User, other_user.id)
+
+      assert User.following?(other_user, user) == false
+
+      conn =
+        build_conn()
+        |> assign(:user, user)
+        |> post("/api/v1/follow_requests/#{other_user.id}/authorize")
+
+      assert relationship = json_response(conn, 200)
+      assert to_string(other_user.id) == relationship["id"]
+
+      user = Repo.get(User, user.id)
+      other_user = Repo.get(User, other_user.id)
+
+      assert User.following?(other_user, user) == true
+    end
+
+    test "/api/v1/follow_requests/:id/reject works" do
+      user = insert(:user, %{info: %{"locked" => true}})
+      other_user = insert(:user)
+
+      {:ok, activity} = ActivityPub.follow(other_user, user)
+
+      conn =
+        build_conn()
+        |> assign(:user, user)
+        |> post("/api/v1/follow_requests/#{other_user.id}/reject")
+
+      assert relationship = json_response(conn, 200)
+      assert to_string(other_user.id) == relationship["id"]
+
+      user = Repo.get(User, user.id)
+      other_user = Repo.get(User, other_user.id)
+
+      assert User.following?(other_user, user) == false
+    end
+  end
+
   test "account fetching", %{conn: conn} do
     user = insert(:user)
 
diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs
index 68f4331df..bd11551df 100644
--- a/test/web/twitter_api/twitter_api_controller_test.exs
+++ b/test/web/twitter_api/twitter_api_controller_test.exs
@@ -762,6 +762,38 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
 
       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)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> post("/api/account/update_profile.json", %{
+          "locked" => "true"
+        })
+
+      user = Repo.get!(User, user.id)
+      assert user.info["locked"] == true
+
+      assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user})
+    end
+
+    test "it unlocks an account", %{conn: conn} do
+      user = insert(:user)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> post("/api/account/update_profile.json", %{
+          "locked" => "false"
+        })
+
+      user = Repo.get!(User, user.id)
+      assert user.info["locked"] == false
+
+      assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user})
+    end
   end
 
   defp valid_user(_context) do
@@ -926,4 +958,72 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
       :timer.sleep(1000)
     end
   end
+
+  describe "GET /api/pleroma/friend_requests" do
+    test "it lists friend requests" do
+      user = insert(:user, %{info: %{"locked" => true}})
+      other_user = insert(:user)
+
+      {:ok, activity} = ActivityPub.follow(other_user, user)
+
+      user = Repo.get(User, user.id)
+      other_user = Repo.get(User, other_user.id)
+
+      assert User.following?(other_user, user) == false
+
+      conn =
+        build_conn()
+        |> assign(:user, user)
+        |> get("/api/pleroma/friend_requests")
+
+      assert [relationship] = json_response(conn, 200)
+      assert other_user.id == relationship["id"]
+    end
+  end
+
+  describe "POST /api/pleroma/friendships/approve" do
+    test "it approves a friend request" do
+      user = insert(:user, %{info: %{"locked" => true}})
+      other_user = insert(:user)
+
+      {:ok, activity} = ActivityPub.follow(other_user, user)
+
+      user = Repo.get(User, user.id)
+      other_user = Repo.get(User, 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)})
+
+      assert relationship = json_response(conn, 200)
+      assert other_user.id == relationship["id"]
+      assert relationship["follows_you"] == true
+    end
+  end
+
+  describe "POST /api/pleroma/friendships/deny" do
+    test "it denies a friend request" do
+      user = insert(:user, %{info: %{"locked" => true}})
+      other_user = insert(:user)
+
+      {:ok, activity} = ActivityPub.follow(other_user, user)
+
+      user = Repo.get(User, user.id)
+      other_user = Repo.get(User, 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)})
+
+      assert relationship = json_response(conn, 200)
+      assert other_user.id == relationship["id"]
+      assert relationship["follows_you"] == false
+    end
+  end
 end
diff --git a/test/web/twitter_api/views/user_view_test.exs b/test/web/twitter_api/views/user_view_test.exs
index 9f8bf4cdc..eea743b32 100644
--- a/test/web/twitter_api/views/user_view_test.exs
+++ b/test/web/twitter_api/views/user_view_test.exs
@@ -59,7 +59,8 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
       "statusnet_profile_url" => user.ap_id,
       "cover_photo" => banner,
       "background_image" => nil,
-      "is_local" => true
+      "is_local" => true,
+      "locked" => false
     }
 
     assert represented == UserView.render("show.json", %{user: user})
@@ -94,7 +95,8 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
       "statusnet_profile_url" => user.ap_id,
       "cover_photo" => banner,
       "background_image" => nil,
-      "is_local" => true
+      "is_local" => true,
+      "locked" => false
     }
 
     assert represented == UserView.render("show.json", %{user: user, for: follower})
@@ -130,7 +132,8 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
       "statusnet_profile_url" => follower.ap_id,
       "cover_photo" => banner,
       "background_image" => nil,
-      "is_local" => true
+      "is_local" => true,
+      "locked" => false
     }
 
     assert represented == UserView.render("show.json", %{user: follower, for: user})
@@ -173,7 +176,8 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
       "statusnet_profile_url" => user.ap_id,
       "cover_photo" => banner,
       "background_image" => nil,
-      "is_local" => true
+      "is_local" => true,
+      "locked" => false
     }
 
     blocker = Repo.get(User, blocker.id)