Browse Source

Merge branch 'frontend-bundles-redux' into 'develop'

Changeable frontends MVP

See merge request pleroma/pleroma!2801
frontends/logic-flow
lain 3 years ago
parent
commit
165ea038bd
8 changed files with 179 additions and 11 deletions
  1. +9
    -0
      config/config.exs
  2. +25
    -0
      config/description.exs
  3. +22
    -0
      docs/configuration/cheatsheet.md
  4. +54
    -0
      lib/pleroma/plugs/frontend_static.ex
  5. +5
    -10
      lib/pleroma/plugs/instance_static.ex
  6. +11
    -0
      lib/pleroma/web/endpoint.ex
  7. +30
    -0
      test/plugs/frontend_static_test.exs
  8. +23
    -1
      test/plugs/instance_static_test.exs

+ 9
- 0
config/config.exs View File

@@ -645,6 +645,15 @@ config :pleroma, Pleroma.Plugs.RemoteIp, enabled: true

config :pleroma, :static_fe, enabled: false

# Example of frontend configuration
# This example will make us serve the primary frontend from the
# `/frontends/pleroma/develop` folder in your instance static directory.
#
# With no frontend configuration, the bundled files from the `static` directory will
# be used.
#
# config :pleroma, :frontends, primary: %{"name" => "pleroma", "ref" => "develop"}

config :pleroma, :web_cache_ttl,
activity_pub: nil,
activity_pub_question: 30_000


+ 25
- 0
config/description.exs View File

@@ -3481,5 +3481,30 @@ config :pleroma, :config_description, [
suggestions: ["s3.eu-central-1.amazonaws.com"]
}
]
},
%{
group: :pleroma,
key: :frontends,
type: :group,
description: "Installed frontends management",
children: [
%{
key: :primary,
type: :map,
description: "Primary frontend, the one that is served for all pages by default",
children: [
%{
key: "name",
type: :string,
description: "Name of the installed primary frontend"
},
%{
key: "ref",
type: :string,
description: "reference of the installed primary frontend to be used"
}
]
}
]
}
]

+ 22
- 0
docs/configuration/cheatsheet.md View File

@@ -1046,3 +1046,25 @@ Note: setting `restrict_unauthenticated/timelines/local` to `true` has no practi
Control favicons for instances.

* `enabled`: Allow/disallow displaying and getting instances favicons

## Frontend management

Frontends in Pleroma are swappable - you can specify which one to use here.

For now, you can set a frontend with the key `primary` and the options of `name` and `ref`. This will then make Pleroma serve the frontend from a folder constructed by concatenating the instance static path, `frontends` and the name and ref.

The key `primary` refers to the frontend that will be served by default for general requests. In the future, other frontends like the admin frontend will also be configurable here.

If you don't set anything here, the bundled frontend will be used.

Example:

```
config :pleroma, :frontends,
primary: %{
"name" => "pleroma",
"ref" => "stable"
}
```

This would serve the frontend from the the folder at `$instance_static/frontends/pleroma/stable`. You have to copy the frontend into this folder yourself. You can choose the name and ref any way you like, but they will be used by mix tasks to automate installation in the future, the name referring to the project and the ref referring to a commit.

+ 54
- 0
lib/pleroma/plugs/frontend_static.ex View File

@@ -0,0 +1,54 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Plugs.FrontendStatic do
require Pleroma.Constants

@moduledoc """
This is a shim to call `Plug.Static` but with runtime `from` configuration`. It dispatches to the different frontends.
"""
@behaviour Plug

def file_path(path, frontend_type \\ :primary) do
if configuration = Pleroma.Config.get([:frontends, frontend_type]) do
instance_static_path = Pleroma.Config.get([:instance, :static_dir], "instance/static")

Path.join([
instance_static_path,
"frontends",
configuration["name"],
configuration["ref"],
path
])
else
nil
end
end

