diff options
author | Maksim Pechnikov <parallel588@gmail.com> | 2020-01-27 15:20:47 +0300 |
---|---|---|
committer | Maksim Pechnikov <parallel588@gmail.com> | 2020-01-27 15:20:47 +0300 |
commit | e442ea5722404ca551135b6f4767c016952bbda3 (patch) | |
tree | 91bb371d96fbc8b46d59c378f6dd690ba30f3da3 /lib/pleroma/web/admin_api | |
parent | 6fbafb1cdcba3dc2a7e8b9718e295c9811a726d9 (diff) | |
parent | 0b582d415ba5215495047ddae1cb4e4fc1e016e6 (diff) | |
download | pleroma-e442ea5722404ca551135b6f4767c016952bbda3.tar.gz |
Merge branch 'develop' into issue/1276
Diffstat (limited to 'lib/pleroma/web/admin_api')
-rw-r--r-- | lib/pleroma/web/admin_api/admin_api_controller.ex | 256 | ||||
-rw-r--r-- | lib/pleroma/web/admin_api/config.ex | 182 | ||||
-rw-r--r-- | lib/pleroma/web/admin_api/views/config_view.ex | 10 | ||||
-rw-r--r-- | lib/pleroma/web/admin_api/views/report_view.ex | 25 | ||||
-rw-r--r-- | lib/pleroma/web/admin_api/views/status_view.ex | 42 |
5 files changed, 255 insertions, 260 deletions
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index b003d1f35..2314d3274 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -4,16 +4,20 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do use Pleroma.Web, :controller + + import Pleroma.Web.ControllerHelper, only: [json_response: 3] + alias Pleroma.Activity + alias Pleroma.ConfigDB alias Pleroma.ModerationLog alias Pleroma.Plugs.OAuthScopesPlug + alias Pleroma.ReportNote alias Pleroma.User alias Pleroma.UserInviteToken alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.AdminAPI.AccountView - alias Pleroma.Web.AdminAPI.Config alias Pleroma.Web.AdminAPI.ConfigView alias Pleroma.Web.AdminAPI.ModerationLogView alias Pleroma.Web.AdminAPI.Report @@ -24,26 +28,22 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do alias Pleroma.Web.MastodonAPI.StatusView alias Pleroma.Web.Router - import Pleroma.Web.ControllerHelper, only: [json_response: 3] - require Logger + @descriptions_json Pleroma.Docs.JSON.compile() + @users_page_size 50 + plug( OAuthScopesPlug, - %{scopes: ["read:accounts"]} - when action in [:list_users, :user_show, :right_get, :invites] + %{scopes: ["read:accounts"], admin: true} + when action in [:list_users, :user_show, :right_get] ) plug( OAuthScopesPlug, - %{scopes: ["write:accounts"]} + %{scopes: ["write:accounts"], admin: true} when action in [ - :get_invite_token, - :revoke_invite, - :email_invite, :get_password_reset, - :user_follow, - :user_unfollow, :user_delete, :users_create, :user_toggle_activation, @@ -56,41 +56,55 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do ] ) + plug(OAuthScopesPlug, %{scopes: ["read:invites"], admin: true} when action == :invites) + plug( OAuthScopesPlug, - %{scopes: ["read:reports"]} when action in [:list_reports, :report_show] + %{scopes: ["write:invites"], admin: true} + when action in [:create_invite_token, :revoke_invite, :email_invite] ) plug( OAuthScopesPlug, - %{scopes: ["write:reports"]} - when action in [:report_update_state, :report_respond] + %{scopes: ["write:follows"], admin: true} + when action in [:user_follow, :user_unfollow, :relay_follow, :relay_unfollow] ) plug( OAuthScopesPlug, - %{scopes: ["read:statuses"]} when action == :list_user_statuses + %{scopes: ["read:reports"], admin: true} + when action in [:list_reports, :report_show] ) plug( OAuthScopesPlug, - %{scopes: ["write:statuses"]} - when action in [:status_update, :status_delete] + %{scopes: ["write:reports"], admin: true} + when action in [:reports_update] ) plug( OAuthScopesPlug, - %{scopes: ["read"]} - when action in [:config_show, :migrate_to_db, :migrate_from_db, :list_log] + %{scopes: ["read:statuses"], admin: true} + when action == :list_user_statuses ) plug( OAuthScopesPlug, - %{scopes: ["write"]} - when action in [:relay_follow, :relay_unfollow, :config_update] + %{scopes: ["write:statuses"], admin: true} + when action in [:status_update, :status_delete] ) - @users_page_size 50 + plug( + OAuthScopesPlug, + %{scopes: ["read"], admin: true} + when action in [:config_show, :migrate_from_db, :list_log] + ) + + plug( + OAuthScopesPlug, + %{scopes: ["write"], admin: true} + when action == :config_update + ) action_fallback(:errors) @@ -238,7 +252,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do }) conn - |> put_view(StatusView) + |> put_view(Pleroma.Web.AdminAPI.StatusView) |> render("index.json", %{activities: activities, as: :activity}) end @@ -627,7 +641,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do def force_password_reset(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do users = nicknames |> Enum.map(&User.get_cached_by_nickname/1) - Enum.map(users, &User.force_password_reset_async/1) + Enum.each(users, &User.force_password_reset_async/1) ModerationLog.insert_log(%{ actor: admin, @@ -641,9 +655,11 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do def list_reports(conn, params) do {page, page_size} = page_params(params) + reports = Utils.get_reports(params, page, page_size) + conn |> put_view(ReportView) - |> render("index.json", %{reports: Utils.get_reports(params, page, page_size)}) + |> render("index.json", %{reports: reports}) end def list_grouped_reports(conn, _params) do @@ -687,32 +703,39 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end end - def report_respond(%{assigns: %{user: user}} = conn, %{"id" => id} = params) do - with false <- is_nil(params["status"]), - %Activity{} <- Activity.get_by_id(id) do - params = - params - |> Map.put("in_reply_to_status_id", id) - |> Map.put("visibility", "direct") + def report_notes_create(%{assigns: %{user: user}} = conn, %{ + "id" => report_id, + "content" => content + }) do + with {:ok, _} <- ReportNote.create(user.id, report_id, content) do + ModerationLog.insert_log(%{ + action: "report_note", + actor: user, + subject: Activity.get_by_id(report_id), + text: content + }) - {:ok, activity} = CommonAPI.post(user, params) + json_response(conn, :no_content, "") + else + _ -> json_response(conn, :bad_request, "") + end + end + def report_notes_delete(%{assigns: %{user: user}} = conn, %{ + "id" => note_id, + "report_id" => report_id + }) do + with {:ok, note} <- ReportNote.destroy(note_id) do ModerationLog.insert_log(%{ - action: "report_response", + action: "report_note_delete", actor: user, - subject: activity, - text: params["status"] + subject: Activity.get_by_id(report_id), + text: note.content }) - conn - |> put_view(StatusView) - |> render("show.json", %{activity: activity}) + json_response(conn, :no_content, "") else - true -> - {:param_cast, nil} - - nil -> - {:error, :not_found} + _ -> json_response(conn, :bad_request, "") end end @@ -764,49 +787,132 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do |> render("index.json", %{log: log}) end - def migrate_to_db(conn, _params) do - Mix.Tasks.Pleroma.Config.run(["migrate_to_db"]) - json(conn, %{}) + def config_descriptions(conn, _params) do + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(200, @descriptions_json) end def migrate_from_db(conn, _params) do - Mix.Tasks.Pleroma.Config.run(["migrate_from_db", Pleroma.Config.get(:env), "true"]) - json(conn, %{}) + with :ok <- configurable_from_database(conn) do + Mix.Tasks.Pleroma.Config.run([ + "migrate_from_db", + "--env", + to_string(Pleroma.Config.get(:env)), + "-d" + ]) + + json(conn, %{}) + end end - def config_show(conn, _params) do - configs = Pleroma.Repo.all(Config) + def config_show(conn, %{"only_db" => true}) do + with :ok <- configurable_from_database(conn) do + configs = Pleroma.Repo.all(ConfigDB) - conn - |> put_view(ConfigView) - |> render("index.json", %{configs: configs}) + if configs == [] do + errors( + conn, + {:error, "To use configuration from database migrate your settings to database."} + ) + else + conn + |> put_view(ConfigView) + |> render("index.json", %{configs: configs}) + end + end end - def config_update(conn, %{"configs" => configs}) do - updated = - if Pleroma.Config.get([:instance, :dynamic_configuration]) do - updated = - Enum.map(configs, fn - %{"group" => group, "key" => key, "delete" => "true"} = params -> - {:ok, config} = Config.delete(%{group: group, key: key, subkeys: params["subkeys"]}) - config - - %{"group" => group, "key" => key, "value" => value} -> - {:ok, config} = Config.update_or_create(%{group: group, key: key, value: value}) - config + def config_show(conn, _params) do + with :ok <- configurable_from_database(conn) do + configs = ConfigDB.get_all_as_keyword() + + if configs == [] do + errors( + conn, + {:error, "To use configuration from database migrate your settings to database."} + ) + else + merged = + Pleroma.Config.Holder.config() + |> ConfigDB.merge(configs) + |> Enum.map(fn {group, values} -> + Enum.map(values, fn {key, value} -> + db = + if configs[group][key] do + ConfigDB.get_db_keys(configs[group][key], key) + end + + db_value = configs[group][key] + + merged_value = + if !is_nil(db_value) and Keyword.keyword?(db_value) and + ConfigDB.sub_key_full_update?(group, key, Keyword.keys(db_value)) do + ConfigDB.merge_group(group, key, value, db_value) + else + value + end + + setting = %{ + group: ConfigDB.convert(group), + key: ConfigDB.convert(key), + value: ConfigDB.convert(merged_value) + } + + if db, do: Map.put(setting, :db, db), else: setting + end) end) - |> Enum.reject(&is_nil(&1)) + |> List.flatten() - Pleroma.Config.TransferTask.load_and_update_env() - Mix.Tasks.Pleroma.Config.run(["migrate_from_db", Pleroma.Config.get(:env), "false"]) - updated - else - [] + json(conn, %{configs: merged}) end + end + end - conn - |> put_view(ConfigView) - |> render("index.json", %{configs: updated}) + def config_update(conn, %{"configs" => configs}) do + with :ok <- configurable_from_database(conn) do + {_errors, results} = + Enum.map(configs, fn + %{"group" => group, "key" => key, "delete" => true} = params -> + ConfigDB.delete(%{group: group, key: key, subkeys: params["subkeys"]}) + + %{"group" => group, "key" => key, "value" => value} -> + ConfigDB.update_or_create(%{group: group, key: key, value: value}) + end) + |> Enum.split_with(fn result -> elem(result, 0) == :error end) + + {deleted, updated} = + results + |> Enum.map(fn {:ok, config} -> + Map.put(config, :db, ConfigDB.get_db_keys(config)) + end) + |> Enum.split_with(fn config -> + Ecto.get_meta(config, :state) == :deleted + end) + + Pleroma.Config.TransferTask.load_and_update_env(deleted) + + Mix.Tasks.Pleroma.Config.run([ + "migrate_from_db", + "--env", + to_string(Pleroma.Config.get(:env)) + ]) + + conn + |> put_view(ConfigView) + |> render("index.json", %{configs: updated}) + end + end + + defp configurable_from_database(conn) do + if Pleroma.Config.get(:configurable_from_database) do + :ok + else + errors( + conn, + {:error, "To use this endpoint you need to enable configuration from database."} + ) + end end def reload_emoji(conn, _params) do diff --git a/lib/pleroma/web/admin_api/config.ex b/lib/pleroma/web/admin_api/config.ex deleted file mode 100644 index 1917a5580..000000000 --- a/lib/pleroma/web/admin_api/config.ex +++ /dev/null @@ -1,182 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.AdminAPI.Config do - use Ecto.Schema - import Ecto.Changeset - import Pleroma.Web.Gettext - alias __MODULE__ - alias Pleroma.Repo - - @type t :: %__MODULE__{} - - schema "config" do - field(:key, :string) - field(:group, :string) - field(:value, :binary) - - timestamps() - end - - @spec get_by_params(map()) :: Config.t() | nil - def get_by_params(params), do: Repo.get_by(Config, params) - - @spec changeset(Config.t(), map()) :: Changeset.t() - def changeset(config, params \\ %{}) do - config - |> cast(params, [:key, :group, :value]) - |> validate_required([:key, :group, :value]) - |> unique_constraint(:key, name: :config_group_key_index) - end - - @spec create(map()) :: {:ok, Config.t()} | {:error, Changeset.t()} - def create(params) do - %Config{} - |> changeset(Map.put(params, :value, transform(params[:value]))) - |> Repo.insert() - end - - @spec update(Config.t(), map()) :: {:ok, Config} | {:error, Changeset.t()} - def update(%Config{} = config, %{value: value}) do - config - |> change(value: transform(value)) - |> Repo.update() - end - - @spec update_or_create(map()) :: {:ok, Config.t()} | {:error, Changeset.t()} - def update_or_create(params) do - with %Config{} = config <- Config.get_by_params(Map.take(params, [:group, :key])) do - Config.update(config, params) - else - nil -> Config.create(params) - end - end - - @spec delete(map()) :: {:ok, Config.t()} | {:error, Changeset.t()} - def delete(params) do - with %Config{} = config <- Config.get_by_params(Map.delete(params, :subkeys)) do - if params[:subkeys] do - updated_value = - Keyword.drop( - :erlang.binary_to_term(config.value), - Enum.map(params[:subkeys], &do_transform_string(&1)) - ) - - Config.update(config, %{value: updated_value}) - else - Repo.delete(config) - {:ok, nil} - end - else - nil -> - err = - dgettext("errors", "Config with params %{params} not found", params: inspect(params)) - - {:error, err} - end - end - - @spec from_binary(binary()) :: term() - def from_binary(binary), do: :erlang.binary_to_term(binary) - - @spec from_binary_with_convert(binary()) :: any() - def from_binary_with_convert(binary) do - from_binary(binary) - |> do_convert() - end - - defp do_convert(entity) when is_list(entity) do - for v <- entity, into: [], do: do_convert(v) - end - - defp do_convert(%Regex{} = entity), do: inspect(entity) - - defp do_convert(entity) when is_map(entity) do - for {k, v} <- entity, into: %{}, do: {do_convert(k), do_convert(v)} - end - - defp do_convert({:dispatch, [entity]}), do: %{"tuple" => [":dispatch", [inspect(entity)]]} - defp do_convert({:partial_chain, entity}), do: %{"tuple" => [":partial_chain", inspect(entity)]} - - defp do_convert(entity) when is_tuple(entity), - do: %{"tuple" => do_convert(Tuple.to_list(entity))} - - defp do_convert(entity) when is_boolean(entity) or is_number(entity) or is_nil(entity), - do: entity - - defp do_convert(entity) when is_atom(entity) do - string = to_string(entity) - - if String.starts_with?(string, "Elixir."), - do: do_convert(string), - else: ":" <> string - end - - defp do_convert("Elixir." <> module_name), do: module_name - - defp do_convert(entity) when is_binary(entity), do: entity - - @spec transform(any()) :: binary() - def transform(entity) when is_binary(entity) or is_map(entity) or is_list(entity) do - :erlang.term_to_binary(do_transform(entity)) - end - - def transform(entity), do: :erlang.term_to_binary(entity) - - defp do_transform(%Regex{} = entity), do: entity - - defp do_transform(%{"tuple" => [":dispatch", [entity]]}) do - {dispatch_settings, []} = do_eval(entity) - {:dispatch, [dispatch_settings]} - end - - defp do_transform(%{"tuple" => [":partial_chain", entity]}) do - {partial_chain, []} = do_eval(entity) - {:partial_chain, partial_chain} - end - - defp do_transform(%{"tuple" => entity}) do - Enum.reduce(entity, {}, fn val, acc -> Tuple.append(acc, do_transform(val)) end) - end - - defp do_transform(entity) when is_map(entity) do - for {k, v} <- entity, into: %{}, do: {do_transform(k), do_transform(v)} - end - - defp do_transform(entity) when is_list(entity) do - for v <- entity, into: [], do: do_transform(v) - end - - defp do_transform(entity) when is_binary(entity) do - String.trim(entity) - |> do_transform_string() - end - - defp do_transform(entity), do: entity - - defp do_transform_string("~r/" <> pattern) do - modificator = String.split(pattern, "/") |> List.last() - pattern = String.trim_trailing(pattern, "/" <> modificator) - - case modificator do - "" -> ~r/#{pattern}/ - "i" -> ~r/#{pattern}/i - "u" -> ~r/#{pattern}/u - "s" -> ~r/#{pattern}/s - end - end - - defp do_transform_string(":" <> atom), do: String.to_atom(atom) - - defp do_transform_string(value) do - if String.starts_with?(value, "Pleroma") or String.starts_with?(value, "Phoenix"), - do: String.to_existing_atom("Elixir." <> value), - else: value - end - - defp do_eval(entity) do - cleaned_string = String.replace(entity, ~r/[^\w|^{:,[|^,|^[|^\]^}|^\/|^\.|^"]^\s/, "") - Code.eval_string(cleaned_string, [], requires: [], macros: []) - end -end diff --git a/lib/pleroma/web/admin_api/views/config_view.ex b/lib/pleroma/web/admin_api/views/config_view.ex index 49add0b6e..23d97e847 100644 --- a/lib/pleroma/web/admin_api/views/config_view.ex +++ b/lib/pleroma/web/admin_api/views/config_view.ex @@ -12,10 +12,16 @@ defmodule Pleroma.Web.AdminAPI.ConfigView do end def render("show.json", %{config: config}) do - %{ + map = %{ key: config.key, group: config.group, - value: Pleroma.Web.AdminAPI.Config.from_binary_with_convert(config.value) + value: Pleroma.ConfigDB.from_binary_with_convert(config.value) } + + if config.db != [] do + Map.put(map, :db, config.db) + else + map + end end end diff --git a/lib/pleroma/web/admin_api/views/report_view.ex b/lib/pleroma/web/admin_api/views/report_view.ex index 13602efd9..4880d2992 100644 --- a/lib/pleroma/web/admin_api/views/report_view.ex +++ b/lib/pleroma/web/admin_api/views/report_view.ex @@ -39,7 +39,8 @@ defmodule Pleroma.Web.AdminAPI.ReportView do content: content, created_at: created_at, statuses: StatusView.render("index.json", %{activities: statuses, as: :activity}), - state: report.data["state"] + state: report.data["state"], + notes: render(__MODULE__, "index_notes.json", %{notes: report.report_notes}) } end @@ -69,6 +70,28 @@ defmodule Pleroma.Web.AdminAPI.ReportView do } end + def render("index_notes.json", %{notes: notes}) when is_list(notes) do + Enum.map(notes, &render(__MODULE__, "show_note.json", &1)) + end + + def render("index_notes.json", _), do: [] + + def render("show_note.json", %{ + id: id, + content: content, + user_id: user_id, + inserted_at: inserted_at + }) do + user = User.get_by_id(user_id) + + %{ + id: id, + content: content, + user: merge_account_views(user), + created_at: Utils.to_masto_date(inserted_at) + } + end + defp merge_account_views(%User{} = user) do Pleroma.Web.MastodonAPI.AccountView.render("show.json", %{user: user}) |> Map.merge(Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: user})) diff --git a/lib/pleroma/web/admin_api/views/status_view.ex b/lib/pleroma/web/admin_api/views/status_view.ex new file mode 100644 index 000000000..6f2b2b09c --- /dev/null +++ b/lib/pleroma/web/admin_api/views/status_view.ex @@ -0,0 +1,42 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.StatusView do + use Pleroma.Web, :view + + require Pleroma.Constants + + alias Pleroma.User + + def render("index.json", opts) do + render_many(opts.activities, __MODULE__, "show.json", opts) + end + + def render("show.json", %{activity: %{data: %{"object" => _object}} = activity} = opts) do + user = get_user(activity.data["actor"]) + + Pleroma.Web.MastodonAPI.StatusView.render("show.json", opts) + |> Map.merge(%{account: merge_account_views(user)}) + end + + defp merge_account_views(%User{} = user) do + Pleroma.Web.MastodonAPI.AccountView.render("show.json", %{user: user}) + |> Map.merge(Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: user})) + end + + defp merge_account_views(_), do: %{} + + defp get_user(ap_id) do + cond do + user = User.get_cached_by_ap_id(ap_id) -> + user + + user = User.get_by_guessed_nickname(ap_id) -> + user + + true -> + User.error_user(ap_id) + end + end +end |