2019-06-14 15:45:05 +00:00
|
|
|
# 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
|
|
|
|
alias __MODULE__
|
|
|
|
alias Pleroma.Repo
|
|
|
|
|
|
|
|
@type t :: %__MODULE__{}
|
|
|
|
|
|
|
|
schema "config" do
|
|
|
|
field(:key, :string)
|
|
|
|
field(:value, :binary)
|
|
|
|
|
|
|
|
timestamps()
|
|
|
|
end
|
|
|
|
|
|
|
|
@spec get_by_key(String.t()) :: Config.t() | nil
|
|
|
|
def get_by_key(key), do: Repo.get_by(Config, key: key)
|
|
|
|
|
|
|
|
@spec changeset(Config.t(), map()) :: Changeset.t()
|
|
|
|
def changeset(config, params \\ %{}) do
|
|
|
|
config
|
|
|
|
|> cast(params, [:key, :value])
|
|
|
|
|> validate_required([:key, :value])
|
|
|
|
|> unique_constraint(:key)
|
|
|
|
end
|
|
|
|
|
|
|
|
@spec create(map()) :: {:ok, Config.t()} | {:error, Changeset.t()}
|
|
|
|
def create(%{key: key, value: value}) do
|
|
|
|
%Config{}
|
|
|
|
|> changeset(%{key: key, value: transform(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(%{key: key} = params) do
|
|
|
|
with %Config{} = config <- Config.get_by_key(key) do
|
|
|
|
Config.update(config, params)
|
|
|
|
else
|
|
|
|
nil -> Config.create(params)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
@spec delete(String.t()) :: {:ok, Config.t()} | {:error, Changeset.t()}
|
|
|
|
def delete(key) do
|
|
|
|
with %Config{} = config <- Config.get_by_key(key) do
|
|
|
|
Repo.delete(config)
|
|
|
|
else
|
|
|
|
nil -> {:error, "Config with key #{key} not found"}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
@spec from_binary(binary()) :: term()
|
|
|
|
def from_binary(value), do: :erlang.binary_to_term(value)
|
|
|
|
|
|
|
|
@spec from_binary_to_map(binary()) :: any()
|
|
|
|
def from_binary_to_map(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(values) when is_list(values), do: for(val <- values, do: do_convert(val))
|
|
|
|
|
|
|
|
defp do_convert({k, v} = value) when is_tuple(value),
|
|
|
|
do: %{k => do_convert(v)}
|
|
|
|
|
2019-06-22 14:30:53 +00:00
|
|
|
defp do_convert(value) when is_tuple(value), do: %{"tuple" => do_convert(Tuple.to_list(value))}
|
|
|
|
|
2019-06-22 06:01:30 +00:00
|
|
|
defp do_convert(value) when is_binary(value) or is_map(value) or is_number(value), do: value
|
|
|
|
|
|
|
|
defp do_convert(value) when is_atom(value) do
|
|
|
|
string = to_string(value)
|
|
|
|
|
|
|
|
if String.starts_with?(string, "Elixir."),
|
|
|
|
do: String.trim_leading(string, "Elixir."),
|
|
|
|
else: value
|
|
|
|
end
|
2019-06-14 15:45:05 +00:00
|
|
|
|
|
|
|
@spec transform(any()) :: binary()
|
|
|
|
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)}
|
|
|
|
|
|
|
|
Enum.reject(tuples, fn {_k, v} -> is_nil(v) end)
|
|
|
|
|> Enum.sort()
|
|
|
|
|> :erlang.term_to_binary()
|
|
|
|
end
|
|
|
|
|
|
|
|
def transform(entity) when is_list(entity) do
|
|
|
|
list = Enum.map(entity, &do_transform(&1))
|
|
|
|
:erlang.term_to_binary(list)
|
|
|
|
end
|
|
|
|
|
|
|
|
def transform(entity), do: :erlang.term_to_binary(entity)
|
|
|
|
|
|
|
|
defp do_transform(%Regex{} = value) when is_map(value), do: value
|
|
|
|
|
2019-06-22 14:30:53 +00:00
|
|
|
defp do_transform(%{"tuple" => [k, values] = entity}) when length(entity) == 2 do
|
|
|
|
{do_transform(k), do_transform(values)}
|
|
|
|
end
|
|
|
|
|
|
|
|
defp do_transform(%{"tuple" => values}) do
|
|
|
|
Enum.reduce(values, {}, fn val, acc -> Tuple.append(acc, do_transform(val)) end)
|
|
|
|
end
|
|
|
|
|
2019-06-14 15:45:05 +00:00
|
|
|
defp do_transform(value) when is_map(value) do
|
2019-06-22 14:30:53 +00:00
|
|
|
values = for {key, val} <- value, into: [], do: {String.to_atom(key), do_transform(val)}
|
2019-06-14 15:45:05 +00:00
|
|
|
|
|
|
|
Enum.sort(values)
|
|
|
|
end
|
|
|
|
|
|
|
|
defp do_transform(value) when is_list(value) do
|
|
|
|
Enum.map(value, &do_transform(&1))
|
|
|
|
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
|
2019-06-22 14:30:53 +00:00
|
|
|
String.trim(value)
|
|
|
|
|> do_transform_string()
|
|
|
|
end
|
|
|
|
|
|
|
|
defp do_transform(value), do: value
|
2019-06-14 15:45:05 +00:00
|
|
|
|
2019-06-22 14:30:53 +00:00
|
|
|
defp do_transform_string(value) when byte_size(value) == 0, do: nil
|
2019-06-14 15:45:05 +00:00
|
|
|
|
2019-06-22 14:30:53 +00:00
|
|
|
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)
|
2019-06-14 15:45:05 +00:00
|
|
|
|
2019-06-22 14:30:53 +00:00
|
|
|
String.starts_with?(value, ":") ->
|
|
|
|
String.replace(value, ":", "") |> String.to_existing_atom()
|
2019-06-14 15:45:05 +00:00
|
|
|
|
2019-06-22 14:30:53 +00:00
|
|
|
String.starts_with?(value, "i:") ->
|
|
|
|
String.replace(value, "i:", "") |> String.to_integer()
|
2019-06-14 15:45:05 +00:00
|
|
|
|
2019-06-22 14:30:53 +00:00
|
|
|
true ->
|
|
|
|
value
|
2019-06-14 15:45:05 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|