diff options
author | kaniini <nenolod@gmail.com> | 2019-06-14 15:45:05 +0000 |
---|---|---|
committer | kaniini <nenolod@gmail.com> | 2019-06-14 15:45:05 +0000 |
commit | 270f09dbc2cb145e5a06b72189bd1b91dd3d3a02 (patch) | |
tree | bf75fc306788d784d74fb6ca617f3ddd27b75fd2 /lib/pleroma/web/admin_api | |
parent | b7fc722a2e9e93341229cb122aac605421782295 (diff) | |
parent | c2ca1f22a25d22d6d863406ed05b08c643e5824c (diff) | |
download | pleroma-270f09dbc2cb145e5a06b72189bd1b91dd3d3a02.tar.gz |
Merge branch 'feature/905-dynamic-configuration-in-sql' into 'develop'
Feature/905 dynamic configuration in sql
Closes #905
See merge request pleroma/pleroma!1195
Diffstat (limited to 'lib/pleroma/web/admin_api')
-rw-r--r-- | lib/pleroma/web/admin_api/admin_api_controller.ex | 37 | ||||
-rw-r--r-- | lib/pleroma/web/admin_api/config.ex | 144 | ||||
-rw-r--r-- | lib/pleroma/web/admin_api/views/config_view.ex | 16 |
3 files changed, 197 insertions, 0 deletions
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index de2a13c01..03dfdca82 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -10,6 +10,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.AdminAPI.AccountView + alias Pleroma.Web.AdminAPI.Config + alias Pleroma.Web.AdminAPI.ConfigView alias Pleroma.Web.AdminAPI.ReportView alias Pleroma.Web.AdminAPI.Search alias Pleroma.Web.CommonAPI @@ -362,6 +364,41 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end end + def config_show(conn, _params) do + configs = Pleroma.Repo.all(Config) + + conn + |> put_view(ConfigView) + |> render("index.json", %{configs: configs}) + end + + def config_update(conn, %{"configs" => configs}) do + updated = + if Pleroma.Config.get([:instance, :dynamic_configuration]) do + updated = + Enum.map(configs, fn + %{"key" => key, "value" => value} -> + {:ok, config} = Config.update_or_create(%{key: key, value: value}) + config + + %{"key" => key, "delete" => "true"} -> + {:ok, _} = Config.delete(key) + nil + end) + |> Enum.reject(&is_nil(&1)) + + Pleroma.Config.TransferTask.load_and_update_env() + Mix.Tasks.Pleroma.Config.run(["migrate_from_db", Pleroma.Config.get(:env)]) + updated + else + [] + end + + conn + |> put_view(ConfigView) + |> render("index.json", %{configs: updated}) + end + def errors(conn, {:error, :not_found}) do conn |> put_status(404) diff --git a/lib/pleroma/web/admin_api/config.ex b/lib/pleroma/web/admin_api/config.ex new file mode 100644 index 000000000..b7072f050 --- /dev/null +++ b/lib/pleroma/web/admin_api/config.ex @@ -0,0 +1,144 @@ +# 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)} + + defp do_convert(value) when is_binary(value) or is_atom(value) or is_map(value), + do: value + + @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 + + 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) + 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 + value = String.trim(value) + + case String.length(value) do + 0 -> + nil + + _ -> + cond do + String.starts_with?(value, "Pleroma") -> + String.to_existing_atom("Elixir." <> value) + + String.starts_with?(value, ":") -> + String.replace(value, ":", "") |> String.to_existing_atom() + + String.starts_with?(value, "i:") -> + String.replace(value, "i:", "") |> String.to_integer() + + true -> + value + end + end + end + + defp do_transform(value), do: value +end diff --git a/lib/pleroma/web/admin_api/views/config_view.ex b/lib/pleroma/web/admin_api/views/config_view.ex new file mode 100644 index 000000000..c8560033e --- /dev/null +++ b/lib/pleroma/web/admin_api/views/config_view.ex @@ -0,0 +1,16 @@ +defmodule Pleroma.Web.AdminAPI.ConfigView do + use Pleroma.Web, :view + + def render("index.json", %{configs: configs}) do + %{ + configs: render_many(configs, __MODULE__, "show.json", as: :config) + } + end + + def render("show.json", %{config: config}) do + %{ + key: config.key, + value: Pleroma.Web.AdminAPI.Config.from_binary_to_map(config.value) + } + end +end |