admin api configure changes
authorAlexander Strizhakov <alex.strizhakov@gmail.com>
Thu, 11 Jul 2019 13:02:13 +0000 (13:02 +0000)
committerkaniini <ariadne@dereferenced.org>
Thu, 11 Jul 2019 13:02:13 +0000 (13:02 +0000)
CHANGELOG.md
docs/api/admin_api.md
lib/pleroma/web/admin_api/admin_api_controller.ex
lib/pleroma/web/admin_api/config.ex
lib/pleroma/web/admin_api/views/config_view.ex
test/web/admin_api/admin_api_controller_test.exs
test/web/admin_api/config_test.exs

index f27446f36b954a63cbb71d13781edeb4970c5c92..da2aee88314e5a5ad1c5986b3c0b9fe98bbb1862 100644 (file)
@@ -25,10 +25,15 @@ Configuration: `federation_incoming_replies_max_depth` option
 - Admin API: Return users' tags when querying reports
 - Admin API: Return avatar and display name when querying users
 - Admin API: Allow querying user by ID
+- Admin API: Added support for `tuples`.
 - Added synchronization of following/followers counters for external users
 - Configuration: `enabled` option for `Pleroma.Emails.Mailer`, defaulting to `false`.
 - Mastodon API: Add support for categories for custom emojis by reusing the group feature. <https://github.com/tootsuite/mastodon/pull/11196>
 
+### Changed
+- Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text
+- Admin API: changed json structure for saving config settings.
+
 ## [1.0.0] - 2019-06-29
 ### Security
 - Mastodon API: Fix display names not being sanitized
index bce5e399bbedecc806f9c50f7171a108dade74c3..c429da822860988db7e8bffdd518d0f729a4dc34 100644 (file)
@@ -573,7 +573,7 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
   configs: [
     {
       "group": string,
-      "key": string,
+      "key": string or string with leading `:` for atoms,
       "value": string or {} or [] or {"tuple": []}
      }
   ]
@@ -583,10 +583,11 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
 ## `/api/pleroma/admin/config`
 ### Update config settings
 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"`. For keys it is not needed.
-Integer with `i:`, e.g. `"i:150"`.
-Tuple with more than 2 values with `{"tuple": ["first_val", Pleroma.Module, []]}`.
+Atom keys and values can be passed with `:` in the beginning, e.g. `":upload"`.
+Tuples can be passed as `{"tuple": ["first_val", Pleroma.Module, []]}`.
 `{"tuple": ["some_string", "Pleroma.Some.Module", []]}` will be converted to `{"some_string", Pleroma.Some.Module, []}`.
+Keywords can be passed as lists with 2 child tuples, e.g.
+`[{"tuple": ["first_val", Pleroma.Module]}, {"tuple": ["second_val", true]}]`.
 
 Compile time settings (need instance reboot):
 - all settings by this keys:
@@ -603,7 +604,7 @@ Compile time settings (need instance reboot):
 - Params:
   - `configs` => [
     - `group` (string)
-    - `key` (string)
+    - `key` (string or string with leading `:` for atoms)
     - `value` (string, [], {} or {"tuple": []})
     - `delete` = true (optional, if parameter must be deleted)
   ]
@@ -616,24 +617,25 @@ Compile time settings (need instance reboot):
     {
       "group": "pleroma",
       "key": "Pleroma.Upload",
-      "value": {
-        "uploader": "Pleroma.Uploaders.Local",
-        "filters": ["Pleroma.Upload.Filter.Dedupe"],
-        "link_name": ":true",
-        "proxy_remote": ":false",
-        "proxy_opts": {
-          "redirect_on_failure": ":false",
-          "max_body_length": "i:1048576",
-          "http": {
-            "follow_redirect": ":true",
-            "pool": ":upload"
-          }
-        },
-        "dispatch": {
+      "value": [
+        {"tuple": [":uploader", "Pleroma.Uploaders.Local"]},
+        {"tuple": [":filters", ["Pleroma.Upload.Filter.Dedupe"]]},
+        {"tuple": [":link_name", true]},
+        {"tuple": [":proxy_remote", false]},
+        {"tuple": [":proxy_opts", [
+          {"tuple": [":redirect_on_failure", false]},
+          {"tuple": [":max_body_length", 1048576]},
+          {"tuple": [":http": [
+            {"tuple": [":follow_redirect", true]},
+            {"tuple": [":pool", ":upload"]},
+          ]]}
+        ]
+        ]},
+        {"tuple": [":dispatch", {
           "tuple": ["/api/v1/streaming", "Pleroma.Web.MastodonAPI.WebsocketHandler", []]
-        }
-      }
-     }
+        }]}
+      ]
+    }
   ]
 }
 
