a794344cbbb7450a2da26c936942f00e0a09f45a
[akkoma] / lib / mix / tasks / pleroma / config.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 Mix.Tasks.Pleroma.Config do
6 use Mix.Task
7
8 import Mix.Pleroma
9
10 alias Pleroma.ConfigDB
11 alias Pleroma.Repo
12
13 @shortdoc "Manages the location of the config"
14 @moduledoc File.read!("docs/administration/CLI_tasks/config.md")
15
16 def run(["migrate_to_db"]) do
17 start_pleroma()
18 migrate_to_db()
19 end
20
21 def run(["migrate_from_db" | options]) do
22 start_pleroma()
23
24 {opts, _} =
25 OptionParser.parse!(options,
26 strict: [env: :string, delete: :boolean],
27 aliases: [d: :delete]
28 )
29
30 migrate_from_db(opts)
31 end
32
33 def run(["dump"]) do
34 with true <- Pleroma.Config.get([:configurable_from_database]) do
35 start_pleroma()
36
37 header = config_header()
38
39 shell_info("#{header}")
40
41 ConfigDB
42 |> Repo.all()
43 |> Enum.sort()
44 |> Enum.each(&dump(&1))
45 else
46 _ -> configdb_not_enabled()
47 end
48 end
49
50 def run(["dump", group, key]) do
51 with true <- Pleroma.Config.get([:configurable_from_database]) do
52 start_pleroma()
53
54 dump_key(group, key)
55 else
56 _ -> configdb_not_enabled()
57 end
58 end
59
60 def run(["dump", group]) do
61 with true <- Pleroma.Config.get([:configurable_from_database]) do
62 start_pleroma()
63
64 dump_group(group)
65 else
66 _ -> configdb_not_enabled()
67 end
68 end
69
70 def run(["groups"]) do
71 with true <- Pleroma.Config.get([:configurable_from_database]) do
72 start_pleroma()
73
74 groups =
75 ConfigDB
76 |> Repo.all()
77 |> Enum.map(fn x -> x.group end)
78 |> Enum.sort()
79 |> Enum.uniq()
80
81 if length(groups) > 0 do
82 shell_info("The following configuration groups are set in ConfigDB:\r\n")
83 groups |> Enum.each(fn x -> shell_info("- #{x}") end)
84 shell_info("\r\n")
85 end
86 else
87 _ -> configdb_not_enabled()
88 end
89 end
90
91 def run(["keys" | group]) do
92 with true <- Pleroma.Config.get([:configurable_from_database]) do
93 start_pleroma()
94
95 keys =
96 ConfigDB
97 |> Repo.all()
98 |> Enum.map(fn x ->
99 if x.group == group do
100 x.key
101 end
102 end)
103 |> Enum.sort()
104 |> Enum.uniq()
105 |> Enum.reject(fn x -> x == nil end)
106
107 if length(keys) > 0 do
108 shell_info("The following configuration keys under :#{group} are set in ConfigDB:\r\n")
109 keys |> Enum.each(fn x -> shell_info("- #{x}") end)
110 shell_info("\r\n")
111 end
112 else
113 _ -> configdb_not_enabled()
114 end
115 end
116
117 def run(["reset"]) do
118 with true <- Pleroma.Config.get([:configurable_from_database]) do
119 start_pleroma()
120
121 if shell_prompt("Are you sure you want to continue?", "n") in ~w(Yn Y y) do
122 Ecto.Adapters.SQL.query!(Repo, "TRUNCATE config;")
123 Ecto.Adapters.SQL.query!(Repo, "ALTER SEQUENCE config_id_seq RESTART;")
124
125 shell_info("The ConfigDB settings have been removed from the database.")
126 else
127 shell_info("No changes made.")
128 end
129 else
130 _ -> configdb_not_enabled()
131 end
132 end
133
134 def run(["delete" | args]) when is_list(args) and length(args) == 2 do
135 with true <- Pleroma.Config.get([:configurable_from_database]) do
136 start_pleroma()
137
138 [group, key] = args
139
140 if shell_prompt("Are you sure you want to continue?", "n") in ~w(Yn Y y) do
141 ConfigDB
142 |> Repo.all()
143 |> Enum.filter(fn x ->
144 if x.group == group and x.key == key do
145 x |> delete(true)
146 end
147 end)
148 else
149 shell_info("No changes made.")
150 end
151 else
152 _ -> configdb_not_enabled()
153 end
154 end
155
156 @spec migrate_to_db(Path.t() | nil) :: any()
157 def migrate_to_db(file_path \\ nil) do
158 with true <- Pleroma.Config.get([:configurable_from_database]),
159 :ok <- Pleroma.Config.DeprecationWarnings.warn() do
160 config_file =
161 if file_path do
162 file_path
163 else
164 if Pleroma.Config.get(:release) do
165 Pleroma.Config.get(:config_path)
166 else
167 "config/#{Pleroma.Config.get(:env)}.secret.exs"
168 end
169 end
170
171 do_migrate_to_db(config_file)
172 else
173 :error -> deprecation_error()
174 _ -> migration_error()
175 end
176 end
177
178 defp do_migrate_to_db(config_file) do
179 if File.exists?(config_file) do
180 shell_info("Migrating settings from file: #{Path.expand(config_file)}")
181 Ecto.Adapters.SQL.query!(Repo, "TRUNCATE config;")
182 Ecto.Adapters.SQL.query!(Repo, "ALTER SEQUENCE config_id_seq RESTART;")
183
184 custom_config =
185 config_file
186 |> read_file()
187 |> elem(0)
188
189 custom_config
190 |> Keyword.keys()
191 |> Enum.each(&create(&1, custom_config))
192 else
193 shell_info("To migrate settings, you must define custom settings in #{config_file}.")
194 end
195 end
196
197 defp create(group, settings) do
198 group
199 |> Pleroma.Config.Loader.filter_group(settings)
200 |> Enum.each(fn {key, value} ->
201 {:ok, _} = ConfigDB.update_or_create(%{group: group, key: key, value: value})
202
203 shell_info("Settings for key #{key} migrated.")
204 end)
205
206 shell_info("Settings for group :#{group} migrated.")
207 end
208
209 defp migrate_from_db(opts) do
210 if Pleroma.Config.get([:configurable_from_database]) do
211 env = opts[:env] || Pleroma.Config.get(:env)
212
213 config_path =
214 if Pleroma.Config.get(:release) do
215 :config_path
216 |> Pleroma.Config.get()
217 |> Path.dirname()
218 else
219 "config"
220 end
221 |> Path.join("#{env}.exported_from_db.secret.exs")
222
223 file = File.open!(config_path, [:write, :utf8])
224
225 IO.write(file, config_header())
226
227 ConfigDB
228 |> Repo.all()
229 |> Enum.each(&write_and_delete(&1, file, opts[:delete]))
230
231 :ok = File.close(file)
232 System.cmd("mix", ["format", config_path])
233
234 shell_info(
235 "Database configuration settings have been exported to config/#{env}.exported_from_db.secret.exs"
236 )
237 else
238 migration_error()
239 end
240 end
241
242 defp migration_error do
243 shell_error(
244 "Migration is not allowed in config. You can change this behavior by setting `config :pleroma, configurable_from_database: true`"
245 )
246 end
247
248 defp deprecation_error do
249 shell_error("Migration is not allowed until all deprecation warnings have been resolved.")
250 end
251
252 if Code.ensure_loaded?(Config.Reader) do
253 defp config_header, do: "import Config\r\n\r\n"
254 defp read_file(config_file), do: Config.Reader.read_imports!(config_file)
255 else
256 defp config_header, do: "use Mix.Config\r\n\r\n"
257 defp read_file(config_file), do: Mix.Config.eval!(config_file)
258 end
259
260 defp write_and_delete(config, file, delete?) do
261 config
262 |> write(file)
263 |> delete(delete?)
264 end
265
266 defp write(config, file) do
267 value = inspect(config.value, limit: :infinity)
268
269 IO.write(file, "config #{inspect(config.group)}, #{inspect(config.key)}, #{value}\r\n\r\n")
270
271 config
272 end
273
274 defp delete(config, true) do
275 {:ok, _} = Repo.delete(config)
276 shell_info("#{config.key} deleted from the ConfigDB.")
277 end
278
279 defp delete(_config, _), do: :ok
280
281 defp dump(%Pleroma.ConfigDB{} = config) do
282 value = inspect(config.value, limit: :infinity)
283
284 shell_info("config #{inspect(config.group)}, #{inspect(config.key)}, #{value}\r\n\r\n")
285 end
286
287 defp configdb_not_enabled do
288 shell_error(
289 "ConfigDB not enabled. Please check the value of :configurable_from_database in your configuration."
290 )
291 end
292
293 defp dump_key(group, key) do
294 group = group |> String.to_atom()
295 key = key |> String.to_atom()
296
297 ConfigDB
298 |> Repo.all()
299 |> Enum.filter(fn x ->
300 if x.group == group && x.key == key do
301 x |> dump
302 end
303 end)
304 end
305
306 defp dump_group(group) do
307 group = group |> String.to_atom()
308
309 ConfigDB
310 |> Repo.all()
311 |> Enum.filter(fn x ->
312 if x.group == group do
313 x |> dump
314 end
315 end)
316 end
317 end