Add spec for AccountController.update_credentials

This commit is contained in:
Egor Kislitsyn 2020-04-07 14:53:12 +04:00
parent f80116125f
commit 260cbddc94
No known key found for this signature in database
GPG Key ID: 1B49CB15B71E7805
8 changed files with 229 additions and 16 deletions

View File

@ -4,7 +4,7 @@
defmodule Pleroma.Web.ApiSpec.Helpers do defmodule Pleroma.Web.ApiSpec.Helpers do
def request_body(description, schema_ref, opts \\ []) do def request_body(description, schema_ref, opts \\ []) do
media_types = ["application/json", "multipart/form-data"] media_types = ["application/json", "multipart/form-data", "application/x-www-form-urlencoded"]
content = content =
media_types media_types

View File

@ -8,6 +8,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
alias Pleroma.Web.ApiSpec.Schemas.Account alias Pleroma.Web.ApiSpec.Schemas.Account
alias Pleroma.Web.ApiSpec.Schemas.AccountCreateRequest alias Pleroma.Web.ApiSpec.Schemas.AccountCreateRequest
alias Pleroma.Web.ApiSpec.Schemas.AccountCreateResponse alias Pleroma.Web.ApiSpec.Schemas.AccountCreateResponse
alias Pleroma.Web.ApiSpec.Schemas.AccountUpdateCredentialsRequest
@spec open_api_operation(atom) :: Operation.t() @spec open_api_operation(atom) :: Operation.t()
def open_api_operation(action) do def open_api_operation(action) do
@ -44,7 +45,18 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
end end
def update_credentials_operation do def update_credentials_operation do
:ok %Operation{
tags: ["accounts"],
summary: "Update account credentials",
description: "Update the user's display and preferences.",
operationId: "AccountController.update_credentials",
security: [%{"oAuth" => ["write:accounts"]}],
requestBody:
Helpers.request_body("Parameters", AccountUpdateCredentialsRequest, required: true),
responses: %{
200 => Operation.response("Account", "application/json", Account)
}
}
end end
def relationships_operation do def relationships_operation do

View File

@ -0,0 +1,26 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ApiSpec.Schemas.AccountAttributeField do
alias OpenApiSpex.Schema
require OpenApiSpex
OpenApiSpex.schema(%{
title: "AccountAttributeField",
description: "Request schema for account custom fields",
type: :object,
properties: %{
name: %Schema{type: :string},
value: %Schema{type: :string}
},
required: [:name, :value],
example: %{
"JSON" => %{
"name" => "Website",
"value" => "https://pleroma.com"
}
}
})
end

View File

@ -0,0 +1,123 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ApiSpec.Schemas.AccountUpdateCredentialsRequest do
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Schemas.AccountAttributeField
require OpenApiSpex
OpenApiSpex.schema(%{
title: "AccountUpdateCredentialsRequest",
description: "POST body for creating an account",
type: :object,
properties: %{
bot: %Schema{
type: :boolean,
description: "Whether the account has a bot flag."
},
display_name: %Schema{
type: :string,
description: "The display name to use for the profile."
},
note: %Schema{type: :string, description: "The account bio."},
avatar: %Schema{
type: :string,
description: "Avatar image encoded using multipart/form-data",
format: :binary
},
header: %Schema{
type: :string,
description: "Header image encoded using multipart/form-data",
format: :binary
},
locked: %Schema{
type: :boolean,
description: "Whether manual approval of follow requests is required."
},
fields_attributes: %Schema{
oneOf: [%Schema{type: :array, items: AccountAttributeField}, %Schema{type: :object}]
},
# NOTE: `source` field is not supported
#
# source: %Schema{
# type: :object,
# properties: %{
# privacy: %Schema{type: :string},
# sensitive: %Schema{type: :boolean},
# language: %Schema{type: :string}
# }
# },
# Pleroma-specific fields
no_rich_text: %Schema{
type: :boolean,
description: "html tags are stripped from all statuses requested from the API"
},
hide_followers: %Schema{type: :boolean, description: "user's followers will be hidden"},
hide_follows: %Schema{type: :boolean, description: "user's follows will be hidden"},
hide_followers_count: %Schema{
type: :boolean,
description: "user's follower count will be hidden"
},
hide_follows_count: %Schema{
type: :boolean,
description: "user's follow count will be hidden"
},
hide_favorites: %Schema{
type: :boolean,
description: "user's favorites timeline will be hidden"
},
show_role: %Schema{
type: :boolean,
description: "user's role (e.g admin, moderator) will be exposed to anyone in the
API"
},
default_scope: %Schema{
type: :string,
description: "The scope returned under privacy key in Source subentity"
},
pleroma_settings_store: %Schema{
type: :object,
description: "Opaque user settings to be saved on the backend."
},
skip_thread_containment: %Schema{
type: :boolean,
description: "Skip filtering out broken threads"
},
allow_following_move: %Schema{
type: :boolean,
description: "Allows automatically follow moved following accounts"
},
pleroma_background_image: %Schema{
type: :string,
description: "Sets the background image of the user.",
format: :binary
},
discoverable: %Schema{
type: :boolean,
description: "Discovery of this account in search results and other services is allowed."
},
actor_type: %Schema{type: :string, description: "the type of this account."}
},
example: %{
bot: false,
display_name: "cofe",
note: "foobar",
fields_attributes: [%{name: "foo", value: "bar"}],
no_rich_text: false,
hide_followers: true,
hide_follows: false,
hide_followers_count: false,
hide_follows_count: false,
hide_favorites: false,
show_role: false,
default_scope: "private",
pleroma_settings_store: %{"pleroma-fe" => %{"key" => "val"}},
skip_thread_containment: false,
allow_following_move: false,
discoverable: false,
actor_type: "Person"
}
})
end

