in dev, allow dev FE
[akkoma] / lib / pleroma / web / admin_api / controllers / config_controller.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 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.Web.Plugs.OAuthScopesPlug
11
12 plug(Pleroma.Web.ApiSpec.CastAndValidate)
13 plug(OAuthScopesPlug, %{scopes: ["admin:write"]} when action == :update)
14
15 plug(
16 OAuthScopesPlug,
17 %{scopes: ["admin:read"]}
18 when action in [:show, :descriptions]
19 )
20
21 action_fallback(Pleroma.Web.AdminAPI.FallbackController)
22
23 defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.ConfigOperation
24
25 defp translate_descriptions(descriptions, path \\ []) do
26 Enum.map(descriptions, fn desc -> translate_item(desc, path) end)
27 end
28
29 defp translate_string(str, path, type) do
30 Gettext.dpgettext(
31 Pleroma.Web.Gettext,
32 "config_descriptions",
33 Pleroma.Docs.Translator.Compiler.msgctxt_for(path, type),
34 str
35 )
36 end
37
38 defp maybe_put_translated(item, key, path) do
39 if item[key] do
40 Map.put(
41 item,
42 key,
43 translate_string(
44 item[key],
45 path ++ [Pleroma.Docs.Translator.Compiler.key_for(item)],
46 to_string(key)
47 )
48 )
49 else
50 item
51 end
52 end
53
54 defp translate_item(item, path) do
55 item
56 |> maybe_put_translated(:label, path)
57 |> maybe_put_translated(:description, path)
58 |> translate_children(path)
59 end
60
61 defp translate_children(%{children: children} = item, path) when is_list(children) do
62 item
63 |> Map.put(
64 :children,
65 translate_descriptions(children, path ++ [Pleroma.Docs.Translator.Compiler.key_for(item)])
66 )
67 end
68
69 defp translate_children(item, _path) do
70 item
71 end
72
73 def descriptions(conn, _params) do
74 descriptions = Enum.filter(Pleroma.Docs.JSON.compiled_descriptions(), &whitelisted_config?/1)
75
76 json(conn, translate_descriptions(descriptions))
77 end
78
79 def show(conn, %{only_db: true}) do
80 with :ok <- configurable_from_database() do
81 configs = Pleroma.Repo.all(ConfigDB)
82
83 render(conn, "index.json", %{
84 configs: configs,
85 need_reboot: Restarter.Pleroma.need_reboot?()
86 })
87 end
88 end
89
90 def show(conn, _params) do
91 with :ok <- configurable_from_database() do
92 configs = ConfigDB.get_all_as_keyword()
93
94 merged =
95 Config.Holder.default_config()
96 |> ConfigDB.merge(configs)
97 |> Enum.map(fn {group, values} ->
98 Enum.map(values, fn {key, value} ->
99 db =
100 if configs[group][key] do
101 ConfigDB.get_db_keys(configs[group][key], key)
102 end
103
104 db_value = configs[group][key]
105
106 merged_value =
107 if not is_nil(db_value) and Keyword.keyword?(db_value) and
108 ConfigDB.sub_key_full_update?(group, key, Keyword.keys(db_value)) do
109 ConfigDB.merge_group(group, key, value, db_value)
110 else
111 value
112 end
113
114 %ConfigDB{
115 group: group,
116 key: key,
117 value: merged_value
118 }
119 |> Pleroma.Maps.put_if_present(:db, db)
120 end)
121 end)
122 |> List.flatten()
123
124 render(conn, "index.json", %{
125 configs: merged,
126 need_reboot: Restarter.Pleroma.need_reboot?()
127 })
128 end
129 end
130
131 def update(%{body_params: %{configs: configs}} = conn, _) do
132 with :ok <- configurable_from_database() do
133 results =
134 configs
135 |> Enum.filter(&whitelisted_config?/1)
136 |> Enum.map(fn
137 %{group: group, key: key, delete: true} = params ->
138 ConfigDB.delete(%{group: group, key: key, subkeys: params[:subkeys]})
139
140 %{group: group, key: key, value: value} ->
141 ConfigDB.update_or_create(%{group: group, key: key, value: value})
142 end)
143 |> Enum.reject(fn {result, _} -> result == :error end)
144
145 {deleted, updated} =
146 results
147 |> Enum.map(fn {:ok, %{key: key, value: value} = config} ->
148 Map.put(config, :db, ConfigDB.get_db_keys(value, key))
149 end)
150 |> Enum.split_with(&(Ecto.get_meta(&1, :state) == :deleted))
151
152 Config.TransferTask.load_and_update_env(deleted, false)
153
154 if not Restarter.Pleroma.need_reboot?() do
155 changed_reboot_settings? =
156 (updated ++ deleted)
157 |> Enum.any?(&Config.TransferTask.pleroma_need_restart?(&1.group, &1.key, &1.value))
158
159 if changed_reboot_settings?, do: Restarter.Pleroma.need_reboot()
160 end
161
162 render(conn, "index.json", %{
163 configs: updated,
164 need_reboot: Restarter.Pleroma.need_reboot?()
165 })
166 end
167 end
168
169 defp configurable_from_database do
170 if Config.get(:configurable_from_database) do
171 :ok
172 else
173 {:error, "You must enable configurable_from_database in your config file."}
174 end
175 end
176
177 defp whitelisted_config?(group, key) do
178 if whitelisted_configs = Config.get(:database_config_whitelist) do
179 Enum.any?(whitelisted_configs, fn
180 {whitelisted_group} ->
181 group == inspect(whitelisted_group)
182
183 {whitelisted_group, whitelisted_key} ->
184 group == inspect(whitelisted_group) && key == inspect(whitelisted_key)
185 end)
186 else
187 true
188 end
189 end
190
191 defp whitelisted_config?(%{group: group, key: key}) do
192 whitelisted_config?(group, key)
193 end
194
195 defp whitelisted_config?(%{group: group} = config) do
196 whitelisted_config?(group, config[:key])
197 end
198 end