@@ -644,7 +646,7 @@ Compile time settings (need instance reboot):
   configs: [
     {
       "group": string,
-      "key": string,
+      "key": string or string with leading `:` for atoms,
       "value": string or {} or [] or {"tuple": []}
      }
   ]
index 8b3c3c91f0826c7beb8f04b34ba3c9c3b8a6755a..4a0bf482346782a5bd25010efe5b18bfb2edc949 100644 (file)
@@ -371,13 +371,13 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
       if Pleroma.Config.get([:instance, :dynamic_configuration]) do
         updated =
           Enum.map(configs, fn
-            %{"group" => group, "key" => key, "value" => value} ->
-              {:ok, config} = Config.update_or_create(%{group: group, key: key, value: value})
-              config
-
             %{"group" => group, "key" => key, "delete" => "true"} ->
               {:ok, _} = Config.delete(%{group: group, key: key})
               nil
+
+            %{"group" => group, "key" => key, "value" => value} ->
+              {:ok, config} = Config.update_or_create(%{group: group, key: key, value: value})
+              config
           end)
           |> Enum.reject(&is_nil(&1))
 
index 24674abc5b03c0cc774dcec91c56a223326018e6..b4eb8e002a5de0a0fa0649c38317b624e43b7e54 100644 (file)
@@ -67,99 +67,86 @@ defmodule Pleroma.Web.AdminAPI.Config do
   end
 
   @spec from_binary(binary()) :: term()
-  def from_binary(value), do: :erlang.binary_to_term(value)
+  def from_binary(binary), do: :erlang.binary_to_term(binary)
 
-  @spec from_binary_to_map(binary()) :: any()
-  def from_binary_to_map(binary) do
+  @spec from_binary_with_convert(binary()) :: any()
+  def from_binary_with_convert(binary) do
     from_binary(binary)
     |> do_convert()
   end
 
-  defp do_convert([{k, v}] = value) when is_list(value) and length(value) == 1,
-    do: %{k => do_convert(v)}
+  defp do_convert(entity) when is_list(entity) do
+    for v <- entity, into: [], do: do_convert(v)
+  end
 
-  defp do_convert(values) when is_list(values), do: for(val <- values, do: do_convert(val))
+  defp do_convert(entity) when is_map(entity) do
+    for {k, v} <- entity, into: %{}, do: {do_convert(k), do_convert(v)}
+  end
 
-  defp do_convert({k, v} = value) when is_tuple(value),
-    do: %{k => do_convert(v)}
+  defp do_convert({:dispatch, [entity]}), do: %{"tuple" => [":dispatch", [inspect(entity)]]}
 
-  defp do_convert(value) when is_tuple(value), do: %{"tuple" => do_convert(Tuple.to_list(value))}
+  defp do_convert(entity) when is_tuple(entity),
+    do: %{"tuple" => do_convert(Tuple.to_list(entity))}
 
-  defp do_convert(value) when is_binary(value) or is_map(value) or is_number(value), do: value
+  defp do_convert(entity) when is_boolean(entity) or is_number(entity) or is_nil(entity),
+    do: entity
 
-  defp do_convert(value) when is_atom(value) do
-    string = to_string(value)
+  defp do_convert(entity) when is_atom(entity) do
+    string = to_string(entity)
 
     if String.starts_with?(string, "Elixir."),
-      do: String.trim_leading(string, "Elixir."),
-      else: value
+      do: do_convert(string),
+      else: ":" <> string
   end
 
-  @spec transform(any()) :: binary()
-  def transform(%{"tuple" => _} = entity), do: :erlang.term_to_binary(do_transform(entity))
-
-  def transform(entity) when is_map(entity) do
-    tuples =
-      for {k, v} <- entity,
-          into: [],
-          do: {if(is_atom(k), do: k, else: String.to_atom(k)), do_transform(v)}
+  defp do_convert("Elixir." <> module_name), do: module_name
 
-    Enum.reject(tuples, fn {_k, v} -> is_nil(v) end)
-    |> Enum.sort()
-    |> :erlang.term_to_binary()
-  end
+  defp do_convert(entity) when is_binary(entity), do: entity
 
