diff options
Diffstat (limited to 'test/web')
| -rw-r--r-- | test/web/admin_api/controllers/admin_api_controller_test.exs | 1220 | ||||
| -rw-r--r-- | test/web/admin_api/controllers/config_controller_test.exs | 1290 | 
2 files changed, 1290 insertions, 1220 deletions
| diff --git a/test/web/admin_api/controllers/admin_api_controller_test.exs b/test/web/admin_api/controllers/admin_api_controller_test.exs index a1bff5688..2aaec510d 100644 --- a/test/web/admin_api/controllers/admin_api_controller_test.exs +++ b/test/web/admin_api/controllers/admin_api_controller_test.exs @@ -12,7 +12,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do    alias Pleroma.Activity    alias Pleroma.Config -  alias Pleroma.ConfigDB    alias Pleroma.HTML    alias Pleroma.MFA    alias Pleroma.ModerationLog @@ -1197,1175 +1196,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      end    end -  describe "GET /api/pleroma/admin/config" do -    setup do: clear_config(:configurable_from_database, true) - -    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, 400) == -               %{ -                 "error" => "To use this endpoint you need to enable configuration from database." -               } -    end - -    test "with settings only in db", %{conn: conn} do -      config1 = insert(:config) -      config2 = insert(:config) - -      conn = get(conn, "/api/pleroma/admin/config", %{"only_db" => true}) - -      %{ -        "configs" => [ -          %{ -            "group" => ":pleroma", -            "key" => key1, -            "value" => _ -          }, -          %{ -            "group" => ":pleroma", -            "key" => key2, -            "value" => _ -          } -        ] -      } = json_response(conn, 200) - -      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) == -             %{"error" => "To use this endpoint you need to enable configuration from database."} -  end - -  describe "POST /api/pleroma/admin/config" do -    setup do -      http = Application.get_env(:pleroma, :http) - -      on_exit(fn -> -        Application.delete_env(:pleroma, :key1) -        Application.delete_env(:pleroma, :key2) -        Application.delete_env(:pleroma, :key3) -        Application.delete_env(:pleroma, :key4) -        Application.delete_env(:pleroma, :keyaa1) -        Application.delete_env(:pleroma, :keyaa2) -        Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal) -        Application.delete_env(:pleroma, Pleroma.Captcha.NotReal) -        Application.put_env(:pleroma, :http, http) -        Application.put_env(:tesla, :adapter, Tesla.Mock) -        Restarter.Pleroma.refresh() -      end) -    end - -    setup do: clear_config(:configurable_from_database, true) - -    @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: ":ueberauth", -              key: "Ueberauth", -              value: [%{"tuple" => [":consumer_secret", "aaaa"]}] -            }, -            %{ -              group: ":pleroma", -              key: ":key2", -              value: %{ -                ":nested_1" => "nested_value1", -                ":nested_2" => [ -                  %{":nested_22" => "nested_value222"}, -                  %{":nested_33" => %{":nested_44" => "nested_444"}} -                ] -              } -            }, -            %{ -              group: ":pleroma", -              key: ":key3", -              value: [ -                %{"nested_3" => ":nested_3", "nested_33" => "nested_33"}, -                %{"nested_4" => true} -              ] -            }, -            %{ -              group: ":pleroma", -              key: ":key4", -              value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"} -            }, -            %{ -              group: ":idna", -              key: ":key5", -              value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]} -            } -          ] -        }) - -      assert json_response(conn, 200) == %{ -               "configs" => [ -                 %{ -                   "group" => ":pleroma", -                   "key" => ":key1", -                   "value" => "value1", -                   "db" => [":key1"] -                 }, -                 %{ -                   "group" => ":ueberauth", -                   "key" => "Ueberauth", -                   "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}], -                   "db" => [":consumer_secret"] -                 }, -                 %{ -                   "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", -                   "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"}, -                   "db" => [":key4"] -                 }, -                 %{ -                   "group" => ":idna", -                   "key" => ":key5", -                   "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}, -                   "db" => [":key5"] -                 } -               ] -             } - -      assert Application.get_env(:pleroma, :key1) == "value1" - -      assert Application.get_env(:pleroma, :key2) == %{ -               nested_1: "nested_value1", -               nested_2: [ -                 %{nested_22: "nested_value222"}, -                 %{nested_33: %{nested_44: "nested_444"}} -               ] -             } - -      assert Application.get_env(:pleroma, :key3) == [ -               %{"nested_3" => :nested_3, "nested_33" => "nested_33"}, -               %{"nested_4" => true} -             ] - -      assert Application.get_env(:pleroma, :key4) == %{ -               "endpoint" => "https://example.com", -               nested_5: :upload -             } - -      assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []} -    end - -    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) - -      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: ":quack", -              key: ":level", -              value: ":info" -            }, -            %{ -              group: ":quack", -              key: ":meta", -              value: [":none"] -            }, -            %{ -              group: ":quack", -              key: ":webhook_url", -              value: "https://hooks.slack.com/services/KEY" -            } -          ] -        }) - -      assert json_response(conn, 200) == %{ -               "configs" => [ -                 %{ -                   "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) - -      assert configs["need_reboot"] == false -    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) - -      assert configs["need_reboot"] == false -    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([]) -        ) - -      Pleroma.Config.TransferTask.load_and_update_env([], false) - -      assert Application.get_env(:logger, :backends) == [] - -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{ -              group: config.group, -              key: config.key, -              value: [":console"] -            } -          ] -        }) - -      assert json_response(conn, 200) == %{ -               "configs" => [ -                 %{ -                   "group" => ":logger", -                   "key" => ":backends", -                   "value" => [ -                     ":console" -                   ], -                   "db" => [":backends"] -                 } -               ] -             } - -      assert Application.get_env(:logger, :backends) == [ -               :console -             ] -    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"] -                 } -               ] -             } -    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", -                   "db" => [":keyaa1"] -                 }, -                 %{ -                   "group" => ":pleroma", -                   "key" => config2.key, -                   "value" => "another_value", -                   "db" => [":keyaa2"] -                 } -               ] -             } - -      assert Application.get_env(:pleroma, :keyaa1) == "another_value" -      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 -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{ -              "group" => ":pleroma", -              "key" => "Pleroma.Captcha.NotReal", -              "value" => [ -                %{"tuple" => [":enabled", false]}, -                %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]}, -                %{"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" => [":name", "Pleroma"]} -              ] -            } -          ] -        }) - -      assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma" - -      assert json_response(conn, 200) == %{ -               "configs" => [ -                 %{ -                   "group" => ":pleroma", -                   "key" => "Pleroma.Captcha.NotReal", -                   "value" => [ -                     %{"tuple" => [":enabled", false]}, -                     %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]}, -                     %{"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" => [":name", "Pleroma"]} -                   ], -                   "db" => [ -                     ":enabled", -                     ":method", -                     ":seconds_valid", -                     ":path", -                     ":key1", -                     ":partial_chain", -                     ":regex1", -                     ":regex2", -                     ":regex3", -                     ":regex4", -                     ":name" -                   ] -                 } -               ] -             } -    end - -    test "tuples with more than two values", %{conn: conn} do -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{ -              "group" => ":pleroma", -              "key" => "Pleroma.Web.Endpoint.NotReal", -              "value" => [ -                %{ -                  "tuple" => [ -                    ":http", -                    [ -                      %{ -                        "tuple" => [ -                          ":key2", -                          [ -                            %{ -                              "tuple" => [ -                                ":_", -                                [ -                                  %{ -                                    "tuple" => [ -                                      "/api/v1/streaming", -                                      "Pleroma.Web.MastodonAPI.WebsocketHandler", -                                      [] -                                    ] -                                  }, -                                  %{ -                                    "tuple" => [ -                                      "/websocket", -                                      "Phoenix.Endpoint.CowboyWebSocket", -                                      %{ -                                        "tuple" => [ -                                          "Phoenix.Transports.WebSocket", -                                          %{ -                                            "tuple" => [ -                                              "Pleroma.Web.Endpoint", -                                              "Pleroma.Web.UserSocket", -                                              [] -                                            ] -                                          } -                                        ] -                                      } -                                    ] -                                  }, -                                  %{ -                                    "tuple" => [ -                                      ":_", -                                      "Phoenix.Endpoint.Cowboy2Handler", -                                      %{"tuple" => ["Pleroma.Web.Endpoint", []]} -                                    ] -                                  } -                                ] -                              ] -                            } -                          ] -                        ] -                      } -                    ] -                  ] -                } -              ] -            } -          ] -        }) - -      assert json_response(conn, 200) == %{ -               "configs" => [ -                 %{ -                   "group" => ":pleroma", -                   "key" => "Pleroma.Web.Endpoint.NotReal", -                   "value" => [ -                     %{ -                       "tuple" => [ -                         ":http", -                         [ -                           %{ -                             "tuple" => [ -                               ":key2", -                               [ -                                 %{ -                                   "tuple" => [ -                                     ":_", -                                     [ -                                       %{ -                                         "tuple" => [ -                                           "/api/v1/streaming", -                                           "Pleroma.Web.MastodonAPI.WebsocketHandler", -                                           [] -                                         ] -                                       }, -                                       %{ -                                         "tuple" => [ -                                           "/websocket", -                                           "Phoenix.Endpoint.CowboyWebSocket", -                                           %{ -                                             "tuple" => [ -                                               "Phoenix.Transports.WebSocket", -                                               %{ -                                                 "tuple" => [ -                                                   "Pleroma.Web.Endpoint", -                                                   "Pleroma.Web.UserSocket", -                                                   [] -                                                 ] -                                               } -                                             ] -                                           } -                                         ] -                                       }, -                                       %{ -                                         "tuple" => [ -                                           ":_", -                                           "Phoenix.Endpoint.Cowboy2Handler", -                                           %{"tuple" => ["Pleroma.Web.Endpoint", []]} -                                         ] -                                       } -                                     ] -                                   ] -                                 } -                               ] -                             ] -                           } -                         ] -                       ] -                     } -                   ], -                   "db" => [":http"] -                 } -               ] -             } -    end - -    test "settings with nesting map", %{conn: conn} do -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{ -              "group" => ":pleroma", -              "key" => ":key1", -              "value" => [ -                %{"tuple" => [":key2", "some_val"]}, -                %{ -                  "tuple" => [ -                    ":key3", -                    %{ -                      ":max_options" => 20, -                      ":max_option_chars" => 200, -                      ":min_expiration" => 0, -                      ":max_expiration" => 31_536_000, -                      "nested" => %{ -                        ":max_options" => 20, -                        ":max_option_chars" => 200, -                        ":min_expiration" => 0, -                        ":max_expiration" => 31_536_000 -                      } -                    } -                  ] -                } -              ] -            } -          ] -        }) - -      assert json_response(conn, 200) == -               %{ -                 "configs" => [ -                   %{ -                     "group" => ":pleroma", -                     "key" => ":key1", -                     "value" => [ -                       %{"tuple" => [":key2", "some_val"]}, -                       %{ -                         "tuple" => [ -                           ":key3", -                           %{ -                             ":max_expiration" => 31_536_000, -                             ":max_option_chars" => 200, -                             ":max_options" => 20, -                             ":min_expiration" => 0, -                             "nested" => %{ -                               ":max_expiration" => 31_536_000, -                               ":max_option_chars" => 200, -                               ":max_options" => 20, -                               ":min_expiration" => 0 -                             } -                           } -                         ] -                       } -                     ], -                     "db" => [":key2", ":key3"] -                   } -                 ] -               } -    end - -    test "value as map", %{conn: conn} do -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{ -              "group" => ":pleroma", -              "key" => ":key1", -              "value" => %{"key" => "some_val"} -            } -          ] -        }) - -      assert json_response(conn, 200) == -               %{ -                 "configs" => [ -                   %{ -                     "group" => ":pleroma", -                     "key" => ":key1", -                     "value" => %{"key" => "some_val"}, -                     "db" => [":key1"] -                   } -                 ] -               } -    end - -    test "queues key as atom", %{conn: conn} do -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{ -              "group" => ":oban", -              "key" => ":queues", -              "value" => [ -                %{"tuple" => [":federator_incoming", 50]}, -                %{"tuple" => [":federator_outgoing", 50]}, -                %{"tuple" => [":web_push", 50]}, -                %{"tuple" => [":mailer", 10]}, -                %{"tuple" => [":transmogrifier", 20]}, -                %{"tuple" => [":scheduled_activities", 10]}, -                %{"tuple" => [":background", 5]} -              ] -            } -          ] -        }) - -      assert json_response(conn, 200) == %{ -               "configs" => [ -                 %{ -                   "group" => ":oban", -                   "key" => ":queues", -                   "value" => [ -                     %{"tuple" => [":federator_incoming", 50]}, -                     %{"tuple" => [":federator_outgoing", 50]}, -                     %{"tuple" => [":web_push", 50]}, -                     %{"tuple" => [":mailer", 10]}, -                     %{"tuple" => [":transmogrifier", 20]}, -                     %{"tuple" => [":scheduled_activities", 10]}, -                     %{"tuple" => [":background", 5]} -                   ], -                   "db" => [ -                     ":federator_incoming", -                     ":federator_outgoing", -                     ":web_push", -                     ":mailer", -                     ":transmogrifier", -                     ":scheduled_activities", -                     ":background" -                   ] -                 } -               ] -             } -    end - -    test "delete part of settings by atom subkeys", %{conn: conn} do -      config = -        insert(:config, -          key: ":keyaa1", -          value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3") -        ) - -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{ -              group: config.group, -              key: config.key, -              subkeys: [":subkey1", ":subkey3"], -              delete: true -            } -          ] -        }) - -      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: ":http", -              value: [ -                %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]} -              ] -            } -          ] -        }) - -      assert %{ -               "configs" => [ -                 %{ -                   "group" => ":pleroma", -                   "key" => ":http", -                   "value" => value, -                   "db" => db -                 } -               ] -             } = json_response(conn, 200) - -      assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]} in value -      assert ":proxy_url" in db -    end - -    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]}]} -              ] -            } -          ] -        }) - -      assert %{ -               "configs" => [ -                 %{ -                   "group" => ":pleroma", -                   "key" => ":http", -                   "value" => value, -                   "db" => db -                 } -               ] -             } = json_response(conn, 200) - -      assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]} in value -      assert ":proxy_url" in db -    end - -    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]}]} -              ] -            } -          ] -        }) - -      assert %{ -               "configs" => [ -                 %{ -                   "group" => ":pleroma", -                   "key" => ":http", -                   "value" => value, -                   "db" => db -                 } -               ] -             } = json_response(conn, 200) - -      assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]} in value -      assert ":proxy_url" in db -    end - -    @tag capture_log: true -    test "doesn't set keys not in the whitelist", %{conn: conn} do -      clear_config(:database_config_whitelist, [ -        {:pleroma, :key1}, -        {:pleroma, :key2}, -        {:pleroma, Pleroma.Captcha.NotReal}, -        {:not_real} -      ]) - -      post(conn, "/api/pleroma/admin/config", %{ -        configs: [ -          %{group: ":pleroma", key: ":key1", value: "value1"}, -          %{group: ":pleroma", key: ":key2", value: "value2"}, -          %{group: ":pleroma", key: ":key3", value: "value3"}, -          %{group: ":pleroma", key: "Pleroma.Web.Endpoint.NotReal", value: "value4"}, -          %{group: ":pleroma", key: "Pleroma.Captcha.NotReal", value: "value5"}, -          %{group: ":not_real", key: ":anything", value: "value6"} -        ] -      }) - -      assert Application.get_env(:pleroma, :key1) == "value1" -      assert Application.get_env(:pleroma, :key2) == "value2" -      assert Application.get_env(:pleroma, :key3) == nil -      assert Application.get_env(:pleroma, Pleroma.Web.Endpoint.NotReal) == nil -      assert Application.get_env(:pleroma, Pleroma.Captcha.NotReal) == "value5" -      assert Application.get_env(:not_real, :anything) == "value6" -    end -  end -    describe "GET /api/pleroma/admin/restart" do      setup do: clear_config(:configurable_from_database, true) @@ -2914,56 +1744,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      end    end -  describe "GET /api/pleroma/admin/config/descriptions" do -    test "structure", %{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 - -    test "filters by database configuration whitelist", %{conn: conn} do -      clear_config(:database_config_whitelist, [ -        {:pleroma, :instance}, -        {:pleroma, :activitypub}, -        {:pleroma, Pleroma.Upload}, -        {:esshd} -      ]) - -      admin = insert(:user, is_admin: true) - -      conn = -        assign(conn, :user, admin) -        |> get("/api/pleroma/admin/config/descriptions") - -      children = json_response(conn, 200) - -      assert length(children) == 4 - -      assert Enum.count(children, fn c -> c["group"] == ":pleroma" end) == 3 - -      instance = Enum.find(children, fn c -> c["key"] == ":instance" end) -      assert instance["children"] - -      activitypub = Enum.find(children, fn c -> c["key"] == ":activitypub" end) -      assert activitypub["children"] - -      web_endpoint = Enum.find(children, fn c -> c["key"] == "Pleroma.Upload" end) -      assert web_endpoint["children"] - -      esshd = Enum.find(children, fn c -> c["group"] == ":esshd" end) -      assert esshd["children"] -    end -  end -    describe "/api/pleroma/admin/stats" do      test "status visibility count", %{conn: conn} do        admin = insert(:user, is_admin: true) diff --git a/test/web/admin_api/controllers/config_controller_test.exs b/test/web/admin_api/controllers/config_controller_test.exs new file mode 100644 index 000000000..780de8d18 --- /dev/null +++ b/test/web/admin_api/controllers/config_controller_test.exs @@ -0,0 +1,1290 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do +  use Pleroma.Web.ConnCase, async: true + +  import ExUnit.CaptureLog +  import Pleroma.Factory + +  alias Pleroma.Config +  alias Pleroma.ConfigDB + +  setup do +    admin = insert(:user, is_admin: true) +    token = insert(:oauth_admin_token, user: admin) + +    conn = +      build_conn() +      |> assign(:user, admin) +      |> assign(:token, token) + +    {:ok, %{admin: admin, token: token, conn: conn}} +  end + +  describe "GET /api/pleroma/admin/config" do +    setup do: clear_config(:configurable_from_database, true) + +    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_and_validate_schema(conn, 400) == +               %{ +                 "error" => "To use this endpoint you need to enable configuration from database." +               } +    end + +    test "with settings only in db", %{conn: conn} do +      config1 = insert(:config) +      config2 = insert(:config) + +      conn = get(conn, "/api/pleroma/admin/config?only_db=true") + +      %{ +        "configs" => [ +          %{ +            "group" => ":pleroma", +            "key" => key1, +            "value" => _ +          }, +          %{ +            "group" => ":pleroma", +            "key" => key2, +            "value" => _ +          } +        ] +      } = json_response_and_validate_schema(conn, 200) + +      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_and_validate_schema(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_and_validate_schema(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_and_validate_schema(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 = +      conn +      |> put_req_header("content-type", "application/json") +      |> post("/api/pleroma/admin/config", %{"configs" => []}) + +    assert json_response_and_validate_schema(conn, 400) == +             %{"error" => "To use this endpoint you need to enable configuration from database."} +  end + +  describe "POST /api/pleroma/admin/config" do +    setup do +      http = Application.get_env(:pleroma, :http) + +      on_exit(fn -> +        Application.delete_env(:pleroma, :key1) +        Application.delete_env(:pleroma, :key2) +        Application.delete_env(:pleroma, :key3) +        Application.delete_env(:pleroma, :key4) +        Application.delete_env(:pleroma, :keyaa1) +        Application.delete_env(:pleroma, :keyaa2) +        Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal) +        Application.delete_env(:pleroma, Pleroma.Captcha.NotReal) +        Application.put_env(:pleroma, :http, http) +        Application.put_env(:tesla, :adapter, Tesla.Mock) +        Restarter.Pleroma.refresh() +      end) +    end + +    setup do: clear_config(:configurable_from_database, true) + +    @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 = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{group: ":pleroma", key: ":key1", value: "value1"}, +            %{ +              group: ":ueberauth", +              key: "Ueberauth", +              value: [%{"tuple" => [":consumer_secret", "aaaa"]}] +            }, +            %{ +              group: ":pleroma", +              key: ":key2", +              value: %{ +                ":nested_1" => "nested_value1", +                ":nested_2" => [ +                  %{":nested_22" => "nested_value222"}, +                  %{":nested_33" => %{":nested_44" => "nested_444"}} +                ] +              } +            }, +            %{ +              group: ":pleroma", +              key: ":key3", +              value: [ +                %{"nested_3" => ":nested_3", "nested_33" => "nested_33"}, +                %{"nested_4" => true} +              ] +            }, +            %{ +              group: ":pleroma", +              key: ":key4", +              value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"} +            }, +            %{ +              group: ":idna", +              key: ":key5", +              value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]} +            } +          ] +        }) + +      assert json_response_and_validate_schema(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => ":key1", +                   "value" => "value1", +                   "db" => [":key1"] +                 }, +                 %{ +                   "group" => ":ueberauth", +                   "key" => "Ueberauth", +                   "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}], +                   "db" => [":consumer_secret"] +                 }, +                 %{ +                   "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", +                   "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"}, +                   "db" => [":key4"] +                 }, +                 %{ +                   "group" => ":idna", +                   "key" => ":key5", +                   "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}, +                   "db" => [":key5"] +                 } +               ] +             } + +      assert Application.get_env(:pleroma, :key1) == "value1" + +      assert Application.get_env(:pleroma, :key2) == %{ +               nested_1: "nested_value1", +               nested_2: [ +                 %{nested_22: "nested_value222"}, +                 %{nested_33: %{nested_44: "nested_444"}} +               ] +             } + +      assert Application.get_env(:pleroma, :key3) == [ +               %{"nested_3" => :nested_3, "nested_33" => "nested_33"}, +               %{"nested_4" => true} +             ] + +      assert Application.get_env(:pleroma, :key4) == %{ +               "endpoint" => "https://example.com", +               nested_5: :upload +             } + +      assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []} +    end + +    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) + +      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 = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              group: ":quack", +              key: ":level", +              value: ":info" +            }, +            %{ +              group: ":quack", +              key: ":meta", +              value: [":none"] +            }, +            %{ +              group: ":quack", +              key: ":webhook_url", +              value: "https://hooks.slack.com/services/KEY" +            } +          ] +        }) + +      assert json_response_and_validate_schema(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "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 = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{group: config.group, key: config.key, value: [%{"tuple" => [":key3", 3]}]} +          ] +        }) + +      assert json_response_and_validate_schema(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 conn +             |> put_req_header("content-type", "application/json") +             |> post( +               "/api/pleroma/admin/config", +               %{ +                 configs: [ +                   %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]} +                 ] +               } +             ) +             |> json_response_and_validate_schema(200) == %{ +               "configs" => [ +                 %{ +                   "db" => [":enabled"], +                   "group" => ":pleroma", +                   "key" => ":chat", +                   "value" => [%{"tuple" => [":enabled", true]}] +                 } +               ], +               "need_reboot" => true +             } + +      configs = +        conn +        |> get("/api/pleroma/admin/config") +        |> json_response_and_validate_schema(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_and_validate_schema(200) + +      assert configs["need_reboot"] == false +    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 conn +             |> put_req_header("content-type", "application/json") +             |> post( +               "/api/pleroma/admin/config", +               %{ +                 configs: [ +                   %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]} +                 ] +               } +             ) +             |> json_response_and_validate_schema(200) == %{ +               "configs" => [ +                 %{ +                   "db" => [":enabled"], +                   "group" => ":pleroma", +                   "key" => ":chat", +                   "value" => [%{"tuple" => [":enabled", true]}] +                 } +               ], +               "need_reboot" => true +             } + +      assert conn +             |> put_req_header("content-type", "application/json") +             |> post("/api/pleroma/admin/config", %{ +               configs: [ +                 %{group: ":pleroma", key: ":key1", value: [%{"tuple" => [":key3", 3]}]} +               ] +             }) +             |> json_response_and_validate_schema(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_and_validate_schema(200) + +      assert configs["need_reboot"] == false +    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 = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/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_and_validate_schema(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 = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          "configs" => [ +            %{ +              "group" => ":pleroma", +              "key" => ":key1", +              "value" => [ +                %{ +                  "tuple" => [ +                    ":ssl_options", +                    [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}] +                  ] +                } +              ] +            } +          ] +        }) + +      assert json_response_and_validate_schema(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([]) +        ) + +      Pleroma.Config.TransferTask.load_and_update_env([], false) + +      assert Application.get_env(:logger, :backends) == [] + +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              group: config.group, +              key: config.key, +              value: [":console"] +            } +          ] +        }) + +      assert json_response_and_validate_schema(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":logger", +                   "key" => ":backends", +                   "value" => [ +                     ":console" +                   ], +                   "db" => [":backends"] +                 } +               ] +             } + +      assert Application.get_env(:logger, :backends) == [ +               :console +             ] +    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 = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{group: config.group, key: config.key, value: "Tesla.Adapter.Httpc"} +          ] +        }) + +      assert json_response_and_validate_schema(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":tesla", +                   "key" => ":adapter", +                   "value" => "Tesla.Adapter.Httpc", +                   "db" => [":adapter"] +                 } +               ] +             } +    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 = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/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_and_validate_schema(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => config1.key, +                   "value" => "another_value", +                   "db" => [":keyaa1"] +                 }, +                 %{ +                   "group" => ":pleroma", +                   "key" => config2.key, +                   "value" => "another_value", +                   "db" => [":keyaa2"] +                 } +               ] +             } + +      assert Application.get_env(:pleroma, :keyaa1) == "another_value" +      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) +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{group: config2.group, key: config2.key, delete: true}, +            %{ +              group: ":ueberauth", +              key: "Ueberauth", +              delete: true +            } +          ] +        }) + +      assert json_response_and_validate_schema(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 +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              "group" => ":pleroma", +              "key" => "Pleroma.Captcha.NotReal", +              "value" => [ +                %{"tuple" => [":enabled", false]}, +                %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]}, +                %{"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" => [":name", "Pleroma"]} +              ] +            } +          ] +        }) + +      assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma" + +      assert json_response_and_validate_schema(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => "Pleroma.Captcha.NotReal", +                   "value" => [ +                     %{"tuple" => [":enabled", false]}, +                     %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]}, +                     %{"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" => [":name", "Pleroma"]} +                   ], +                   "db" => [ +                     ":enabled", +                     ":method", +                     ":seconds_valid", +                     ":path", +                     ":key1", +                     ":partial_chain", +                     ":regex1", +                     ":regex2", +                     ":regex3", +                     ":regex4", +                     ":name" +                   ] +                 } +               ] +             } +    end + +    test "tuples with more than two values", %{conn: conn} do +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              "group" => ":pleroma", +              "key" => "Pleroma.Web.Endpoint.NotReal", +              "value" => [ +                %{ +                  "tuple" => [ +                    ":http", +                    [ +                      %{ +                        "tuple" => [ +                          ":key2", +                          [ +                            %{ +                              "tuple" => [ +                                ":_", +                                [ +                                  %{ +                                    "tuple" => [ +                                      "/api/v1/streaming", +                                      "Pleroma.Web.MastodonAPI.WebsocketHandler", +                                      [] +                                    ] +                                  }, +                                  %{ +                                    "tuple" => [ +                                      "/websocket", +                                      "Phoenix.Endpoint.CowboyWebSocket", +                                      %{ +                                        "tuple" => [ +                                          "Phoenix.Transports.WebSocket", +                                          %{ +                                            "tuple" => [ +                                              "Pleroma.Web.Endpoint", +                                              "Pleroma.Web.UserSocket", +                                              [] +                                            ] +                                          } +                                        ] +                                      } +                                    ] +                                  }, +                                  %{ +                                    "tuple" => [ +                                      ":_", +                                      "Phoenix.Endpoint.Cowboy2Handler", +                                      %{"tuple" => ["Pleroma.Web.Endpoint", []]} +                                    ] +                                  } +                                ] +                              ] +                            } +                          ] +                        ] +                      } +                    ] +                  ] +                } +              ] +            } +          ] +        }) + +      assert json_response_and_validate_schema(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => "Pleroma.Web.Endpoint.NotReal", +                   "value" => [ +                     %{ +                       "tuple" => [ +                         ":http", +                         [ +                           %{ +                             "tuple" => [ +                               ":key2", +                               [ +                                 %{ +                                   "tuple" => [ +                                     ":_", +                                     [ +                                       %{ +                                         "tuple" => [ +                                           "/api/v1/streaming", +                                           "Pleroma.Web.MastodonAPI.WebsocketHandler", +                                           [] +                                         ] +                                       }, +                                       %{ +                                         "tuple" => [ +                                           "/websocket", +                                           "Phoenix.Endpoint.CowboyWebSocket", +                                           %{ +                                             "tuple" => [ +                                               "Phoenix.Transports.WebSocket", +                                               %{ +                                                 "tuple" => [ +                                                   "Pleroma.Web.Endpoint", +                                                   "Pleroma.Web.UserSocket", +                                                   [] +                                                 ] +                                               } +                                             ] +                                           } +                                         ] +                                       }, +                                       %{ +                                         "tuple" => [ +                                           ":_", +                                           "Phoenix.Endpoint.Cowboy2Handler", +                                           %{"tuple" => ["Pleroma.Web.Endpoint", []]} +                                         ] +                                       } +                                     ] +                                   ] +                                 } +                               ] +                             ] +                           } +                         ] +                       ] +                     } +                   ], +                   "db" => [":http"] +                 } +               ] +             } +    end + +    test "settings with nesting map", %{conn: conn} do +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              "group" => ":pleroma", +              "key" => ":key1", +              "value" => [ +                %{"tuple" => [":key2", "some_val"]}, +                %{ +                  "tuple" => [ +                    ":key3", +                    %{ +                      ":max_options" => 20, +                      ":max_option_chars" => 200, +                      ":min_expiration" => 0, +                      ":max_expiration" => 31_536_000, +                      "nested" => %{ +                        ":max_options" => 20, +                        ":max_option_chars" => 200, +                        ":min_expiration" => 0, +                        ":max_expiration" => 31_536_000 +                      } +                    } +                  ] +                } +              ] +            } +          ] +        }) + +      assert json_response_and_validate_schema(conn, 200) == +               %{ +                 "configs" => [ +                   %{ +                     "group" => ":pleroma", +                     "key" => ":key1", +                     "value" => [ +                       %{"tuple" => [":key2", "some_val"]}, +                       %{ +                         "tuple" => [ +                           ":key3", +                           %{ +                             ":max_expiration" => 31_536_000, +                             ":max_option_chars" => 200, +                             ":max_options" => 20, +                             ":min_expiration" => 0, +                             "nested" => %{ +                               ":max_expiration" => 31_536_000, +                               ":max_option_chars" => 200, +                               ":max_options" => 20, +                               ":min_expiration" => 0 +                             } +                           } +                         ] +                       } +                     ], +                     "db" => [":key2", ":key3"] +                   } +                 ] +               } +    end + +    test "value as map", %{conn: conn} do +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              "group" => ":pleroma", +              "key" => ":key1", +              "value" => %{"key" => "some_val"} +            } +          ] +        }) + +      assert json_response_and_validate_schema(conn, 200) == +               %{ +                 "configs" => [ +                   %{ +                     "group" => ":pleroma", +                     "key" => ":key1", +                     "value" => %{"key" => "some_val"}, +                     "db" => [":key1"] +                   } +                 ] +               } +    end + +    test "queues key as atom", %{conn: conn} do +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              "group" => ":oban", +              "key" => ":queues", +              "value" => [ +                %{"tuple" => [":federator_incoming", 50]}, +                %{"tuple" => [":federator_outgoing", 50]}, +                %{"tuple" => [":web_push", 50]}, +                %{"tuple" => [":mailer", 10]}, +                %{"tuple" => [":transmogrifier", 20]}, +                %{"tuple" => [":scheduled_activities", 10]}, +                %{"tuple" => [":background", 5]} +              ] +            } +          ] +        }) + +      assert json_response_and_validate_schema(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":oban", +                   "key" => ":queues", +                   "value" => [ +                     %{"tuple" => [":federator_incoming", 50]}, +                     %{"tuple" => [":federator_outgoing", 50]}, +                     %{"tuple" => [":web_push", 50]}, +                     %{"tuple" => [":mailer", 10]}, +                     %{"tuple" => [":transmogrifier", 20]}, +                     %{"tuple" => [":scheduled_activities", 10]}, +                     %{"tuple" => [":background", 5]} +                   ], +                   "db" => [ +                     ":federator_incoming", +                     ":federator_outgoing", +                     ":web_push", +                     ":mailer", +                     ":transmogrifier", +                     ":scheduled_activities", +                     ":background" +                   ] +                 } +               ] +             } +    end + +    test "delete part of settings by atom subkeys", %{conn: conn} do +      config = +        insert(:config, +          key: ":keyaa1", +          value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3") +        ) + +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              group: config.group, +              key: config.key, +              subkeys: [":subkey1", ":subkey3"], +              delete: true +            } +          ] +        }) + +      assert json_response_and_validate_schema(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => ":keyaa1", +                   "value" => [%{"tuple" => [":subkey2", "val2"]}], +                   "db" => [":subkey2"] +                 } +               ] +             } +    end + +    test "proxy tuple localhost", %{conn: conn} do +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              group: ":pleroma", +              key: ":http", +              value: [ +                %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]} +              ] +            } +          ] +        }) + +      assert %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => ":http", +                   "value" => value, +                   "db" => db +                 } +               ] +             } = json_response_and_validate_schema(conn, 200) + +      assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]} in value +      assert ":proxy_url" in db +    end + +    test "proxy tuple domain", %{conn: conn} do +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              group: ":pleroma", +              key: ":http", +              value: [ +                %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]} +              ] +            } +          ] +        }) + +      assert %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => ":http", +                   "value" => value, +                   "db" => db +                 } +               ] +             } = json_response_and_validate_schema(conn, 200) + +      assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]} in value +      assert ":proxy_url" in db +    end + +    test "proxy tuple ip", %{conn: conn} do +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              group: ":pleroma", +              key: ":http", +              value: [ +                %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]} +              ] +            } +          ] +        }) + +      assert %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => ":http", +                   "value" => value, +                   "db" => db +                 } +               ] +             } = json_response_and_validate_schema(conn, 200) + +      assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]} in value +      assert ":proxy_url" in db +    end + +    @tag capture_log: true +    test "doesn't set keys not in the whitelist", %{conn: conn} do +      clear_config(:database_config_whitelist, [ +        {:pleroma, :key1}, +        {:pleroma, :key2}, +        {:pleroma, Pleroma.Captcha.NotReal}, +        {:not_real} +      ]) + +      conn +      |> put_req_header("content-type", "application/json") +      |> post("/api/pleroma/admin/config", %{ +        configs: [ +          %{group: ":pleroma", key: ":key1", value: "value1"}, +          %{group: ":pleroma", key: ":key2", value: "value2"}, +          %{group: ":pleroma", key: ":key3", value: "value3"}, +          %{group: ":pleroma", key: "Pleroma.Web.Endpoint.NotReal", value: "value4"}, +          %{group: ":pleroma", key: "Pleroma.Captcha.NotReal", value: "value5"}, +          %{group: ":not_real", key: ":anything", value: "value6"} +        ] +      }) + +      assert Application.get_env(:pleroma, :key1) == "value1" +      assert Application.get_env(:pleroma, :key2) == "value2" +      assert Application.get_env(:pleroma, :key3) == nil +      assert Application.get_env(:pleroma, Pleroma.Web.Endpoint.NotReal) == nil +      assert Application.get_env(:pleroma, Pleroma.Captcha.NotReal) == "value5" +      assert Application.get_env(:not_real, :anything) == "value6" +    end +  end + +  describe "GET /api/pleroma/admin/config/descriptions" do +    test "structure", %{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_and_validate_schema(conn, 200) + +      assert child["children"] +      assert child["key"] +      assert String.starts_with?(child["group"], ":") +      assert child["description"] +    end + +    test "filters by database configuration whitelist", %{conn: conn} do +      clear_config(:database_config_whitelist, [ +        {:pleroma, :instance}, +        {:pleroma, :activitypub}, +        {:pleroma, Pleroma.Upload}, +        {:esshd} +      ]) + +      admin = insert(:user, is_admin: true) + +      conn = +        assign(conn, :user, admin) +        |> get("/api/pleroma/admin/config/descriptions") + +      children = json_response_and_validate_schema(conn, 200) + +      assert length(children) == 4 + +      assert Enum.count(children, fn c -> c["group"] == ":pleroma" end) == 3 + +      instance = Enum.find(children, fn c -> c["key"] == ":instance" end) +      assert instance["children"] + +      activitypub = Enum.find(children, fn c -> c["key"] == ":activitypub" end) +      assert activitypub["children"] + +      web_endpoint = Enum.find(children, fn c -> c["key"] == "Pleroma.Upload" end) +      assert web_endpoint["children"] + +      esshd = Enum.find(children, fn c -> c["group"] == ":esshd" end) +      assert esshd["children"] +    end +  end +end | 
