X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fweb%2Fmastodon_api%2Fcontrollers%2Faccount_controller.ex;h=b5008d69b261daca246932809629bf0fe5bf821c;hb=0883a706dc376fdfb7de9df1366803e87c8e7c98;hp=b9ed2d7b27e3ef34160c26503277b46f898e2d66;hpb=a2a8c8e9e09b3aa5bc488a958a0afe5909a6e89c;p=akkoma diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index b9ed2d7b2..b5008d69b 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -10,15 +10,18 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do add_link_headers: 2, truthy_param?: 1, assign_account_by_id: 2, - json_response: 3, - skip_relationships?: 1 + embed_relationships?: 1, + json_response: 3 ] + alias Pleroma.Maps alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug alias Pleroma.Plugs.OAuthScopesPlug alias Pleroma.Plugs.RateLimiter alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.ActivityPub.Builder + alias Pleroma.Web.ActivityPub.Pipeline alias Pleroma.Web.CommonAPI alias Pleroma.Web.MastodonAPI.ListView alias Pleroma.Web.MastodonAPI.MastodonAPI @@ -81,7 +84,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do plug( RateLimiter, - [name: :relation_id_action, params: ["id", "uri"]] when action in @relationship_actions + [name: :relation_id_action, params: [:id, :uri]] when action in @relationship_actions ) plug(RateLimiter, [name: :relations_actions] when action in @relationship_actions) @@ -139,9 +142,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do end @doc "PATCH /api/v1/accounts/update_credentials" - def update_credentials(%{assigns: %{user: original_user}, body_params: params} = conn, _params) do - user = original_user - + def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _params) do params = params |> Enum.filter(fn {_, value} -> not is_nil(value) end) @@ -162,41 +163,60 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do :discoverable ] |> Enum.reduce(%{}, fn key, acc -> - add_if_present(acc, params, key, key, &{:ok, truthy_param?(&1)}) + Maps.put_if_present(acc, key, params[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, + |> Maps.put_if_present(:name, params[:display_name]) + |> Maps.put_if_present(:bio, params[:note]) + |> Maps.put_if_present(:raw_bio, params[:note]) + |> Maps.put_if_present(:avatar, params[:avatar]) + |> Maps.put_if_present(:banner, params[:header]) + |> Maps.put_if_present(:background, params[:pleroma_background_image]) + |> Maps.put_if_present( :raw_fields, + params[:fields_attributes], &{: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) + |> Maps.put_if_present(:pleroma_settings_store, params[:pleroma_settings_store]) + |> Maps.put_if_present(:default_scope, params[:default_scope]) + |> Maps.put_if_present(:default_scope, params["source"]["privacy"]) + |> Maps.put_if_present(:actor_type, params[:bot], fn bot -> + if bot, do: {:ok, "Service"}, else: {:ok, "Person"} + end) + |> Maps.put_if_present(:actor_type, params[:actor_type]) + + # What happens here: + # + # We want to update the user through the pipeline, but the ActivityPub + # update information is not quite enough for this, because this also + # contains local settings that don't federate and don't even appear + # in the Update activity. + # + # So we first build the normal local changeset, then apply it to the + # user data, but don't persist it. With this, we generate the object + # data for our update activity. We feed this and the changeset as meta + # inforation into the pipeline, where they will be properly updated and + # federated. + with changeset <- User.update_changeset(user, user_params), + {:ok, unpersisted_user} <- Ecto.Changeset.apply_action(changeset, :update), + updated_object <- + Pleroma.Web.ActivityPub.UserView.render("user.json", user: user) + |> Map.delete("@context"), + {:ok, update_data, []} <- Builder.update(user, updated_object), + {:ok, _update, _} <- + Pipeline.common_pipeline(update_data, + local: true, + user_update_changeset: changeset + ) do + render(conn, "show.json", + user: unpersisted_user, + for: unpersisted_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) @@ -221,23 +241,21 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do @doc "GET /api/v1/accounts/:id" def show(%{assigns: %{user: for_user}} = conn, %{id: nickname_or_id}) do with %User{} = user <- User.get_cached_by_nickname_or_id(nickname_or_id, for: for_user), - true <- User.visible_for?(user, for_user) do + :visible <- User.visible_for(user, for_user) do render(conn, "show.json", user: user, for: for_user) else - _e -> render_error(conn, :not_found, "Can't find user") + error -> user_visibility_error(conn, error) end end @doc "GET /api/v1/accounts/:id/statuses" def statuses(%{assigns: %{user: reading_user}} = conn, params) do with %User{} = user <- User.get_cached_by_nickname_or_id(params.id, for: reading_user), - true <- User.visible_for?(user, reading_user) do + :visible <- User.visible_for(user, reading_user) do params = params |> Map.delete(:tagged) - |> Enum.filter(&(not is_nil(&1))) - |> Map.new(fn {key, value} -> {to_string(key), value} end) - |> Map.put("tag", params[:tagged]) + |> Map.put(:tag, params[:tagged]) activities = ActivityPub.fetch_user_activities(user, reading_user, params) @@ -247,11 +265,20 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do |> render("index.json", activities: activities, for: reading_user, - as: :activity, - skip_relationships: skip_relationships?(params) + as: :activity ) else - _e -> render_error(conn, :not_found, "Can't find user") + error -> user_visibility_error(conn, error) + end + end + + defp user_visibility_error(conn, error) do + case error do + :restrict_unauthenticated -> + render_error(conn, :unauthorized, "This API requires an authenticated user") + + _ -> + render_error(conn, :not_found, "Can't find user") end end @@ -271,7 +298,13 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do conn |> add_link_headers(followers) - |> render("index.json", for: for_user, users: followers, as: :user) + # https://git.pleroma.social/pleroma/pleroma-fe/-/issues/838#note_59223 + |> render("index.json", + for: for_user, + users: followers, + as: :user, + embed_relationships: embed_relationships?(params) + ) end @doc "GET /api/v1/accounts/:id/following" @@ -290,7 +323,13 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do conn |> add_link_headers(followers) - |> render("index.json", for: for_user, users: followers, as: :user) + # https://git.pleroma.social/pleroma/pleroma-fe/-/issues/838#note_59223 + |> render("index.json", + for: for_user, + users: followers, + as: :user, + embed_relationships: embed_relationships?(params) + ) end @doc "GET /api/v1/accounts/:id/lists" @@ -346,8 +385,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do @doc "POST /api/v1/accounts/:id/block" def block(%{assigns: %{user: blocker, account: blocked}} = conn, _params) do - with {:ok, _user_block} <- User.block(blocker, blocked), - {:ok, _activity} <- ActivityPub.block(blocker, blocked) do + with {:ok, _activity} <- CommonAPI.block(blocker, blocked) do render(conn, "relationship.json", user: blocker, target: blocked) else {:error, message} -> json_response(conn, :forbidden, %{error: message})