-  def transform(entity) when is_list(entity) do
-    list = Enum.map(entity, &do_transform(&1))
-    :erlang.term_to_binary(list)
+  @spec transform(any()) :: binary()
+  def transform(entity) when is_binary(entity) or is_map(entity) or is_list(entity) do
+    :erlang.term_to_binary(do_transform(entity))
   end
 
   def transform(entity), do: :erlang.term_to_binary(entity)
 
-  defp do_transform(%Regex{} = value) when is_map(value), do: value
+  defp do_transform(%Regex{} = entity) when is_map(entity), do: entity
 
-  defp do_transform(%{"tuple" => [k, values] = entity}) when length(entity) == 2 do
-    {do_transform(k), do_transform(values)}
+  defp do_transform(%{"tuple" => [":dispatch", [entity]]}) do
+    cleaned_string = String.replace(entity, ~r/[^\w|^{:,[|^,|^[|^\]^}|^\/|^\.|^"]^\s/, "")
+    {dispatch_settings, []} = Code.eval_string(cleaned_string, [], requires: [], macros: [])
+    {:dispatch, [dispatch_settings]}
   end
 
-  defp do_transform(%{"tuple" => values}) do
-    Enum.reduce(values, {}, fn val, acc -> Tuple.append(acc, do_transform(val)) end)
+  defp do_transform(%{"tuple" => entity}) do
+    Enum.reduce(entity, {}, fn val, acc -> Tuple.append(acc, do_transform(val)) end)
   end
 
-  defp do_transform(value) when is_map(value) do
-    values = for {key, val} <- value, into: [], do: {String.to_atom(key), do_transform(val)}
-
-    Enum.sort(values)
+  defp do_transform(entity) when is_map(entity) do
+    for {k, v} <- entity, into: %{}, do: {do_transform(k), do_transform(v)}
   end
 
-  defp do_transform(value) when is_list(value) do
-    Enum.map(value, &do_transform(&1))
+  defp do_transform(entity) when is_list(entity) do
+    for v <- entity, into: [], do: do_transform(v)
   end
 
-  defp do_transform(entity) when is_list(entity) and length(entity) == 1, do: hd(entity)
-
-  defp do_transform(value) when is_binary(value) do
-    String.trim(value)
+  defp do_transform(entity) when is_binary(entity) do
+    String.trim(entity)
     |> do_transform_string()
   end
 
-  defp do_transform(value), do: value
-
-  defp do_transform_string(value) when byte_size(value) == 0, do: nil
-
-  defp do_transform_string(value) do
-    cond do
-      String.starts_with?(value, "Pleroma") or String.starts_with?(value, "Phoenix") ->
-        String.to_existing_atom("Elixir." <> value)
+  defp do_transform(entity), do: entity
 
-      String.starts_with?(value, ":") ->
-        String.replace(value, ":", "") |> String.to_existing_atom()
+  defp do_transform_string("~r/" <> pattern) do
+    pattern = String.trim_trailing(pattern, "/")
+    ~r/#{pattern}/
+  end
 
-      String.starts_with?(value, "i:") ->
-        String.replace(value, "i:", "") |> String.to_integer()
+  defp do_transform_string(":" <> atom), do: String.to_atom(atom)
 
-      true ->
-        value
-    end
+  defp do_transform_string(value) do
+    if String.starts_with?(value, "Pleroma") or String.starts_with?(value, "Phoenix"),
+      do: String.to_existing_atom("Elixir." <> value),
+      else: value
   end
 end
index a31f1041fd1e3334d8ef17f9a14a1d86f3ea9a6c..49add0b6e286a98e434daf8f617bc1f237a17e72 100644 (file)
@@ -15,7 +15,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigView do
     %{
       key: config.key,
       group: config.group,
-      value: Pleroma.Web.AdminAPI.Config.from_binary_to_map(config.value)
+      value: Pleroma.Web.AdminAPI.Config.from_binary_with_convert(config.value)
     }
   end
 end
index 0e04e7e9477efc59190dc15dd94608cea7f16ea3..1b71cbff384835fb033489f71d90b41b452c82c8 100644 (file)
@@ -1407,14 +1407,19 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
         post(conn, "/api/pleroma/admin/config", %{
           configs: [
             %{group: "pleroma", key: "key1", value: "value1"},
+            %{
+              group: "ueberauth",
+              key: "Ueberauth.Strategy.Twitter.OAuth",
+              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"}}
+                ":nested_1" => "nested_value1",
+                ":nested_2" => [
+                  %{":nested_22" => "nested_value222"},
+                  %{":nested_33" => %{":nested_44" => "nested_444"}}
                 ]
               }
             },
@@ -1423,13 +1428,13 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
               key: "key3",
               value: [
                 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
-                %{"nested_4" => ":true"}
+                %{"nested_4" => true}
               ]
             },
             %{
               group: "pleroma",
               key: "key4",
-              value: %{"nested_5" => ":upload", "endpoint" => "https://example.com"}
+              value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"}
             },
             %{
               group: "idna",
@@ -1446,31 +1451,34 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                    "key" => "key1",
                    "value" => "value1"
                  },
+                 %{
+                   "group" => "ueberauth",
+                   "key" => "Ueberauth.Strategy.Twitter.OAuth",
+                   "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"}}
-                       ]
-                     }
-                   ]
+                   "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_3" => ":nested_3", "nested_33" => "nested_33"},
                      %{"nested_4" => true}
                    ]
                  },
                  %{
                    "group" => "pleroma",
                    "key" => "key4",
-                   "value" => [%{"endpoint" => "https://example.com"}, %{"nested_5" => "upload"}]
+                   "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"}
                  },
                  %{
                    "group" => "idna",
@@ -1482,23 +1490,23 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
 
       assert Application.get_env(:pleroma, :key1) == "value1"
 
-      assert Application.get_env(:pleroma, :key2) == [
+      assert Application.get_env(:pleroma, :key2) == %{
                nested_1: "nested_value1",
                nested_2: [
-                 [nested_22: "nested_value222"],
-                 [nested_33: [nested_44: "nested_444"]]
+                 %{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]
+               %{"nested_3" => :nested_3, "nested_33" => "nested_33"},
+               %{"nested_4" => true}
              ]
 
-      assert Application.get_env(:pleroma, :key4) == [
-               endpoint: "https://example.com",
+      assert Application.get_env(:pleroma, :key4) == %{
+               "endpoint" => "https://example.com",
                nested_5: :upload
-             ]
+             }
 
       assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []}
     end
@@ -1507,11 +1515,22 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
       config1 = insert(:config, key: "keyaa1")
       config2 = insert(:config, key: "keyaa2")
 
+      insert(:config,
+        group: "ueberauth",
+        key: "Ueberauth.Strategy.Microsoft.OAuth",
+        value: :erlang.term_to_binary([])
+      )
+
       conn =
         post(conn, "/api/pleroma/admin/config", %{
           configs: [
             %{group: config1.group, key: config1.key, value: "another_value"},
-            %{group: config2.group, key: config2.key, delete: "true"}
+            %{group: config2.group, key: config2.key, delete: "true"},
+            %{
+              group: "ueberauth",
+              key: "Ueberauth.Strategy.Microsoft.OAuth",
+              delete: "true"
+            }
           ]
         })
 
@@ -1536,11 +1555,13 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
             %{
               "group" => "pleroma",
               "key" => "Pleroma.Captcha.NotReal",
-              "value" => %{
-                "enabled" => ":false",
-                "method" => "Pleroma.Captcha.Kocaptcha",
-                "seconds_valid" => "i:60"
-              }
+              "value" => [
+                %{"tuple" => [":enabled", false]},
+                %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
+                %{"tuple" => [":seconds_valid", 60]},
+                %{"tuple" => [":path", ""]},
+                %{"tuple" => [":key1", nil]}
+              ]
             }
           ]
         })
