diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index ff56927de..3c0de4f24 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -2289,6 +2289,19 @@ defmodule Pleroma.User do end end + def delete_alias(user, alias_user) do + current_aliases = user.also_known_as || [] + alias_ap_id = alias_user.ap_id + + if alias_ap_id in current_aliases do + user + |> cast(%{also_known_as: current_aliases -- [alias_ap_id]}, [:also_known_as]) + |> update_and_set_cache() + else + {:error, :no_such_alias} + end + end + # Internal function; public one is `deactivate/2` defp set_activation_status(user, status) do user diff --git a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex index 0fb54743d..3e915575c 100644 --- a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex +++ b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex @@ -312,6 +312,46 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do } end + def delete_alias_operation do + %Operation{ + tags: ["Account credentials"], + summary: "Delete an alias from this account", + security: [%{"oAuth" => ["write:accounts"]}], + operationId: "UtilController.delete_alias", + requestBody: request_body("Parameters", delete_alias_request(), required: true), + responses: %{ + 200 => + Operation.response("Success", "application/json", %Schema{ + type: :object, + properties: %{ + status: %Schema{ + type: :string, + example: "success" + } + } + }), + 400 => Operation.response("Error", "application/json", ApiError), + 403 => Operation.response("Error", "application/json", ApiError), + 404 => Operation.response("Error", "application/json", ApiError) + } + } + end + + defp delete_alias_request do + %Schema{ + title: "DeleteAliasRequest", + description: "PUT body for deleting aliases", + type: :object, + required: [:alias], + properties: %{ + alias: %Schema{ + type: :string, + description: "The nickname of the account to delete from aliases" + } + } + } + end + def healthcheck_operation do %Operation{ tags: ["Accounts"], diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 9ce0c9961..4f97bb451 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -347,6 +347,7 @@ defmodule Pleroma.Web.Router do put("/aliases", UtilController, :add_alias) get("/aliases", UtilController, :list_aliases) + delete("/aliases", UtilController, :delete_alias) end scope "/api/pleroma", Pleroma.Web.PleromaAPI do diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 4c7d11e8d..b3e16d527 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -29,7 +29,8 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do :update_notificaton_settings, :disable_account, :move_account, - :add_alias + :add_alias, + :delete_alias ] ) @@ -198,8 +199,24 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end end + def delete_alias(%{assigns: %{user: user}, body_params: body_params} = conn, _) do + with {:ok, alias_user} <- find_user_by_nickname(body_params.alias), + {:ok, _user} <- user |> User.delete_alias(alias_user) do + json(conn, %{status: "success"}) + else + {:error, :no_such_alias} -> + conn + |> put_status(404) + |> json(%{error: "Account has no such alias."}) + + {:error, error} -> + json(conn, %{error: error}) + end + end + def list_aliases(%{assigns: %{user: user}} = conn, %{}) do - alias_nicks = user + alias_nicks = + user |> User.alias_users() |> Enum.map(&User.full_nickname/1) diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index 9971aba66..984a837e2 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -2550,4 +2550,28 @@ defmodule Pleroma.UserTest do assert alias_user.ap_id == user.ap_id end end + + describe "delete_alias/2" do + test "should delete existing alias" do + user = insert(:user) + user2 = insert(:user, also_known_as: [user.ap_id]) + + assert {:ok, user_updated} = user2 |> User.delete_alias(user) + + assert user_updated.also_known_as == [] + end + + test "should report error on non-existing alias" do + user = insert(:user) + user2 = insert(:user) + user3 = insert(:user, also_known_as: [user.ap_id]) + + assert {:error, :no_such_alias} = user3 |> User.delete_alias(user2) + + user3_updated = User.get_cached_by_ap_id(user3.ap_id) + + assert user3_updated.also_known_as |> length() == 1 + assert user.ap_id in user3_updated.also_known_as + end + end end diff --git a/test/pleroma/web/twitter_api/util_controller_test.exs b/test/pleroma/web/twitter_api/util_controller_test.exs index 4a1bba5c6..40fcadb72 100644 --- a/test/pleroma/web/twitter_api/util_controller_test.exs +++ b/test/pleroma/web/twitter_api/util_controller_test.exs @@ -669,9 +669,10 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do test "with permissions", %{ conn: conn } do - assert %{"aliases" => []} = conn - |> get("/api/pleroma/aliases") - |> json_response_and_validate_schema(200) + assert %{"aliases" => []} = + conn + |> get("/api/pleroma/aliases") + |> json_response_and_validate_schema(200) end test "with permissions and aliases", %{} do @@ -682,9 +683,11 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do %{user: _user, conn: conn} = oauth_access(["read:accounts"], user: user) - assert %{"aliases" => aliases} = conn - |> get("/api/pleroma/aliases") - |> json_response_and_validate_schema(200) + assert %{"aliases" => aliases} = + conn + |> get("/api/pleroma/aliases") + |> json_response_and_validate_schema(200) + assert aliases == [user2 |> User.full_nickname()] end end @@ -730,4 +733,62 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do } end end + + describe "DELETE /api/pleroma/aliases" do + setup do + alias_user = insert(:user) + non_alias_user = insert(:user) + user = insert(:user, also_known_as: [alias_user.ap_id]) + + oauth_access(["write:accounts"], user: user) + |> Map.put(:alias_user, alias_user) + |> Map.put(:non_alias_user, non_alias_user) + end + + test "without permissions", %{conn: conn} do + conn = + conn + |> assign(:token, nil) + |> put_req_header("content-type", "application/json") + |> delete("/api/pleroma/aliases", %{alias: "none"}) + + assert json_response_and_validate_schema(conn, 403) == %{ + "error" => "Insufficient permissions: write:accounts." + } + end + + test "with permissions, no alias param", %{conn: conn} do + conn = + conn + |> put_req_header("content-type", "application/json") + |> delete("/api/pleroma/aliases", %{}) + + assert %{"error" => "Missing field: alias."} = json_response_and_validate_schema(conn, 400) + end + + test "with permissions, account does not have such alias", %{ + conn: conn, + non_alias_user: non_alias_user + } do + conn = + conn + |> put_req_header("content-type", "application/json") + |> delete("/api/pleroma/aliases", %{alias: non_alias_user |> User.full_nickname()}) + + assert %{"error" => "Account has no such alias."} = + json_response_and_validate_schema(conn, 404) + end + + test "with permissions, account does have such alias", %{ + conn: conn, + alias_user: alias_user + } do + conn = + conn + |> put_req_header("content-type", "application/json") + |> delete("/api/pleroma/aliases", %{alias: alias_user |> User.full_nickname()}) + + assert %{"status" => "success"} = json_response_and_validate_schema(conn, 200) + end + end end