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