X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fweb%2Fadmin_api%2Fadmin_api_controller.ex;h=67222ebaebd9ceb241f464906d7d1c74c5d196c9;hb=a17bfb5fababbe25fa2abcfccd013c9f3edc2ef7;hp=7118faf94b66d77ebdb95013bfff299808064423;hpb=b8d5c09f48a4b643f0dc60930bc69772a32a3b5e;p=akkoma diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 7118faf94..9c79310c0 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -1,20 +1,25 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors +# Copyright © 2017-2020 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.AdminAPI.AdminAPIController do use Pleroma.Web, :controller + + import Pleroma.Web.ControllerHelper, only: [json_response: 3] + alias Pleroma.Activity + alias Pleroma.Config + alias Pleroma.ConfigDB alias Pleroma.ModerationLog alias Pleroma.Plugs.OAuthScopesPlug alias Pleroma.ReportNote + alias Pleroma.Stats 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 @@ -22,17 +27,20 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do alias Pleroma.Web.AdminAPI.Search alias Pleroma.Web.CommonAPI alias Pleroma.Web.Endpoint + alias Pleroma.Web.MastodonAPI.AppView alias Pleroma.Web.MastodonAPI.StatusView + alias Pleroma.Web.OAuth.App 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"], admin: true} - when action in [:list_users, :user_show, :right_get] + when action in [:list_users, :user_show, :right_get, :show_user_credentials] ) plug( @@ -48,7 +56,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do :tag_users, :untag_users, :right_add, - :right_delete + :right_delete, + :update_user_credentials ] ) @@ -93,7 +102,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do plug( OAuthScopesPlug, %{scopes: ["read"], admin: true} - when action in [:config_show, :migrate_to_db, :migrate_from_db, :list_log] + when action in [:config_show, :list_log, :stats] ) plug( @@ -102,8 +111,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do when action == :config_update ) - @users_page_size 50 - action_fallback(:errors) def user_delete(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do @@ -240,21 +247,24 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end def list_instance_statuses(conn, %{"instance" => instance} = params) do + with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true {page, page_size} = page_params(params) activities = - ActivityPub.fetch_instance_activities(%{ + ActivityPub.fetch_statuses(nil, %{ "instance" => instance, "limit" => page_size, - "offset" => (page - 1) * page_size + "offset" => (page - 1) * page_size, + "exclude_reblogs" => !with_reblogs && "true" }) conn |> put_view(Pleroma.Web.AdminAPI.StatusView) - |> render("index.json", %{activities: activities, as: :activity}) + |> render("index.json", %{activities: activities, as: :activity, skip_relationships: false}) end def list_user_statuses(conn, %{"nickname" => nickname} = params) do + with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true godmode = params["godmode"] == "true" || params["godmode"] == true with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do @@ -263,12 +273,13 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do activities = ActivityPub.fetch_user_activities(user, nil, %{ "limit" => page_size, - "godmode" => godmode + "godmode" => godmode, + "exclude_reblogs" => !with_reblogs && "true" }) conn |> put_view(StatusView) - |> render("index.json", %{activities: activities, as: :activity}) + |> render("index.json", %{activities: activities, as: :activity, skip_relationships: false}) else _ -> {:error, :not_found} end @@ -567,9 +578,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do @doc "Sends registration invite via email" def email_invite(%{assigns: %{user: user}} = conn, %{"email" => email} = params) do - with true <- - Pleroma.Config.get([:instance, :invites_enabled]) && - !Pleroma.Config.get([:instance, :registrations_open]), + with {_, false} <- {:registrations_open, Config.get([:instance, :registrations_open])}, + {_, true} <- {:invites_enabled, Config.get([:instance, :invites_enabled])}, {:ok, invite_token} <- UserInviteToken.create_invite(), email <- Pleroma.Emails.UserEmail.user_invitation_email( @@ -580,6 +590,18 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do ), {:ok, _} <- Pleroma.Emails.Mailer.deliver(email) do json_response(conn, :no_content, "") + else + {:registrations_open, _} -> + errors( + conn, + {:error, "To send invites you need to set the `registrations_open` option to false."} + ) + + {:invites_enabled, _} -> + errors( + conn, + {:error, "To send invites you need to set the `invites_enabled` option to true."} + ) end end @@ -650,6 +672,52 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do json_response(conn, :no_content, "") end + @doc "Show a given user's credentials" + def show_user_credentials(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do + with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do + conn + |> put_view(AccountView) + |> render("credentials.json", %{user: user, for: admin}) + else + _ -> {:error, :not_found} + end + end + + @doc "Updates a given user" + def update_user_credentials( + %{assigns: %{user: admin}} = conn, + %{"nickname" => nickname} = params + ) do + with {_, user} <- {:user, User.get_cached_by_nickname(nickname)}, + {:ok, _user} <- + User.update_as_admin(user, params) do + ModerationLog.insert_log(%{ + actor: admin, + subject: [user], + action: "updated_users" + }) + + if params["password"] do + User.force_password_reset_async(user) + end + + ModerationLog.insert_log(%{ + actor: admin, + subject: [user], + action: "force_password_reset" + }) + + json(conn, %{status: "success"}) + else + {:error, changeset} -> + {_, {error, _}} = Enum.at(changeset.errors, 0) + json(conn, %{error: "New password #{error}."}) + + _ -> + json(conn, %{error: "Unable to change password."}) + end + end + def list_reports(conn, params) do {page, page_size} = page_params(params) @@ -660,14 +728,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do |> render("index.json", %{reports: reports}) end - def list_grouped_reports(conn, _params) do - statuses = Utils.get_reported_activities() - - conn - |> put_view(ReportView) - |> render("index_grouped.json", Utils.get_reports_grouped_by_status(statuses)) - end - def report_show(conn, %{"id" => id}) do with %Activity{} = report <- Activity.get_by_id(id) do conn @@ -737,6 +797,26 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end end + def list_statuses(%{assigns: %{user: _admin}} = conn, params) do + godmode = params["godmode"] == "true" || params["godmode"] == true + local_only = params["local_only"] == "true" || params["local_only"] == true + with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true + {page, page_size} = page_params(params) + + activities = + ActivityPub.fetch_statuses(nil, %{ + "godmode" => godmode, + "local_only" => local_only, + "limit" => page_size, + "offset" => (page - 1) * page_size, + "exclude_reblogs" => !with_reblogs && "true" + }) + + conn + |> put_view(Pleroma.Web.AdminAPI.StatusView) + |> render("index.json", %{activities: activities, as: :activity, skip_relationships: false}) + end + def status_update(%{assigns: %{user: admin}} = conn, %{"id" => id} = params) do with {:ok, activity} <- CommonAPI.update_activity_scope(id, params) do {:ok, sensitive} = Ecto.Type.cast(:boolean, params["sensitive"]) @@ -785,49 +865,124 @@ 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, %{}) + 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}) + end end def config_show(conn, _params) do - configs = Pleroma.Repo.all(Config) + with :ok <- configurable_from_database(conn) do + configs = ConfigDB.get_all_as_keyword() + + merged = + Config.Holder.default_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) + |> List.flatten() - conn - |> put_view(ConfigView) - |> render("index.json", %{configs: configs}) + json(conn, %{configs: merged, need_reboot: Restarter.Pleroma.need_reboot?()}) + 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 + 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) + + Config.TransferTask.load_and_update_env(deleted, false) + + if !Restarter.Pleroma.need_reboot?() do + changed_reboot_settings? = + (updated ++ deleted) + |> Enum.any?(fn config -> + group = ConfigDB.from_string(config.group) + key = ConfigDB.from_string(config.key) + value = ConfigDB.from_binary(config.value) + Config.TransferTask.pleroma_need_restart?(group, key, value) end) - |> Enum.reject(&is_nil(&1)) - Pleroma.Config.TransferTask.load_and_update_env() - Mix.Tasks.Pleroma.Config.run(["migrate_from_db", Pleroma.Config.get(:env), "false"]) - updated - else - [] + if changed_reboot_settings?, do: Restarter.Pleroma.need_reboot() end - conn - |> put_view(ConfigView) - |> render("index.json", %{configs: updated}) + conn + |> put_view(ConfigView) + |> render("index.json", %{configs: updated, need_reboot: Restarter.Pleroma.need_reboot?()}) + end + end + + def restart(conn, _params) do + with :ok <- configurable_from_database(conn) do + Restarter.Pleroma.restart(Config.get(:env), 50) + + json(conn, %{}) + end + end + + def need_reboot(conn, _params) do + json(conn, %{need_reboot: Restarter.Pleroma.need_reboot?()}) + end + + defp configurable_from_database(conn) do + if 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 @@ -864,6 +1019,90 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do conn |> json("") end + def oauth_app_create(conn, params) do + params = + if params["name"] do + Map.put(params, "client_name", params["name"]) + else + params + end + + result = + case App.create(params) do + {:ok, app} -> + AppView.render("show.json", %{app: app, admin: true}) + + {:error, changeset} -> + App.errors(changeset) + end + + json(conn, result) + end + + def oauth_app_update(conn, params) do + params = + if params["name"] do + Map.put(params, "client_name", params["name"]) + else + params + end + + with {:ok, app} <- App.update(params) do + json(conn, AppView.render("show.json", %{app: app, admin: true})) + else + {:error, changeset} -> + json(conn, App.errors(changeset)) + + nil -> + json_response(conn, :bad_request, "") + end + end + + def oauth_app_list(conn, params) do + {page, page_size} = page_params(params) + + search_params = %{ + client_name: params["name"], + client_id: params["client_id"], + page: page, + page_size: page_size + } + + search_params = + if Map.has_key?(params, "trusted") do + Map.put(search_params, :trusted, params["trusted"]) + else + search_params + end + + with {:ok, apps, count} <- App.search(search_params) do + json( + conn, + AppView.render("index.json", + apps: apps, + count: count, + page_size: page_size, + admin: true + ) + ) + end + end + + def oauth_app_delete(conn, params) do + with {:ok, _app} <- App.destroy(params["id"]) do + json_response(conn, :no_content, "") + else + _ -> json_response(conn, :bad_request, "") + end + end + + def stats(conn, _) do + count = Stats.get_status_visibility_count() + + conn + |> json(%{"status_visibility" => count}) + end + def errors(conn, {:error, :not_found}) do conn |> put_status(:not_found)