diff options
Diffstat (limited to 'lib/pleroma')
-rw-r--r-- | lib/pleroma/frontend.ex | 143 | ||||
-rw-r--r-- | lib/pleroma/web/admin_api/controllers/frontend_controller.ex | 10 |
2 files changed, 117 insertions, 36 deletions
diff --git a/lib/pleroma/frontend.ex b/lib/pleroma/frontend.ex index 34b7befb8..18bb6c488 100644 --- a/lib/pleroma/frontend.ex +++ b/lib/pleroma/frontend.ex @@ -4,41 +4,45 @@ defmodule Pleroma.Frontend do alias Pleroma.Config + alias Pleroma.ConfigDB + alias Pleroma.Frontend require Logger - def install(name, opts \\ []) do - frontend_info = %{ - "ref" => opts[:ref], - "build_url" => opts[:build_url], - "build_dir" => opts[:build_dir] - } - - frontend_info = - [:frontends, :available, name] - |> Config.get(%{}) - |> Map.merge(frontend_info, fn _key, config, cmd -> - # This only overrides things that are actually set - cmd || config - end) + @unknown_name "unknown" + @frontend_types [:admin, :primary] - ref = frontend_info["ref"] + defstruct [:name, :ref, :git, :build_url, :build_dir, :file, :"custom-http-headers"] - unless ref do - raise "No ref given or configured" - end + def install(%Frontend{} = frontend) do + frontend + |> maybe_put_name() + |> hydrate() + |> validate!() + |> do_install() + end + + defp maybe_put_name(%{name: nil} = fe), do: Map.put(fe, :name, @unknown_name) + defp maybe_put_name(fe), do: fe + # Merges a named frontend with the provided one + defp hydrate(%Frontend{name: name} = frontend) do + get_named_frontend(name) + |> merge(frontend) + end + + defp do_install(%Frontend{ref: ref, name: name} = frontend) do dest = Path.join([dir(), name, ref]) label = "#{name} (#{ref})" tmp_dir = Path.join(dir(), "tmp") - with {_, :ok} <- - {:download_or_unzip, download_or_unzip(frontend_info, tmp_dir, opts[:file])}, + with {_, :ok} <- {:download_or_unzip, download_or_unzip(frontend, tmp_dir)}, Logger.info("Installing #{label} to #{dest}"), - :ok <- install_frontend(frontend_info, tmp_dir, dest) do + :ok <- install_frontend(frontend, tmp_dir, dest) do File.rm_rf!(tmp_dir) Logger.info("Frontend #{label} installed to #{dest}") + frontend else {:download_or_unzip, _} -> Logger.info("Could not download or unzip the frontend") @@ -50,21 +54,53 @@ defmodule Pleroma.Frontend do end end - def dir(opts \\ []) do - if is_nil(opts[:static_dir]) do - Pleroma.Config.get!([:instance, :static_dir]) + def enable(%Frontend{} = frontend, frontend_type) when frontend_type in @frontend_types do + with {:config_db, true} <- {:config_db, Config.get(:configurable_from_database)} do + frontend + |> maybe_put_name() + |> hydrate() + |> validate!() + |> do_enable(frontend_type) else - opts[:static_dir] + {:config_db, _} -> + map = to_map(frontend) + + raise """ + Can't enable frontend; database configuration is disabled. + Enable the frontend by manually adding this line to your config: + + config :pleroma, :frontends, #{to_string(frontend_type)}: #{inspect(map)} + + Alternatively, enable database configuration: + + config :pleroma, configurable_from_database: true + """ + end + end + + def do_enable(%Frontend{name: name} = frontend, frontend_type) do + value = Keyword.put([], frontend_type, to_map(frontend)) + params = %{group: :pleroma, key: :frontends, value: value} + + with {:ok, _} <- ConfigDB.update_or_create(params), + :ok <- Config.TransferTask.load_and_update_env([], false) do + Logger.info("Frontend #{name} successfully enabled") + frontend end + end + + def dir do + Config.get!([:instance, :static_dir]) |> Path.join("frontends") end - defp download_or_unzip(frontend_info, temp_dir, nil), - do: download_build(frontend_info, temp_dir) + defp download_or_unzip(%Frontend{build_url: build_url} = frontend, dest) + when is_binary(build_url), + do: download_build(frontend, dest) - defp download_or_unzip(_frontend_info, temp_dir, file) do + defp download_or_unzip(%Frontend{file: file}, dest) when is_binary(file) do with {:ok, zip} <- File.read(Path.expand(file)) do - unzip(zip, temp_dir) + unzip(zip, dest) end end @@ -87,9 +123,13 @@ defmodule Pleroma.Frontend do end end - defp download_build(frontend_info, dest) do - Logger.info("Downloading pre-built bundle for #{frontend_info["name"]}") - url = String.replace(frontend_info["build_url"], "${ref}", frontend_info["ref"]) + def parse_build_url(%Frontend{ref: ref, build_url: build_url}) do + String.replace(build_url, "${ref}", ref) + end + + defp download_build(%Frontend{name: name} = frontend, dest) do + Logger.info("Downloading pre-built bundle for #{name}") + url = parse_build_url(frontend) with {:ok, %{status: 200, body: zip_body}} <- Pleroma.HTTP.get(url, [], pool: :media, recv_timeout: 120_000) do @@ -100,11 +140,46 @@ defmodule Pleroma.Frontend do end end - defp install_frontend(frontend_info, source, dest) do - from = frontend_info["build_dir"] || "dist" + defp install_frontend(%Frontend{} = frontend, source, dest) do + from = frontend.build_dir || "dist" File.rm_rf!(dest) File.mkdir_p!(dest) File.cp_r!(Path.join([source, from]), dest) :ok end + + # Converts a named frontend into a %Frontend{} struct + def get_named_frontend(name) do + [:frontends, :available, name] + |> Config.get(%{}) + |> from_map() + end + + def merge(%Frontend{} = fe1, %Frontend{} = fe2) do + Map.merge(fe1, fe2, fn _key, v1, v2 -> + # This only overrides things that are actually set + v1 || v2 + end) + end + + def validate!(%Frontend{ref: ref} = fe) when is_binary(ref), do: fe + def validate!(_), do: raise("No ref given or configured") + + def from_map(frontend) when is_map(frontend) do + struct(Frontend, atomize_keys(frontend)) + end + + def to_map(%Frontend{} = frontend) do + frontend + |> Map.from_struct() + |> stringify_keys() + end + + defp atomize_keys(map) do + Map.new(map, fn {k, v} -> {String.to_existing_atom(k), v} end) + end + + defp stringify_keys(map) do + Map.new(map, fn {k, v} -> {to_string(k), v} end) + end end diff --git a/lib/pleroma/web/admin_api/controllers/frontend_controller.ex b/lib/pleroma/web/admin_api/controllers/frontend_controller.ex index 722f51bd2..c1332bdcd 100644 --- a/lib/pleroma/web/admin_api/controllers/frontend_controller.ex +++ b/lib/pleroma/web/admin_api/controllers/frontend_controller.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Web.AdminAPI.FrontendController do use Pleroma.Web, :controller alias Pleroma.Config + alias Pleroma.Frontend alias Pleroma.Web.Plugs.OAuthScopesPlug plug(Pleroma.Web.ApiSpec.CastAndValidate) @@ -29,12 +30,17 @@ defmodule Pleroma.Web.AdminAPI.FrontendController do end def install(%{body_params: params} = conn, _params) do - with :ok <- Pleroma.Frontend.install(params.name, Map.delete(params, :name)) do + with %Frontend{} = frontend <- params_to_frontend(params), + %Frontend{} <- Frontend.install(frontend) do index(conn, %{}) end end defp installed do - File.ls!(Pleroma.Frontend.dir()) + File.ls!(Frontend.dir()) + end + + defp params_to_frontend(params) when is_map(params) do + struct(Frontend, params) end end |