@@ -1551,9 +1572,11 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                    "group" => "pleroma",
                    "key" => "Pleroma.Captcha.NotReal",
                    "value" => [
-                     %{"enabled" => false},
-                     %{"method" => "Pleroma.Captcha.Kocaptcha"},
-                     %{"seconds_valid" => 60}
+                     %{"tuple" => [":enabled", false]},
+                     %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
+                     %{"tuple" => [":seconds_valid", 60]},
+                     %{"tuple" => [":path", ""]},
+                     %{"tuple" => [":key1", nil]}
                    ]
                  }
                ]
@@ -1569,51 +1592,57 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
               "key" => "Pleroma.Web.Endpoint.NotReal",
               "value" => [
                 %{
-                  "http" => %{
-                    "dispatch" => [
+                  "tuple" => [
+                    ":http",
+                    [
                       %{
                         "tuple" => [
-                          ":_",
+                          ":key2",
                           [
-                            %{
-                              "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", []]
-                                }
+                                [
+                                  %{
+                                    "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", []]}
+                                    ]
+                                  }
+                                ]
                               ]
                             }
                           ]
                         ]
                       }
                     ]
-                  }
+                  ]
                 }
               ]
             }
@@ -1627,41 +1656,206 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                    "key" => "Pleroma.Web.Endpoint.NotReal",
                    "value" => [
                      %{
-                       "http" => %{
-                         "dispatch" => %{
-                           "_" => [
-                             %{
-                               "tuple" => [
-                                 "/api/v1/streaming",
-                                 "Pleroma.Web.MastodonAPI.WebsocketHandler",
-                                 []
-                               ]
-                             },
-                             %{
-                               "tuple" => [
-                                 "/websocket",
-                                 "Phoenix.Endpoint.CowboyWebSocket",
+                       "tuple" => [
+                         ":http",
+                         [
+                           %{
+                             "tuple" => [
+                               ":key2",
+                               [
                                  %{
-                                   "Elixir.Phoenix.Transports.WebSocket" => %{
-                                     "tuple" => [
-                                       "Pleroma.Web.Endpoint",
-                                       "Pleroma.Web.UserSocket",
-                                       []
+                                   "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", []]}
+                                         ]
+                                       }
                                      ]
-                                   }
+                                   ]
                                  }
                                ]
-                             },
-                             %{
-                               "tuple" => [
-                                 "_",
-                                 "Phoenix.Endpoint.Cowboy2Handler",
-                                 %{"Elixir.Pleroma.Web.Endpoint" => []}
-                               ]
+                             ]
+                           }
+                         ]
+                       ]
+                     }
+                   ]
+                 }
+               ]
+             }
+    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
                              }