View File

@ -82,7 +82,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
plug( plug(
OpenApiSpex.Plug.CastAndValidate, OpenApiSpex.Plug.CastAndValidate,
[render_error: Pleroma.Web.ApiSpec.RenderError] when action == :create [render_error: Pleroma.Web.ApiSpec.RenderError]
when action in [:create, :verify_credentials, :update_credentials]
) )
action_fallback(Pleroma.Web.MastodonAPI.FallbackController) action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
@ -152,9 +153,15 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
end end
@doc "PATCH /api/v1/accounts/update_credentials" @doc "PATCH /api/v1/accounts/update_credentials"
def update_credentials(%{assigns: %{user: original_user}} = conn, params) do def update_credentials(%{assigns: %{user: original_user}, body_params: params} = conn, _params) do
user = original_user user = original_user
params =
params
|> Map.from_struct()
|> Enum.filter(fn {_, value} -> not is_nil(value) end)
|> Enum.into(%{})
user_params = user_params =
[ [
:no_rich_text, :no_rich_text,
@ -170,22 +177,22 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
:discoverable :discoverable
] ]
|> Enum.reduce(%{}, fn key, acc -> |> Enum.reduce(%{}, fn key, acc ->
add_if_present(acc, params, to_string(key), key, &{:ok, truthy_param?(&1)}) add_if_present(acc, params, key, key, &{:ok, truthy_param?(&1)})
end) end)
|> add_if_present(params, "display_name", :name) |> add_if_present(params, :display_name, :name)
|> add_if_present(params, "note", :bio) |> add_if_present(params, :note, :bio)
|> add_if_present(params, "avatar", :avatar) |> add_if_present(params, :avatar, :avatar)
|> add_if_present(params, "header", :banner) |> add_if_present(params, :header, :banner)
|> add_if_present(params, "pleroma_background_image", :background) |> add_if_present(params, :pleroma_background_image, :background)
|> add_if_present( |> add_if_present(
params, params,
"fields_attributes", :fields_attributes,
:raw_fields, :raw_fields,
&{:ok, normalize_fields_attributes(&1)} &{:ok, normalize_fields_attributes(&1)}
) )
|> add_if_present(params, "pleroma_settings_store", :pleroma_settings_store) |> add_if_present(params, :pleroma_settings_store, :pleroma_settings_store)
|> add_if_present(params, "default_scope", :default_scope) |> add_if_present(params, :default_scope, :default_scope)
|> add_if_present(params, "actor_type", :actor_type) |> add_if_present(params, :actor_type, :actor_type)
changeset = User.update_changeset(user, user_params) changeset = User.update_changeset(user, user_params)
@ -200,7 +207,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
defp add_if_present(map, params, params_field, map_field, value_function \\ &{:ok, &1}) do defp add_if_present(map, params, params_field, map_field, value_function \\ &{:ok, &1}) do
with true <- Map.has_key?(params, params_field), with true <- Map.has_key?(params, params_field),
{:ok, new_value} <- value_function.(params[params_field]) do {:ok, new_value} <- value_function.(Map.get(params, params_field)) do
Map.put(map, map_field, new_value) Map.put(map, map_field, new_value)
else else
_ -> map _ -> map
@ -211,7 +218,13 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
if Enum.all?(fields, &is_tuple/1) do if Enum.all?(fields, &is_tuple/1) do
Enum.map(fields, fn {_, v} -> v end) Enum.map(fields, fn {_, v} -> v end)
else else
fields Enum.map(fields, fn
%Pleroma.Web.ApiSpec.Schemas.AccountAttributeField{} = field ->
%{"name" => field.name, "value" => field.value}
field ->
field
end)
end end
end end

