574f8f4beb11271e3c2b269168add3f7f1e960f8
[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.each(&dump(&1))
44 else
45 _ -> configdb_not_enabled()
46 end
47 end
48
49 def run(["dump" | dbkey]) do
50 with true <- Pleroma.Config.get([:configurable_from_database]) do
51 start_pleroma()
52
53 dbkey = dbkey |> List.first() |> String.to_atom()
54
55 ConfigDB
56 |> Repo.all()
57 |> Enum.filter(fn x ->
58 if x.key == dbkey do
59 x |> dump
60 end
61 end)
62 else
63 _ -> configdb_not_enabled()
64 end
65 end
66
67 def run(["keylist"]) do
68 with true <- Pleroma.Config.get([:configurable_from_database]) do
69 start_pleroma()
70
71 keys =
72 ConfigDB
73 |> Repo.all()
74 |> Enum.map(fn x -> x.key end)
75
76 if length(keys) > 0 do
77 shell_info("The following configuration keys are set in ConfigDB:\r\n")
78 keys |> Enum.each(fn x -> shell_info("- #{x}") end)
79 shell_info("\r\n")
80 end
81 else
82 _ -> configdb_not_enabled()
83 end
84 end
85
86 def run(["reset"]) do
87 with true <- Pleroma.Config.get([:configurable_from_database]) do
88 start_pleroma()
89
90 Ecto.Adapters.SQL.query!(Repo, "TRUNCATE config;")
91 Ecto.Adapters.SQL.query!(Repo, "ALTER SEQUENCE config_id_seq RESTART;")
92
93 shell_info("The ConfigDB settings have been removed from the database.")
94 else
95 _ -> configdb_not_enabled()
96 end
97 end
98
99 def run(["keydel" | dbkey]) do
100 unless [] == dbkey do
101 with true <- Pleroma.Config.get([:configurable_from_database]) do
102 start_pleroma()
103
104 dbkey = dbkey |> List.first() |> String.to_atom()
105
106 ConfigDB
107 |> Repo.all()
108 |> Enum.filter(fn x ->
109 if x.key == dbkey do
110 x |> delete(true)
111 end
112 end)
113 else
114 _ -> configdb_not_enabled()
115 end
116 else
117 shell_error(
118 "You must provide a key to delete. Use the keylist command to get a list of valid keys."
119 )
120 end
121 end
122
123 @spec migrate_to_db(Path.t() | nil) :: any()
124 def migrate_to_db(file_path \\ nil) do
125 with true <- Pleroma.Config.get([:configurable_from_database]),
126 :ok <- Pleroma.Config.DeprecationWarnings.warn() do
127 config_file =
128 if file_path do
129 file_path
130 else
131 if Pleroma.Config.get(:release) do
132 Pleroma.Config.get(:config_path)
133 else
134 "config/#{Pleroma.Config.get(:env)}.secret.exs"
135 end
136 end
137
138 do_migrate_to_db(config_file)
139 else
140 :error -> deprecation_error()
141 _ -> migration_error()
142 end
143 end
144
145 defp do_migrate_to_db(config_file) do
146 if File.exists?(config_file) do
147 shell_info("Migrating settings from file: #{Path.expand(config_file)}")
148 Ecto.Adapters.SQL.query!(Repo, "TRUNCATE config;")
149 Ecto.Adapters.SQL.query!(Repo, "ALTER SEQUENCE config_id_seq RESTART;")
150
151 custom_config =
152 config_file
153 |> read_file()
154 |> elem(0)
155
156 custom_config
157 |> Keyword.keys()
158 |> Enum.each(&create(&1, custom_config))
159 else
160 shell_info("To migrate settings, you must define custom settings in #{config_file}.")
161 end
162 end
163
164 defp create(group, settings) do
165 group
166 |> Pleroma.Config.Loader.filter_group(settings)
167 |> Enum.each(fn {key, value} ->
168 {:ok, _} = ConfigDB.update_or_create(%{group: group, key: key, value: value})
169
170 shell_info("Settings for key #{key} migrated.")
171 end)
172
173 shell_info("Settings for group :#{group} migrated.")
174 end
175
176 defp migrate_from_db(opts) do
177 if Pleroma.Config.get([:configurable_from_database]) do
178 env = opts[:env] || Pleroma.Config.get(:env)
179
180 config_path =
181 if Pleroma.Config.get(:release) do
182 :config_path
183 |> Pleroma.Config.get()
184 |> Path.dirname()
185 else
186 "config"
187 end
188 |> Path.join("#{env}.exported_from_db.secret.exs")
189
190 file = File.open!(config_path, [:write, :utf8])
191
192 IO.write(file, config_header())
193
194 ConfigDB
195 |> Repo.all()
196 |> Enum.each(&write_and_delete(&1, file, opts[:delete]))
197
198 :ok = File.close(file)
199 System.cmd("mix", ["format", config_path])
200
201 shell_info(
202 "Database configuration settings have been exported to config/#{env}.exported_from_db.secret.exs"
203 )
204 else
205 migration_error()
206 end
207 end
208
209 defp migration_error do
210 shell_error(
211 "Migration is not allowed in config. You can change this behavior by setting `config :pleroma, configurable_from_database: true`"
212 )
213 end
214
215 defp deprecation_error do
216 shell_error("Migration is not allowed until all deprecation warnings have been resolved.")
217 end
218
219 if Code.ensure_loaded?(Config.Reader) do
220 defp config_header, do: "import Config\r\n\r\n"
221 defp read_file(config_file), do: Config.Reader.read_imports!(config_file)
222 else
223 defp config_header, do: "use Mix.Config\r\n\r\n"
224 defp read_file(config_file), do: Mix.Config.eval!(config_file)
225 end
226
227 defp write_and_delete(config, file, delete?) do
228 config
229 |> write(file)
230 |> delete(delete?)
231 end
232
233 defp write(config, file) do
234 value = inspect(config.value, limit: :infinity)
235
236 IO.write(file, "config #{inspect(config.group)}, #{inspect(config.key)}, #{value}\r\n\r\n")
237
238 config
239 end
240
241 defp delete(config, true) do
242 {:ok, _} = Repo.delete(config)
243 shell_info("#{config.key} deleted from the ConfigDB.")
244 end
245
246 defp delete(_config, _), do: :ok
247
248 defp dump(%Pleroma.ConfigDB{} = config) do
249 value = inspect(config.value, limit: :infinity)
250
251 shell_info("config #{inspect(config.group)}, #{inspect(config.key)}, #{value}\r\n\r\n")
252 end
253
254 defp configdb_not_enabled do
255 shell_error(
256 "ConfigDB not enabled. Please check the value of :configurable_from_database in your configuration."
257 )
258 end
259 end