-                           ]
-                         }
+                           }
+                         ]
                        }
+                     ]
+                   }
+                 ]
+               }
+    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"}
+                   }
+                 ]
+               }
+    end
+
+    test "dispatch setting", %{conn: conn} do
+      conn =
+        post(conn, "/api/pleroma/admin/config", %{
+          configs: [
+            %{
+              "group" => "pleroma",
+              "key" => "Pleroma.Web.Endpoint.NotReal",
+              "value" => [
+                %{
+                  "tuple" => [
+                    ":http",
+                    [
+                      %{"tuple" => [":ip", %{"tuple" => [127, 0, 0, 1]}]},
+                      %{"tuple" => [":dispatch", ["{:_,
+       [
+         {\"/api/v1/streaming\", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
+         {\"/websocket\", Phoenix.Endpoint.CowboyWebSocket,
+          {Phoenix.Transports.WebSocket,
+           {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: \"/websocket\"]}}},
+         {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
+       ]}"]]}
+                    ]
+                  ]
+                }
+              ]
+            }
+          ]
+        })
+
+      dispatch_string =
+        "{:_, [{\"/api/v1/streaming\", Pleroma.Web.MastodonAPI.WebsocketHandler, []}, " <>
+          "{\"/websocket\", Phoenix.Endpoint.CowboyWebSocket, {Phoenix.Transports.WebSocket, " <>
+          "{Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: \"/websocket\"]}}}, " <>
+          "{:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}]}"
+
+      assert json_response(conn, 200) == %{
+               "configs" => [
+                 %{
+                   "group" => "pleroma",
+                   "key" => "Pleroma.Web.Endpoint.NotReal",
+                   "value" => [
+                     %{
+                       "tuple" => [
+                         ":http",
+                         [
+                           %{"tuple" => [":ip", %{"tuple" => [127, 0, 0, 1]}]},
+                           %{
+                             "tuple" => [
+                               ":dispatch",
+                               [
+                                 dispatch_string
+                               ]
+                             ]
+                           }
+                         ]
+                       ]
                      }
                    ]
                  }
index b281831e3d6edc361d077e43806c0967bfa8d2b7..d41666ef3e0fbb425d3c74269c8b6ee0f5062284 100644 (file)
@@ -61,117 +61,306 @@ defmodule Pleroma.Web.AdminAPI.ConfigTest do
       assert Config.from_binary(binary) == "value as string"
     end
 
+    test "boolean" do
+      binary = Config.transform(false)
+      assert binary == :erlang.term_to_binary(false)
+      assert Config.from_binary(binary) == false
+    end
+
+    test "nil" do
+      binary = Config.transform(nil)
+      assert binary == :erlang.term_to_binary(nil)
+      assert Config.from_binary(binary) == nil
+    end
+
+    test "integer" do
+      binary = Config.transform(150)
+      assert binary == :erlang.term_to_binary(150)
+      assert Config.from_binary(binary) == 150
+    end
+
+    test "atom" do
+      binary = Config.transform(":atom")
+      assert binary == :erlang.term_to_binary(:atom)
+      assert Config.from_binary(binary) == :atom
+    end
+
+    test "pleroma module" do
+      binary = Config.transform("Pleroma.Bookmark")
+      assert binary == :erlang.term_to_binary(Pleroma.Bookmark)
+      assert Config.from_binary(binary) == Pleroma.Bookmark
+    end
+
+    test "phoenix module" do
+      binary = Config.transform("Phoenix.Socket.V1.JSONSerializer")
+      assert binary == :erlang.term_to_binary(Phoenix.Socket.V1.JSONSerializer)
+      assert Config.from_binary(binary) == Phoenix.Socket.V1.JSONSerializer
+    end
+
+    test "sigil" do
+      binary = Config.transform("~r/comp[lL][aA][iI][nN]er/")
+      assert binary == :erlang.term_to_binary(~r/comp[lL][aA][iI][nN]er/)
+      assert Config.from_binary(binary) == ~r/comp[lL][aA][iI][nN]er/
+    end
+
+    test "2 child tuple" do
+      binary = Config.transform(%{"tuple" => ["v1", ":v2"]})
+      assert binary == :erlang.term_to_binary({"v1", :v2})
+      assert Config.from_binary(binary) == {"v1", :v2}
+    end
+
+    test "tuple with n childs" do
+      binary =
+        Config.transform(%{
+          "tuple" => [
+            "v1",
+            ":v2",
+            "Pleroma.Bookmark",
+            150,
+            false,
+            "Phoenix.Socket.V1.JSONSerializer"
+          ]
+        })
+
+      assert binary ==
+               :erlang.term_to_binary(
+                 {"v1", :v2, Pleroma.Bookmark, 150, false, Phoenix.Socket.V1.JSONSerializer}
+               )
+
+      assert Config.from_binary(binary) ==
+               {"v1", :v2, Pleroma.Bookmark, 150, false, Phoenix.Socket.V1.JSONSerializer}
+    end
+
+    test "tuple with dispatch key" do
+      binary = Config.transform(%{"tuple" => [":dispatch", ["{:_,
+       [
+         {\"/api/v1/streaming\", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
+         {\"/websocket\", Phoenix.Endpoint.CowboyWebSocket,
+          {Phoenix.Transports.WebSocket,
+           {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: \"/websocket\"]}}},
+         {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
+       ]}"]]})
+
+      assert binary ==
+               :erlang.term_to_binary(
+                 {:dispatch,
+                  [
+                    {:_,
+                     [
+                       {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
+                       {"/websocket", Phoenix.Endpoint.CowboyWebSocket,
+                        {Phoenix.Transports.WebSocket,
+                         {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: "/websocket"]}}},
+                       {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
+                     ]}
+                  ]}
+               )
+
+      assert Config.from_binary(binary) ==
+               {:dispatch,
+                [
+                  {:_,
+                   [
+                     {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
+                     {"/websocket", Phoenix.Endpoint.CowboyWebSocket,
+                      {Phoenix.Transports.WebSocket,
+                       {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: "/websocket"]}}},
+                     {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
+                   ]}
+                ]}
+    end
+
+    test "map with string key" do
+      binary = Config.transform(%{"key" => "value"})
+      assert binary == :erlang.term_to_binary(%{"key" => "value"})
+      assert Config.from_binary(binary) == %{"key" => "value"}
+    end
+
+    test "map with atom key" do
+      binary = Config.transform(%{":key" => "value"})
+      assert binary == :erlang.term_to_binary(%{key: "value"})
+      assert Config.from_binary(binary) == %{key: "value"}
+    end
+
+    test "list of strings" do
+      binary = Config.transform(["v1", "v2", "v3"])
+      assert binary == :erlang.term_to_binary(["v1", "v2", "v3"])
+      assert Config.from_binary(binary) == ["v1", "v2", "v3"]
+    end
+
     test "list of modules" do
       binary = Config.transform(["Pleroma.Repo", "Pleroma.Activity"])
       assert binary == :erlang.term_to_binary([Pleroma.Repo, Pleroma.Activity])
       assert Config.from_binary(binary) == [Pleroma.Repo, Pleroma.Activity]
     end
 
-    test "list of strings" do
-      binary = Config.transform(["string1", "string2"])
-      assert binary == :erlang.term_to_binary(["string1", "string2"])
-      assert Config.from_binary(binary) == ["string1", "string2"]
+    test "list of atoms" do
+      binary = Config.transform([":v1", ":v2", ":v3"])
+      assert binary == :erlang.term_to_binary([:v1, :v2, :v3])
+      assert Config.from_binary(binary) == [:v1, :v2, :v3]
     end
 
-    test "map" do
+    test "list of mixed values" do
       binary =
-        Config.transform(%{
-          "types" => "Pleroma.PostgresTypes",
-          "telemetry_event" => ["Pleroma.Repo.Instrumenter"],
-          "migration_lock" => ""
-        })
+        Config.transform([
+          "v1",
+          ":v2",
+          "Pleroma.Repo",
+          "Phoenix.Socket.V1.JSONSerializer",
+          15,
+          false
+        ])
+
+      assert binary ==
+               :erlang.term_to_binary([
+                 "v1",
+                 :v2,
+                 Pleroma.Repo,
+                 Phoenix.Socket.V1.JSONSerializer,
+                 15,
+                 false
+               ])
+
+      assert Config.from_binary(binary) == [
+               "v1",
+               :v2,
+               Pleroma.Repo,
+               Phoenix.Socket.V1.JSONSerializer,
+               15,
+               false
+             ]
+    end
+
+    test "simple keyword" do
+      binary = Config.transform([%{"tuple" => [":key", "value"]}])
+      assert binary == :erlang.term_to_binary([{:key, "value"}])
+      assert Config.from_binary(binary) == [{:key, "value"}]
+      assert Config.from_binary(binary) == [key: "value"]
+    end
+
+    test "keyword" do
+      binary =
+        Config.transform([
+          %{"tuple" => [":types", "Pleroma.PostgresTypes"]},
+          %{"tuple" => [":telemetry_event", ["Pleroma.Repo.Instrumenter"]]},
+          %{"tuple" => [":migration_lock", nil]},
+          %{"tuple" => [":key1", 150]},
+          %{"tuple" => [":key2", "string"]}
+        ])
 
       assert binary ==
                :erlang.term_to_binary(
+                 types: Pleroma.PostgresTypes,
                  telemetry_event: [Pleroma.Repo.Instrumenter],
-                 types: Pleroma.PostgresTypes
+                 migration_lock: nil,
+                 key1: 150,
+                 key2: "string"
                )
 
       assert Config.from_binary(binary) == [
+               types: Pleroma.PostgresTypes,
                telemetry_event: [Pleroma.Repo.Instrumenter],
-               types: Pleroma.PostgresTypes
+               migration_lock: nil,
+               key1: 150,
+               key2: "string"
              ]
     end
 
-    test "complex map with nested integers, lists and atoms" do
+    test "complex keyword with nested mixed childs" do
       binary =
-        Config.transform(%{
-          "uploader" => "Pleroma.Uploaders.Local",
-          "filters" => ["Pleroma.Upload.Filter.Dedupe"],
-          "link_name" => ":true",
-          "proxy_remote" => ":false",
-          "proxy_opts" => %{
-            "redirect_on_failure" => ":false",
-            "max_body_length" => "i:1048576",
-            "http" => %{
-              "follow_redirect" => ":true",
-              "pool" => ":upload"
-            }
+        Config.transform([
+          %{"tuple" => [":uploader", "Pleroma.Uploaders.Local"]},
+          %{"tuple" => [":filters", ["Pleroma.Upload.Filter.Dedupe"]]},
+          %{"tuple" => [":link_name", true]},
+          %{"tuple" => [":proxy_remote", false]},
+          %{"tuple" => [":common_map", %{":key" => "value"}]},
+          %{
+            "tuple" => [
+              ":proxy_opts",
+              [
+                %{"tuple" => [":redirect_on_failure", false]},
+                %{"tuple" => [":max_body_length", 1_048_576]},
+                %{
+                  "tuple" => [
+                    ":http",
+                    [%{"tuple" => [":follow_redirect", true]}, %{"tuple" => [":pool", ":upload"]}]
+                  ]
+                }
+              ]
+            ]
           }
-        })
+        ])
 
       assert binary ==
                :erlang.term_to_binary(
+                 uploader: Pleroma.Uploaders.Local,
                  filters: [Pleroma.Upload.Filter.Dedupe],
                  link_name: true,
+                 proxy_remote: false,
+                 common_map: %{key: "value"},
                  proxy_opts: [
+                   redirect_on_failure: false,
+                   max_body_length: 1_048_576,
                    http: [
                      follow_redirect: true,
                      pool: :upload
-                   ],
-                   max_body_length: 1_048_576,
-                   redirect_on_failure: false
-                 ],
-                 proxy_remote: false,
-                 uploader: Pleroma.Uploaders.Local
+                   ]
+                 ]
                )
 
       assert Config.from_binary(binary) ==
                [
+                 uploader: Pleroma.Uploaders.Local,
                  filters: [Pleroma.Upload.Filter.Dedupe],
                  link_name: true,
+                 proxy_remote: false,
+                 common_map: %{key: "value"},
                  proxy_opts: [
+                   redirect_on_failure: false,
+                   max_body_length: 1_048_576,
                    http: [
                      follow_redirect: true,
                      pool: :upload
-                   ],
-                   max_body_length: 1_048_576,
-                   redirect_on_failure: false
-                 ],
-                 proxy_remote: false,
-                 uploader: Pleroma.Uploaders.Local
+                   ]
+                 ]
                ]
     end
 
-    test "keyword" do
+    test "common keyword" do
       binary =
-        Config.transform(%{
-          "level" => ":warn",
-          "meta" => [":all"],
-          "webhook_url" => "https://hooks.slack.com/services/YOUR-KEY-HERE"
-        })
+        Config.transform([
+          %{"tuple" => [":level", ":warn"]},
+          %{"tuple" => [":meta", [":all"]]},
+          %{"tuple" => [":path", ""]},
+          %{"tuple" => [":val", nil]},
+          %{"tuple" => [":webhook_url", "https://hooks.slack.com/services/YOUR-KEY-HERE"]}
+        ])
 
       assert binary ==
                :erlang.term_to_binary(
                  level: :warn,
                  meta: [:all],
+                 path: "",
+                 val: nil,
                  webhook_url: "https://hooks.slack.com/services/YOUR-KEY-HERE"
                )
 
       assert Config.from_binary(binary) == [
                level: :warn,
                meta: [:all],
+               path: "",
+               val: nil,
                webhook_url: "https://hooks.slack.com/services/YOUR-KEY-HERE"
              ]
     end
 
-    test "complex map with sigil" do
+    test "complex keyword with sigil" do
       binary =
-        Config.transform(%{
-          federated_timeline_removal: [],
-          reject: [~r/comp[lL][aA][iI][nN]er/],
-          replace: []
-        })
+        Config.transform([
+          %{"tuple" => [":federated_timeline_removal", []]},
+          %{"tuple" => [":reject", ["~r/comp[lL][aA][iI][nN]er/"]]},
+          %{"tuple" => [":replace", []]}
+        ])
 
       assert binary ==
                :erlang.term_to_binary(
@@ -184,54 +373,68 @@ defmodule Pleroma.Web.AdminAPI.ConfigTest do
                [federated_timeline_removal: [], reject: [~r/comp[lL][aA][iI][nN]er/], replace: []]
     end
 
-    test "complex map with tuples with more than 2 values" do
+    test "complex keyword with tuples with more than 2 values" do
       binary =
-        Config.transform(%{
-          "http" => %{
-            "dispatch" => [
-              %{
-                "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", []]}
+        Config.transform([
+          %{
+            "tuple" => [
+              ":http",
+              [
+                %{
+                  "tuple" => [
+                    ":key1",
+                    [
+                      %{
+                        "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", []]}
+                              ]
+                            }
                           ]
-                        }
-                      ]
-                    },
-                    %{
-                      "tuple" => [
-                        ":_",
-                        "Phoenix.Endpoint.Cowboy2Handler",
-                        %{
-                          "tuple" => ["Pleroma.Web.Endpoint", []]
-                        }
-                      ]
-                    }
+                        ]
+                      }
+                    ]
                   ]
-                ]
-              }
+                }
+              ]
             ]
           }
-        })
+        ])
 
       assert binary ==
                :erlang.term_to_binary(
                  http: [
-                   dispatch: [
+                   key1: [
                      _: [
                        {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
                        {"/websocket", Phoenix.Endpoint.CowboyWebSocket,
@@ -245,7 +448,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigTest do
 
       assert Config.from_binary(binary) == [
                http: [
-                 dispatch: [
+                 key1: [
                    {:_,
                     [
                       {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},