View File

@ -51,6 +51,11 @@ defmodule Pleroma.Web.ConnCase do
%{user: user, token: token, conn: conn} %{user: user, token: token, conn: conn}
end end
defp request_content_type(%{conn: conn}) do
conn = put_req_header(conn, "content-type", "multipart/form-data")
[conn: conn]
end
defp ensure_federating_or_authenticated(conn, url, user) do defp ensure_federating_or_authenticated(conn, url, user) do
initial_setting = Config.get([:instance, :federating]) initial_setting = Config.get([:instance, :federating])
on_exit(fn -> Config.put([:instance, :federating], initial_setting) end) on_exit(fn -> Config.put([:instance, :federating], initial_setting) end)

View File

@ -9,6 +9,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperationTest do
alias Pleroma.Web.ApiSpec.Schemas.Account alias Pleroma.Web.ApiSpec.Schemas.Account
alias Pleroma.Web.ApiSpec.Schemas.AccountCreateRequest alias Pleroma.Web.ApiSpec.Schemas.AccountCreateRequest
alias Pleroma.Web.ApiSpec.Schemas.AccountCreateResponse alias Pleroma.Web.ApiSpec.Schemas.AccountCreateResponse
alias Pleroma.Web.ApiSpec.Schemas.AccountUpdateCredentialsRequest
import OpenApiSpex.TestAssertions import OpenApiSpex.TestAssertions
import Pleroma.Factory import Pleroma.Factory
@ -31,6 +32,12 @@ defmodule Pleroma.Web.ApiSpec.AccountOperationTest do
assert_schema(schema.example, "AccountCreateResponse", api_spec) assert_schema(schema.example, "AccountCreateResponse", api_spec)
end end
test "AccountUpdateCredentialsRequest example matches schema" do
api_spec = ApiSpec.spec()
schema = AccountUpdateCredentialsRequest.schema()
assert_schema(schema.example, "AccountUpdateCredentialsRequest", api_spec)
end
test "AccountController produces a AccountCreateResponse", %{conn: conn} do test "AccountController produces a AccountCreateResponse", %{conn: conn} do
api_spec = ApiSpec.spec() api_spec = ApiSpec.spec()
app_token = insert(:oauth_token, user: nil) app_token = insert(:oauth_token, user: nil)
@ -52,4 +59,29 @@ defmodule Pleroma.Web.ApiSpec.AccountOperationTest do
assert_schema(json, "AccountCreateResponse", api_spec) assert_schema(json, "AccountCreateResponse", api_spec)
end end
test "AccountUpdateCredentialsRequest produces an Account", %{conn: conn} do
api_spec = ApiSpec.spec()
token = insert(:oauth_token, scopes: ["read", "write"])
json =
conn
|> put_req_header("authorization", "Bearer " <> token.token)
|> put_req_header("content-type", "application/json")
|> patch(
"/api/v1/accounts/update_credentials",
%{
hide_followers_count: "true",
hide_follows_count: "true",
skip_thread_containment: "true",
hide_follows: "true",
pleroma_settings_store: %{"pleroma-fe" => %{"key" => "val"}},
note: "foobar",
fields_attributes: [%{name: "foo", value: "bar"}]
}
)
|> json_response(200)
assert_schema(json, "Account", api_spec)
end
end end

View File

@ -14,6 +14,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do
describe "updating credentials" do describe "updating credentials" do
setup do: oauth_access(["write:accounts"]) setup do: oauth_access(["write:accounts"])
setup :request_content_type
test "sets user settings in a generic way", %{conn: conn} do test "sets user settings in a generic way", %{conn: conn} do
res_conn = res_conn =
@ -237,6 +238,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do
for token <- [token1, token2] do for token <- [token1, token2] do
conn = conn =
build_conn() build_conn()
|> put_req_header("content-type", "multipart/form-data")
|> put_req_header("authorization", "Bearer #{token.token}") |> put_req_header("authorization", "Bearer #{token.token}")
|> patch("/api/v1/accounts/update_credentials", %{}) |> patch("/api/v1/accounts/update_credentials", %{})