+ defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.AccountOperation
+
+ @doc "POST /api/v1/accounts"
+ def create(%{assigns: %{app: app}, body_params: params} = conn, _params) do
+ with :ok <- validate_email_param(params),
+ :ok <- TwitterAPI.validate_captcha(app, params),
+ {:ok, user} <- TwitterAPI.register_user(params, need_confirmation: true),
+ {:ok, token} <- Token.create_token(app, user, %{scopes: app.scopes}) do
+ json(conn, %{
+ token_type: "Bearer",
+ access_token: token.token,
+ scope: app.scopes,
+ created_at: Token.Utils.format_created_at(token)
+ })
+ else
+ {:error, error} -> json_response(conn, :bad_request, %{error: error})
+ end
+ end
+
+ def create(%{assigns: %{app: _app}} = conn, _) do
+ render_error(conn, :bad_request, "Missing parameters")
+ end
+
+ def create(conn, _) do
+ render_error(conn, :forbidden, "Invalid credentials")
+ end
+
+ defp validate_email_param(%{email: email}) when not is_nil(email), do: :ok
+
+ defp validate_email_param(_) do
+ case Pleroma.Config.get([:instance, :account_activation_required]) do
+ true -> {:error, dgettext("errors", "Missing parameter: %{name}", name: "email")}
+ _ -> :ok
+ end
+ end
+
+ @doc "GET /api/v1/accounts/verify_credentials"
+ def verify_credentials(%{assigns: %{user: user}} = conn, _) do
+ chat_token = Phoenix.Token.sign(conn, "user socket", user.id)
+
+ render(conn, "show.json",
+ user: user,
+ for: user,
+ with_pleroma_settings: true,
+ with_chat_token: chat_token
+ )
+ end
+
+ @doc "PATCH /api/v1/accounts/update_credentials"
+ def update_credentials(%{assigns: %{user: original_user}, body_params: params} = conn, _params) do
+ user = original_user
+
+ params =
+ params
+ |> Enum.filter(fn {_, value} -> not is_nil(value) end)
+ |> Enum.into(%{})
+
+ user_params =
+ [
+ :no_rich_text,
+ :locked,
+ :hide_followers_count,
+ :hide_follows_count,
+ :hide_followers,
+ :hide_follows,
+ :hide_favorites,
+ :show_role,
+ :skip_thread_containment,
+ :allow_following_move,
+ :discoverable
+ ]
+ |> Enum.reduce(%{}, fn key, acc ->
+ add_if_present(acc, params, key, key, &{:ok, truthy_param?(&1)})
+ end)
+ |> add_if_present(params, :display_name, :name)
+ |> add_if_present(params, :note, :bio)
+ |> add_if_present(params, :avatar, :avatar)
+ |> add_if_present(params, :header, :banner)
+ |> add_if_present(params, :pleroma_background_image, :background)
+ |> add_if_present(
+ params,
+ :fields_attributes,
+ :raw_fields,
+ &{:ok, normalize_fields_attributes(&1)}
+ )
+ |> add_if_present(params, :pleroma_settings_store, :pleroma_settings_store)
+ |> add_if_present(params, :default_scope, :default_scope)
+ |> add_if_present(params, :actor_type, :actor_type)
+
+ changeset = User.update_changeset(user, user_params)
+
+ with {:ok, user} <- User.update_and_set_cache(changeset) do
+ render(conn, "show.json", user: user, for: user, with_pleroma_settings: true)
+ else
+ _e -> render_error(conn, :forbidden, "Invalid request")
+ end
+ end
+
+ defp add_if_present(map, params, params_field, map_field, value_function \\ &{:ok, &1}) do
+ with true <- Map.has_key?(params, params_field),
+ {:ok, new_value} <- value_function.(Map.get(params, params_field)) do
+ Map.put(map, map_field, new_value)
+ else
+ _ -> map
+ end
+ end
+
+ defp normalize_fields_attributes(fields) do
+ if Enum.all?(fields, &is_tuple/1) do
+ Enum.map(fields, fn {_, v} -> v end)
+ else
+ Enum.map(fields, fn
+ %{} = field -> %{"name" => field.name, "value" => field.value}
+ field -> field
+ end)
+ end
+ end
+
+ @doc "GET /api/v1/accounts/relationships"
+ def relationships(%{assigns: %{user: user}} = conn, %{id: id}) do
+ targets = User.get_all_by_ids(List.wrap(id))
+
+ render(conn, "relationships.json", user: user, targets: targets)
+ end
+
+ # Instead of returning a 400 when no "id" params is present, Mastodon returns an empty array.
+ def relationships(%{assigns: %{user: _user}} = conn, _), do: json(conn, [])
+