Commit 8b7860f1 authored by kaniini's avatar kaniini

Merge branch 'admin-config' into 'develop'

Admin config

See merge request pleroma/pleroma!1328
parents 72f365df b37ede5d
Pipeline #13729 passed with stages
in 56 minutes and 55 seconds
...@@ -568,8 +568,9 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret ...@@ -568,8 +568,9 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
{ {
configs: [ configs: [
{ {
"group": string,
"key": string, "key": string,
"value": string or {} or [] "value": string or {} or [] or {"tuple": []}
} }
] ]
} }
...@@ -580,6 +581,8 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret ...@@ -580,6 +581,8 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
Module name can be passed as string, which starts with `Pleroma`, e.g. `"Pleroma.Upload"`. Module name can be passed as string, which starts with `Pleroma`, e.g. `"Pleroma.Upload"`.
Atom or boolean value can be passed with `:` in the beginning, e.g. `":true"`, `":upload"`. Atom or boolean value can be passed with `:` in the beginning, e.g. `":true"`, `":upload"`.
Integer with `i:`, e.g. `"i:150"`. Integer with `i:`, e.g. `"i:150"`.
Tuple with more than 2 values with `{"tuple": ["first_val", Pleroma.Module, []]}`.
`{"tuple": ["some_string", "Pleroma.Some.Module", []]}` will be converted to `{"some_string", Pleroma.Some.Module, []}`.
Compile time settings (need instance reboot): Compile time settings (need instance reboot):
- all settings by this keys: - all settings by this keys:
...@@ -595,8 +598,9 @@ Compile time settings (need instance reboot): ...@@ -595,8 +598,9 @@ Compile time settings (need instance reboot):
- Method `POST` - Method `POST`
- Params: - Params:
- `configs` => [ - `configs` => [
- `group` (string)
- `key` (string) - `key` (string)
- `value` (string, [], {}) - `value` (string, [], {} or {"tuple": []})
- `delete` = true (optional, if parameter must be deleted) - `delete` = true (optional, if parameter must be deleted)
] ]
...@@ -606,6 +610,7 @@ Compile time settings (need instance reboot): ...@@ -606,6 +610,7 @@ Compile time settings (need instance reboot):
{ {
configs: [ configs: [
{ {
"group": "pleroma",
"key": "Pleroma.Upload", "key": "Pleroma.Upload",
"value": { "value": {
"uploader": "Pleroma.Uploaders.Local", "uploader": "Pleroma.Uploaders.Local",
...@@ -619,6 +624,9 @@ Compile time settings (need instance reboot): ...@@ -619,6 +624,9 @@ Compile time settings (need instance reboot):
"follow_redirect": ":true", "follow_redirect": ":true",
"pool": ":upload" "pool": ":upload"
} }
},
"dispatch": {
"tuple": ["/api/v1/streaming", "Pleroma.Web.MastodonAPI.WebsocketHandler", []]
} }
} }
} }
...@@ -631,8 +639,9 @@ Compile time settings (need instance reboot): ...@@ -631,8 +639,9 @@ Compile time settings (need instance reboot):
{ {
configs: [ configs: [
{ {
"group": string,
"key": string, "key": string,
"value": string or {} or [] "value": string or {} or [] or {"tuple": []}
} }
] ]
} }
......
...@@ -24,7 +24,7 @@ defmodule Mix.Tasks.Pleroma.Config do ...@@ -24,7 +24,7 @@ defmodule Mix.Tasks.Pleroma.Config do
|> Enum.reject(fn {k, _v} -> k in [Pleroma.Repo, :env] end) |> Enum.reject(fn {k, _v} -> k in [Pleroma.Repo, :env] end)
|> Enum.each(fn {k, v} -> |> Enum.each(fn {k, v} ->
key = to_string(k) |> String.replace("Elixir.", "") key = to_string(k) |> String.replace("Elixir.", "")
{:ok, _} = Config.update_or_create(%{key: key, value: v}) {:ok, _} = Config.update_or_create(%{group: "pleroma", key: key, value: v})
Mix.shell().info("#{key} is migrated.") Mix.shell().info("#{key} is migrated.")
end) end)
...@@ -51,7 +51,9 @@ defmodule Mix.Tasks.Pleroma.Config do ...@@ -51,7 +51,9 @@ defmodule Mix.Tasks.Pleroma.Config do
IO.write( IO.write(
file, file,
"config :pleroma, #{config.key}#{mark} #{inspect(Config.from_binary(config.value))}\r\n" "config :#{config.group}, #{config.key}#{mark} #{
inspect(Config.from_binary(config.value))
}\r\n"
) )
{:ok, _} = Repo.delete(config) {:ok, _} = Repo.delete(config)
......
...@@ -11,8 +11,17 @@ defmodule Pleroma.Config.TransferTask do ...@@ -11,8 +11,17 @@ defmodule Pleroma.Config.TransferTask do
def load_and_update_env do def load_and_update_env do
if Pleroma.Config.get([:instance, :dynamic_configuration]) and if Pleroma.Config.get([:instance, :dynamic_configuration]) and
Ecto.Adapters.SQL.table_exists?(Pleroma.Repo, "config") do Ecto.Adapters.SQL.table_exists?(Pleroma.Repo, "config") do
Pleroma.Repo.all(Config) for_restart =
|> Enum.each(&update_env(&1)) Pleroma.Repo.all(Config)
|> Enum.map(&update_env(&1))
# We need to restart applications for loaded settings take effect
for_restart
|> Enum.reject(&(&1 in [:pleroma, :ok]))
|> Enum.each(fn app ->
Application.stop(app)
:ok = Application.start(app)
end)
end end
end end
...@@ -25,11 +34,15 @@ defmodule Pleroma.Config.TransferTask do ...@@ -25,11 +34,15 @@ defmodule Pleroma.Config.TransferTask do
setting.key setting.key
end end
group = String.to_existing_atom(setting.group)
Application.put_env( Application.put_env(
:pleroma, group,
String.to_existing_atom(key), String.to_existing_atom(key),
Config.from_binary(setting.value) Config.from_binary(setting.value)
) )
group
rescue rescue
e -> e ->
require Logger require Logger
......
...@@ -377,12 +377,12 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do ...@@ -377,12 +377,12 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
if Pleroma.Config.get([:instance, :dynamic_configuration]) do if Pleroma.Config.get([:instance, :dynamic_configuration]) do
updated = updated =
Enum.map(configs, fn Enum.map(configs, fn
%{"key" => key, "value" => value} -> %{"group" => group, "key" => key, "value" => value} ->
{:ok, config} = Config.update_or_create(%{key: key, value: value}) {:ok, config} = Config.update_or_create(%{group: group, key: key, value: value})
config config
%{"key" => key, "delete" => "true"} -> %{"group" => group, "key" => key, "delete" => "true"} ->
{:ok, _} = Config.delete(key) {:ok, _} = Config.delete(%{group: group, key: key})
nil nil
end) end)
|> Enum.reject(&is_nil(&1)) |> Enum.reject(&is_nil(&1))
......
...@@ -12,26 +12,27 @@ defmodule Pleroma.Web.AdminAPI.Config do ...@@ -12,26 +12,27 @@ defmodule Pleroma.Web.AdminAPI.Config do
schema "config" do schema "config" do
field(:key, :string) field(:key, :string)
field(:group, :string)
field(:value, :binary) field(:value, :binary)
timestamps() timestamps()
end end
@spec get_by_key(String.t()) :: Config.t() | nil @spec get_by_params(map()) :: Config.t() | nil
def get_by_key(key), do: Repo.get_by(Config, key: key) def get_by_params(params), do: Repo.get_by(Config, params)
@spec changeset(Config.t(), map()) :: Changeset.t() @spec changeset(Config.t(), map()) :: Changeset.t()
def changeset(config, params \\ %{}) do def changeset(config, params \\ %{}) do
config config
|> cast(params, [:key, :value]) |> cast(params, [:key, :group, :value])
|> validate_required([:key, :value]) |> validate_required([:key, :group, :value])
|> unique_constraint(:key) |> unique_constraint(:key, name: :config_group_key_index)
end end
@spec create(map()) :: {:ok, Config.t()} | {:error, Changeset.t()} @spec create(map()) :: {:ok, Config.t()} | {:error, Changeset.t()}
def create(%{key: key, value: value}) do def create(params) do
%Config{} %Config{}
|> changeset(%{key: key, value: transform(value)}) |> changeset(Map.put(params, :value, transform(params[:value])))
|> Repo.insert() |> Repo.insert()
end end
...@@ -43,20 +44,20 @@ defmodule Pleroma.Web.AdminAPI.Config do ...@@ -43,20 +44,20 @@ defmodule Pleroma.Web.AdminAPI.Config do
end end
@spec update_or_create(map()) :: {:ok, Config.t()} | {:error, Changeset.t()} @spec update_or_create(map()) :: {:ok, Config.t()} | {:error, Changeset.t()}
def update_or_create(%{key: key} = params) do def update_or_create(params) do
with %Config{} = config <- Config.get_by_key(key) do with %Config{} = config <- Config.get_by_params(Map.take(params, [:group, :key])) do
Config.update(config, params) Config.update(config, params)
else else
nil -> Config.create(params) nil -> Config.create(params)
end end
end end
@spec delete(String.t()) :: {:ok, Config.t()} | {:error, Changeset.t()} @spec delete(map()) :: {:ok, Config.t()} | {:error, Changeset.t()}
def delete(key) do def delete(params) do
with %Config{} = config <- Config.get_by_key(key) do with %Config{} = config <- Config.get_by_params(params) do
Repo.delete(config) Repo.delete(config)
else else
nil -> {:error, "Config with key #{key} not found"} nil -> {:error, "Config with params #{inspect(params)} not found"}
end end
end end
...@@ -77,10 +78,21 @@ defmodule Pleroma.Web.AdminAPI.Config do ...@@ -77,10 +78,21 @@ defmodule Pleroma.Web.AdminAPI.Config do
defp do_convert({k, v} = value) when is_tuple(value), defp do_convert({k, v} = value) when is_tuple(value),
do: %{k => do_convert(v)} do: %{k => do_convert(v)}
defp do_convert(value) when is_binary(value) or is_atom(value) or is_map(value), defp do_convert(value) when is_tuple(value), do: %{"tuple" => do_convert(Tuple.to_list(value))}
do: value
defp do_convert(value) when is_binary(value) or is_map(value) or is_number(value), do: value
defp do_convert(value) when is_atom(value) do
string = to_string(value)
if String.starts_with?(string, "Elixir."),
do: String.trim_leading(string, "Elixir."),
else: value
end
@spec transform(any()) :: binary() @spec transform(any()) :: binary()
def transform(%{"tuple" => _} = entity), do: :erlang.term_to_binary(do_transform(entity))
def transform(entity) when is_map(entity) do def transform(entity) when is_map(entity) do
tuples = tuples =
for {k, v} <- entity, for {k, v} <- entity,
...@@ -101,11 +113,16 @@ defmodule Pleroma.Web.AdminAPI.Config do ...@@ -101,11 +113,16 @@ defmodule Pleroma.Web.AdminAPI.Config do
defp do_transform(%Regex{} = value) when is_map(value), do: value defp do_transform(%Regex{} = value) when is_map(value), do: value
defp do_transform(%{"tuple" => [k, values] = entity}) when length(entity) == 2 do
{do_transform(k), do_transform(values)}
end
defp do_transform(%{"tuple" => values}) do
Enum.reduce(values, {}, fn val, acc -> Tuple.append(acc, do_transform(val)) end)
end
defp do_transform(value) when is_map(value) do defp do_transform(value) when is_map(value) do
values = values = for {key, val} <- value, into: [], do: {String.to_atom(key), do_transform(val)}
for {key, val} <- value,
into: [],
do: {String.to_atom(key), do_transform(val)}
Enum.sort(values) Enum.sort(values)
end end
...@@ -117,28 +134,27 @@ defmodule Pleroma.Web.AdminAPI.Config do ...@@ -117,28 +134,27 @@ defmodule Pleroma.Web.AdminAPI.Config do
defp do_transform(entity) when is_list(entity) and length(entity) == 1, do: hd(entity) defp do_transform(entity) when is_list(entity) and length(entity) == 1, do: hd(entity)
defp do_transform(value) when is_binary(value) do defp do_transform(value) when is_binary(value) do
value = String.trim(value) String.trim(value)
|> do_transform_string()
end
case String.length(value) do defp do_transform(value), do: value
0 ->
nil
_ -> defp do_transform_string(value) when byte_size(value) == 0, do: nil
cond do
String.starts_with?(value, "Pleroma") ->
String.to_existing_atom("Elixir." <> value)
String.starts_with?(value, ":") -> defp do_transform_string(value) do
String.replace(value, ":", "") |> String.to_existing_atom() cond do
String.starts_with?(value, "Pleroma") or String.starts_with?(value, "Phoenix") ->
String.to_existing_atom("Elixir." <> value)
String.starts_with?(value, "i:") -> String.starts_with?(value, ":") ->
String.replace(value, "i:", "") |> String.to_integer() String.replace(value, ":", "") |> String.to_existing_atom()
true -> String.starts_with?(value, "i:") ->
value String.replace(value, "i:", "") |> String.to_integer()
end
true ->
value
end end
end end
defp do_transform(value), do: value
end end
...@@ -10,6 +10,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigView do ...@@ -10,6 +10,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigView do
def render("show.json", %{config: config}) do def render("show.json", %{config: config}) do
%{ %{
key: config.key, key: config.key,
group: config.group,
value: Pleroma.Web.AdminAPI.Config.from_binary_to_map(config.value) value: Pleroma.Web.AdminAPI.Config.from_binary_to_map(config.value)
} }
end end
......
defmodule Pleroma.Repo.Migrations.AddGroupKeyToConfig do
use Ecto.Migration
def change do
alter table("config") do
add(:group, :string)
end
drop(unique_index("config", :key))
create(unique_index("config", [:group, :key]))
end
end
...@@ -13,19 +13,37 @@ defmodule Pleroma.Config.TransferTaskTest do ...@@ -13,19 +13,37 @@ defmodule Pleroma.Config.TransferTaskTest do
test "transfer config values from db to env" do test "transfer config values from db to env" do
refute Application.get_env(:pleroma, :test_key) refute Application.get_env(:pleroma, :test_key)
Pleroma.Web.AdminAPI.Config.create(%{key: "test_key", value: [live: 2, com: 3]}) refute Application.get_env(:idna, :test_key)
Pleroma.Web.AdminAPI.Config.create(%{
group: "pleroma",
key: "test_key",
value: [live: 2, com: 3]
})
Pleroma.Web.AdminAPI.Config.create(%{
group: "idna",
key: "test_key",
value: [live: 15, com: 35]
})
Pleroma.Config.TransferTask.start_link() Pleroma.Config.TransferTask.start_link()
assert Application.get_env(:pleroma, :test_key) == [live: 2, com: 3] assert Application.get_env(:pleroma, :test_key) == [live: 2, com: 3]
assert Application.get_env(:idna, :test_key) == [live: 15, com: 35]
on_exit(fn -> on_exit(fn ->
Application.delete_env(:pleroma, :test_key) Application.delete_env(:pleroma, :test_key)
Application.delete_env(:idna, :test_key)
end) end)
end end
test "non existing atom" do test "non existing atom" do
Pleroma.Web.AdminAPI.Config.create(%{key: "undefined_atom_key", value: [live: 2, com: 3]}) Pleroma.Web.AdminAPI.Config.create(%{
group: "pleroma",
key: "undefined_atom_key",
value: [live: 2, com: 3]
})
assert ExUnit.CaptureLog.capture_log(fn -> assert ExUnit.CaptureLog.capture_log(fn ->
Pleroma.Config.TransferTask.start_link() Pleroma.Config.TransferTask.start_link()
......
...@@ -314,6 +314,7 @@ defmodule Pleroma.Factory do ...@@ -314,6 +314,7 @@ defmodule Pleroma.Factory do
def config_factory do def config_factory do
%Pleroma.Web.AdminAPI.Config{ %Pleroma.Web.AdminAPI.Config{
key: sequence(:key, &"some_key_#{&1}"), key: sequence(:key, &"some_key_#{&1}"),
group: "pleroma",
value: value:
sequence( sequence(
:value, :value,
......
...@@ -30,17 +30,26 @@ defmodule Mix.Tasks.Pleroma.ConfigTest do ...@@ -30,17 +30,26 @@ defmodule Mix.Tasks.Pleroma.ConfigTest do
Mix.Tasks.Pleroma.Config.run(["migrate_to_db"]) Mix.Tasks.Pleroma.Config.run(["migrate_to_db"])
first_db = Config.get_by_key("first_setting") first_db = Config.get_by_params(%{group: "pleroma", key: "first_setting"})
second_db = Config.get_by_key("second_setting") second_db = Config.get_by_params(%{group: "pleroma", key: "second_setting"})
refute Config.get_by_key("Pleroma.Repo") refute Config.get_by_params(%{group: "pleroma", key: "Pleroma.Repo"})
assert Config.from_binary(first_db.value) == [key: "value", key2: [Pleroma.Repo]] assert Config.from_binary(first_db.value) == [key: "value", key2: [Pleroma.Repo]]
assert Config.from_binary(second_db.value) == [key: "value2", key2: [Pleroma.Activity]] assert Config.from_binary(second_db.value) == [key: "value2", key2: [Pleroma.Activity]]
end end
test "settings are migrated to file and deleted from db", %{temp_file: temp_file} do test "settings are migrated to file and deleted from db", %{temp_file: temp_file} do
Config.create(%{key: "setting_first", value: [key: "value", key2: [Pleroma.Activity]]}) Config.create(%{
Config.create(%{key: "setting_second", value: [key: "valu2", key2: [Pleroma.Repo]]}) group: "pleroma",
key: "setting_first",
value: [key: "value", key2: [Pleroma.Activity]]
})
Config.create(%{
group: "pleroma",
key: "setting_second",
value: [key: "valu2", key2: [Pleroma.Repo]]
})
Mix.Tasks.Pleroma.Config.run(["migrate_from_db", "temp"]) Mix.Tasks.Pleroma.Config.run(["migrate_from_db", "temp"])
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do
use Pleroma.DataCase use Pleroma.DataCase
import Pleroma.Factory import Pleroma.Factory
import ExUnit.CaptureLog
alias Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy alias Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy
...@@ -114,7 +115,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do ...@@ -114,7 +115,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do
@linkless_message @linkless_message
|> Map.put("actor", "http://invalid.actor") |> Map.put("actor", "http://invalid.actor")
{:reject, _} = AntiLinkSpamPolicy.filter(message) assert capture_log(fn ->
{:reject, _} = AntiLinkSpamPolicy.filter(message)
end) =~ "[error] Could not decode user at fetch http://invalid.actor"
end end
test "it rejects posts with links" do test "it rejects posts with links" do
...@@ -122,7 +125,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do ...@@ -122,7 +125,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do
@linkful_message @linkful_message
|> Map.put("actor", "http://invalid.actor") |> Map.put("actor", "http://invalid.actor")
{:reject, _} = AntiLinkSpamPolicy.filter(message) assert capture_log(fn ->
{:reject, _} = AntiLinkSpamPolicy.filter(message)
end) =~ "[error] Could not decode user at fetch http://invalid.actor"
end end
end end
......
...@@ -1343,6 +1343,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do ...@@ -1343,6 +1343,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
Application.delete_env(:pleroma, :key4) Application.delete_env(:pleroma, :key4)
Application.delete_env(:pleroma, :keyaa1) Application.delete_env(:pleroma, :keyaa1)
Application.delete_env(:pleroma, :keyaa2) 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) :ok = File.rm(temp_file)
end) end)
...@@ -1361,8 +1363,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do ...@@ -1361,8 +1363,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
conn = conn =
post(conn, "/api/pleroma/admin/config", %{ post(conn, "/api/pleroma/admin/config", %{
configs: [ configs: [
%{key: "key1", value: "value1"}, %{group: "pleroma", key: "key1", value: "value1"},
%{ %{
group: "pleroma",
key: "key2", key: "key2",
value: %{ value: %{
"nested_1" => "nested_value1", "nested_1" => "nested_value1",
...@@ -1373,6 +1376,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do ...@@ -1373,6 +1376,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
} }
}, },
%{ %{
group: "pleroma",
key: "key3", key: "key3",
value: [ value: [
%{"nested_3" => ":nested_3", "nested_33" => "nested_33"}, %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
...@@ -1380,8 +1384,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do ...@@ -1380,8 +1384,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
] ]
}, },
%{ %{
group: "pleroma",
key: "key4", key: "key4",
value: %{"nested_5" => ":upload", "endpoint" => "https://example.com"} value: %{"nested_5" => ":upload", "endpoint" => "https://example.com"}
},
%{
group: "idna",
key: "key5",
value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
} }
] ]
}) })
...@@ -1389,10 +1399,12 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do ...@@ -1389,10 +1399,12 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
assert json_response(conn, 200) == %{ assert json_response(conn, 200) == %{
"configs" => [ "configs" => [
%{ %{
"group" => "pleroma",
"key" => "key1", "key" => "key1",
"value" => "value1" "value" => "value1"
}, },
%{ %{
"group" => "pleroma",
"key" => "key2", "key" => "key2",
"value" => [ "value" => [
%{"nested_1" => "nested_value1"}, %{"nested_1" => "nested_value1"},
...@@ -1405,6 +1417,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do ...@@ -1405,6 +1417,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
] ]
}, },
%{ %{
"group" => "pleroma",
"key" => "key3", "key" => "key3",
"value" => [ "value" => [
[%{"nested_3" => "nested_3"}, %{"nested_33" => "nested_33"}], [%{"nested_3" => "nested_3"}, %{"nested_33" => "nested_33"}],
...@@ -1412,8 +1425,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do ...@@ -1412,8 +1425,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
] ]
}, },
%{ %{
"group" => "pleroma",
"key" => "key4", "key" => "key4",
"value" => [%{"endpoint" => "https://example.com"}, %{"nested_5" => "upload"}] "value" => [%{"endpoint" => "https://example.com"}, %{"nested_5" => "upload"}]
},
%{
"group" => "idna",
"key" => "key5",
"value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
} }
] ]
} }
...@@ -1437,6 +1456,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do ...@@ -1437,6 +1456,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
endpoint: "https://example.com", endpoint: "https://example.com",
nested_5: :upload nested_5: :upload
] ]
assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []}
end end
test "update config setting & delete", %{conn: conn} do test "update config setting & delete", %{conn: conn} do
...@@ -1446,14 +1467,15 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do ...@@ -1446,14 +1467,15 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
conn = conn =
post(conn, "/api/pleroma/admin/config", %{ post(conn, "/api/pleroma/admin/config", %{
configs: [ configs: [
%{key: config1.key, value: "another_value"}, %{group: config1.group, key: config1.key, value: "another_value"},
%{key: config2.key, delete: "true"} %{group: config2.group, key: config2.key, delete: "true"}