X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=test%2Fweb%2Fadmin_api%2Fadmin_api_controller_test.exs;h=d6b8399480b200b8ccc70b5bb4b5cb362a64cc05;hb=b2eb1124d115beda0907121c3c6f10783b34f352;hp=d11b26207f18909767a4d79c04e340f5442824ca;hpb=6a716e3fe5290df80af72e3ad5e45ee3afb581a8;p=akkoma diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index d11b26207..d6b839948 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -1,12 +1,17 @@ # 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.AdminAPIControllerTest do use Pleroma.Web.ConnCase use Oban.Testing, repo: Pleroma.Repo + import Pleroma.Factory + import ExUnit.CaptureLog + alias Pleroma.Activity + alias Pleroma.Config + alias Pleroma.ConfigDB alias Pleroma.HTML alias Pleroma.ModerationLog alias Pleroma.Repo @@ -18,7 +23,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do alias Pleroma.Web.CommonAPI alias Pleroma.Web.MastodonAPI.StatusView alias Pleroma.Web.MediaProxy - import Pleroma.Factory setup_all do Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) @@ -40,7 +44,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do describe "with [:auth, :enforce_oauth_admin_scope_usage]," do clear_config([:auth, :enforce_oauth_admin_scope_usage]) do - Pleroma.Config.put([:auth, :enforce_oauth_admin_scope_usage], true) + Config.put([:auth, :enforce_oauth_admin_scope_usage], true) end test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope", @@ -90,7 +94,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do describe "unless [:auth, :enforce_oauth_admin_scope_usage]," do clear_config([:auth, :enforce_oauth_admin_scope_usage]) do - Pleroma.Config.put([:auth, :enforce_oauth_admin_scope_usage], false) + Config.put([:auth, :enforce_oauth_admin_scope_usage], false) end test "GET /api/pleroma/admin/users/:nickname requires " <> @@ -578,11 +582,11 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do describe "POST /api/pleroma/admin/email_invite, with valid config" do clear_config([:instance, :registrations_open]) do - Pleroma.Config.put([:instance, :registrations_open], false) + Config.put([:instance, :registrations_open], false) end clear_config([:instance, :invites_enabled]) do - Pleroma.Config.put([:instance, :invites_enabled], true) + Config.put([:instance, :invites_enabled], true) end test "sends invitation and returns 204", %{admin: admin, conn: conn} do @@ -597,12 +601,12 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do assert json_response(conn, :no_content) - token_record = List.last(Pleroma.Repo.all(Pleroma.UserInviteToken)) + token_record = List.last(Repo.all(Pleroma.UserInviteToken)) assert token_record refute token_record.used - notify_email = Pleroma.Config.get([:instance, :notify_email]) - instance_name = Pleroma.Config.get([:instance, :name]) + notify_email = Config.get([:instance, :notify_email]) + instance_name = Config.get([:instance, :name]) email = Pleroma.Emails.UserEmail.user_invitation_email( @@ -638,8 +642,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do clear_config([:instance, :invites_enabled]) test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do - Pleroma.Config.put([:instance, :registrations_open], false) - Pleroma.Config.put([:instance, :invites_enabled], false) + Config.put([:instance, :registrations_open], false) + Config.put([:instance, :invites_enabled], false) conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD") @@ -647,8 +651,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do end test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do - Pleroma.Config.put([:instance, :registrations_open], true) - Pleroma.Config.put([:instance, :invites_enabled], true) + Config.put([:instance, :registrations_open], true) + Config.put([:instance, :invites_enabled], true) conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD") @@ -1363,9 +1367,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do } end - test "requires write:reports scope", %{conn: conn, id: id, admin: admin} do - read_token = insert(:oauth_token, user: admin, scopes: ["read"]) - write_token = insert(:oauth_token, user: admin, scopes: ["write:reports"]) + test "requires admin:write:reports scope", %{conn: conn, id: id, admin: admin} do + read_token = insert(:oauth_token, user: admin, scopes: ["admin:read"]) + write_token = insert(:oauth_token, user: admin, scopes: ["admin:write:reports"]) response = conn @@ -1376,7 +1380,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do |> json_response(403) assert response == %{ - "error" => "Insufficient permissions: admin:write:reports | write:reports." + "error" => "Insufficient permissions: admin:write:reports." } conn @@ -1876,33 +1880,41 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do "@#{admin.nickname} deleted status ##{id}" end - test "returns error when status is not exist", %{conn: conn} do + test "returns 404 when the status does not exist", %{conn: conn} do conn = delete(conn, "/api/pleroma/admin/statuses/test") - assert json_response(conn, :bad_request) == "Could not delete" + assert json_response(conn, :not_found) == "Not found" end end describe "GET /api/pleroma/admin/config" do - test "without any settings in db", %{conn: conn} do + clear_config(:configurable_from_database) do + Config.put(:configurable_from_database, true) + end + + test "when configuration from database is off", %{conn: conn} do + Config.put(:configurable_from_database, false) conn = get(conn, "/api/pleroma/admin/config") - assert json_response(conn, 200) == %{"configs" => []} + assert json_response(conn, 400) == + "To use this endpoint you need to enable configuration from database." end - test "with settings in db", %{conn: conn} do + test "with settings only in db", %{conn: conn} do config1 = insert(:config) config2 = insert(:config) - conn = get(conn, "/api/pleroma/admin/config") + conn = get(conn, "/api/pleroma/admin/config", %{"only_db" => true}) %{ "configs" => [ %{ + "group" => ":pleroma", "key" => key1, "value" => _ }, %{ + "group" => ":pleroma", "key" => key2, "value" => _ } @@ -1912,11 +1924,107 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do assert key1 == config1.key assert key2 == config2.key end + + test "db is added to settings that are in db", %{conn: conn} do + _config = insert(:config, key: ":instance", value: ConfigDB.to_binary(name: "Some name")) + + %{"configs" => configs} = + conn + |> get("/api/pleroma/admin/config") + |> json_response(200) + + [instance_config] = + Enum.filter(configs, fn %{"group" => group, "key" => key} -> + group == ":pleroma" and key == ":instance" + end) + + assert instance_config["db"] == [":name"] + end + + test "merged default setting with db settings", %{conn: conn} do + config1 = insert(:config) + config2 = insert(:config) + + config3 = + insert(:config, + value: ConfigDB.to_binary(k1: :v1, k2: :v2) + ) + + %{"configs" => configs} = + conn + |> get("/api/pleroma/admin/config") + |> json_response(200) + + assert length(configs) > 3 + + received_configs = + Enum.filter(configs, fn %{"group" => group, "key" => key} -> + group == ":pleroma" and key in [config1.key, config2.key, config3.key] + end) + + assert length(received_configs) == 3 + + db_keys = + config3.value + |> ConfigDB.from_binary() + |> Keyword.keys() + |> ConfigDB.convert() + + Enum.each(received_configs, fn %{"value" => value, "db" => db} -> + assert db in [[config1.key], [config2.key], db_keys] + + assert value in [ + ConfigDB.from_binary_with_convert(config1.value), + ConfigDB.from_binary_with_convert(config2.value), + ConfigDB.from_binary_with_convert(config3.value) + ] + end) + end + + test "subkeys with full update right merge", %{conn: conn} do + config1 = + insert(:config, + key: ":emoji", + value: ConfigDB.to_binary(groups: [a: 1, b: 2], key: [a: 1]) + ) + + config2 = + insert(:config, + key: ":assets", + value: ConfigDB.to_binary(mascots: [a: 1, b: 2], key: [a: 1]) + ) + + %{"configs" => configs} = + conn + |> get("/api/pleroma/admin/config") + |> json_response(200) + + vals = + Enum.filter(configs, fn %{"group" => group, "key" => key} -> + group == ":pleroma" and key in [config1.key, config2.key] + end) + + emoji = Enum.find(vals, fn %{"key" => key} -> key == ":emoji" end) + assets = Enum.find(vals, fn %{"key" => key} -> key == ":assets" end) + + emoji_val = ConfigDB.transform_with_out_binary(emoji["value"]) + assets_val = ConfigDB.transform_with_out_binary(assets["value"]) + + assert emoji_val[:groups] == [a: 1, b: 2] + assert assets_val[:mascots] == [a: 1, b: 2] + end + end + + test "POST /api/pleroma/admin/config error", %{conn: conn} do + conn = post(conn, "/api/pleroma/admin/config", %{"configs" => []}) + + assert json_response(conn, 400) == + "To use this endpoint you need to enable configuration from database." end describe "POST /api/pleroma/admin/config" do setup do - temp_file = "config/test.exported_from_db.secret.exs" + http = Application.get_env(:pleroma, :http) on_exit(fn -> Application.delete_env(:pleroma, :key1) @@ -1927,28 +2035,33 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do Application.delete_env(:pleroma, :keyaa2) Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal) Application.delete_env(:pleroma, Pleroma.Captcha.NotReal) - :ok = File.rm(temp_file) + Application.put_env(:pleroma, :http, http) + Application.put_env(:tesla, :adapter, Tesla.Mock) + Restarter.Pleroma.refresh() end) end - clear_config([:instance, :dynamic_configuration]) do - Pleroma.Config.put([:instance, :dynamic_configuration], true) + clear_config(:configurable_from_database) do + Config.put(:configurable_from_database, true) end @tag capture_log: true test "create new config setting in db", %{conn: conn} do + ueberauth = Application.get_env(:ueberauth, Ueberauth) + on_exit(fn -> Application.put_env(:ueberauth, Ueberauth, ueberauth) end) + conn = post(conn, "/api/pleroma/admin/config", %{ configs: [ - %{group: "pleroma", key: "key1", value: "value1"}, + %{group: ":pleroma", key: ":key1", value: "value1"}, %{ - group: "ueberauth", - key: "Ueberauth.Strategy.Twitter.OAuth", + group: ":ueberauth", + key: "Ueberauth", value: [%{"tuple" => [":consumer_secret", "aaaa"]}] }, %{ - group: "pleroma", - key: "key2", + group: ":pleroma", + key: ":key2", value: %{ ":nested_1" => "nested_value1", ":nested_2" => [ @@ -1958,21 +2071,21 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do } }, %{ - group: "pleroma", - key: "key3", + group: ":pleroma", + key: ":key3", value: [ %{"nested_3" => ":nested_3", "nested_33" => "nested_33"}, %{"nested_4" => true} ] }, %{ - group: "pleroma", - key: "key4", + group: ":pleroma", + key: ":key4", value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"} }, %{ - group: "idna", - key: "key5", + group: ":idna", + key: ":key5", value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]} } ] @@ -1981,43 +2094,49 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do assert json_response(conn, 200) == %{ "configs" => [ %{ - "group" => "pleroma", - "key" => "key1", - "value" => "value1" + "group" => ":pleroma", + "key" => ":key1", + "value" => "value1", + "db" => [":key1"] }, %{ - "group" => "ueberauth", - "key" => "Ueberauth.Strategy.Twitter.OAuth", - "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}] + "group" => ":ueberauth", + "key" => "Ueberauth", + "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}], + "db" => [":consumer_secret"] }, %{ - "group" => "pleroma", - "key" => "key2", + "group" => ":pleroma", + "key" => ":key2", "value" => %{ ":nested_1" => "nested_value1", ":nested_2" => [ %{":nested_22" => "nested_value222"}, %{":nested_33" => %{":nested_44" => "nested_444"}} ] - } + }, + "db" => [":key2"] }, %{ - "group" => "pleroma", - "key" => "key3", + "group" => ":pleroma", + "key" => ":key3", "value" => [ %{"nested_3" => ":nested_3", "nested_33" => "nested_33"}, %{"nested_4" => true} - ] + ], + "db" => [":key3"] }, %{ - "group" => "pleroma", - "key" => "key4", - "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"} + "group" => ":pleroma", + "key" => ":key4", + "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"}, + "db" => [":key4"] }, %{ - "group" => "idna", - "key" => "key5", - "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]} + "group" => ":idna", + "key" => ":key5", + "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}, + "db" => [":key5"] } ] } @@ -2045,25 +2164,34 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []} end - test "update config setting & delete", %{conn: conn} do - config1 = insert(:config, key: "keyaa1") - config2 = insert(:config, key: "keyaa2") + test "save configs setting without explicit key", %{conn: conn} do + level = Application.get_env(:quack, :level) + meta = Application.get_env(:quack, :meta) + webhook_url = Application.get_env(:quack, :webhook_url) - insert(:config, - group: "ueberauth", - key: "Ueberauth.Strategy.Microsoft.OAuth", - value: :erlang.term_to_binary([]) - ) + on_exit(fn -> + Application.put_env(:quack, :level, level) + Application.put_env(:quack, :meta, meta) + Application.put_env(:quack, :webhook_url, webhook_url) + end) conn = post(conn, "/api/pleroma/admin/config", %{ configs: [ - %{group: config1.group, key: config1.key, value: "another_value"}, - %{group: config2.group, key: config2.key, delete: "true"}, %{ - group: "ueberauth", - key: "Ueberauth.Strategy.Microsoft.OAuth", - delete: "true" + group: ":quack", + key: ":level", + value: ":info" + }, + %{ + group: ":quack", + key: ":meta", + value: [":none"] + }, + %{ + group: ":quack", + key: ":webhook_url", + value: "https://hooks.slack.com/services/KEY" } ] }) @@ -2071,23 +2199,401 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do assert json_response(conn, 200) == %{ "configs" => [ %{ - "group" => "pleroma", + "group" => ":quack", + "key" => ":level", + "value" => ":info", + "db" => [":level"] + }, + %{ + "group" => ":quack", + "key" => ":meta", + "value" => [":none"], + "db" => [":meta"] + }, + %{ + "group" => ":quack", + "key" => ":webhook_url", + "value" => "https://hooks.slack.com/services/KEY", + "db" => [":webhook_url"] + } + ] + } + + assert Application.get_env(:quack, :level) == :info + assert Application.get_env(:quack, :meta) == [:none] + assert Application.get_env(:quack, :webhook_url) == "https://hooks.slack.com/services/KEY" + end + + test "saving config with partial update", %{conn: conn} do + config = insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: 2)) + + conn = + post(conn, "/api/pleroma/admin/config", %{ + configs: [ + %{group: config.group, key: config.key, value: [%{"tuple" => [":key3", 3]}]} + ] + }) + + assert json_response(conn, 200) == %{ + "configs" => [ + %{ + "group" => ":pleroma", + "key" => ":key1", + "value" => [ + %{"tuple" => [":key1", 1]}, + %{"tuple" => [":key2", 2]}, + %{"tuple" => [":key3", 3]} + ], + "db" => [":key1", ":key2", ":key3"] + } + ] + } + end + + test "saving config which need pleroma reboot", %{conn: conn} do + chat = Config.get(:chat) + on_exit(fn -> Config.put(:chat, chat) end) + + assert post( + conn, + "/api/pleroma/admin/config", + %{ + configs: [ + %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]} + ] + } + ) + |> json_response(200) == %{ + "configs" => [ + %{ + "db" => [":enabled"], + "group" => ":pleroma", + "key" => ":chat", + "value" => [%{"tuple" => [":enabled", true]}] + } + ], + "need_reboot" => true + } + + configs = + conn + |> get("/api/pleroma/admin/config") + |> json_response(200) + + assert configs["need_reboot"] + + capture_log(fn -> + assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{} + end) =~ "pleroma restarted" + + configs = + conn + |> get("/api/pleroma/admin/config") + |> json_response(200) + + refute Map.has_key?(configs, "need_reboot") + end + + test "update setting which need reboot, don't change reboot flag until reboot", %{conn: conn} do + chat = Config.get(:chat) + on_exit(fn -> Config.put(:chat, chat) end) + + assert post( + conn, + "/api/pleroma/admin/config", + %{ + configs: [ + %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]} + ] + } + ) + |> json_response(200) == %{ + "configs" => [ + %{ + "db" => [":enabled"], + "group" => ":pleroma", + "key" => ":chat", + "value" => [%{"tuple" => [":enabled", true]}] + } + ], + "need_reboot" => true + } + + assert post(conn, "/api/pleroma/admin/config", %{ + configs: [ + %{group: ":pleroma", key: ":key1", value: [%{"tuple" => [":key3", 3]}]} + ] + }) + |> json_response(200) == %{ + "configs" => [ + %{ + "group" => ":pleroma", + "key" => ":key1", + "value" => [ + %{"tuple" => [":key3", 3]} + ], + "db" => [":key3"] + } + ], + "need_reboot" => true + } + + capture_log(fn -> + assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{} + end) =~ "pleroma restarted" + + configs = + conn + |> get("/api/pleroma/admin/config") + |> json_response(200) + + refute Map.has_key?(configs, "need_reboot") + end + + test "saving config with nested merge", %{conn: conn} do + config = + insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: [k1: 1, k2: 2])) + + conn = + post(conn, "/api/pleroma/admin/config", %{ + configs: [ + %{ + group: config.group, + key: config.key, + value: [ + %{"tuple" => [":key3", 3]}, + %{ + "tuple" => [ + ":key2", + [ + %{"tuple" => [":k2", 1]}, + %{"tuple" => [":k3", 3]} + ] + ] + } + ] + } + ] + }) + + assert json_response(conn, 200) == %{ + "configs" => [ + %{ + "group" => ":pleroma", + "key" => ":key1", + "value" => [ + %{"tuple" => [":key1", 1]}, + %{"tuple" => [":key3", 3]}, + %{ + "tuple" => [ + ":key2", + [ + %{"tuple" => [":k1", 1]}, + %{"tuple" => [":k2", 1]}, + %{"tuple" => [":k3", 3]} + ] + ] + } + ], + "db" => [":key1", ":key3", ":key2"] + } + ] + } + end + + test "saving special atoms", %{conn: conn} do + conn = + post(conn, "/api/pleroma/admin/config", %{ + "configs" => [ + %{ + "group" => ":pleroma", + "key" => ":key1", + "value" => [ + %{ + "tuple" => [ + ":ssl_options", + [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}] + ] + } + ] + } + ] + }) + + assert json_response(conn, 200) == %{ + "configs" => [ + %{ + "group" => ":pleroma", + "key" => ":key1", + "value" => [ + %{ + "tuple" => [ + ":ssl_options", + [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}] + ] + } + ], + "db" => [":ssl_options"] + } + ] + } + + assert Application.get_env(:pleroma, :key1) == [ + ssl_options: [versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"]] + ] + end + + test "saving full setting if value is in full_key_update list", %{conn: conn} do + backends = Application.get_env(:logger, :backends) + on_exit(fn -> Application.put_env(:logger, :backends, backends) end) + + config = + insert(:config, + group: ":logger", + key: ":backends", + value: :erlang.term_to_binary([]) + ) + + conn = + post(conn, "/api/pleroma/admin/config", %{ + configs: [ + %{ + group: config.group, + key: config.key, + value: [":console", %{"tuple" => ["ExSyslogger", ":ex_syslogger"]}] + } + ] + }) + + assert json_response(conn, 200) == %{ + "configs" => [ + %{ + "group" => ":logger", + "key" => ":backends", + "value" => [ + ":console", + %{"tuple" => ["ExSyslogger", ":ex_syslogger"]} + ], + "db" => [":backends"] + } + ] + } + + assert Application.get_env(:logger, :backends) == [ + :console, + {ExSyslogger, :ex_syslogger} + ] + + capture_log(fn -> + require Logger + Logger.warn("Ooops...") + end) =~ "Ooops..." + end + + test "saving full setting if value is not keyword", %{conn: conn} do + config = + insert(:config, + group: ":tesla", + key: ":adapter", + value: :erlang.term_to_binary(Tesla.Adapter.Hackey) + ) + + conn = + post(conn, "/api/pleroma/admin/config", %{ + configs: [ + %{group: config.group, key: config.key, value: "Tesla.Adapter.Httpc"} + ] + }) + + assert json_response(conn, 200) == %{ + "configs" => [ + %{ + "group" => ":tesla", + "key" => ":adapter", + "value" => "Tesla.Adapter.Httpc", + "db" => [":adapter"] + } + ], + "need_reboot" => true + } + end + + test "update config setting & delete with fallback to default value", %{ + conn: conn, + admin: admin, + token: token + } do + ueberauth = Application.get_env(:ueberauth, Ueberauth) + config1 = insert(:config, key: ":keyaa1") + config2 = insert(:config, key: ":keyaa2") + + config3 = + insert(:config, + group: ":ueberauth", + key: "Ueberauth" + ) + + conn = + post(conn, "/api/pleroma/admin/config", %{ + configs: [ + %{group: config1.group, key: config1.key, value: "another_value"}, + %{group: config2.group, key: config2.key, value: "another_value"} + ] + }) + + assert json_response(conn, 200) == %{ + "configs" => [ + %{ + "group" => ":pleroma", "key" => config1.key, - "value" => "another_value" + "value" => "another_value", + "db" => [":keyaa1"] + }, + %{ + "group" => ":pleroma", + "key" => config2.key, + "value" => "another_value", + "db" => [":keyaa2"] } ] } assert Application.get_env(:pleroma, :keyaa1) == "another_value" - refute Application.get_env(:pleroma, :keyaa2) + assert Application.get_env(:pleroma, :keyaa2) == "another_value" + assert Application.get_env(:ueberauth, Ueberauth) == ConfigDB.from_binary(config3.value) + + conn = + build_conn() + |> assign(:user, admin) + |> assign(:token, token) + |> post("/api/pleroma/admin/config", %{ + configs: [ + %{group: config2.group, key: config2.key, delete: true}, + %{ + group: ":ueberauth", + key: "Ueberauth", + delete: true + } + ] + }) + + assert json_response(conn, 200) == %{ + "configs" => [] + } + + assert Application.get_env(:ueberauth, Ueberauth) == ueberauth + refute Keyword.has_key?(Application.get_all_env(:pleroma), :keyaa2) end test "common config example", %{conn: conn} do + adapter = Application.get_env(:tesla, :adapter) + on_exit(fn -> Application.put_env(:tesla, :adapter, adapter) end) + conn = post(conn, "/api/pleroma/admin/config", %{ configs: [ %{ - "group" => "pleroma", + "group" => ":pleroma", "key" => "Pleroma.Captcha.NotReal", "value" => [ %{"tuple" => [":enabled", false]}, @@ -2095,20 +2601,28 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do %{"tuple" => [":seconds_valid", 60]}, %{"tuple" => [":path", ""]}, %{"tuple" => [":key1", nil]}, - %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]}, %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]}, %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]}, %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]}, - %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]} + %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]}, + %{"tuple" => [":name", "Pleroma"]} ] + }, + %{ + "group" => ":tesla", + "key" => ":adapter", + "value" => "Tesla.Adapter.Httpc" } ] }) + assert Application.get_env(:tesla, :adapter) == Tesla.Adapter.Httpc + assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma" + assert json_response(conn, 200) == %{ "configs" => [ %{ - "group" => "pleroma", + "group" => ":pleroma", "key" => "Pleroma.Captcha.NotReal", "value" => [ %{"tuple" => [":enabled", false]}, @@ -2116,14 +2630,33 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do %{"tuple" => [":seconds_valid", 60]}, %{"tuple" => [":path", ""]}, %{"tuple" => [":key1", nil]}, - %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]}, %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]}, %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]}, %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]}, - %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]} + %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]}, + %{"tuple" => [":name", "Pleroma"]} + ], + "db" => [ + ":enabled", + ":method", + ":seconds_valid", + ":path", + ":key1", + ":regex1", + ":regex2", + ":regex3", + ":regex4", + ":name" ] + }, + %{ + "group" => ":tesla", + "key" => ":adapter", + "value" => "Tesla.Adapter.Httpc", + "db" => [":adapter"] } - ] + ], + "need_reboot" => true } end @@ -2132,7 +2665,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do post(conn, "/api/pleroma/admin/config", %{ configs: [ %{ - "group" => "pleroma", + "group" => ":pleroma", "key" => "Pleroma.Web.Endpoint.NotReal", "value" => [ %{ @@ -2196,7 +2729,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do assert json_response(conn, 200) == %{ "configs" => [ %{ - "group" => "pleroma", + "group" => ":pleroma", "key" => "Pleroma.Web.Endpoint.NotReal", "value" => [ %{ @@ -2252,7 +2785,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do ] ] } - ] + ], + "db" => [":http"] } ] } @@ -2263,7 +2797,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do post(conn, "/api/pleroma/admin/config", %{ configs: [ %{ - "group" => "pleroma", + "group" => ":pleroma", "key" => ":key1", "value" => [ %{"tuple" => [":key2", "some_val"]}, @@ -2293,7 +2827,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do %{ "configs" => [ %{ - "group" => "pleroma", + "group" => ":pleroma", "key" => ":key1", "value" => [ %{"tuple" => [":key2", "some_val"]}, @@ -2314,7 +2848,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do } ] } - ] + ], + "db" => [":key2", ":key3"] } ] } @@ -2325,7 +2860,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do post(conn, "/api/pleroma/admin/config", %{ configs: [ %{ - "group" => "pleroma", + "group" => ":pleroma", "key" => ":key1", "value" => %{"key" => "some_val"} } @@ -2336,83 +2871,21 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do %{ "configs" => [ %{ - "group" => "pleroma", + "group" => ":pleroma", "key" => ":key1", - "value" => %{"key" => "some_val"} + "value" => %{"key" => "some_val"}, + "db" => [":key1"] } ] } end - test "dispatch setting", %{conn: conn} do - conn = - post(conn, "/api/pleroma/admin/config", %{ - configs: [ - %{ - "group" => "pleroma", - "key" => "Pleroma.Web.Endpoint.NotReal", - "value" => [ - %{ - "tuple" => [ - ":http", - [ - %{"tuple" => [":ip", %{"tuple" => [127, 0, 0, 1]}]}, - %{"tuple" => [":dispatch", ["{:_, - [ - {\"/api/v1/streaming\", Pleroma.Web.MastodonAPI.WebsocketHandler, []}, - {\"/websocket\", Phoenix.Endpoint.CowboyWebSocket, - {Phoenix.Transports.WebSocket, - {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: \"/websocket\"]}}}, - {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}} - ]}"]]} - ] - ] - } - ] - } - ] - }) - - dispatch_string = - "{:_, [{\"/api/v1/streaming\", Pleroma.Web.MastodonAPI.WebsocketHandler, []}, " <> - "{\"/websocket\", Phoenix.Endpoint.CowboyWebSocket, {Phoenix.Transports.WebSocket, " <> - "{Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: \"/websocket\"]}}}, " <> - "{:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}]}" - - assert json_response(conn, 200) == %{ - "configs" => [ - %{ - "group" => "pleroma", - "key" => "Pleroma.Web.Endpoint.NotReal", - "value" => [ - %{ - "tuple" => [ - ":http", - [ - %{"tuple" => [":ip", %{"tuple" => [127, 0, 0, 1]}]}, - %{ - "tuple" => [ - ":dispatch", - [ - dispatch_string - ] - ] - } - ] - ] - } - ] - } - ] - } - end - test "queues key as atom", %{conn: conn} do conn = post(conn, "/api/pleroma/admin/config", %{ configs: [ %{ - "group" => "oban", + "group" => ":oban", "key" => ":queues", "value" => [ %{"tuple" => [":federator_incoming", 50]}, @@ -2430,7 +2903,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do assert json_response(conn, 200) == %{ "configs" => [ %{ - "group" => "oban", + "group" => ":oban", "key" => ":queues", "value" => [ %{"tuple" => [":federator_incoming", 50]}, @@ -2440,6 +2913,15 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do %{"tuple" => [":transmogrifier", 20]}, %{"tuple" => [":scheduled_activities", 10]}, %{"tuple" => [":background", 5]} + ], + "db" => [ + ":federator_incoming", + ":federator_outgoing", + ":web_push", + ":mailer", + ":transmogrifier", + ":scheduled_activities", + ":background" ] } ] @@ -2449,7 +2931,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do test "delete part of settings by atom subkeys", %{conn: conn} do config = insert(:config, - key: "keyaa1", + key: ":keyaa1", value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3") ) @@ -2460,57 +2942,171 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do group: config.group, key: config.key, subkeys: [":subkey1", ":subkey3"], - delete: "true" + delete: true } ] }) - assert( - json_response(conn, 200) == %{ - "configs" => [ + assert json_response(conn, 200) == %{ + "configs" => [ + %{ + "group" => ":pleroma", + "key" => ":keyaa1", + "value" => [%{"tuple" => [":subkey2", "val2"]}], + "db" => [":subkey2"] + } + ] + } + end + + test "proxy tuple localhost", %{conn: conn} do + conn = + post(conn, "/api/pleroma/admin/config", %{ + configs: [ %{ - "group" => "pleroma", - "key" => "keyaa1", - "value" => [%{"tuple" => [":subkey2", "val2"]}] + group: ":pleroma", + key: ":http", + value: [ + %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]}, + %{"tuple" => [":send_user_agent", false]} + ] } ] - } - ) + }) + + assert json_response(conn, 200) == %{ + "configs" => [ + %{ + "group" => ":pleroma", + "key" => ":http", + "value" => [ + %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]}, + %{"tuple" => [":send_user_agent", false]} + ], + "db" => [":proxy_url", ":send_user_agent"] + } + ] + } end - end - describe "config mix tasks run" do - setup do - temp_file = "config/test.exported_from_db.secret.exs" + test "proxy tuple domain", %{conn: conn} do + conn = + post(conn, "/api/pleroma/admin/config", %{ + configs: [ + %{ + group: ":pleroma", + key: ":http", + value: [ + %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]}, + %{"tuple" => [":send_user_agent", false]} + ] + } + ] + }) + + assert json_response(conn, 200) == %{ + "configs" => [ + %{ + "group" => ":pleroma", + "key" => ":http", + "value" => [ + %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]}, + %{"tuple" => [":send_user_agent", false]} + ], + "db" => [":proxy_url", ":send_user_agent"] + } + ] + } + end - Mix.shell(Mix.Shell.Quiet) + test "proxy tuple ip", %{conn: conn} do + conn = + post(conn, "/api/pleroma/admin/config", %{ + configs: [ + %{ + group: ":pleroma", + key: ":http", + value: [ + %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]}, + %{"tuple" => [":send_user_agent", false]} + ] + } + ] + }) - on_exit(fn -> - Mix.shell(Mix.Shell.IO) - :ok = File.rm(temp_file) - end) + assert json_response(conn, 200) == %{ + "configs" => [ + %{ + "group" => ":pleroma", + "key" => ":http", + "value" => [ + %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]}, + %{"tuple" => [":send_user_agent", false]} + ], + "db" => [":proxy_url", ":send_user_agent"] + } + ] + } + end + end - :ok + describe "GET /api/pleroma/admin/restart" do + clear_config(:configurable_from_database) do + Config.put(:configurable_from_database, true) end - clear_config([:instance, :dynamic_configuration]) do - Pleroma.Config.put([:instance, :dynamic_configuration], true) + test "pleroma restarts", %{conn: conn} do + capture_log(fn -> + assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{} + end) =~ "pleroma restarted" + + refute Restarter.Pleroma.need_reboot?() end + end + + describe "GET /api/pleroma/admin/statuses" do + test "returns all public, unlisted, and direct statuses", %{conn: conn, admin: admin} do + blocked = insert(:user) + user = insert(:user) + User.block(admin, blocked) + + {:ok, _} = + CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"}) + + {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"}) + {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"}) + {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"}) + {:ok, _} = CommonAPI.post(blocked, %{"status" => ".", "visibility" => "public"}) - clear_config([:feed, :post_title]) do - Pleroma.Config.put([:feed, :post_title], %{max_length: 100, omission: "…"}) + response = + conn + |> get("/api/pleroma/admin/statuses") + |> json_response(200) + + refute "private" in Enum.map(response, & &1["visibility"]) + assert length(response) == 4 end - test "transfer settings to DB and to file", %{conn: conn} do - assert Pleroma.Repo.all(Pleroma.Web.AdminAPI.Config) == [] - ret_conn = get(conn, "/api/pleroma/admin/config/migrate_to_db") - assert json_response(ret_conn, 200) == %{} - assert Pleroma.Repo.all(Pleroma.Web.AdminAPI.Config) > 0 + test "returns only local statuses with local_only on", %{conn: conn} do + user = insert(:user) + remote_user = insert(:user, local: false, nickname: "archaeme@archae.me") + insert(:note_activity, user: user, local: true) + insert(:note_activity, user: remote_user, local: false) - ret_conn = get(conn, "/api/pleroma/admin/config/migrate_from_db") + response = + conn + |> get("/api/pleroma/admin/statuses?local_only=true") + |> json_response(200) - assert json_response(ret_conn, 200) == %{} - assert Pleroma.Repo.all(Pleroma.Web.AdminAPI.Config) == [] + assert length(response) == 1 + end + + test "returns private statuses with godmode on", %{conn: conn} do + user = insert(:user) + {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"}) + {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"}) + conn = get(conn, "/api/pleroma/admin/statuses?godmode=true") + assert json_response(conn, 200) |> length() == 2 end end @@ -2564,6 +3160,20 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do assert json_response(conn, 200) |> length() == 5 end + + test "excludes reblogs by default", %{conn: conn, user: user} do + other_user = insert(:user) + {:ok, activity} = CommonAPI.post(user, %{"status" => "."}) + {:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, other_user) + + conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses") + assert json_response(conn_res, 200) |> length() == 0 + + conn_res = + get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true") + + assert json_response(conn_res, 200) |> length() == 1 + end end describe "GET /api/pleroma/admin/moderation_log" do @@ -2846,7 +3456,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do user = insert(:user, local: false, nickname: "archaeme@archae.me") user2 = insert(:user, local: false, nickname: "test@test.com") insert_pair(:note_activity, user: user) - insert(:note_activity, user: user2) + activity = insert(:note_activity, user: user2) ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses") @@ -2865,6 +3475,16 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do response = json_response(ret_conn, 200) assert Enum.empty?(response) + + CommonAPI.repeat(activity.id, user) + + ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses") + response = json_response(ret_conn, 200) + assert length(response) == 2 + + ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true") + response = json_response(ret_conn, 200) + assert length(response) == 3 end end @@ -2979,6 +3599,40 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do assert ReportNote |> Repo.all() |> length() == 1 end end + + test "GET /api/pleroma/admin/config/descriptions", %{conn: conn} do + admin = insert(:user, is_admin: true) + + conn = + assign(conn, :user, admin) + |> get("/api/pleroma/admin/config/descriptions") + + assert [child | _others] = json_response(conn, 200) + + assert child["children"] + assert child["key"] + assert String.starts_with?(child["group"], ":") + assert child["description"] + end + + describe "/api/pleroma/admin/stats" do + test "status visibility count", %{conn: conn} do + admin = insert(:user, is_admin: true) + user = insert(:user) + CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"}) + CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"}) + CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"}) + + response = + conn + |> assign(:user, admin) + |> get("/api/pleroma/admin/stats") + |> json_response(200) + + assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} = + response["status_visibility"] + end + end end # Needed for testing