summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoman Chvanikov <chvanikoff@pm.me>2020-07-30 20:33:22 +0300
committerRoman Chvanikov <chvanikoff@pm.me>2020-07-30 20:33:35 +0300
commitef12eb5e12ba34e78428c0f070efe328d94587ac (patch)
treedbbeb8cf7820e45cbea99a3ac2b03882ddb0f7a1
parent93dbba9b8a5aacbbf43a45a07e27b328579eabf8 (diff)
Add frontends plug and controller flow
-rw-r--r--lib/pleroma/frontend.ex56
-rw-r--r--lib/pleroma/plugs/frontend_plug.ex11
-rw-r--r--lib/pleroma/plugs/instance_static.ex11
-rw-r--r--lib/pleroma/web/controller/frontend/pleroma_controller.ex4
-rw-r--r--lib/pleroma/web/controller/frontend_controller.ex87
-rw-r--r--lib/pleroma/web/endpoint.ex1
-rw-r--r--lib/pleroma/web/fallback_redirect_controller.ex3
-rw-r--r--lib/pleroma/web/preload/instance.ex13
-rw-r--r--lib/pleroma/web/router.ex15
-rw-r--r--lib/pleroma/web/web.ex2
-rw-r--r--test/frontend_test.exs75
-rw-r--r--test/plugs/frontend_plug_test.exs21
-rw-r--r--test/plugs/frontend_static_test.exs2
-rw-r--r--test/plugs/instance_static_test.exs13
14 files changed, 279 insertions, 35 deletions
diff --git a/lib/pleroma/frontend.ex b/lib/pleroma/frontend.ex
new file mode 100644
index 000000000..646a0c806
--- /dev/null
+++ b/lib/pleroma/frontend.ex
@@ -0,0 +1,56 @@
+defmodule Pleroma.Frontend do
+ @type frontend_kind :: :primary
+
+ def get_config(frontend \\ :primary)
+
+ def get_config(:primary) do
+ primary_fe_config = Pleroma.Config.get([:frontends, :primary], %{"name" => "pleroma"})
+
+ {config, controller} =
+ if primary_fe_config["name"] == "none" do
+ {%{}, Pleroma.Web.Frontend.HeadlessController}
+ else
+ {primary_fe_config,
+ Module.concat([
+ Pleroma.Web.Frontend,
+ String.capitalize(primary_fe_config["name"]) <> "Controller"
+ ])}
+ end
+
+ %{"config" => config, "controller" => controller}
+ end
+
+ @spec file_path(String.t(), frontend_kind()) :: {:ok, String.t()} | {:error, String.t()}
+ def file_path(file, kind \\ :primary) do
+ config = get_config(kind)
+
+ instance_static_dir = Pleroma.Config.get([:instance, :static_dir], "instance/static")
+
+ frontend_path =
+ case config["config"] do
+ %{"name" => name, "ref" => ref} ->
+ Path.join([instance_static_dir, "frontends", name, ref, file])
+
+ _ ->
+ false
+ end
+
+ instance_path = Path.join([instance_static_dir, file])
+ priv_path = Application.app_dir(:pleroma, ["priv", "static", file])
+
+ cond do
+ File.exists?(instance_path) ->
+ {:ok, instance_path}
+
+ frontend_path && File.exists?(frontend_path) ->
+ {:ok, frontend_path}
+
+ File.exists?(priv_path) ->
+ {:ok, priv_path}
+
+ true ->
+ {:error,
+ "File #{file} not found in #{inspect([instance_path, frontend_path, priv_path])}"}
+ end
+ end
+end
diff --git a/lib/pleroma/plugs/frontend_plug.ex b/lib/pleroma/plugs/frontend_plug.ex
new file mode 100644
index 000000000..b6bc23ae7
--- /dev/null
+++ b/lib/pleroma/plugs/frontend_plug.ex
@@ -0,0 +1,11 @@
+defmodule Pleroma.Plugs.FrontendPlug do
+ import Plug.Conn
+
+ @behaviour Plug
+
+ def init(opts), do: opts
+
+ def call(conn, _opts) do
+ put_private(conn, :frontend, Pleroma.Frontend.get_config())
+ end
+end
diff --git a/lib/pleroma/plugs/instance_static.ex b/lib/pleroma/plugs/instance_static.ex
index 0fb57e422..bb813a41a 100644
--- a/lib/pleroma/plugs/instance_static.ex
+++ b/lib/pleroma/plugs/instance_static.ex
@@ -12,17 +12,6 @@ defmodule Pleroma.Plugs.InstanceStatic do
"""
@behaviour Plug
- def file_path(path) do
- instance_path =
- Path.join(Pleroma.Config.get([:instance, :static_dir], "instance/static/"), path)
-
- frontend_path = Pleroma.Plugs.FrontendStatic.file_path(path, :primary)
-
- (File.exists?(instance_path) && instance_path) ||
- (frontend_path && File.exists?(frontend_path) && frontend_path) ||
- Path.join(Application.app_dir(:pleroma, "priv/static/"), path)
- end
-
def init(opts) do
opts
|> Keyword.put(:from, "__unconfigured_instance_static_plug")
diff --git a/lib/pleroma/web/controller/frontend/pleroma_controller.ex b/lib/pleroma/web/controller/frontend/pleroma_controller.ex
new file mode 100644
index 000000000..18a376e6b
--- /dev/null
+++ b/lib/pleroma/web/controller/frontend/pleroma_controller.ex
@@ -0,0 +1,4 @@
+defmodule Pleroma.Web.Frontend.PleromaController do
+ use Pleroma.Web, :controller
+ use Pleroma.Web.FrontendController
+end
diff --git a/lib/pleroma/web/controller/frontend_controller.ex b/lib/pleroma/web/controller/frontend_controller.ex
new file mode 100644
index 000000000..fc717fa29
--- /dev/null
+++ b/lib/pleroma/web/controller/frontend_controller.ex
@@ -0,0 +1,87 @@
+defmodule Pleroma.Web.FrontendController do
+ use Pleroma.Web, :controller
+
+ defmacro __using__(_opts) do
+ quote do
+ require Logger
+
+ def fallback(conn, _params) do
+ conn
+ |> put_status(404)
+ |> text("Not found")
+ end
+
+ def redirector_with_preload(conn, %{"path" => ["pleroma", "admin"]}) do
+ redirect(conn, to: "/pleroma/admin/")
+ end
+
+ def redirector_with_preload(conn, params) do
+ index_with_generated_data(conn, params, [:preload])
+ end
+
+ def index_with_generated_data(conn, params, generators) do
+ {:ok, path} = Pleroma.Frontend.file_path("index.html")
+ {:ok, index_content} = File.read(path)
+
+ generated =
+ Enum.reduce(generators, "", fn generator, acc ->
+ acc <> generate_data(conn, params, generator)
+ end)
+
+ response = String.replace(index_content, "<!--server-generated-meta-->", generated)
+
+ html(conn, response)
+ end
+
+ defp generate_data(conn, params, :preload) do
+ try do
+ Pleroma.Web.Preload.build_tags(conn, params)
+ rescue
+ e ->
+ Logger.error(
+ "Preloading for #{conn.request_path} failed.\n" <>
+ Exception.format(:error, e, __STACKTRACE__)
+ )
+
+ ""
+ end
+ end
+
+ defp generate_data(conn, params, :metadata) do
+ try do
+ Pleroma.Web.Metadata.build_tags(params)
+ rescue
+ e ->
+ Logger.error(
+ "Metadata rendering for #{conn.request_path} failed.\n" <>
+ Exception.format(:error, e, __STACKTRACE__)
+ )
+
+ ""
+ end
+ end
+
+ defoverridable redirector_with_preload: 2, fallback: 2
+ end
+ end
+
+ defp action(conn, _opts) do
+ fe_config = conn.private[:frontend] || Pleroma.Frontend.get_config(:primary)
+
+ action_name = action_name(conn)
+
+ {controller, action} =
+ cond do
+ function_exported?(fe_config["controller"], action_name, 2) ->
+ {fe_config["controller"], action_name}
+
+ true ->
+ {fe_config["controller"], :fallback}
+ end
+
+ conn
+ |> put_private(:frontend, fe_config)
+ |> put_view(Phoenix.Controller.__view__(controller))
+ |> controller.call(controller.init(action))
+ end
+end
diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex
index 527fb288d..22dfe8298 100644
--- a/lib/pleroma/web/endpoint.ex
+++ b/lib/pleroma/web/endpoint.ex
@@ -13,6 +13,7 @@ defmodule Pleroma.Web.Endpoint do
plug(CORSPlug)
plug(Pleroma.Plugs.HTTPSecurityPlug)
plug(Pleroma.Plugs.UploadedMedia)
+ plug(Pleroma.Plugs.FrontendPlug)
@static_cache_control "public, no-cache"
diff --git a/lib/pleroma/web/fallback_redirect_controller.ex b/lib/pleroma/web/fallback_redirect_controller.ex
index 431ad5485..a59c2a02e 100644
--- a/lib/pleroma/web/fallback_redirect_controller.ex
+++ b/lib/pleroma/web/fallback_redirect_controller.ex
@@ -75,7 +75,8 @@ defmodule Fallback.RedirectController do
end
defp index_file_path do
- Pleroma.Plugs.InstanceStatic.file_path("index.html")
+ {:ok, file} = Pleroma.Frontend.file_path("index.html", :primary)
+ file
end
defp build_tags(conn, params) do
diff --git a/lib/pleroma/web/preload/instance.ex b/lib/pleroma/web/preload/instance.ex
index 50d1f3382..ad8f33f6f 100644
--- a/lib/pleroma/web/preload/instance.ex
+++ b/lib/pleroma/web/preload/instance.ex
@@ -3,7 +3,6 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Preload.Providers.Instance do
- alias Pleroma.Plugs.InstanceStatic
alias Pleroma.Web.MastodonAPI.InstanceView
alias Pleroma.Web.Nodeinfo.Nodeinfo
alias Pleroma.Web.Preload.Providers.Provider
@@ -28,13 +27,13 @@ defmodule Pleroma.Web.Preload.Providers.Instance do
end
defp build_panel_tag(acc) do
- instance_path = InstanceStatic.file_path(@panel_url |> to_string())
+ case Pleroma.Frontend.file_path(@panel_url |> to_string()) do
+ {:ok, file} ->
+ panel_data = File.read!(file)
+ Map.put(acc, @panel_url, panel_data)
- if File.exists?(instance_path) do
- panel_data = File.read!(instance_path)
- Map.put(acc, @panel_url, panel_data)
- else
- acc
+ _ ->
+ acc
end
end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 386308362..b8c93a389 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -714,12 +714,13 @@ defmodule Pleroma.Web.Router do
get("/check_password", MongooseIMController, :check_password)
end
- scope "/", Fallback do
- get("/registration/:token", RedirectController, :registration_page)
- get("/:maybe_nickname_or_id", RedirectController, :redirector_with_meta)
- get("/api*path", RedirectController, :api_not_implemented)
- get("/*path", RedirectController, :redirector_with_preload)
-
- options("/*path", RedirectController, :empty)
+ scope "/" do
+ get("/registration/:token", Fallback.RedirectController, :registration_page)
+ get("/:maybe_nickname_or_id", Fallback.RedirectController, :redirector_with_meta)
+ get("/api*path", Fallback.RedirectController, :api_not_implemented)
+ # get("/*path", RedirectController, :redirector_with_preload)
+ get("/*path", Pleroma.Web.FrontendController, :redirector_with_preload)
+
+ options("/*path", Fallback.RedirectController, :empty)
end
end
diff --git a/lib/pleroma/web/web.ex b/lib/pleroma/web/web.ex
index 4f9281851..920d68461 100644
--- a/lib/pleroma/web/web.ex
+++ b/lib/pleroma/web/web.ex
@@ -120,6 +120,8 @@ defmodule Pleroma.Web do
conn
end
end
+
+ defoverridable(action: 2)
end
end
diff --git a/test/frontend_test.exs b/test/frontend_test.exs
new file mode 100644
index 000000000..ad8568092
--- /dev/null
+++ b/test/frontend_test.exs
@@ -0,0 +1,75 @@
+defmodule Pleroma.FrontendTest do
+ use ExUnit.Case
+ use Pleroma.Tests.Helpers
+
+ describe "get_config/1" do
+ test "Primary config" do
+ config = %{"name" => "monsta", "ref" => "pika"}
+
+ clear_config([:frontends, :primary], config)
+
+ fe_config = Pleroma.Frontend.get_config()
+ assert fe_config["config"] == config
+ assert fe_config["controller"] == Pleroma.Web.Frontend.MonstaController
+ end
+
+ test "Headless" do
+ config = %{"name" => "none", "ref" => "void"}
+
+ clear_config([:frontends, :primary], config)
+
+ fe_config = Pleroma.Frontend.get_config()
+ assert fe_config["config"] == %{}
+ assert fe_config["controller"] == Pleroma.Web.Frontend.HeadlessController
+ end
+ end
+
+ describe "file_path/2" do
+ @dir "test/tmp/instance_static"
+ @filename "gif.bat"
+
+ setup do
+ File.mkdir_p!(@dir)
+
+ config = %{"name" => "monsta", "ref" => "mew"}
+
+ clear_config([:frontends, :primary], config)
+ clear_config([:instance, :static_dir], @dir)
+
+ fe_path = Path.join([@dir, "frontends", config["name"], config["ref"]])
+ File.mkdir_p!(fe_path)
+ priv_path = Application.app_dir(:pleroma, ["priv", "static"])
+
+ on_exit(fn ->
+ File.rm_rf(@dir)
+ File.rm(Path.join(priv_path, @filename))
+ end)
+
+ {:ok, %{frontend_path: fe_path, priv_path: priv_path}}
+ end
+
+ test "instance static path priority", %{frontend_path: fp, priv_path: pp} do
+ Enum.each([@dir, fp, pp], &File.write!(Path.join(&1, @filename), "sup"))
+
+ assert Pleroma.Frontend.file_path(@filename) == {:ok, Path.join(@dir, @filename)}
+ end
+
+ test "frontend path priority", %{frontend_path: fp, priv_path: pp} do
+ Enum.each([fp, pp], &File.write!(Path.join(&1, @filename), "sup"))
+
+ assert Pleroma.Frontend.file_path(@filename) == {:ok, Path.join(fp, @filename)}
+ end
+
+ test "priv path fallback", %{priv_path: pp} do
+ File.write!(Path.join(pp, @filename), "sup")
+
+ assert Pleroma.Frontend.file_path(@filename) == {:ok, Path.join(pp, @filename)}
+ end
+
+ test "non-existing file" do
+ assert {:error, error} = Pleroma.Frontend.file_path("miseeen.jgp.pgn.mp5.avee")
+
+ assert String.valid?(error)
+ end
+ end
+end
diff --git a/test/plugs/frontend_plug_test.exs b/test/plugs/frontend_plug_test.exs
new file mode 100644
index 000000000..d75c7a54b
--- /dev/null
+++ b/test/plugs/frontend_plug_test.exs
@@ -0,0 +1,21 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.FrontendPlugTest do
+ use Pleroma.Web.ConnCase
+
+ test "Puts correct conn.private.frontend", %{conn: conn} do
+ config = %{"name" => "sake", "ref" => "beer"}
+
+ clear_config([:frontends, :primary], config)
+
+ plug = Pleroma.Plugs.FrontendPlug.init(nil)
+ conn = Pleroma.Plugs.FrontendPlug.call(conn, plug)
+
+ frontend = Map.get(conn.private, :frontend, %{})
+
+ assert frontend["controller"] == Pleroma.Web.Frontend.SakeController
+ assert frontend["config"] == config
+ end
+end
diff --git a/test/plugs/frontend_static_test.exs b/test/plugs/frontend_static_test.exs
index d11d91d78..c0ffc9bda 100644
--- a/test/plugs/frontend_static_test.exs
+++ b/test/plugs/frontend_static_test.exs
@@ -15,7 +15,7 @@ defmodule Pleroma.Web.FrontendStaticPlugTest do
setup do: clear_config([:instance, :static_dir], @dir)
test "overrides existing static files", %{conn: conn} do
- name = "pelmora"
+ name = "pleroma"
ref = "uguu"
clear_config([:frontends, :primary], %{"name" => name, "ref" => ref})
diff --git a/test/plugs/instance_static_test.exs b/test/plugs/instance_static_test.exs
index d42ba817e..c4c5e948e 100644
--- a/test/plugs/instance_static_test.exs
+++ b/test/plugs/instance_static_test.exs
@@ -6,14 +6,16 @@ defmodule Pleroma.Web.InstanceStaticPlugTest do
use Pleroma.Web.ConnCase
@dir "test/tmp/instance_static"
+ @fe_name "pleroma"
+ @fe_ref "uguu"
setup do
File.mkdir_p!(@dir)
on_exit(fn -> File.rm_rf(@dir) end)
+ clear_config([:instance, :static_dir], @dir)
+ clear_config([:frontends, :primary], %{"name" => @fe_name, "ref" => @fe_ref})
end
- setup do: clear_config([:instance, :static_dir], @dir)
-
test "overrides index" do
bundled_index = get(build_conn(), "/")
refute html_response(bundled_index, 200) == "hello world"
@@ -25,15 +27,10 @@ defmodule Pleroma.Web.InstanceStaticPlugTest do
end
test "also overrides frontend files", %{conn: conn} do
- name = "pelmora"
- ref = "uguu"
-
- clear_config([:frontends, :primary], %{"name" => name, "ref" => ref})
-
bundled_index = get(conn, "/")
refute html_response(bundled_index, 200) == "from frontend plug"
- path = "#{@dir}/frontends/#{name}/#{ref}"
+ path = "#{@dir}/frontends/#{@fe_name}/#{@fe_ref}"
File.mkdir_p!(path)
File.write!("#{path}/index.html", "from frontend plug")