def init(opts) do
opts
|> Keyword.put(:from, "__unconfigured_frontend_static_plug")
|> Plug.Static.init()
end

def call(conn, opts) do
frontend_type = Map.get(opts, :frontend_type, :primary)
path = file_path("", frontend_type)

if path do
conn
|> call_static(opts, path)
else
conn
end
end

defp call_static(conn, opts, from) do
opts =
opts
|> Map.put(:from, from)

Plug.Static.call(conn, opts)
end
end

+ 5
- 10
lib/pleroma/plugs/instance_static.ex View File

@@ -16,28 +16,24 @@ defmodule Pleroma.Plugs.InstanceStatic do
instance_path =
Path.join(Pleroma.Config.get([:instance, :static_dir], "instance/static/"), path)

if File.exists?(instance_path) do
instance_path
else
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
end

def init(opts) do
opts
|> Keyword.put(:from, "__unconfigured_instance_static_plug")
|> Keyword.put(:at, "/__unconfigured_instance_static_plug")
|> Plug.Static.init()
end

for only <- Pleroma.Constants.static_only_files() do
at = Plug.Router.Utils.split("/")

def call(%{request_path: "/" <> unquote(only) <> _} = conn, opts) do
call_static(
conn,
opts,
unquote(at),
Pleroma.Config.get([:instance, :static_dir], "instance/static")
)
end
@@ -47,11 +43,10 @@ defmodule Pleroma.Plugs.InstanceStatic do
conn
end

defp call_static(conn, opts, at, from) do
defp call_static(conn, opts, from) do
opts =
opts
|> Map.put(:from, from)
|> Map.put(:at, at)

Plug.Static.call(conn, opts)
end


+ 11
- 0
lib/pleroma/web/endpoint.ex View File

@@ -28,6 +28,17 @@ defmodule Pleroma.Web.Endpoint do
}
)

# Careful! No `only` restriction here, as we don't know what frontends contain.
plug(Pleroma.Plugs.FrontendStatic,
at: "/",
frontend_type: :primary,
gzip: true,
cache_control_for_etags: @static_cache_control,
headers: %{
"cache-control" => @static_cache_control
}
)

# Serve at "/" the static files from "priv/static" directory.
#
# You should set gzip to true if you are running phoenix.digest


+ 30
- 0
test/plugs/frontend_static_test.exs View File

@@ -0,0 +1,30 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.FrontendStaticPlugTest do
use Pleroma.Web.ConnCase

@dir "test/tmp/instance_static"

setup do
File.mkdir_p!(@dir)
on_exit(fn -> File.rm_rf(@dir) end)
end

setup do: clear_config([:instance, :static_dir], @dir)

test "overrides existing static files", %{conn: conn} do
name = "pelmora"
ref = "uguu"

clear_config([:frontends, :primary], %{"name" => name, "ref" => ref})
path = "#{@dir}/frontends/#{name}/#{ref}"

File.mkdir_p!(path)
File.write!("#{path}/index.html", "from frontend plug")

index = get(conn, "/")
assert html_response(index, 200) == "from frontend plug"
end
end

+ 23
- 1
test/plugs/instance_static_test.exs View File

@@ -2,7 +2,7 @@
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.RuntimeStaticPlugTest do
defmodule Pleroma.Web.InstanceStaticPlugTest do
use Pleroma.Web.ConnCase

@dir "test/tmp/instance_static"
@@ -24,6 +24,28 @@ defmodule Pleroma.Web.RuntimeStaticPlugTest do
assert html_response(index, 200) == "hello world"
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}"
File.mkdir_p!(path)
File.write!("#{path}/index.html", "from frontend plug")

index = get(conn, "/")
assert html_response(index, 200) == "from frontend plug"

File.write!(@dir <> "/index.html", "from instance static")

index = get(conn, "/")
assert html_response(index, 200) == "from instance static"
end

test "overrides any file in static/static" do
bundled_index = get(build_conn(), "/static/terms-of-service.html")



Loading…
Cancel
Save