commit
e151dea276
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,79 @@
|
|||||||
|
# Configuring instance
|
||||||
|
You can configure your instance from admin interface. You need account with admin rights and little change in config file, which will allow settings configuration from database.
|
||||||
|
|
||||||
|
```elixir
|
||||||
|
config :pleroma, configurable_from_database: true
|
||||||
|
```
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
Settings are stored in database and are applied in `runtime` after each change. Most of the settings take effect immediately, except some, which need instance reboot. These settings are needed in `compile time`, that's why settings are duplicated to the file.
|
||||||
|
|
||||||
|
File with duplicated settings is located in `config/{env}.exported_from_db.exs` if pleroma is runned from source. For prod env it will be `config/prod.exported_from_db.exs`.
|
||||||
|
|
||||||
|
For releases: `/etc/pleroma/prod.exported_from_db.secret.exs` or `PLEROMA_CONFIG_PATH/prod.exported_from_db.exs`.
|
||||||
|
|
||||||
|
## How to set it up
|
||||||
|
You need to migrate your existing settings to the database. This task will migrate only added by user settings.
|
||||||
|
For example you add settings to `prod.secret.exs` file, only these settings will be migrated to database. For release it will be `/etc/pleroma/config.exs` or `PLEROMA_CONFIG_PATH`.
|
||||||
|
You can do this with mix task (all config files will remain untouched):
|
||||||
|
|
||||||
|
```sh tab="OTP"
|
||||||
|
./bin/pleroma_ctl config migrate_to_db
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh tab="From Source"
|
||||||
|
mix pleroma.config migrate_to_db
|
||||||
|
```
|
||||||
|
|
||||||
|
Now you can change settings in admin interface. After each save, settings from database are duplicated to the `config/{env}.exported_from_db.exs` file.
|
||||||
|
|
||||||
|
<span style="color:red">**ATTENTION**</span>
|
||||||
|
|
||||||
|
**<span style="color:red">Be careful while changing the settings. Every inaccurate configuration change can break the federation or the instance load.</span>**
|
||||||
|
|
||||||
|
*Compile time settings, which require instance reboot and can break instance loading:*
|
||||||
|
- all settings inside these keys:
|
||||||
|
- `:hackney_pools`
|
||||||
|
- `:chat`
|
||||||
|
- partially settings inside these keys:
|
||||||
|
- `:seconds_valid` in `Pleroma.Captcha`
|
||||||
|
- `:proxy_remote` in `Pleroma.Upload`
|
||||||
|
- `:upload_limit` in `:instance`
|
||||||
|
|
||||||
|
## How to dump settings from database to file
|
||||||
|
|
||||||
|
*Adding `-d` flag will delete migrated settings from database table.*
|
||||||
|
|
||||||
|
```sh tab="OTP"
|
||||||
|
./bin/pleroma_ctl config migrate_from_db [-d]
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh tab="From Source"
|
||||||
|
mix pleroma.config migrate_from_db [-d]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## How to completely remove it
|
||||||
|
|
||||||
|
1. Truncate or delete all values from `config` table
|
||||||
|
```sql
|
||||||
|
TRUNCATE TABLE config;
|
||||||
|
```
|
||||||
|
2. Delete `config/{env}.exported_from_db.exs`.
|
||||||
|
|
||||||
|
For `prod` env:
|
||||||
|
```bash
|
||||||
|
cd /opt/pleroma
|
||||||
|
cp config/prod.exported_from_db.exs config/exported_from_db.back
|
||||||
|
rm -rf config/prod.exported_from_db.exs
|
||||||
|
```
|
||||||
|
*If you don't want to backup settings, you can skip step with `cp` command.*
|
||||||
|
|
||||||
|
3. Set configurable_from_database to `false`.
|
||||||
|
```elixir
|
||||||
|
config :pleroma, configurable_from_database: false
|
||||||
|
```
|
||||||
|
4. Restart pleroma instance
|
||||||
|
```bash
|
||||||
|
sudo service pleroma restart
|
||||||
|
```
|
@ -0,0 +1,422 @@
|
|||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.ConfigDB do
|
||||||
|
use Ecto.Schema
|
||||||
|
|
||||||
|
import Ecto.Changeset
|
||||||
|
import Ecto.Query
|
||||||
|
import Pleroma.Web.Gettext
|
||||||
|
|
||||||
|
alias __MODULE__
|
||||||
|
alias Pleroma.Repo
|
||||||
|
|
||||||
|
@type t :: %__MODULE__{}
|
||||||
|
|
||||||
|
@full_key_update [
|
||||||
|
{:pleroma, :ecto_repos},
|
||||||
|
{:quack, :meta},
|
||||||
|
{:mime, :types},
|
||||||
|
{:cors_plug, [:max_age, :methods, :expose, :headers]},
|
||||||
|
{:auto_linker, :opts},
|
||||||
|
{:swarm, :node_blacklist},
|
||||||
|
{:logger, :backends}
|
||||||
|
]
|
||||||
|
|
||||||
|
@full_subkey_update [
|
||||||
|
{:pleroma, :assets, :mascots},
|
||||||
|
{:pleroma, :emoji, :groups},
|
||||||
|
{:pleroma, :workers, :retries},
|
||||||
|
{:pleroma, :mrf_subchain, :match_actor},
|
||||||
|
{:pleroma, :mrf_keyword, :replace}
|
||||||
|
]
|
||||||
|
|
||||||
|
@regex ~r/^~r(?'delimiter'[\/|"'([{<]{1})(?'pattern'.+)[\/|"')\]}>]{1}(?'modifier'[uismxfU]*)/u
|
||||||
|
|
||||||
|
@delimiters ["/", "|", "\"", "'", {"(", ")"}, {"[", "]"}, {"{", "}"}, {"<", ">"}]
|
||||||
|
|
||||||
|
schema "config" do
|
||||||
|
field(:key, :string)
|
||||||
|
field(:group, :string)
|
||||||
|
field(:value, :binary)
|
||||||
|
field(:db, {:array, :string}, virtual: true, default: [])
|
||||||
|
|
||||||
|
timestamps()
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec get_all_as_keyword() :: keyword()
|
||||||
|
def get_all_as_keyword do
|
||||||
|
ConfigDB
|
||||||
|
|> select([c], {c.group, c.key, c.value})
|
||||||
|
|> Repo.all()
|
||||||
|
|> Enum.reduce([], fn {group, key, value}, acc ->
|
||||||
|
group = ConfigDB.from_string(group)
|
||||||
|
key = ConfigDB.from_string(key)
|
||||||
|
value = from_binary(value)
|
||||||
|
|
||||||
|
Keyword.update(acc, group, [{key, value}], &Keyword.merge(&1, [{key, value}]))
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec get_by_params(map()) :: ConfigDB.t() | nil
|
||||||
|
def get_by_params(params), do: Repo.get_by(ConfigDB, params)
|
||||||
|
|
||||||
|
@spec changeset(ConfigDB.t(), map()) :: Changeset.t()
|
||||||
|
def changeset(config, params \\ %{}) do
|
||||||
|
params = Map.put(params, :value, transform(params[:value]))
|
||||||
|
|
||||||
|
config
|
||||||
|
|> cast(params, [:key, :group, :value])
|
||||||
|
|> validate_required([:key, :group, :value])
|
||||||
|
|> unique_constraint(:key, name: :config_group_key_index)
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec create(map()) :: {:ok, ConfigDB.t()} | {:error, Changeset.t()}
|
||||||
|
def create(params) do
|
||||||
|
%ConfigDB{}
|
||||||
|
|> changeset(params)
|
||||||
|
|> Repo.insert()
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec update(ConfigDB.t(), map()) :: {:ok, ConfigDB.t()} | {:error, Changeset.t()}
|
||||||
|
def update(%ConfigDB{} = config, %{value: value}) do
|
||||||
|
config
|
||||||
|
|> changeset(%{value: value})
|
||||||
|
|> Repo.update()
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec get_db_keys(ConfigDB.t()) :: [String.t()]
|
||||||
|
def get_db_keys(%ConfigDB{} = config) do
|
||||||
|
config.value
|
||||||
|
|> ConfigDB.from_binary()
|
||||||
|
|> get_db_keys(config.key)
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec get_db_keys(keyword(), any()) :: [String.t()]
|
||||||
|
def get_db_keys(value, key) do
|
||||||
|
if Keyword.keyword?(value) do
|
||||||
|
value |> Keyword.keys() |> Enum.map(&convert(&1))
|
||||||
|
else
|
||||||
|
[convert(key)]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec merge_group(atom(), atom(), keyword(), keyword()) :: keyword()
|
||||||
|
def merge_group(group, key, old_value, new_value) do
|
||||||
|
new_keys = to_map_set(new_value)
|
||||||
|
|
||||||
|
intersect_keys =
|
||||||
|
old_value |> to_map_set() |> MapSet.intersection(new_keys) |> MapSet.to_list()
|
||||||
|
|
||||||
|
merged_value = ConfigDB.merge(old_value, new_value)
|
||||||
|
|
||||||
|
@full_subkey_update
|
||||||
|
|> Enum.map(fn
|
||||||
|
{g, k, subkey} when g == group and k == key ->
|
||||||
|
if subkey in intersect_keys, do: subkey, else: []
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
[]
|
||||||
|
end)
|
||||||
|
|> List.flatten()
|
||||||
|
|> Enum.reduce(merged_value, fn subkey, acc ->
|
||||||
|
Keyword.put(acc, subkey, new_value[subkey])
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp to_map_set(keyword) do
|
||||||
|
keyword
|
||||||
|
|> Keyword.keys()
|
||||||
|
|> MapSet.new()
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec sub_key_full_update?(atom(), atom(), [Keyword.key()]) :: boolean()
|
||||||
|
def sub_key_full_update?(group, key, subkeys) do
|
||||||
|
Enum.any?(@full_subkey_update, fn {g, k, subkey} ->
|
||||||
|
g == group and k == key and subkey in subkeys
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec merge(keyword(), keyword()) :: keyword()
|
||||||
|
def merge(config1, config2) when is_list(config1) and is_list(config2) do
|
||||||
|
Keyword.merge(config1, config2, fn _, app1, app2 ->
|
||||||
|
if Keyword.keyword?(app1) and Keyword.keyword?(app2) do
|
||||||
|
Keyword.merge(app1, app2, &deep_merge/3)
|
||||||
|
else
|
||||||
|
app2
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp deep_merge(_key, value1, value2) do
|
||||||
|
if Keyword.keyword?(value1) and Keyword.keyword?(value2) do
|
||||||
|
Keyword.merge(value1, value2, &deep_merge/3)
|
||||||
|
else
|
||||||
|
value2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec update_or_create(map()) :: {:ok, ConfigDB.t()} | {:error, Changeset.t()}
|
||||||
|
def update_or_create(params) do
|
||||||
|
search_opts = Map.take(params, [:group, :key])
|
||||||
|
|
||||||
|
with %ConfigDB{} = config <- ConfigDB.get_by_params(search_opts),
|
||||||
|
{:partial_update, true, config} <-
|
||||||
|
{:partial_update, can_be_partially_updated?(config), config},
|
||||||
|
old_value <- from_binary(config.value),
|
||||||
|
transformed_value <- do_transform(params[:value]),
|
||||||
|
{:can_be_merged, true, config} <- {:can_be_merged, is_list(transformed_value), config},
|
||||||
|
new_value <-
|
||||||
|
merge_group(
|
||||||
|
ConfigDB.from_string(config.group),
|
||||||
|
ConfigDB.from_string(config.key),
|
||||||
|
old_value,
|
||||||
|
transformed_value
|
||||||
|
) do
|
||||||
|
ConfigDB.update(config, %{value: new_value})
|
||||||
|
else
|
||||||
|
{reason, false, config} when reason in [:partial_update, :can_be_merged] ->
|
||||||
|
ConfigDB.update(config, params)
|
||||||
|
|
||||||
|
nil ->
|
||||||
|
ConfigDB.create(params)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp can_be_partially_updated?(%ConfigDB{} = config), do: not only_full_update?(config)
|
||||||
|
|
||||||
|
defp only_full_update?(%ConfigDB{} = config) do
|
||||||
|
config_group = ConfigDB.from_string(config.group)
|
||||||
|
config_key = ConfigDB.from_string(config.key)
|
||||||
|
|
||||||
|
Enum.any?(@full_key_update, fn
|
||||||
|
{group, key} when is_list(key) ->
|
||||||
|
config_group == group and config_key in key
|
||||||
|
|
||||||
|
{group, key} ->
|
||||||
|
config_group == group and config_key == key
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec delete(map()) :: {:ok, ConfigDB.t()} | {:error, Changeset.t()}
|
||||||
|
def delete(params) do
|
||||||
|
search_opts = Map.delete(params, :subkeys)
|
||||||
|
|
||||||
|
with %ConfigDB{} = config <- ConfigDB.get_by_params(search_opts),
|
||||||
|
{config, sub_keys} when is_list(sub_keys) <- {config, params[:subkeys]},
|
||||||
|
old_value <- from_binary(config.value),
|
||||||
|
keys <- Enum.map(sub_keys, &do_transform_string(&1)),
|
||||||
|
{:partial_remove, config, new_value} when new_value != [] <-
|
||||||
|
{:partial_remove, config, Keyword.drop(old_value, keys)} do
|
||||||
|
ConfigDB.update(config, %{value: new_value})
|
||||||
|
else
|
||||||
|
{:partial_remove, config, []} ->
|
||||||
|
Repo.delete(config)
|
||||||
|
|
||||||
|
{config, nil} ->
|
||||||
|
Repo.delete(config)
|
||||||
|
|
||||||
|
nil ->
|
||||||
|
err =
|
||||||
|
dgettext("errors", "Config with params %{params} not found", params: inspect(params))
|
||||||
|
|
||||||
|
{:error, err}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec from_binary(binary()) :: term()
|
||||||
|
def from_binary(binary), do: :erlang.binary_to_term(binary)
|
||||||
|
|
||||||
|
@spec from_binary_with_convert(binary()) :: any()
|
||||||
|
def from_binary_with_convert(binary) do
|
||||||
|
binary
|
||||||
|
|> from_binary()
|
||||||
|
|> do_convert()
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec from_string(String.t()) :: atom() | no_return()
|
||||||
|
def from_string(":" <> entity), do: String.to_existing_atom(entity)
|
||||||
|
|
||||||
|
def from_string(entity) when is_binary(entity) do
|
||||||
|
if is_module_name?(entity) do
|
||||||
|
String.to_existing_atom("Elixir.#{entity}")
|
||||||
|
else
|
||||||
|
entity
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec convert(any()) :: any()
|
||||||
|
def convert(entity), do: do_convert(entity)
|
||||||
|
|
||||||
|
defp do_convert(entity) when is_list(entity) do
|
||||||
|
for v <- entity, into: [], do: do_convert(v)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp do_convert(%Regex{} = entity), do: inspect(entity)
|
||||||
|
|
||||||
|
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({:proxy_url, {type, :localhost, port}}) do
|
||||||
|
%{"tuple" => [":proxy_url", %{"tuple" => [do_convert(type), "localhost", port]}]}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp do_convert({:proxy_url, {type, host, port}}) when is_tuple(host) do
|
||||||
|
ip =
|
||||||
|
host
|
||||||
|
|> :inet_parse.ntoa()
|
||||||
|
|> to_string()
|
||||||
|
|
||||||
|
%{
|
||||||
|
"tuple" => [
|
||||||
|
":proxy_url",
|
||||||
|
%{"tuple" => [do_convert(type), ip, port]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp do_convert({:proxy_url, {type, host, port}}) do
|
||||||
|
%{
|
||||||
|
"tuple" => [
|
||||||
|
":proxy_url",
|
||||||
|
%{"tuple" => [do_convert(type), to_string(host), port]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp do_convert({:partial_chain, entity}), do: %{"tuple" => [":partial_chain", inspect(entity)]}
|
||||||
|
|
||||||
|
defp do_convert(entity) when is_tuple(entity) do
|
||||||
|
value =
|
||||||
|
entity
|
||||||
|
|> Tuple.to_list()
|
||||||
|
|> do_convert()
|
||||||
|
|
||||||
|
%{"tuple" => value}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp do_convert(entity) when is_boolean(entity) or is_number(entity) or is_nil(entity) do
|
||||||
|
entity
|
||||||
|
end
|
||||||
|
|
||||||
|
defp do_convert(entity)
|
||||||
|
when is_atom(entity) and entity in [:"tlsv1.1", :"tlsv1.2", :"tlsv1.3"] do
|
||||||
|
":#{entity}"
|
||||||
|
end
|
||||||
|
|
||||||
|
defp do_convert(entity) when is_atom(entity), do: inspect(entity)
|
||||||
|
|
||||||
|
defp do_convert(entity) when is_binary(entity), do: entity
|
||||||
|
|
||||||
|
@spec transform(any()) :: binary() | no_return()
|
||||||
|
def transform(entity) when is_binary(entity) or is_map(entity) or is_list(entity) do
|
||||||
|
entity
|
||||||
|
|> do_transform()
|
||||||
|
|> to_binary()
|
||||||
|
end
|
||||||
|
|
||||||
|
def transform(entity), do: to_binary(entity)
|
||||||
|
|
||||||
|
@spec transform_with_out_binary(any()) :: any()
|
||||||
|
def transform_with_out_binary(entity), do: do_transform(entity)
|
||||||
|
|
||||||
|
@spec to_binary(any()) :: binary()
|
||||||
|
def to_binary(entity), do: :erlang.term_to_binary(entity)
|
||||||
|
|
||||||
|
defp do_transform(%Regex{} = entity), do: entity
|
||||||
|
|
||||||
|
defp do_transform(%{"tuple" => [":proxy_url", %{"tuple" => [type, host, port]}]}) do
|
||||||
|
{:proxy_url, {do_transform_string(type), parse_host(host), port}}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp do_transform(%{"tuple" => [":partial_chain", entity]}) do
|
||||||
|
{partial_chain, []} =
|
||||||
|
entity
|
||||||
|
|> String.replace(~r/[^\w|^{:,[|^,|^[|^\]^}|^\/|^\.|^"]^\s/, "")
|
||||||
|
|> Code.eval_string()
|
||||||
|
|
||||||
|
{:partial_chain, partial_chain}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp do_transform(%{"tuple" => entity}) do
|
||||||
|
Enum.reduce(entity, {}, fn val, acc -> Tuple.append(acc, do_transform(val)) end)
|
||||||
|
end
|
||||||
|
|
||||||
|
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(entity) when is_list(entity) do
|
||||||
|
for v <- entity, into: [], do: do_transform(v)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp do_transform(entity) when is_binary(entity) do
|
||||||
|
entity
|
||||||
|
|> String.trim()
|
||||||
|
|> do_transform_string()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp do_transform(entity), do: entity
|
||||||
|
|
||||||
|
defp parse_host("localhost"), do: :localhost
|
||||||
|
|
||||||
|
defp parse_host(host) do
|
||||||
|
charlist = to_charlist(host)
|
||||||
|
|
||||||
|
case :inet.parse_address(charlist) do
|
||||||
|
{:error, :einval} ->
|
||||||
|
charlist
|
||||||
|
|
||||||
|
{:ok, ip} ->
|
||||||
|
ip
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp find_valid_delimiter([], _string, _) do
|
||||||
|
raise(ArgumentError, message: "valid delimiter for Regex expression not found")
|
||||||
|
end
|
||||||
|
|
||||||
|
defp find_valid_delimiter([{leading, closing} = delimiter | others], pattern, regex_delimiter)
|
||||||
|
when is_tuple(delimiter) do
|
||||||
|
if String.contains?(pattern, closing) do
|
||||||
|
find_valid_delimiter(others, pattern, regex_delimiter)
|
||||||
|
else
|
||||||
|
{:ok, {leading, closing}}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp find_valid_delimiter([delimiter | others], pattern, regex_delimiter) do
|
||||||
|
if String.contains?(pattern, delimiter) do
|
||||||
|
find_valid_delimiter(others, pattern, regex_delimiter)
|
||||||
|
else
|
||||||
|
{:ok, {delimiter, delimiter}}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp do_transform_string("~r" <> _pattern = regex) do
|
||||||
|
with %{"modifier" => modifier, "pattern" => pattern, "delimiter" => regex_delimiter} <-
|
||||||
|
Regex.named_captures(@regex, regex),
|
||||||
|
{:ok, {leading, closing}} <- find_valid_delimiter(@delimiters, pattern, regex_delimiter),
|
||||||
|
{result, _} <- Code.eval_string("~r#{leading}#{pattern}#{closing}#{modifier}") do
|
||||||
|
result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp do_transform_string(":" <> atom), do: String.to_atom(atom)
|
||||||
|
|
||||||
|
defp do_transform_string(value) do
|
||||||
|
if is_module_name?(value) do
|
||||||
|
String.to_existing_atom("Elixir." <> value)
|
||||||
|
else
|
||||||
|
value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec is_module_name?(String.t()) :: boolean()
|
||||||
|
def is_module_name?(string) do
|
||||||
|
Regex.match?(~r/^(Pleroma|Phoenix|Tesla|Quack|Ueberauth)\./, string) or
|
||||||
|
string in ["Oban", "Ueberauth", "ExSyslogger"]
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,16 @@
|
|||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Config.Holder do
|
||||||
|
@config Pleroma.Config.Loader.load_and_merge()
|
||||||
|
|
||||||
|
@spec config() :: keyword()
|
||||||
|
def config, do: @config
|
||||||
|
|
||||||
|
@spec config(atom()) :: any()
|
||||||
|
def config(group), do: @config[group]
|
||||||
|
|
||||||
|
@spec config(atom(), atom()) :: any()
|
||||||
|
def config(group, key), do: @config[group][key]
|
||||||
|
end
|
@ -0,0 +1,59 @@
|
|||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Config.Loader do
|
||||||
|
@paths ["config/config.exs", "config/#{Mix.env()}.exs"]
|
||||||
|
|
||||||
|
@reject_keys [
|
||||||
|
Pleroma.Repo,
|
||||||
|
Pleroma.Web.Endpoint,
|
||||||
|
:env,
|
||||||
|
:configurable_from_database,
|
||||||
|
:database,
|
||||||
|
:swarm
|
||||||
|
]
|
||||||
|
|
||||||
|
if Code.ensure_loaded?(Config.Reader) do
|
||||||
|
@spec load(Path.t()) :: keyword()
|
||||||
|
def load(path), do: Config.Reader.read!(path)
|
||||||
|
|
||||||
|
defp do_merge(conf1, conf2), do: Config.Reader.merge(conf1, conf2)
|
||||||
|
else
|
||||||
|
# support for Elixir less than 1.9
|
||||||
|
@spec load(Path.t()) :: keyword()
|
||||||
|
def load(path) do
|
||||||
|
path
|
||||||
|
|> Mix.Config.eval!()
|
||||||
|
|> elem(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp do_merge(conf1, conf2), do: Mix.Config.merge(conf1, conf2)
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec load_and_merge() :: keyword()
|
||||||
|
def load_and_merge do
|
||||||
|
all_paths =
|
||||||
|
if Pleroma.Config.get(:release),
|
||||||
|
do: @paths ++ ["config/releases.exs"],
|
||||||
|
else: @paths
|
||||||
|
|
||||||
|
all_paths
|
||||||
|
|> Enum.map(&load(&1))
|
||||||
|
|> Enum.reduce([], &do_merge(&2, &1))
|
||||||
|
|> filter()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp filter(configs) do
|
||||||
|
configs
|
||||||
|
|> Keyword.keys()
|
||||||
|
|> Enum.reduce([], &Keyword.put(&2, &1, filter_group(&1, configs)))
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec filter_group(atom(), keyword()) :: keyword()
|
||||||
|
def filter_group(group, configs) do
|
||||||
|
Enum.reject(configs[group], fn {key, _v} ->
|
||||||
|
key in @reject_keys or (group == :phoenix and key == :serve_endpoints)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
@ -1,182 +0,0 @@
|
|||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
defmodule Pleroma.Web.AdminAPI.Config do
|
|
||||||
use Ecto.Schema
|
|
||||||
import Ecto.Changeset
|
|
||||||
import Pleroma.Web.Gettext
|
|
||||||
alias __MODULE__
|
|
||||||
alias Pleroma.Repo
|
|
||||||
|
|
||||||
@type t :: %__MODULE__{}
|
|
||||||
|
|
||||||
schema "config" do
|
|
||||||
field(:key, :string)
|
|
||||||
field(:group, :string)
|
|
||||||
field(:value, :binary)
|
|
||||||
|
|
||||||
timestamps()
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec get_by_params(map()) :: Config.t() | nil
|
|
||||||
def get_by_params(params), do: Repo.get_by(Config, params)
|
|
||||||
|
|
||||||
@spec changeset(Config.t(), map()) :: Changeset.t()
|
|
||||||
def changeset(config, params \\ %{}) do
|
|
||||||
config
|
|
||||||
|> cast(params, [:key, :group, :value])
|
|
||||||
|> validate_required([:key, :group, :value])
|
|
||||||
|> unique_constraint(:key, name: :config_group_key_index)
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec create(map()) :: {:ok, Config.t()} | {:error, Changeset.t()}
|
|
||||||
def create(params) do
|
|
||||||
%Config{}
|
|
||||||
|> changeset(Map.put(params, :value, transform(params[:value])))
|
|
||||||
|> Repo.insert()
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec update(Config.t(), map()) :: {:ok, Config} | {:error, Changeset.t()}
|
|
||||||
def update(%Config{} = config, %{value: value}) do
|
|
||||||
config
|
|
||||||
|> change(value: transform(value))
|
|
||||||
|> Repo.update()
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec update_or_create(map()) :: {:ok, Config.t()} | {:error, Changeset.t()}
|
|
||||||
def update_or_create(params) do
|
|
||||||
with %Config{} = config <- Config.get_by_params(Map.take(params, [:group, :key])) do
|
|
||||||
Config.update(config, params)
|
|
||||||
else
|
|
||||||
nil -> Config.create(params)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec delete(map()) :: {:ok, Config.t()} | {:error, Changeset.t()}
|
|
||||||
def delete(params) do
|
|
||||||
with %Config{} = config <- Config.get_by_params(Map.delete(params, :subkeys)) do
|
|
||||||
if params[:subkeys] do
|
|
||||||
updated_value =
|
|
||||||
Keyword.drop(
|
|
||||||
:erlang.binary_to_term(config.value),
|
|
||||||
Enum.map(params[:subkeys], &do_transform_string(&1))
|
|
||||||
)
|
|
||||||
|
|
||||||
Config.update(config, %{value: updated_value})
|
|
||||||
else
|
|
||||||
Repo.delete(config)
|
|
||||||
{:ok, nil}
|
|
||||||
end
|
|
||||||
else
|
|
||||||
nil ->
|
|
||||||
err =
|
|
||||||
dgettext("errors", "Config with params %{params} not found", params: inspect(params))
|
|
||||||
|
|
||||||
{:error, err}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec from_binary(binary()) :: term()
|
|
||||||
def from_binary(binary), do: :erlang.binary_to_term(binary)
|
|
||||||
|
|
||||||
@spec from_binary_with_convert(binary()) :: any()
|
|
||||||
def from_binary_with_convert(binary) do
|
|
||||||
from_binary(binary)
|
|
||||||
|> do_convert()
|
|
||||||
end
|
|
||||||
|
|
||||||
defp do_convert(entity) when is_list(entity) do
|
|
||||||
for v <- entity, into: [], do: do_convert(v)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp do_convert(%Regex{} = entity), do: inspect(entity)
|
|
||||||
|
|
||||||
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({:dispatch, [entity]}), do: %{"tuple" => [":dispatch", [inspect(entity)]]}
|
|
||||||
defp do_convert({:partial_chain, entity}), do: %{"tuple" => [":partial_chain", inspect(entity)]}
|
|
||||||
|
|
||||||
defp do_convert(entity) when is_tuple(entity),
|
|
||||||
do: %{"tuple" => do_convert(Tuple.to_list(entity))}
|
|
||||||
|
|
||||||
defp do_convert(entity) when is_boolean(entity) or is_number(entity) or is_nil(entity),
|
|
||||||
do: entity
|
|
||||||
|
|
||||||
defp do_convert(entity) when is_atom(entity) do
|
|
||||||
string = to_string(entity)
|
|
||||||
|
|
||||||
if String.starts_with?(string, "Elixir."),
|
|
||||||
do: do_convert(string),
|
|
||||||
else: ":" <> string
|
|
||||||
end
|
|
||||||
|
|
||||||
defp do_convert("Elixir." <> module_name), do: module_name
|
|
||||||
|
|
||||||
defp do_convert(entity) when is_binary(entity), do: entity
|
|
||||||
|
|
||||||
@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{} = entity), do: entity
|
|
||||||
|
|
||||||
defp do_transform(%{"tuple" => [":dispatch", [entity]]}) do
|
|
||||||
{dispatch_settings, []} = do_eval(entity)
|
|
||||||
{:dispatch, [dispatch_settings]}
|
|
||||||
end
|
|
||||||
|
|
||||||
defp do_transform(%{"tuple" => [":partial_chain", entity]}) do
|
|
||||||
{partial_chain, []} = do_eval(entity)
|
|
||||||
{:partial_chain, partial_chain}
|
|
||||||
end
|
|
||||||
|
|
||||||
defp do_transform(%{"tuple" => entity}) do
|
|
||||||
Enum.reduce(entity, {}, fn val, acc -> Tuple.append(acc, do_transform(val)) end)
|
|
||||||
end
|
|
||||||
|
|
||||||
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(entity) when is_list(entity) do
|
|
||||||
for v <- entity, into: [], do: do_transform(v)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp do_transform(entity) when is_binary(entity) do
|
|
||||||
String.trim(entity)
|
|
||||||
|> do_transform_string()
|
|
||||||
end
|
|
||||||
|
|
||||||
defp do_transform(entity), do: entity
|
|
||||||
|
|
||||||
defp do_transform_string("~r/" <> pattern) do
|
|
||||||
modificator = String.split(pattern, "/") |> List.last()
|
|
||||||
pattern = String.trim_trailing(pattern, "/" <> modificator)
|
|
||||||
|
|
||||||
case modificator do
|
|
||||||
"" -> ~r/#{pattern}/
|
|
||||||
"i" -> ~r/#{pattern}/i
|
|
||||||
"u" -> ~r/#{pattern}/u
|
|
||||||
"s" -> ~r/#{pattern}/s
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defp do_transform_string(":" <> atom), do: String.to_atom(atom)
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
defp do_eval(entity) do
|
|
||||||
cleaned_string = String.replace(entity, ~r/[^\w|^{:,[|^,|^[|^\]^}|^\/|^\.|^"]^\s/, "")
|
|
||||||
Code.eval_string(cleaned_string, [], requires: [], macros: [])
|
|
||||||
end
|
|
||||||
end
|
|
@ -0,0 +1,704 @@
|
|||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.ConfigDBTest do
|
||||||
|
use Pleroma.DataCase, async: true
|
||||||
|
import Pleroma.Factory
|
||||||
|
alias Pleroma.ConfigDB
|
||||||
|
|
||||||
|
test "get_by_key/1" do
|
||||||
|
config = insert(:config)
|
||||||
|
insert(:config)
|
||||||
|
|
||||||
|
assert config == ConfigDB.get_by_params(%{group: config.group, key: config.key})
|
||||||
|
end
|
||||||
|
|
||||||
|
test "create/1" do
|
||||||
|
{:ok, config} = ConfigDB.create(%{group: ":pleroma", key: ":some_key", value: "some_value"})
|
||||||
|
assert config == ConfigDB.get_by_params(%{group: ":pleroma", key: ":some_key"})
|
||||||
|
end
|
||||||
|
|
||||||
|
test "update/1" do
|
||||||
|
config = insert(:config)
|
||||||
|
{:ok, updated} = ConfigDB.update(config, %{value: "some_value"})
|
||||||
|
loaded = ConfigDB.get_by_params(%{group: config.group, key: config.key})
|
||||||
|
assert loaded == updated
|
||||||
|
end
|
||||||
|
|
||||||
|
test "get_all_as_keyword/0" do
|
||||||
|
saved = insert(:config)
|
||||||
|
insert(:config, group: ":quack", key: ":level", value: ConfigDB.to_binary(:info))
|
||||||
|
insert(:config, group: ":quack", key: ":meta", value: ConfigDB.to_binary([:none]))
|
||||||
|
|
||||||
|
insert(:config,
|
||||||
|
group: ":quack",
|
||||||
|
key: ":webhook_url",
|
||||||
|
value: ConfigDB.to_binary("https://hooks.slack.com/services/KEY/some_val")
|
||||||
|
)
|
||||||
|
|
||||||
|
config = ConfigDB.get_all_as_keyword()
|
||||||
|
|
||||||
|
assert config[:pleroma] == [
|
||||||
|
{ConfigDB.from_string(saved.key), ConfigDB.from_binary(saved.value)}
|
||||||
|
]
|
||||||
|
|
||||||
|
assert config[:quack] == [
|
||||||
|
level: :info,
|
||||||
|
meta: [:none],
|
||||||
|
webhook_url: "https://hooks.slack.com/services/KEY/some_val"
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "update_or_create/1" do
|
||||||
|
test "common" do
|
||||||
|
config = insert(:config)
|
||||||
|
key2 = "another_key"
|
||||||
|
|
||||||
|
params = [
|
||||||
|
%{group: "pleroma", key: key2, value: "another_value"},
|
||||||
|
%{group: config.group, key: config.key, value: "new_value"}
|
||||||
|
]
|
||||||
|
|
||||||
|
assert Repo.all(ConfigDB) |> length() == 1
|
||||||
|
|
||||||
|
Enum.each(params, &ConfigDB.update_or_create(&1))
|
||||||
|
|
||||||
|
assert Repo.all(ConfigDB) |> length() == 2
|
||||||
|
|
||||||
|
config1 = ConfigDB.get_by_params(%{group: config.group, key: config.key})
|
||||||
|
config2 = ConfigDB.get_by_params(%{group: "pleroma", key: key2})
|
||||||
|
|
||||||
|
assert config1.value == ConfigDB.transform("new_value")
|
||||||
|
assert config2.value == ConfigDB.transform("another_value")
|
||||||
|
end
|
||||||
|
|
||||||
|
test "partial update" do
|
||||||
|
config = insert(:config, value: ConfigDB.to_binary(key1: "val1", key2: :val2))
|
||||||
|
|
||||||
|
{:ok, _config} =
|
||||||
|
ConfigDB.update_or_create(%{
|
||||||
|
group: config.group,
|
||||||
|
key: config.key,
|
||||||
|
value: [key1: :val1, key3: :val3]
|
||||||
|
})
|
||||||
|
|
||||||
|
updated = ConfigDB.get_by_params(%{group: config.group, key: config.key})
|
||||||
|
|
||||||
|
value = ConfigDB.from_binary(updated.value)
|
||||||
|
assert length(value) == 3
|
||||||
|
assert value[:key1] == :val1
|
||||||
|
assert value[:key2] == :val2
|
||||||
|
assert value[:key3] == :val3
|
||||||
|
end
|
||||||
|
|
||||||
|
test "deep merge" do
|
||||||
|
config = insert(:config, value: ConfigDB.to_binary(key1: "val1", key2: [k1: :v1, k2: "v2"]))
|
||||||
|
|
||||||
|
{:ok, config} =
|
||||||
|
ConfigDB.update_or_create(%{
|
||||||
|
group: config.group,
|
||||||
|
key: config.key,
|
||||||
|
value: [key1: :val1, key2: [k2: :v2, k3: :v3], key3: :val3]
|
||||||
|
})
|
||||||
|
|
||||||
|
updated = ConfigDB.get_by_params(%{group: config.group, key: config.key})
|
||||||
|
|
||||||
|
assert config.value == updated.value
|
||||||
|
|
||||||
|
value = ConfigDB.from_binary(updated.value)
|
||||||
|
assert value[:key1] == :val1
|
||||||
|
assert value[:key2] == [k1: :v1, k2: :v2, k3: :v3]
|
||||||
|
assert value[:key3] == :val3
|
||||||
|
end
|
||||||
|
|
||||||
|
test "only full update for some keys" do
|
||||||
|
config1 = insert(:config, key: ":ecto_repos", value: ConfigDB.to_binary(repo: Pleroma.Repo))
|
||||||
|
|
||||||
|
config2 =
|
||||||
|
insert(:config, group: ":cors_plug", key: ":max_age", value: ConfigDB.to_binary(18))
|
||||||
|
|
||||||
|
{:ok, _config} =
|
||||||
|
ConfigDB.update_or_create(%{
|
||||||
|
group: config1.group,
|
||||||
|
key: config1.key,
|
||||||
|
value: [another_repo: [Pleroma.Repo]]
|
||||||
|
})
|
||||||
|
|
||||||
|
{:ok, _config} =
|
||||||
|
ConfigDB.update_or_create(%{
|
||||||
|
group: config2.group,
|
||||||
|
key: config2.key,
|
||||||
|
value: 777
|
||||||
|
})
|
||||||
|
|
||||||
|
updated1 = ConfigDB.get_by_params(%{group: config1.group, key: config1.key})
|
||||||
|
updated2 = ConfigDB.get_by_params(%{group: config2.group, key: config2.key})
|
||||||
|
|
||||||
|
assert ConfigDB.from_binary(updated1.value) == [another_repo: [Pleroma.Repo]]
|
||||||
|
assert ConfigDB.from_binary(updated2.value) == 777
|
||||||
|
end
|
||||||
|
|
||||||
|
test "full update if value is not keyword" do
|
||||||
|
config =
|
||||||
|
insert(:config,
|
||||||
|
group: ":tesla",
|
||||||
|
key: ":adapter",
|
||||||
|
value: ConfigDB.to_binary(Tesla.Adapter.Hackney)
|
||||||
|
)
|
||||||
|
|
||||||
|
{:ok, _config} =
|
||||||
|
ConfigDB.update_or_create(%{
|
||||||
|
group: config.group,
|
||||||
|
key: config.key,
|
||||||
|
value: Tesla.Adapter.Httpc
|
||||||
|
})
|
||||||
|
|
||||||
|
updated = ConfigDB.get_by_params(%{group: config.group, key: config.key})
|
||||||
|
|
||||||
|
assert ConfigDB.from_binary(updated.value) == Tesla.Adapter.Httpc
|
||||||
|
end
|
||||||
|
|
||||||
|
test "only full update for some subkeys" do
|
||||||
|
config1 =
|
||||||
|
insert(:config,
|
||||||
|
key: ":emoji",
|
||||||
|
value: ConfigDB.to_binary(groups: [a: 1, b: 2], key: [a: 1])
|
||||||
|
)
|
||||||
|
|
||||||
|
config2 =
|
||||||
|
insert(:config,
|
||||||
|
key: ":assets",
|
||||||
|
value: ConfigDB.to_binary(mascots: [a: 1, b: 2], key: [a: 1])
|
||||||
|
)
|
||||||
|
|
||||||
|
{:ok, _config} =
|
||||||
|
ConfigDB.update_or_create(%{
|
||||||
|
group: config1.group,
|
||||||
|
key: config1.key,
|
||||||
|
value: [groups: [c: 3, d: 4], key: [b: 2]]
|
||||||
|
})
|
||||||
|
|
||||||
|
{:ok, _config} =
|
||||||
|
ConfigDB.update_or_create(%{
|
||||||
|
group: config2.group,
|
||||||
|
key: config2.key,
|
||||||
|
value: [mascots: [c: 3, d: 4], key: [b: 2]]
|
||||||
|
})
|
||||||
|
|
||||||
|
updated1 = ConfigDB.get_by_params(%{group: config1.group, key: config1.key})
|
||||||
|
updated2 = ConfigDB.get_by_params(%{group: config2.group, key: config2.key})
|
||||||
|
|
||||||
|
assert ConfigDB.from_binary(updated1.value) == [groups: [c: 3, d: 4], key: [a: 1, b: 2]]
|
||||||
|
assert ConfigDB.from_binary(updated2.value) == [mascots: [c: 3, d: 4], key: [a: 1, b: 2]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "delete/1" do
|
||||||
|
test "error on deleting non existing setting" do
|
||||||
|
{:error, error} = ConfigDB.delete(%{group: ":pleroma", key: ":key"})
|
||||||
|
assert error =~ "Config with params %{group: \":pleroma\", key: \":key\"} not found"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "full delete" do
|
||||||
|
config = insert(:config)
|
||||||
|
{:ok, deleted} = ConfigDB.delete(%{group: config.group, key: config.key})
|
||||||
|
assert Ecto.get_meta(deleted, :state) == :deleted
|
||||||
|
refute ConfigDB.get_by_params(%{group: config.group, key: config.key})
|
||||||
|
end
|
||||||
|
|
||||||
|
test "partial subkeys delete" do
|
||||||
|
config = insert(:config, value: ConfigDB.to_binary(groups: [a: 1, b: 2], key: [a: 1]))
|
||||||
|
|
||||||
|
{:ok, deleted} =
|
||||||
|
ConfigDB.delete(%{group: config.group, key: config.key, subkeys: [":groups"]})
|
||||||
|
|
||||||
|
assert Ecto.get_meta(deleted, :state) == :loaded
|
||||||
|
|
||||||
|
assert deleted.value == ConfigDB.to_binary(key: [a: 1])
|
||||||
|
|
||||||
|
updated = ConfigDB.get_by_params(%{group: config.group, key: config.key})
|
||||||
|
|
||||||
|
assert updated.value == deleted.value
|
||||||
|
end
|
||||||
|
|
||||||
|
test "full delete if remaining value after subkeys deletion is empty list" do
|
||||||
|
config = insert(:config, value: ConfigDB.to_binary(groups: [a: 1, b: 2]))
|
||||||
|
|
||||||
|
{:ok, deleted} =
|
||||||
|
ConfigDB.delete(%{group: config.group, key: config.key, subkeys: [":groups"]})
|
||||||
|
|
||||||
|
assert Ecto.get_meta(deleted, :state) == :deleted
|
||||||
|
|
||||||
|
refute ConfigDB.get_by_params(%{group: config.group, key: config.key})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "transform/1" do
|
||||||
|
test "string" do
|
||||||
|
binary = ConfigDB.transform("value as string")
|
||||||
|
assert binary == :erlang.term_to_binary("value as string")
|
||||||
|
assert ConfigDB.from_binary(binary) == "value as string"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "boolean" do
|
||||||
|
binary = ConfigDB.transform(false)
|
||||||
|
assert binary == :erlang.term_to_binary(false)
|
||||||
|
assert ConfigDB.from_binary(binary) == false
|
||||||
|
end
|
||||||
|
|
||||||
|
test "nil" do
|
||||||
|
binary = ConfigDB.transform(nil)
|
||||||
|
assert binary == :erlang.term_to_binary(nil)
|
||||||
|
assert ConfigDB.from_binary(binary) == nil
|
||||||
|
end
|
||||||
|
|
||||||
|
test "integer" do
|
||||||
|
binary = ConfigDB.transform(150)
|
||||||
|
assert binary == :erlang.term_to_binary(150)
|
||||||
|
assert ConfigDB.from_binary(binary) == 150
|
||||||
|
end
|
||||||
|
|
||||||
|
test "atom" do
|
||||||
|
binary = ConfigDB.transform(":atom")
|
||||||
|
assert binary == :erlang.term_to_binary(:atom)
|
||||||
|
assert ConfigDB.from_binary(binary) == :atom
|
||||||
|
end
|
||||||
|
|
||||||
|
test "ssl options" do
|
||||||
|
binary = ConfigDB.transform([":tlsv1", ":tlsv1.1", ":tlsv1.2"])
|
||||||
|
assert binary == :erlang.term_to_binary([:tlsv1, :"tlsv1.1", :"tlsv1.2"])
|
||||||
|
assert ConfigDB.from_binary(binary) == [:tlsv1, :"tlsv1.1", :"tlsv1.2"]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "pleroma module" do
|
||||||
|
binary = ConfigDB.transform("Pleroma.Bookmark")
|
||||||
|
assert binary == :erlang.term_to_binary(Pleroma.Bookmark)
|
||||||
|
assert ConfigDB.from_binary(binary) == Pleroma.Bookmark
|
||||||
|
end
|
||||||
|
|
||||||
|
test "pleroma string" do
|
||||||
|
binary = ConfigDB.transform("Pleroma")
|
||||||
|
assert binary == :erlang.term_to_binary("Pleroma")
|
||||||
|
assert ConfigDB.from_binary(binary) == "Pleroma"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "phoenix module" do
|
||||||
|
binary = ConfigDB.transform("Phoenix.Socket.V1.JSONSerializer")
|
||||||
|
assert binary == :erlang.term_to_binary(Phoenix.Socket.V1.JSONSerializer)
|
||||||
|
assert ConfigDB.from_binary(binary) == Phoenix.Socket.V1.JSONSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
test "tesla module" do
|
||||||
|
binary = ConfigDB.transform("Tesla.Adapter.Hackney")
|
||||||
|
assert binary == :erlang.term_to_binary(Tesla.Adapter.Hackney)
|
||||||
|
assert ConfigDB.from_binary(binary) == Tesla.Adapter.Hackney
|
||||||
|
end
|
||||||
|
|
||||||
|
test "ExSyslogger module" do
|
||||||
|
binary = ConfigDB.transform("ExSyslogger")
|
||||||
|
assert binary == :erlang.term_to_binary(ExSyslogger)
|
||||||
|
assert ConfigDB.from_binary(binary) == ExSyslogger
|
||||||
|
end
|
||||||
|
|
||||||
|
test "Quack.Logger module" do
|
||||||
|
binary = ConfigDB.transform("Quack.Logger")
|
||||||
|
assert binary == :erlang.term_to_binary(Quack.Logger)
|
||||||
|
assert ConfigDB.from_binary(binary) == Quack.Logger
|
||||||
|
end
|
||||||
|
|
||||||
|
test "sigil" do
|
||||||
|
binary = ConfigDB.transform("~r[comp[lL][aA][iI][nN]er]")
|
||||||
|
assert binary == :erlang.term_to_binary(~r/comp[lL][aA][iI][nN]er/)
|
||||||
|
assert ConfigDB.from_binary(binary) == ~r/comp[lL][aA][iI][nN]er/
|
||||||
|
end
|
||||||
|
|
||||||
|
test "link sigil" do
|
||||||
|
binary = ConfigDB.transform("~r/https:\/\/example.com/")
|
||||||
|
assert binary == :erlang.term_to_binary(~r/https:\/\/example.com/)
|
||||||
|
assert ConfigDB.from_binary(binary) == ~r/https:\/\/example.com/
|
||||||
|
end
|
||||||
|
|
||||||
|
test "link sigil with um modifiers" do
|
||||||
|
binary = ConfigDB.transform("~r/https:\/\/example.com/um")
|
||||||
|
assert binary == :erlang.term_to_binary(~r/https:\/\/example.com/um)
|
||||||
|
assert ConfigDB.from_binary(binary) == ~r/https:\/\/example.com/um
|
||||||
|
end
|
||||||
|
|
||||||
|
test "link sigil with i modifier" do
|
||||||
|
binary = ConfigDB.transform("~r/https:\/\/example.com/i")
|
||||||
|
assert binary == :erlang.term_to_binary(~r/https:\/\/example.com/i)
|
||||||
|
assert ConfigDB.from_binary(binary) == ~r/https:\/\/example.com/i
|
||||||
|
end
|
||||||
|
|
||||||
|
test "link sigil with s modifier" do
|
||||||
|
binary = ConfigDB.transform("~r/https:\/\/example.com/s")
|
||||||
|
assert binary == :erlang.term_to_binary(~r/https:\/\/example.com/s)
|
||||||
|
assert ConfigDB.from_binary(binary) == ~r/https:\/\/example.com/s
|
||||||
|
end
|
||||||
|
|
||||||
|
test "raise if valid delimiter not found" do
|
||||||
|
assert_raise ArgumentError, "valid delimiter for Regex expression not found", fn ->
|
||||||
|
ConfigDB.transform("~r/https://[]{}<>\"'()|example.com/s")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "2 child tuple" do
|
||||||
|
binary = ConfigDB.transform(%{"tuple" => ["v1", ":v2"]})
|
||||||
|
assert binary == :erlang.term_to_binary({"v1", :v2})
|
||||||
|
assert ConfigDB.from_binary(binary) == {"v1", :v2}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "proxy tuple with localhost" do
|
||||||
|
binary =
|
||||||
|
ConfigDB.transform(%{
|
||||||
|
"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]
|
||||||
|
})
|
||||||
|
|
||||||
|
assert binary == :erlang.term_to_binary({:proxy_url, {:socks5, :localhost, 1234}})
|
||||||
|
assert ConfigDB.from_binary(binary) == {:proxy_url, {:socks5, :localhost, 1234}}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "proxy tuple with domain" do
|
||||||
|
binary =
|
||||||
|
ConfigDB.transform(%{
|
||||||
|
"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]
|
||||||
|
})
|
||||||
|
|
||||||
|
assert binary == :erlang.term_to_binary({:proxy_url, {:socks5, 'domain.com', 1234}})
|
||||||
|
assert ConfigDB.from_binary(binary) == {:proxy_url, {:socks5, 'domain.com', 1234}}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "proxy tuple with ip" do
|
||||||
|
binary =
|
||||||
|
ConfigDB.transform(%{
|
||||||
|
"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]
|
||||||
|
})
|
||||||
|
|
||||||
|
assert binary == :erlang.term_to_binary({:proxy_url, {:socks5, {127, 0, 0, 1}, 1234}})
|
||||||
|
assert ConfigDB.from_binary(binary) == {:proxy_url, {:socks5, {127, 0, 0, 1}, 1234}}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "tuple with n childs" do
|
||||||
|
binary =
|
||||||
|
ConfigDB.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 ConfigDB.from_binary(binary) ==
|
||||||
|
{"v1", :v2, Pleroma.Bookmark, 150, false, Phoenix.Socket.V1.JSONSerializer}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "map with string key" do
|
||||||
|
binary = ConfigDB.transform(%{"key" => "value"})
|
||||||
|
assert binary == :erlang.term_to_binary(%{"key" => "value"})
|
||||||
|
assert ConfigDB.from_binary(binary) == %{"key" => "value"}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "map with atom key" do
|
||||||
|
binary = ConfigDB.transform(%{":key" => "value"})
|
||||||
|
assert binary == :erlang.term_to_binary(%{key: "value"})
|
||||||
|
assert ConfigDB.from_binary(binary) == %{key: "value"}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "list of strings" do
|
||||||
|
binary = ConfigDB.transform(["v1", "v2", "v3"])
|
||||||
|
assert binary == :erlang.term_to_binary(["v1", "v2", "v3"])
|
||||||
|
assert ConfigDB.from_binary(binary) == ["v1", "v2", "v3"]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "list of modules" do
|
||||||
|
binary = ConfigDB.transform(["Pleroma.Repo", "Pleroma.Activity"])
|
||||||
|
assert binary == :erlang.term_to_binary([Pleroma.Repo, Pleroma.Activity])
|
||||||
|
assert ConfigDB.from_binary(binary) == [Pleroma.Repo, Pleroma.Activity]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "list of atoms" do
|
||||||
|
binary = ConfigDB.transform([":v1", ":v2", ":v3"])
|
||||||
|
assert binary == :erlang.term_to_binary([:v1, :v2, :v3])
|
||||||
|
assert ConfigDB.from_binary(binary) == [:v1, :v2, :v3]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "list of mixed values" do
|
||||||
|
binary =
|
||||||
|
ConfigDB.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 ConfigDB.from_binary(binary) == [
|
||||||
|
"v1",
|
||||||
|
:v2,
|
||||||
|
Pleroma.Repo,
|
||||||
|
Phoenix.Socket.V1.JSONSerializer,
|
||||||
|
15,
|
||||||
|
false
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "simple keyword" do
|
||||||
|
binary = ConfigDB.transform([%{"tuple" => [":key", "value"]}])
|
||||||
|
assert binary == :erlang.term_to_binary([{:key, "value"}])
|
||||||
|
assert ConfigDB.from_binary(binary) == [{:key, "value"}]
|
||||||
|
assert ConfigDB.from_binary(binary) == [key: "value"]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "keyword with partial_chain key" do
|
||||||
|
binary =
|
||||||
|
ConfigDB.transform([%{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]}])
|
||||||
|
|
||||||
|
assert binary == :erlang.term_to_binary(partial_chain: &:hackney_connect.partial_chain/1)
|
||||||
|
assert ConfigDB.from_binary(binary) == [partial_chain: &:hackney_connect.partial_chain/1]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "keyword" do
|
||||||
|
binary =
|
||||||
|
ConfigDB.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],
|
||||||
|
migration_lock: nil,
|
||||||
|
key1: 150,
|
||||||
|
key2: "string"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert ConfigDB.from_binary(binary) == [
|
||||||
|
types: Pleroma.PostgresTypes,
|
||||||
|
telemetry_event: [Pleroma.Repo.Instrumenter],
|
||||||
|
migration_lock: nil,
|
||||||
|
key1: 150,
|
||||||
|
key2: "string"
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "complex keyword with nested mixed childs" do
|
||||||
|
binary =
|
||||||
|
ConfigDB.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
|
||||||
|
]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
assert ConfigDB.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
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "common keyword" do
|
||||||
|
binary =
|
||||||
|
ConfigDB.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 ConfigDB.from_binary(binary) == [
|
||||||
|
level: :warn,
|
||||||
|
meta: [:all],
|
||||||
|
path: "",
|
||||||
|
val: nil,
|
||||||
|
webhook_url: "https://hooks.slack.com/services/YOUR-KEY-HERE"
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "complex keyword with sigil" do
|
||||||
|
binary =
|
||||||
|
ConfigDB.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: []
|
||||||
|
)
|
||||||
|
|
||||||
|
assert ConfigDB.from_binary(binary) ==
|
||||||
|
[federated_timeline_removal: [], reject: [~r/comp[lL][aA][iI][nN]er/], replace: []]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "complex keyword with tuples with more than 2 values" do
|
||||||
|
binary =
|
||||||
|
ConfigDB.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", []]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
assert binary ==
|
||||||
|
:erlang.term_to_binary(
|
||||||
|
http: [
|
||||||
|
key1: [
|
||||||
|
_: [
|
||||||
|
{"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
|
||||||
|
{"/websocket", Phoenix.Endpoint.CowboyWebSocket,
|
||||||
|
{Phoenix.Transports.WebSocket,
|
||||||
|
{Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, []}}},
|
||||||
|
{:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
assert ConfigDB.from_binary(binary) == [
|
||||||
|
http: [
|
||||||
|
key1: [
|
||||||
|
{:_,
|
||||||
|
[
|
||||||
|
{"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
|
||||||
|
{"/websocket", Phoenix.Endpoint.CowboyWebSocket,
|
||||||
|
{Phoenix.Transports.WebSocket,
|
||||||
|
{Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, []}}},
|
||||||
|
{:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
|
||||||
|
]}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,34 @@
|
|||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Config.HolderTest do
|
||||||
|
use ExUnit.Case, async: true
|
||||||
|
|
||||||
|
alias Pleroma.Config.Holder
|
||||||
|
|
||||||
|
test "config/0" do
|
||||||
|
config = Holder.config()
|
||||||
|
assert config[:pleroma][Pleroma.Uploaders.Local][:uploads] == "test/uploads"
|
||||||
|
assert config[:tesla][:adapter] == Tesla.Mock
|
||||||
|
|
||||||
|
refute config[:pleroma][Pleroma.Repo]
|
||||||
|
refute config[:pleroma][Pleroma.Web.Endpoint]
|
||||||
|
refute config[:pleroma][:env]
|
||||||
|
refute config[:pleroma][:configurable_from_database]
|
||||||
|
refute config[:pleroma][:database]
|
||||||
|
refute config[:phoenix][:serve_endpoints]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "config/1" do
|
||||||
|
pleroma_config = Holder.config(:pleroma)
|
||||||
|
assert pleroma_config[Pleroma.Uploaders.Local][:uploads] == "test/uploads"
|
||||||
|
tesla_config = Holder.config(:tesla)
|
||||||
|
assert tesla_config[:adapter] == Tesla.Mock
|
||||||
|
end
|
||||||
|
|
||||||
|
test "config/2" do
|
||||||
|
assert Holder.config(:pleroma, Pleroma.Uploaders.Local) == [uploads: "test/uploads"]
|
||||||
|
assert Holder.config(:tesla, :adapter) == Tesla.Mock
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,44 @@
|
|||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Config.LoaderTest do
|
||||||
|
use ExUnit.Case, async: true
|
||||||
|
|
||||||
|
alias Pleroma.Config.Loader
|
||||||
|
|
||||||
|
test "load/1" do
|
||||||
|
config = Loader.load("test/fixtures/config/temp.secret.exs")
|
||||||
|
assert config[:pleroma][:first_setting][:key] == "value"
|
||||||
|
assert config[:pleroma][:first_setting][:key2] == [Pleroma.Repo]
|
||||||
|
assert config[:quack][:level] == :info
|
||||||
|
end
|
||||||
|
|
||||||
|
test "load_and_merge/0" do
|
||||||
|
config = Loader.load_and_merge()
|
||||||
|
|
||||||
|
refute config[:pleroma][Pleroma.Repo]
|
||||||
|
refute config[:pleroma][Pleroma.Web.Endpoint]
|
||||||
|
refute config[:pleroma][:env]
|
||||||
|
refute config[:pleroma][:configurable_from_database]
|
||||||
|
refute config[:pleroma][:database]
|
||||||
|
refute config[:phoenix][:serve_endpoints]
|
||||||
|
|
||||||
|
assert config[:pleroma][:ecto_repos] == [Pleroma.Repo]
|
||||||
|
assert config[:pleroma][Pleroma.Uploaders.Local][:uploads] == "test/uploads"
|
||||||
|
assert config[:tesla][:adapter] == Tesla.Mock
|
||||||
|
end
|
||||||
|
|
||||||
|
test "filter_group/2" do
|
||||||
|
assert Loader.filter_group(:pleroma,
|
||||||
|
pleroma: [
|
||||||
|
{Pleroma.Repo, [a: 1, b: 2]},
|
||||||
|
{Pleroma.Upload, [a: 1, b: 2]},
|
||||||
|
{Pleroma.Web.Endpoint, []},
|
||||||
|
env: :test,
|
||||||
|
configurable_from_database: true,
|
||||||
|
database: []
|
||||||
|
]
|
||||||
|
) == [{Pleroma.Upload, [a: 1, b: 2]}]
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,230 @@
|
|||||||
|
defmodule Pleroma.Docs.GeneratorTest do
|
||||||
|
use ExUnit.Case, async: true
|
||||||
|
alias Pleroma.Docs.Generator
|
||||||
|
|
||||||
|
@descriptions [
|
||||||
|
%{
|
||||||
|
group: :pleroma,
|
||||||
|
key: Pleroma.Upload,
|
||||||
|
type: :group,
|
||||||
|
description: "",
|
||||||
|
children: [
|
||||||
|
%{
|
||||||
|
key: :uploader,
|
||||||
|
type: :module,
|
||||||
|
description: "",
|
||||||
|
suggestions:
|
||||||
|
Generator.list_modules_in_dir(
|
||||||
|
"lib/pleroma/upload/filter",
|
||||||
|
"Elixir.Pleroma.Upload.Filter."
|
||||||
|
)
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: :filters,
|
||||||
|
type: {:list, :module},
|
||||||
|
description: "",
|
||||||
|
suggestions:
|
||||||
|
Generator.list_modules_in_dir(
|
||||||
|
"lib/pleroma/web/activity_pub/mrf",
|
||||||
|
"Elixir.Pleroma.Web.ActivityPub.MRF."
|
||||||
|
)
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: Pleroma.Upload,
|
||||||
|
type: :string,
|
||||||
|
description: "",
|
||||||
|
suggestions: [""]
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: :some_key,
|
||||||
|
type: :keyword,
|
||||||
|
description: "",
|
||||||
|
suggestions: [],
|
||||||
|
children: [
|
||||||
|
%{
|
||||||
|
key: :another_key,
|
||||||
|
type: :integer,
|
||||||
|
description: "",
|
||||||
|
suggestions: [5]
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: :another_key_with_label,
|
||||||
|
label: "Another label",
|
||||||
|
type: :integer,
|
||||||
|
description: "",
|
||||||
|
suggestions: [7]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: :key1,
|
||||||
|
type: :atom,
|
||||||
|
description: "",
|
||||||
|
suggestions: [
|
||||||
|
:atom,
|
||||||
|
Pleroma.Upload,
|
||||||
|
{:tuple, "string", 8080},
|
||||||
|
[:atom, Pleroma.Upload, {:atom, Pleroma.Upload}]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: Pleroma.Upload,
|
||||||
|
label: "Special Label",
|
||||||
|
type: :string,
|
||||||
|
description: "",
|
||||||
|
suggestions: [""]
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
group: {:subgroup, Swoosh.Adapters.SMTP},
|
||||||
|
key: :auth,
|
||||||
|
type: :atom,
|
||||||
|
description: "`Swoosh.Adapters.SMTP` adapter specific setting",
|
||||||
|
suggestions: [:always, :never, :if_available]
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: "application/xml",
|
||||||
|
type: {:list, :string},
|
||||||
|
suggestions: ["xml"]
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: :versions,
|
||||||
|
type: {:list, :atom},
|
||||||
|
description: "List of TLS version to use",
|
||||||
|
suggestions: [:tlsv1, ":tlsv1.1", ":tlsv1.2"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
group: :tesla,
|
||||||
|
key: :adapter,
|
||||||
|
type: :group,
|
||||||
|
description: ""
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
group: :cors_plug,
|
||||||
|
type: :group,
|
||||||
|
children: [%{key: :key1, type: :string, suggestions: [""]}]
|
||||||
|
},
|
||||||
|
%{group: "Some string group", key: "Some string key", type: :group}
|
||||||
|
]
|
||||||
|
|
||||||
|
describe "convert_to_strings/1" do
|
||||||
|
test "group, key, label" do
|
||||||
|
[desc1, desc2 | _] = Generator.convert_to_strings(@descriptions)
|
||||||
|
|
||||||
|
assert desc1[:group] == ":pleroma"
|
||||||
|
assert desc1[:key] == "Pleroma.Upload"
|
||||||
|
assert desc1[:label] == "Pleroma.Upload"
|
||||||
|
|
||||||
|
assert desc2[:group] == ":tesla"
|
||||||
|
assert desc2[:key] == ":adapter"
|
||||||
|
assert desc2[:label] == "Adapter"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "group without key" do
|
||||||
|
descriptions = Generator.convert_to_strings(@descriptions)
|
||||||
|
desc = Enum.at(descriptions, 2)
|
||||||
|
|
||||||
|
assert desc[:group] == ":cors_plug"
|
||||||
|
refute desc[:key]
|
||||||
|
assert desc[:label] == "Cors plug"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "children key, label, type" do
|
||||||
|
[%{children: [child1, child2, child3, child4 | _]} | _] =
|
||||||
|
Generator.convert_to_strings(@descriptions)
|
||||||
|
|
||||||
|
assert child1[:key] == ":uploader"
|
||||||
|
assert child1[:label] == "Uploader"
|
||||||
|
assert child1[:type] == :module
|
||||||
|
|
||||||
|
assert child2[:key] == ":filters"
|
||||||
|
assert child2[:label] == "Filters"
|
||||||
|
assert child2[:type] == {:list, :module}
|
||||||
|
|
||||||
|
assert child3[:key] == "Pleroma.Upload"
|
||||||
|
assert child3[:label] == "Pleroma.Upload"
|
||||||
|
assert child3[:type] == :string
|
||||||
|
|
||||||
|
assert child4[:key] == ":some_key"
|
||||||
|
assert child4[:label] == "Some key"
|
||||||
|
assert child4[:type] == :keyword
|
||||||
|
end
|
||||||
|
|
||||||
|
test "child with predefined label" do
|
||||||
|
[%{children: children} | _] = Generator.convert_to_strings(@descriptions)
|
||||||
|
child = Enum.at(children, 5)
|
||||||
|
assert child[:key] == "Pleroma.Upload"
|
||||||
|
assert child[:label] == "Special Label"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "subchild" do
|
||||||
|
[%{children: children} | _] = Generator.convert_to_strings(@descriptions)
|
||||||
|
child = Enum.at(children, 3)
|
||||||
|
%{children: [subchild | _]} = child
|
||||||
|
|
||||||
|
assert subchild[:key] == ":another_key"
|
||||||
|
assert subchild[:label] == "Another key"
|
||||||
|
assert subchild[:type] == :integer
|
||||||
|
end
|
||||||
|
|
||||||
|
test "subchild with predefined label" do
|
||||||
|
[%{children: children} | _] = Generator.convert_to_strings(@descriptions)
|
||||||
|
child = Enum.at(children, 3)
|
||||||
|
%{children: subchildren} = child
|
||||||
|
subchild = Enum.at(subchildren, 1)
|
||||||
|
|
||||||
|
assert subchild[:key] == ":another_key_with_label"
|
||||||
|
assert subchild[:label] == "Another label"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "module suggestions" do
|
||||||
|
[%{children: [%{suggestions: suggestions} | _]} | _] =
|
||||||
|
Generator.convert_to_strings(@descriptions)
|
||||||
|
|
||||||
|
Enum.each(suggestions, fn suggestion ->
|
||||||
|
assert String.starts_with?(suggestion, "Pleroma.")
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "atoms in suggestions with leading `:`" do
|
||||||
|
[%{children: children} | _] = Generator.convert_to_strings(@descriptions)
|
||||||
|
%{suggestions: suggestions} = Enum.at(children, 4)
|
||||||
|
assert Enum.at(suggestions, 0) == ":atom"
|
||||||
|
assert Enum.at(suggestions, 1) == "Pleroma.Upload"
|
||||||
|
assert Enum.at(suggestions, 2) == {":tuple", "string", 8080}
|
||||||
|
assert Enum.at(suggestions, 3) == [":atom", "Pleroma.Upload", {":atom", "Pleroma.Upload"}]
|
||||||
|
|
||||||
|
%{suggestions: suggestions} = Enum.at(children, 6)
|
||||||
|
assert Enum.at(suggestions, 0) == ":always"
|
||||||
|
assert Enum.at(suggestions, 1) == ":never"
|
||||||
|
assert Enum.at(suggestions, 2) == ":if_available"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "group, key as string in main desc" do
|
||||||
|
descriptions = Generator.convert_to_strings(@descriptions)
|
||||||
|
desc = Enum.at(descriptions, 3)
|
||||||
|
assert desc[:group] == "Some string group"
|
||||||
|
assert desc[:key] == "Some string key"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "key as string subchild" do
|
||||||
|
[%{children: children} | _] = Generator.convert_to_strings(@descriptions)
|
||||||
|
child = Enum.at(children, 7)
|
||||||
|
assert child[:key] == "application/xml"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "suggestion for tls versions" do
|
||||||
|
[%{children: children} | _] = Generator.convert_to_strings(@descriptions)
|
||||||
|
child = Enum.at(children, 8)
|
||||||
|
assert child[:suggestions] == [":tlsv1", ":tlsv1.1", ":tlsv1.2"]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "subgroup with module name" do
|
||||||
|
[%{children: children} | _] = Generator.convert_to_strings(@descriptions)
|
||||||
|
|
||||||
|
%{group: subgroup} = Enum.at(children, 6)
|
||||||
|
assert subgroup == {":subgroup", "Swoosh.Adapters.SMTP"}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,9 @@
|
|||||||
|
use Mix.Config
|
||||||
|
|
||||||
|
config :pleroma, :first_setting, key: "value", key2: [Pleroma.Repo]
|
||||||
|
|
||||||
|
config :pleroma, :second_setting, key: "value2", key2: ["Activity"]
|
||||||
|
|
||||||
|
config :quack, level: :info
|
||||||
|
|
||||||
|
config :pleroma, Pleroma.Repo, pool: Ecto.Adapters.SQL.Sandbox
|
File diff suppressed because it is too large
Load Diff
@ -1,497 +0,0 @@
|
|||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
defmodule Pleroma.Web.AdminAPI.ConfigTest do
|
|
||||||
use Pleroma.DataCase, async: true
|
|
||||||
import Pleroma.Factory
|
|
||||||
alias Pleroma.Web.AdminAPI.Config
|
|
||||||
|
|
||||||
test "get_by_key/1" do
|
|
||||||
config = insert(:config)
|
|
||||||
insert(:config)
|
|
||||||
|
|
||||||
assert config == Config.get_by_params(%{group: config.group, key: config.key})
|
|
||||||
end
|
|
||||||
|
|
||||||
test "create/1" do
|
|
||||||
{:ok, config} = Config.create(%{group: "pleroma", key: "some_key", value: "some_value"})
|
|
||||||
assert config == Config.get_by_params(%{group: "pleroma", key: "some_key"})
|
|
||||||
end
|
|
||||||
|
|
||||||
test "update/1" do
|
|
||||||
config = insert(:config)
|
|
||||||
{:ok, updated} = Config.update(config, %{value: "some_value"})
|
|
||||||
loaded = Config.get_by_params(%{group: config.group, key: config.key})
|
|
||||||
assert loaded == updated
|
|
||||||
end
|
|
||||||
|
|
||||||
test "update_or_create/1" do
|
|
||||||
config = insert(:config)
|
|
||||||
key2 = "another_key"
|
|
||||||
|
|
||||||
params = [
|
|
||||||
%{group: "pleroma", key: key2, value: "another_value"},
|
|
||||||
%{group: config.group, key: config.key, value: "new_value"}
|
|
||||||
]
|
|
||||||
|
|
||||||
assert Repo.all(Config) |> length() == 1
|
|
||||||
|
|
||||||
Enum.each(params, &Config.update_or_create(&1))
|
|
||||||
|
|
||||||
assert Repo.all(Config) |> length() == 2
|
|
||||||
|
|
||||||
config1 = Config.get_by_params(%{group: config.group, key: config.key})
|
|
||||||
config2 = Config.get_by_params(%{group: "pleroma", key: key2})
|
|
||||||
|
|
||||||
assert config1.value == Config.transform("new_value")
|
|
||||||
assert config2.value == Config.transform("another_value")
|
|
||||||
end
|
|
||||||
|
|
||||||
test "delete/1" do
|
|
||||||
config = insert(:config)
|
|
||||||
{:ok, _} = Config.delete(%{key: config.key, group: config.group})
|
|
||||||
refute Config.get_by_params(%{key: config.key, group: config.group})
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "transform/1" do
|
|
||||||
test "string" do
|
|
||||||
binary = Config.transform("value as string")
|
|
||||||
assert binary == :erlang.term_to_binary("value as 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 "link sigil" do
|
|
||||||
binary = Config.transform("~r/https:\/\/example.com/")
|
|
||||||
assert binary == :erlang.term_to_binary(~r/https:\/\/example.com/)
|
|
||||||
assert Config.from_binary(binary) == ~r/https:\/\/example.com/
|
|
||||||
end
|
|
||||||
|
|
||||||
test "link sigil with u modifier" do
|
|
||||||
binary = Config.transform("~r/https:\/\/example.com/u")
|
|
||||||
assert binary == :erlang.term_to_binary(~r/https:\/\/example.com/u)
|
|
||||||
assert Config.from_binary(binary) == ~r/https:\/\/example.com/u
|
|
||||||
end
|
|
||||||
|
|
||||||
test "link sigil with i modifier" do
|
|
||||||
binary = Config.transform("~r/https:\/\/example.com/i")
|
|
||||||
assert binary == :erlang.term_to_binary(~r/https:\/\/example.com/i)
|
|
||||||
assert Config.from_binary(binary) == ~r/https:\/\/example.com/i
|
|
||||||
end
|
|
||||||
|
|
||||||
test "link sigil with s modifier" do
|
|
||||||
binary = Config.transform("~r/https:\/\/example.com/s")
|
|
||||||
assert binary == :erlang.term_to_binary(~r/https:\/\/example.com/s)
|
|
||||||
assert Config.from_binary(binary) == ~r/https:\/\/example.com/s
|
|
||||||
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 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 "list of mixed values" do
|
|
||||||
binary =
|
|
||||||
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 with partial_chain key" do
|
|
||||||
binary =
|
|
||||||
Config.transform([%{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]}])
|
|
||||||
|
|
||||||
assert binary == :erlang.term_to_binary(partial_chain: &:hackney_connect.partial_chain/1)
|
|
||||||
assert Config.from_binary(binary) == [partial_chain: &:hackney_connect.partial_chain/1]
|
|
||||||
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],
|
|
||||||
migration_lock: nil,
|
|
||||||
key1: 150,
|
|
||||||
key2: "string"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert Config.from_binary(binary) == [
|
|
||||||
types: Pleroma.PostgresTypes,
|
|
||||||
telemetry_event: [Pleroma.Repo.Instrumenter],
|
|
||||||
migration_lock: nil,
|
|
||||||
key1: 150,
|
|
||||||
key2: "string"
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
test "complex keyword with nested mixed childs" do
|
|
||||||
binary =
|
|
||||||
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
|
|
||||||
]
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
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
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
test "common keyword" do
|
|
||||||
binary =
|
|
||||||
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 keyword with sigil" do
|
|
||||||
binary =
|
|
||||||
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: []
|
|
||||||
)
|
|
||||||
|
|
||||||
assert Config.from_binary(binary) ==
|
|
||||||
[federated_timeline_removal: [], reject: [~r/comp[lL][aA][iI][nN]er/], replace: []]
|
|
||||||
end
|
|
||||||
|
|
||||||
test "complex keyword with tuples with more than 2 values" do
|
|
||||||
binary =
|
|
||||||
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", []]}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
])
|
|
||||||
|
|
||||||
assert binary ==
|
|
||||||
:erlang.term_to_binary(
|
|
||||||
http: [
|
|
||||||
key1: [
|
|
||||||
_: [
|
|
||||||
{"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
|
|
||||||
{"/websocket", Phoenix.Endpoint.CowboyWebSocket,
|
|
||||||
{Phoenix.Transports.WebSocket,
|
|
||||||
{Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, []}}},
|
|
||||||
{:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
assert Config.from_binary(binary) == [
|
|
||||||
http: [
|
|
||||||
key1: [
|
|
||||||
{:_,
|
|
||||||
[
|
|
||||||
{"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
|
|
||||||
{"/websocket", Phoenix.Endpoint.CowboyWebSocket,
|
|
||||||
{Phoenix.Transports.WebSocket,
|
|
||||||
{Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, []}}},
|
|
||||||
{:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
|
|
||||||
]}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
Loading…
Reference in new issue