diff options
Diffstat (limited to 'lib/mix/tasks')
-rw-r--r-- | lib/mix/tasks/pleroma/frontend.ex | 222 | ||||
-rw-r--r-- | lib/mix/tasks/pleroma/instance.ex | 93 | ||||
-rw-r--r-- | lib/mix/tasks/pleroma/user.ex | 2 |
3 files changed, 314 insertions, 3 deletions
diff --git a/lib/mix/tasks/pleroma/frontend.ex b/lib/mix/tasks/pleroma/frontend.ex new file mode 100644 index 000000000..8130a71ea --- /dev/null +++ b/lib/mix/tasks/pleroma/frontend.ex @@ -0,0 +1,222 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.Frontend do + use Mix.Task + + import Mix.Pleroma + + # alias Pleroma.Config + + @shortdoc "Manages bundled Pleroma frontends" + @moduledoc File.read!("docs/administration/CLI_tasks/frontend.md") + + @pleroma_gitlab_host "git.pleroma.social" + @frontends %{ + # TODO stable + "admin" => %{"project" => "pleroma/admin-fe"}, + # TODO + "kenoma" => %{"project" => "lambadalambda/kenoma"}, + # TODO + "mastodon" => %{"project" => "pleroma/mastofe"}, + # OK + "pleroma" => %{"project" => "pleroma/pleroma-fe"} + } + @known_frontends Map.keys(@frontends) + + def run(["install", "none" | _args]) do + shell_info("Skipping frontend installation because none was requested") + end + + def run(["install", unknown_fe | _args]) when unknown_fe not in @known_frontends do + shell_error( + "Frontend \"#{unknown_fe}\" is not known. Known frontends are: #{ + Enum.join(@known_frontends, ", ") + }" + ) + end + + def run(["install", frontend | args]) do + log_level = Logger.level() + Logger.configure(level: :warn) + {:ok, _} = Application.ensure_all_started(:pleroma) + + {options, [], []} = + OptionParser.parse( + args, + strict: [ + ref: :string + ] + ) + + ref = suggest_ref(options, frontend) + + %{"name" => bundle_name, "url" => bundle_url} = + get_bundle_meta(ref, @pleroma_gitlab_host, @frontends[frontend]["project"]) + + shell_info("Installing frontend #{frontend}, version: #{bundle_name}") + + dest = Path.join([Pleroma.Config.get!([:instance, :static_dir]), "frontends", frontend, ref]) + + with :ok <- install_bundle(bundle_url, dest), + :ok <- post_install_bundle(frontend, dest) do + shell_info("Installed!") + else + {:error, error} -> + shell_error("Error: #{inspect(error)}") + end + + Logger.configure(level: log_level) + end + + defp post_install_bundle("mastodon", path) do + with :ok <- File.rename("#{path}/public/assets/sw.js", "#{path}/sw.js"), + :ok <- File.rename("#{path}/public/packs", "#{path}/packs"), + {:ok, _deleted_files} <- File.rm_rf("#{path}/public") do + :ok + else + error -> + {:error, error} + end + end + + defp post_install_bundle(_fe_name, _path), do: :ok + + defp suggest_ref(options, frontend) do + case Pleroma.Config.get([:frontends, String.to_atom(frontend)]) do + nil -> + primary_fe_config = Pleroma.Config.get([:frontends, :primary]) + + if primary_fe_config["name"] == frontend do + primary_fe_config["ref"] + else + nil + end + + val -> + val + end + |> case do + nil -> + stable_pleroma? = Pleroma.Application.stable?() + + current_stable_out = + if stable_pleroma? do + "stable" + else + "develop" + end + + get_option( + options, + :ref, + "You are currently running #{current_stable_out} version of Pleroma backend. What version of \"#{ + frontend + }\" frontend you want to install? (\"stable\", \"develop\" or specific ref)", + current_stable_out + ) + + config_value -> + current_ref = + case config_value do + %{"ref" => ref} -> ref + ref -> ref + end + + get_option( + options, + :ref, + "You are currently running \"#{current_ref}\" version of \"#{frontend}\" frontend. What version do you want to install? (\"stable\", \"develop\" or specific ref)", + current_ref + ) + end + end + + defp get_bundle_meta("develop", gitlab_base_url, project) do + url = "#{gitlab_api_url(gitlab_base_url, project)}/repository/branches" + + %{status: 200, body: json} = Tesla.get!(http_client(), url) + + %{"name" => name, "commit" => %{"short_id" => last_commit_ref}} = + Enum.find(json, & &1["default"]) + + %{ + "name" => name, + "url" => build_url(gitlab_base_url, project, last_commit_ref) + } + end + + defp get_bundle_meta("stable", gitlab_base_url, project) do + url = "#{gitlab_api_url(gitlab_base_url, project)}/releases" + %{status: 200, body: json} = Tesla.get!(http_client(), url) + + [%{"commit" => %{"short_id" => commit_id}, "name" => name} = data | _] = + Enum.sort(json, fn r1, r2 -> + {:ok, date1, _offset} = DateTime.from_iso8601(r1["created_at"]) + {:ok, date2, _offset} = DateTime.from_iso8601(r2["created_at"]) + DateTime.compare(date1, date2) != :lt + end) + + IO.inspect(data) + + %{ + "name" => name, + "url" => build_url(gitlab_base_url, project, commit_id) + } + end + + defp get_bundle_meta(ref, gitlab_base_url, project) do + %{ + "name" => ref, + "url" => build_url(gitlab_base_url, project, ref) + } + end + + defp install_bundle(bundle_url, dir) do + http_client = http_client() + + with {:ok, %{status: 200, body: zip_body}} <- Tesla.get(http_client, bundle_url), + {:ok, unzipped} <- :zip.unzip(zip_body, [:memory]) do + File.rm_rf!(dir) + + Enum.each(unzipped, fn {path, data} -> + path = + path + |> to_string() + |> String.replace(~r/^dist\//, "") + + file_path = Path.join(dir, path) + + file_path + |> Path.dirname() + |> File.mkdir_p!() + + File.write!(file_path, data) + end) + else + {:ok, %{status: 404}} -> + {:error, "Bundle not found"} + + error -> + {:error, error} + end + end + + defp gitlab_api_url(gitlab_base_url, project), + do: "https://#{gitlab_base_url}/api/v4/projects/#{URI.encode_www_form(project)}" + + defp build_url(gitlab_base_url, project, ref), + do: + "https://#{gitlab_base_url}/#{project}/-/jobs/artifacts/#{ref}/download?job=build" + |> IO.inspect() + + defp http_client do + middleware = [ + Tesla.Middleware.FollowRedirects, + Tesla.Middleware.JSON + ] + + Tesla.client(middleware) + end +end diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex index bc842a59f..3e0f0fdc8 100644 --- a/lib/mix/tasks/pleroma/instance.ex +++ b/lib/mix/tasks/pleroma/instance.ex @@ -33,7 +33,14 @@ defmodule Mix.Tasks.Pleroma.Instance do uploads_dir: :string, static_dir: :string, listen_ip: :string, - listen_port: :string + listen_port: :string, + fe_primary: :string, + fe_primary_ref: :string, + fe_mastodon: :string, + fe_mastodon_ref: :string, + fe_admin: :string, + fe_admin_ref: :string, + fe_static: :string ], aliases: [ o: :output, @@ -158,6 +165,62 @@ defmodule Mix.Tasks.Pleroma.Instance do Config.put([:instance, :static_dir], static_dir) + install_fe = + case Mix.env() do + :test -> fn _, _ -> :ok end + _ -> &Mix.Tasks.Pleroma.Frontend.run(["install", &1, "--ref", &2]) + end + + fe_primary = + get_option( + options, + :fe_primary, + "Choose primary frontend for your instance (available: pleroma/kenoma/none)", + "pleroma" + ) + + fe_primary_ref = + get_frontend_ref(fe_primary !== "none", fe_primary, :fe_primary_ref, options) + + install_fe.(fe_primary, fe_primary_ref) + + enable_static_fe? = + get_option( + options, + :fe_static, + "Would you like to enable Static frontend (render profiles and posts using server-generated HTML that is viewable without using JavaScript)?", + "y" + ) === "y" + + install_mastodon_fe? = + get_option( + options, + :fe_mastodon, + "Would you like to install Mastodon frontend?", + "y" + ) === "y" + + fe_mastodon_ref = + get_frontend_ref(install_mastodon_fe?, "mastodon", :fe_mastodon_ref, options) + + if install_mastodon_fe? do + install_fe.("mastodon", fe_mastodon_ref) + end + + install_admin_fe? = + get_option( + options, + :fe_admin, + "Would you like to install Admin frontend?", + "y" + ) === "y" + + fe_admin_ref = get_frontend_ref(install_admin_fe?, "admin", :fe_admin_ref, options) + + if install_admin_fe? do + install_fe.("admin", fe_admin_ref) + end + secret = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64) jwt_secret = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64) signing_salt = :crypto.strong_rand_bytes(8) |> Base.encode64() |> binary_part(0, 8) @@ -186,7 +249,11 @@ defmodule Mix.Tasks.Pleroma.Instance do uploads_dir: uploads_dir, rum_enabled: rum_enabled, listen_ip: listen_ip, - listen_port: listen_port + listen_port: listen_port, + fe_primary: %{"name" => fe_primary, "ref" => fe_primary_ref}, + fe_mastodon: %{"name" => "mastodon", "ref" => fe_mastodon_ref}, + fe_admin: %{"name" => "admin", "ref" => fe_admin_ref}, + enable_static_fe?: enable_static_fe? ) result_psql = @@ -247,4 +314,26 @@ defmodule Mix.Tasks.Pleroma.Instance do File.write(robots_txt_path, robots_txt) shell_info("Writing #{robots_txt_path}.") end + + defp get_frontend_ref(false, _frontend, _option_key, _options), do: "" + + defp get_frontend_ref(true, frontend, option_key, options) do + stable_pleroma? = Pleroma.Application.stable?() + + current_stable_out = + if stable_pleroma? do + "stable" + else + "develop" + end + + get_option( + options, + option_key, + "You are currently running #{current_stable_out} version of Pleroma. What version of #{ + frontend + } you want to install? (\"stable\", \"develop\" or specific ref)", + current_stable_out + ) + end end diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 40dd9bdc0..f15112e9e 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -272,7 +272,7 @@ defmodule Mix.Tasks.Pleroma.User do shell_info("Generated user invite token " <> String.replace(invite.invite_type, "_", " ")) url = - Pleroma.Web.Router.Helpers.redirect_url( + Pleroma.Web.Router.Helpers.frontend_url( Pleroma.Web.Endpoint, :registration_page, invite.token |