- 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
configs: [
{
"group": string,
- "key": string,
+ "key": string or string with leading `:` for atoms,
"value": string or {} or [] or {"tuple": []}
}
]
## `/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:
- 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)
]
{
"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", []]
- }
- }
- }
+ }]}
+ ]
+ }
]
}
configs: [
{
"group": string,
- "key": string,
+ "key": string or string with leading `:` for atoms,
"value": string or {} or [] or {"tuple": []}
}
]
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))
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
%{
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
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"}}
]
}
},
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",
"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",
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
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"
+ }
]
})
%{
"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]}
+ ]
}
]
})
"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]}
]
}
]
"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", []]}
+ ]
+ }
+ ]
]
}
]
]
}
]
- }
+ ]
}
]
}
"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
+ ]
+ ]
+ }
+ ]
+ ]
}
]
}
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(
[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,
assert Config.from_binary(binary) == [
http: [
- dispatch: [
+ key1: [
{:_,
[
{"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},