1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Mix.Tasks.Pleroma.Config do
10 alias Pleroma.ConfigDB
13 @shortdoc "Manages the location of the config"
14 @moduledoc File.read!("docs/administration/CLI_tasks/config.md")
16 def run(["migrate_to_db"]) do
21 def run(["migrate_from_db" | options]) do
25 OptionParser.parse!(options,
26 strict: [env: :string, delete: :boolean],
34 with true <- Pleroma.Config.get([:configurable_from_database]) do
37 header = config_header()
44 unless settings == [] do
45 shell_info("#{header}")
47 settings |> Enum.each(&dump(&1))
49 shell_error("No settings in ConfigDB.")
52 _ -> configdb_not_enabled()
56 def run(["dump", group, key]) do
57 with true <- Pleroma.Config.get([:configurable_from_database]) do
60 group = maybe_atomize(group)
61 key = maybe_atomize(key)
65 _ -> configdb_not_enabled()
69 def run(["dump", group]) do
70 with true <- Pleroma.Config.get([:configurable_from_database]) do
73 group = maybe_atomize(group)
77 _ -> configdb_not_enabled()
81 def run(["groups"]) do
82 with true <- Pleroma.Config.get([:configurable_from_database]) do
88 |> Enum.map(fn x -> x.group end)
92 if length(groups) > 0 do
93 shell_info("The following configuration groups are set in ConfigDB:\r\n")
94 groups |> Enum.each(fn x -> shell_info("- #{x}") end)
98 _ -> configdb_not_enabled()
102 def run(["keys", group]) do
103 with true <- Pleroma.Config.get([:configurable_from_database]) do
106 group = maybe_atomize(group)
112 if x.group == group do
118 |> Enum.reject(fn x -> x == nil end)
120 if length(keys) > 0 do
121 shell_info("The following configuration keys under :#{group} are set in ConfigDB:\r\n")
122 keys |> Enum.each(fn x -> shell_info("- #{x}") end)
126 _ -> configdb_not_enabled()
130 def run(["reset"]) do
131 with true <- Pleroma.Config.get([:configurable_from_database]) do
134 if shell_prompt("Are you sure you want to continue?", "n") in ~w(Yn Y y) do
135 Ecto.Adapters.SQL.query!(Repo, "TRUNCATE config;")
136 Ecto.Adapters.SQL.query!(Repo, "ALTER SEQUENCE config_id_seq RESTART;")
138 shell_info("The ConfigDB settings have been removed from the database.")
140 shell_error("No changes made.")
143 _ -> configdb_not_enabled()
147 def run(["delete", group]) do
148 with true <- Pleroma.Config.get([:configurable_from_database]) do
151 group = maybe_atomize(group)
153 if group_exists?(group) do
154 shell_info("The following settings will be removed from ConfigDB:\n")
158 if shell_prompt("Are you sure you want to continue?", "n") in ~w(Yn Y y) do
161 |> Enum.filter(fn x ->
162 if x.group == group do
167 shell_error("No changes made.")
170 shell_error("No settings in ConfigDB for :#{group}. Aborting.")
173 _ -> configdb_not_enabled()
177 def run(["delete", group, key]) do
178 with true <- Pleroma.Config.get([:configurable_from_database]) do
181 group = maybe_atomize(group)
182 key = maybe_atomize(key)
184 if shell_prompt("Are you sure you want to continue?", "n") in ~w(Yn Y y) do
187 |> Enum.filter(fn x ->
188 if x.group == group and x.key == key do
193 shell_error("No changes made.")
196 _ -> configdb_not_enabled()
200 @spec migrate_to_db(Path.t() | nil) :: any()
201 def migrate_to_db(file_path \\ nil) do
202 with true <- Pleroma.Config.get([:configurable_from_database]),
203 :ok <- Pleroma.Config.DeprecationWarnings.warn() do
208 if Pleroma.Config.get(:release) do
209 Pleroma.Config.get(:config_path)
211 "config/#{Pleroma.Config.get(:env)}.secret.exs"
215 do_migrate_to_db(config_file)
217 :error -> deprecation_error()
218 _ -> migration_error()
222 defp do_migrate_to_db(config_file) do
223 if File.exists?(config_file) do
224 shell_info("Migrating settings from file: #{Path.expand(config_file)}")
225 Ecto.Adapters.SQL.query!(Repo, "TRUNCATE config;")
226 Ecto.Adapters.SQL.query!(Repo, "ALTER SEQUENCE config_id_seq RESTART;")
235 |> Enum.each(&create(&1, custom_config))
237 shell_info("To migrate settings, you must define custom settings in #{config_file}.")
241 defp create(group, settings) do
243 |> Pleroma.Config.Loader.filter_group(settings)
244 |> Enum.each(fn {key, value} ->
245 {:ok, _} = ConfigDB.update_or_create(%{group: group, key: key, value: value})
247 shell_info("Settings for key #{key} migrated.")
250 shell_info("Settings for group :#{group} migrated.")
253 defp migrate_from_db(opts) do
254 if Pleroma.Config.get([:configurable_from_database]) do
255 env = opts[:env] || Pleroma.Config.get(:env)
258 if Pleroma.Config.get(:release) do
260 |> Pleroma.Config.get()
265 |> Path.join("#{env}.exported_from_db.secret.exs")
267 file = File.open!(config_path, [:write, :utf8])
269 IO.write(file, config_header())
273 |> Enum.each(&write_and_delete(&1, file, opts[:delete]))
275 :ok = File.close(file)
276 System.cmd("mix", ["format", config_path])
279 "Database configuration settings have been exported to config/#{env}.exported_from_db.secret.exs"
286 defp migration_error do
288 "Migration is not allowed in config. You can change this behavior by setting `config :pleroma, configurable_from_database: true`"
292 defp deprecation_error do
293 shell_error("Migration is not allowed until all deprecation warnings have been resolved.")
296 if Code.ensure_loaded?(Config.Reader) do
297 defp config_header, do: "import Config\r\n\r\n"
298 defp read_file(config_file), do: Config.Reader.read_imports!(config_file)
300 defp config_header, do: "use Mix.Config\r\n\r\n"
301 defp read_file(config_file), do: Mix.Config.eval!(config_file)
304 defp write_and_delete(config, file, delete?) do
310 defp write(config, file) do
311 value = inspect(config.value, limit: :infinity)
313 IO.write(file, "config #{inspect(config.group)}, #{inspect(config.key)}, #{value}\r\n\r\n")
318 defp delete(config, true) do
319 {:ok, _} = Repo.delete(config)
322 "config #{inspect(config.group)}, #{inspect(config.key)} deleted from the ConfigDB."
326 defp delete(_config, _), do: :ok
328 defp dump(%Pleroma.ConfigDB{} = config) do
329 value = inspect(config.value, limit: :infinity)
331 shell_info("config #{inspect(config.group)}, #{inspect(config.key)}, #{value}\r\n\r\n")
334 defp configdb_not_enabled do
336 "ConfigDB not enabled. Please check the value of :configurable_from_database in your configuration."
340 defp dump_key(group, key) when is_atom(group) and is_atom(key) do
343 |> Enum.filter(fn x ->
344 if x.group == group && x.key == key do
350 defp dump_group(group) when is_atom(group) do
353 |> Enum.filter(fn x ->
354 if x.group == group do
360 defp group_exists?(group) when is_atom(group) do
364 |> Enum.filter(fn x ->
365 if x.group == group do
370 unless result == [] do
377 def maybe_atomize(arg) when is_atom(arg), do: arg
379 def maybe_atomize(arg) when is_binary(arg) do
380 chars = String.codepoints(arg)