Merge branch 'develop' into 'openapi/admin/relay'
[akkoma] / lib / pleroma / web / admin_api / controllers / config_controller.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.AdminAPI.ConfigController do
6 use Pleroma.Web, :controller
7
8 alias Pleroma.Config
9 alias Pleroma.ConfigDB
10 alias Pleroma.Plugs.OAuthScopesPlug
11
12 @descriptions Pleroma.Docs.JSON.compile()
13
14 plug(Pleroma.Web.ApiSpec.CastAndValidate)
15 plug(OAuthScopesPlug, %{scopes: ["write"], admin: true} when action == :update)
16
17 plug(
18 OAuthScopesPlug,
19 %{scopes: ["read"], admin: true}
20 when action in [:show, :descriptions]
21 )
22
23 action_fallback(Pleroma.Web.AdminAPI.FallbackController)
24
25 defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.ConfigOperation
26
27 def descriptions(conn, _params) do
28 descriptions = Enum.filter(@descriptions, &whitelisted_config?/1)
29
30 json(conn, descriptions)
31 end
32
33 def show(conn, %{only_db: true}) do
34 with :ok <- configurable_from_database() do
35 configs = Pleroma.Repo.all(ConfigDB)
36 render(conn, "index.json", %{configs: configs})
37 end
38 end
39
40 def show(conn, _params) do
41 with :ok <- configurable_from_database() do
42 configs = ConfigDB.get_all_as_keyword()
43
44 merged =
45 Config.Holder.default_config()
46 |> ConfigDB.merge(configs)
47 |> Enum.map(fn {group, values} ->
48 Enum.map(values, fn {key, value} ->
49 db =
50 if configs[group][key] do
51 ConfigDB.get_db_keys(configs[group][key], key)
52 end
53
54 db_value = configs[group][key]
55
56 merged_value =
57 if not is_nil(db_value) and Keyword.keyword?(db_value) and
58 ConfigDB.sub_key_full_update?(group, key, Keyword.keys(db_value)) do
59 ConfigDB.merge_group(group, key, value, db_value)
60 else
61 value
62 end
63
64 setting = %{
65 group: ConfigDB.convert(group),
66 key: ConfigDB.convert(key),
67 value: ConfigDB.convert(merged_value)
68 }
69
70 if db, do: Map.put(setting, :db, db), else: setting
71 end)
72 end)
73 |> List.flatten()
74
75 json(conn, %{configs: merged, need_reboot: Restarter.Pleroma.need_reboot?()})
76 end
77 end
78
79 def update(%{body_params: %{configs: configs}} = conn, _) do
80 with :ok <- configurable_from_database() do
81 results =
82 configs
83 |> Enum.filter(&whitelisted_config?/1)
84 |> Enum.map(fn
85 %{group: group, key: key, delete: true} = params ->
86 ConfigDB.delete(%{group: group, key: key, subkeys: params[:subkeys]})
87
88 %{group: group, key: key, value: value} ->
89 ConfigDB.update_or_create(%{group: group, key: key, value: value})
90 end)
91 |> Enum.reject(fn {result, _} -> result == :error end)
92
93 {deleted, updated} =
94 results
95 |> Enum.map(fn {:ok, config} ->
96 Map.put(config, :db, ConfigDB.get_db_keys(config))
97 end)
98 |> Enum.split_with(fn config ->
99 Ecto.get_meta(config, :state) == :deleted
100 end)
101
102 Config.TransferTask.load_and_update_env(deleted, false)
103
104 if not Restarter.Pleroma.need_reboot?() do
105 changed_reboot_settings? =
106 (updated ++ deleted)
107 |> Enum.any?(fn config ->
108 group = ConfigDB.from_string(config.group)
109 key = ConfigDB.from_string(config.key)
110 value = ConfigDB.from_binary(config.value)
111 Config.TransferTask.pleroma_need_restart?(group, key, value)
112 end)
113
114 if changed_reboot_settings?, do: Restarter.Pleroma.need_reboot()
115 end
116
117 render(conn, "index.json", %{
118 configs: updated,
119 need_reboot: Restarter.Pleroma.need_reboot?()
120 })
121 end
122 end
123
124 defp configurable_from_database do
125 if Config.get(:configurable_from_database) do
126 :ok
127 else
128 {:error, "To use this endpoint you need to enable configuration from database."}
129 end
130 end
131
132 defp whitelisted_config?(group, key) do
133 if whitelisted_configs = Config.get(:database_config_whitelist) do
134 Enum.any?(whitelisted_configs, fn
135 {whitelisted_group} ->
136 group == inspect(whitelisted_group)
137
138 {whitelisted_group, whitelisted_key} ->
139 group == inspect(whitelisted_group) && key == inspect(whitelisted_key)
140 end)
141 else
142 true
143 end
144 end
145
146 defp whitelisted_config?(%{group: group, key: key}) do
147 whitelisted_config?(group, key)
148 end
149
150 defp whitelisted_config?(%{group: group} = config) do
151 whitelisted_config?(group, config[:key])
152 end
153 end