preload data into index.html
authorstwf <steven.fuchs@dockyard.com>
Tue, 12 May 2020 15:08:00 +0000 (11:08 -0400)
committerstwf <steven.fuchs@dockyard.com>
Wed, 3 Jun 2020 20:34:03 +0000 (16:34 -0400)
15 files changed:
config/config.exs
lib/pleroma/web/fallback_redirect_controller.ex
lib/pleroma/web/nodeinfo/nodeinfo.ex [new file with mode: 0644]
lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
lib/pleroma/web/preload.ex [new file with mode: 0644]
lib/pleroma/web/preload/instance.ex [new file with mode: 0644]
lib/pleroma/web/preload/provider.ex [new file with mode: 0644]
lib/pleroma/web/preload/timelines.ex [new file with mode: 0644]
lib/pleroma/web/preload/user.ex [new file with mode: 0644]
lib/pleroma/web/router.ex
test/plugs/instance_static_test.exs
test/web/fallback_test.exs
test/web/preload/instance_test.exs [new file with mode: 0644]
test/web/preload/timeline_test.exs [new file with mode: 0644]
test/web/preload/user_test.exs [new file with mode: 0644]

index 9508ae07718a24ddfb906506b150154edaa5527b..ee81eb89959419cf5a1e8430c32c027843186022 100644 (file)
@@ -241,18 +241,7 @@ config :pleroma, :instance,
   account_field_value_length: 2048,
   external_user_synchronization: true,
   extended_nickname_format: true,
-  cleanup_attachments: false,
-  multi_factor_authentication: [
-    totp: [
-      # digits 6 or 8
-      digits: 6,
-      period: 30
-    ],
-    backup_codes: [
-      number: 5,
-      length: 16
-    ]
-  ]
+  cleanup_attachments: false
 
 config :pleroma, :feed,
   post_title: %{
@@ -361,8 +350,7 @@ config :pleroma, :mrf_simple,
   reject: [],
   accept: [],
   avatar_removal: [],
-  banner_removal: [],
-  reject_deletes: []
+  banner_removal: []
 
 config :pleroma, :mrf_keyword,
   reject: [],
@@ -428,6 +416,13 @@ config :pleroma, Pleroma.Web.Metadata,
   ],
   unfurl_nsfw: false
 
+config :pleroma, Pleroma.Web.Preload,
+  providers: [
+    Pleroma.Web.Preload.Providers.Instance,
+    Pleroma.Web.Preload.Providers.User,
+    Pleroma.Web.Preload.Providers.Timelines
+  ]
+
 config :pleroma, :http_security,
   enabled: true,
   sts: false,
@@ -682,8 +677,6 @@ config :pleroma, :restrict_unauthenticated,
   profiles: %{local: false, remote: false},
   activities: %{local: false, remote: false}
 
-config :pleroma, Pleroma.Web.ApiSpec.CastAndValidate, strict: false
-
 # Import environment specific config. This must remain at the bottom
 # of this file so it overrides the configuration defined above.
 import_config "#{Mix.env()}.exs"
index 0d9d578fcc2895f9e0690e8f4a28abeef98e4e01..932fb8d7ef647220261c4525cde604c220a25674 100644 (file)
@@ -4,11 +4,10 @@
 
 defmodule Fallback.RedirectController do
   use Pleroma.Web, :controller
-
   require Logger
-
   alias Pleroma.User
   alias Pleroma.Web.Metadata
+  alias Pleroma.Web.Preload
 
   def api_not_implemented(conn, _params) do
     conn
@@ -16,16 +15,7 @@ defmodule Fallback.RedirectController do
     |> json(%{error: "Not implemented"})
   end
 
-  def redirector(conn, _params, code \\ 200)
-
-  # redirect to admin section
-  # /pleroma/admin -> /pleroma/admin/
-  #
-  def redirector(conn, %{"path" => ["pleroma", "admin"]} = _, _code) do
-    redirect(conn, to: "/pleroma/admin/")
-  end
-
-  def redirector(conn, _params, code) do
+  def redirector(conn, _params, code \\ 200) do
     conn
     |> put_resp_content_type("text/html")
     |> send_file(code, index_file_path())
@@ -43,28 +33,34 @@ defmodule Fallback.RedirectController do
   def redirector_with_meta(conn, params) do
     {:ok, index_content} = File.read(index_file_path())
 
-    tags =
-      try do
-        Metadata.build_tags(params)
-      rescue
-        e ->
-          Logger.error(
-            "Metadata rendering for #{conn.request_path} failed.\n" <>
-              Exception.format(:error, e, __STACKTRACE__)
-          )
-
-          ""
-      end
+    tags = build_tags(conn, params)
+    preloads = preload_data(conn, params)
 
-    response = String.replace(index_content, "<!--server-generated-meta-->", tags)
+    response =
+      index_content
+      |> String.replace("<!--server-generated-meta-->", tags)
+      |> String.replace("<!--server-generated-initial-data-->", preloads)
 
     conn
     |> put_resp_content_type("text/html")
     |> send_resp(200, response)
   end
 
-  def index_file_path do
-    Pleroma.Plugs.InstanceStatic.file_path("index.html")
+  def redirector_with_preload(conn, %{"path" => ["pleroma", "admin"]}) do
+    redirect(conn, to: "/pleroma/admin/")
+  end
+
+  def redirector_with_preload(conn, params) do
+    {:ok, index_content} = File.read(index_file_path())
+    preloads = preload_data(conn, params)
+
+    response =
+      index_content
+      |> String.replace("<!--server-generated-initial-data-->", preloads)
+
+    conn
+    |> put_resp_content_type("text/html")
+    |> send_resp(200, response)
   end
 
   def registration_page(conn, params) do
@@ -76,4 +72,36 @@ defmodule Fallback.RedirectController do
     |> put_status(204)
     |> text("")
   end
+
+  defp index_file_path do
+    Pleroma.Plugs.InstanceStatic.file_path("index.html")
+  end
+
+  defp build_tags(conn, params) do
+    try do
+      Metadata.build_tags(params)
+    rescue
+      e ->
+        Logger.error(
+          "Metadata rendering for #{conn.request_path} failed.\n" <>
+            Exception.format(:error, e, __STACKTRACE__)
+        )
+
+        ""
+    end
+  end
+
+  defp preload_data(conn, params) do
+    try do
+      Preload.build_tags(conn, params)
+    rescue
+      e ->
+        Logger.error(
+          "Preloading for #{conn.request_path} failed.\n" <>
+            Exception.format(:error, e, __STACKTRACE__)
+        )
+
+        ""
+    end
+  end
 end
diff --git a/lib/pleroma/web/nodeinfo/nodeinfo.ex b/lib/pleroma/web/nodeinfo/nodeinfo.ex
new file mode 100644 (file)
index 0000000..d26b7c9
--- /dev/null
@@ -0,0 +1,130 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Nodeinfo.Nodeinfo do
+  alias Pleroma.Config
+  alias Pleroma.Stats
+  alias Pleroma.User
+  alias Pleroma.Web.ActivityPub.MRF
+  alias Pleroma.Web.Federator.Publisher
+
+  # returns a nodeinfo 2.0 map, since 2.1 just adds a repository field
+  # under software.
+  def get_nodeinfo("2.0") do
+    stats = Stats.get_stats()
+
+    quarantined = Config.get([:instance, :quarantined_instances], [])
+
+    staff_accounts =
+      User.all_superusers()
+      |> Enum.map(fn u -> u.ap_id end)
+
+    federation_response =
+      if Config.get([:instance, :mrf_transparency]) do
+        {:ok, data} = MRF.describe()
+
+        data
+        |> Map.merge(%{quarantined_instances: quarantined})
+      else
+        %{}
+      end
+      |> Map.put(:enabled, Config.get([:instance, :federating]))
+
+    features =
+      [
+        "pleroma_api",
+        "mastodon_api",
+        "mastodon_api_streaming",
+        "polls",
+        "pleroma_explicit_addressing",
+        "shareable_emoji_packs",
+        "multifetch",
+        "pleroma:api/v1/notifications:include_types_filter",
+        if Config.get([:media_proxy, :enabled]) do
+          "media_proxy"
+        end,
+        if Config.get([:gopher, :enabled]) do
+          "gopher"
+        end,
+        if Config.get([:chat, :enabled]) do
+          "chat"
+        end,
+        if Config.get([:instance, :allow_relay]) do
+          "relay"
+        end,
+        if Config.get([:instance, :safe_dm_mentions]) do
+          "safe_dm_mentions"
+        end,
+        "pleroma_emoji_reactions"
+      ]
+      |> Enum.filter(& &1)
+
+    %{
+      version: "2.0",
+      software: %{
+        name: Pleroma.Application.name() |> String.downcase(),
+        version: Pleroma.Application.version()
+      },
+      protocols: Publisher.gather_nodeinfo_protocol_names(),
+      services: %{
+        inbound: [],
+        outbound: []
+      },
+      openRegistrations: Config.get([:instance, :registrations_open]),
+      usage: %{
+        users: %{
+          total: Map.get(stats, :user_count, 0)
+        },
+        localPosts: Map.get(stats, :status_count, 0)
+      },
+      metadata: %{
+        nodeName: Config.get([:instance, :name]),
+        nodeDescription: Config.get([:instance, :description]),
+        private: !Config.get([:instance, :public], true),
+        suggestions: %{
+          enabled: false
+        },
+        staffAccounts: staff_accounts,
+        federation: federation_response,
+        pollLimits: Config.get([:instance, :poll_limits]),
+        postFormats: Config.get([:instance, :allowed_post_formats]),
+        uploadLimits: %{
+          general: Config.get([:instance, :upload_limit]),
+          avatar: Config.get([:instance, :avatar_upload_limit]),
+          banner: Config.get([:instance, :banner_upload_limit]),
+          background: Config.get([:instance, :background_upload_limit])
+        },
+        fieldsLimits: %{
+          maxFields: Config.get([:instance, :max_account_fields]),
+          maxRemoteFields: Config.get([:instance, :max_remote_account_fields]),
+          nameLength: Config.get([:instance, :account_field_name_length]),
+          valueLength: Config.get([:instance, :account_field_value_length])
+        },
+        accountActivationRequired: Config.get([:instance, :account_activation_required], false),
+        invitesEnabled: Config.get([:instance, :invites_enabled], false),
+        mailerEnabled: Config.get([Pleroma.Emails.Mailer, :enabled], false),
+        features: features,
+        restrictedNicknames: Config.get([Pleroma.User, :restricted_nicknames]),
+        skipThreadContainment: Config.get([:instance, :skip_thread_containment], false)
+      }
+    }
+  end
+
+  def get_nodeinfo("2.1") do
+    raw_response = get_nodeinfo("2.0")
+
+    updated_software =
+      raw_response
+      |> Map.get(:software)
+      |> Map.put(:repository, Pleroma.Application.repository())
+
+    raw_response
+    |> Map.put(:software, updated_software)
+    |> Map.put(:version, "2.1")
+  end
+
+  def get_nodeinfo(_version) do
+    {:error, :missing}
+  end
+end
index 721b599d4b0df32a3d318e6e6cc68dcc28efc47b..8c7a9e56510d1f8ba80f7456963d7f971fe27682 100644 (file)
@@ -5,12 +5,8 @@
 defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
   use Pleroma.Web, :controller
 
-  alias Pleroma.Config
-  alias Pleroma.Stats
-  alias Pleroma.User
   alias Pleroma.Web
-  alias Pleroma.Web.Federator.Publisher
-  alias Pleroma.Web.MastodonAPI.InstanceView
+  alias Pleroma.Web.Nodeinfo.Nodeinfo
 
   def schemas(conn, _params) do
     response = %{
@@ -29,102 +25,20 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
     json(conn, response)
   end
 
-  # returns a nodeinfo 2.0 map, since 2.1 just adds a repository field
-  # under software.
-  def raw_nodeinfo do
-    stats = Stats.get_stats()
-
-    staff_accounts =
-      User.all_superusers()
-      |> Enum.map(fn u -> u.ap_id end)
-
-    features = InstanceView.features()
-    federation = InstanceView.federation()
-
-    %{
-      version: "2.0",
-      software: %{
-        name: Pleroma.Application.name() |> String.downcase(),
-        version: Pleroma.Application.version()
-      },
-      protocols: Publisher.gather_nodeinfo_protocol_names(),
-      services: %{
-        inbound: [],
-        outbound: []
-      },
-      openRegistrations: Config.get([:instance, :registrations_open]),
-      usage: %{
-        users: %{
-          total: Map.get(stats, :user_count, 0)
-        },
-        localPosts: Map.get(stats, :status_count, 0)
-      },
-      metadata: %{
-        nodeName: Config.get([:instance, :name]),
-        nodeDescription: Config.get([:instance, :description]),
-        private: !Config.get([:instance, :public], true),
-        suggestions: %{
-          enabled: false
-        },
-        staffAccounts: staff_accounts,
-        federation: federation,
-        pollLimits: Config.get([:instance, :poll_limits]),
-        postFormats: Config.get([:instance, :allowed_post_formats]),
-        uploadLimits: %{
-          general: Config.get([:instance, :upload_limit]),
-          avatar: Config.get([:instance, :avatar_upload_limit]),
-          banner: Config.get([:instance, :banner_upload_limit]),
-          background: Config.get([:instance, :background_upload_limit])
-        },
-        fieldsLimits: %{
-          maxFields: Config.get([:instance, :max_account_fields]),
-          maxRemoteFields: Config.get([:instance, :max_remote_account_fields]),
-          nameLength: Config.get([:instance, :account_field_name_length]),
-          valueLength: Config.get([:instance, :account_field_value_length])
-        },
-        accountActivationRequired: Config.get([:instance, :account_activation_required], false),
-        invitesEnabled: Config.get([:instance, :invites_enabled], false),
-        mailerEnabled: Config.get([Pleroma.Emails.Mailer, :enabled], false),
-        features: features,
-        restrictedNicknames: Config.get([Pleroma.User, :restricted_nicknames]),
-        skipThreadContainment: Config.get([:instance, :skip_thread_containment], false)
-      }
-    }
-  end
-
   # Schema definition: https://github.com/jhass/nodeinfo/blob/master/schemas/2.0/schema.json
   # and https://github.com/jhass/nodeinfo/blob/master/schemas/2.1/schema.json
-  def nodeinfo(conn, %{"version" => "2.0"}) do
-    conn
-    |> put_resp_header(
-      "content-type",
-      "application/json; profile=http://nodeinfo.diaspora.software/ns/schema/2.0#; charset=utf-8"
-    )
-    |> json(raw_nodeinfo())
-  end
-
-  def nodeinfo(conn, %{"version" => "2.1"}) do
-    raw_response = raw_nodeinfo()
-
-    updated_software =
-      raw_response
-      |> Map.get(:software)
-      |> Map.put(:repository, Pleroma.Application.repository())
-
-    response =
-      raw_response
-      |> Map.put(:software, updated_software)
-      |> Map.put(:version, "2.1")
-
-    conn
-    |> put_resp_header(
-      "content-type",
-      "application/json; profile=http://nodeinfo.diaspora.software/ns/schema/2.1#; charset=utf-8"
-    )
-    |> json(response)
-  end
-
-  def nodeinfo(conn, _) do
-    render_error(conn, :not_found, "Nodeinfo schema version not handled")
+  def nodeinfo(conn, %{"version" => version}) do
+    case Nodeinfo.get_nodeinfo(version) do
+      {:error, :missing} ->
+        render_error(conn, :not_found, "Nodeinfo schema version not handled")
+
+      node_info ->
+        conn
+        |> put_resp_header(
+          "content-type",
+          "application/json; profile=http://nodeinfo.diaspora.software/ns/schema/2.0#; charset=utf-8"
+        )
+        |> json(node_info)
+    end
   end
 end
diff --git a/lib/pleroma/web/preload.ex b/lib/pleroma/web/preload.ex
new file mode 100644 (file)
index 0000000..c2211c5
--- /dev/null
@@ -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.Preload do
+  alias Phoenix.HTML
+  require Logger
+
+  def build_tags(_conn, params) do
+    preload_data =
+      Enum.reduce(Pleroma.Config.get([__MODULE__, :providers], []), %{}, fn parser, acc ->
+        Map.merge(acc, parser.generate_terms(params))
+      end)
+
+    rendered_html =
+      preload_data
+      |> Jason.encode!()
+      |> build_script_tag()
+      |> HTML.safe_to_string()
+
+    rendered_html
+  end
+
+  def build_script_tag(content) do
+    HTML.Tag.content_tag(:script, HTML.raw(content),
+      id: "initial-results",
+      type: "application/json"
+    )
+  end
+end
diff --git a/lib/pleroma/web/preload/instance.ex b/lib/pleroma/web/preload/instance.ex
new file mode 100644 (file)
index 0000000..0b6fd33
--- /dev/null
@@ -0,0 +1,49 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Preload.Providers.Instance do
+  alias Pleroma.Web.MastodonAPI.InstanceView
+  alias Pleroma.Web.Nodeinfo.Nodeinfo
+  alias Pleroma.Web.Preload.Providers.Provider
+
+  @behaviour Provider
+  @instance_url :"/api/v1/instance"
+  @panel_url :"/instance/panel.html"
+  @nodeinfo_url :"/nodeinfo/2.0"
+
+  @impl Provider
+  def generate_terms(_params) do
+    %{}
+    |> build_info_tag()
+    |> build_panel_tag()
+    |> build_nodeinfo_tag()
+  end
+
+  defp build_info_tag(acc) do
+    info_data = InstanceView.render("show.json", %{})
+
+    Map.put(acc, @instance_url, info_data)
+  end
+
+  defp build_panel_tag(acc) do
+    instance_path = Path.join(:code.priv_dir(:pleroma), "static/instance/panel.html")
+
+    if File.exists?(instance_path) do
+      panel_data = File.read!(instance_path)
+      Map.put(acc, @panel_url, panel_data)
+    else
+      acc
+    end
+  end
+
+  defp build_nodeinfo_tag(acc) do
+    case Nodeinfo.get_nodeinfo("2.0") do
+      {:error, _} ->
+        acc
+
+      nodeinfo_data ->
+        Map.put(acc, @nodeinfo_url, nodeinfo_data)
+    end
+  end
+end
diff --git a/lib/pleroma/web/preload/provider.ex b/lib/pleroma/web/preload/provider.ex
new file mode 100644 (file)
index 0000000..7ef595a
--- /dev/null
@@ -0,0 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Preload.Providers.Provider do
+  @callback generate_terms(map()) :: map()
+end
diff --git a/lib/pleroma/web/preload/timelines.ex b/lib/pleroma/web/preload/timelines.ex
new file mode 100644 (file)
index 0000000..dbd7db4
--- /dev/null
@@ -0,0 +1,42 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Preload.Providers.Timelines do
+  alias Pleroma.Web.ActivityPub.ActivityPub
+  alias Pleroma.Web.MastodonAPI.StatusView
+  alias Pleroma.Web.Preload.Providers.Provider
+
+  @behaviour Provider
+  @public_url :"/api/v1/timelines/public"
+
+  @impl Provider
+  def generate_terms(_params) do
+    build_public_tag(%{})
+  end
+
+  def build_public_tag(acc) do
+    if Pleroma.Config.get([:restrict_unauthenticated, :timelines, :federated], true) do
+      acc
+    else
+      Map.put(acc, @public_url, public_timeline(nil))
+    end
+  end
+
+  defp public_timeline(user) do
+    activities =
+      create_timeline_params(user)
+      |> Map.put("local_only", false)
+      |> ActivityPub.fetch_public_activities()
+
+    StatusView.render("index.json", activities: activities, for: user, as: :activity)
+  end
+
+  defp create_timeline_params(user) do
+    %{}
+    |> Map.put("type", ["Create", "Announce"])
+    |> Map.put("blocking_user", user)
+    |> Map.put("muting_user", user)
+    |> Map.put("user", user)
+  end
+end
diff --git a/lib/pleroma/web/preload/user.ex b/lib/pleroma/web/preload/user.ex
new file mode 100644 (file)
index 0000000..3a24484
--- /dev/null
@@ -0,0 +1,25 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Preload.Providers.User do
+  alias Pleroma.Web.MastodonAPI.AccountView
+  alias Pleroma.Web.Preload.Providers.Provider
+
+  @behaviour Provider
+  @account_url :"/api/v1/accounts"
+
+  @impl Provider
+  def generate_terms(%{user: user}) do
+    build_accounts_tag(%{}, user)
+  end
+
+  def generate_terms(_params), do: %{}
+
+  def build_accounts_tag(acc, nil), do: acc
+
+  def build_accounts_tag(acc, user) do
+    account_data = AccountView.render("show.json", %{user: user, for: user})
+    Map.put(acc, @account_url, account_data)
+  end
+end
index 80ea283649df068854f0011b54f1c7446899c5a8..3b55afedee6266658c845296c3d69f5cb30c40c2 100644 (file)
@@ -718,7 +718,7 @@ defmodule Pleroma.Web.Router 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)
+    get("/*path", RedirectController, :redirector_with_preload)
 
     options("/*path", RedirectController, :empty)
   end
index b8f070d6ad6f7b7742b15ab27b2df56db54abc51..be2613ad098ce0907345679811639017a7a91b30 100644 (file)
@@ -16,7 +16,7 @@ defmodule Pleroma.Web.RuntimeStaticPlugTest do
 
   test "overrides index" do
     bundled_index = get(build_conn(), "/")
-    assert html_response(bundled_index, 200) == File.read!("priv/static/index.html")
+    refute html_response(bundled_index, 200) == "hello world"
 
     File.write!(@dir <> "/index.html", "hello world")
 
index 3919ef93a35db61b212e48d423e5e62fbbedc1f6..3b7a51d5e2757a6b0ad8e76f546ceaf08dbbc8a8 100644 (file)
@@ -6,22 +6,36 @@ defmodule Pleroma.Web.FallbackTest do
   use Pleroma.Web.ConnCase
   import Pleroma.Factory
 
-  test "GET /registration/:token", %{conn: conn} do
-    assert conn
-           |> get("/registration/foo")
-           |> html_response(200) =~ "<!--server-generated-meta-->"
+  describe "neither preloaded data nor metadata attached to" do
+    test "GET /registration/:token", %{conn: conn} do
+      response = get(conn, "/registration/foo")
+
+      assert html_response(response, 200) =~ "<!--server-generated-meta-->"
+      assert html_response(response, 200) =~ "<!--server-generated-initial-data-->"
+    end
   end
 
-  test "GET /:maybe_nickname_or_id", %{conn: conn} do
-    user = insert(:user)
+  describe "preloaded data and metadata attached to" do
+    test "GET /:maybe_nickname_or_id", %{conn: conn} do
+      user = insert(:user)
+      user_missing = get(conn, "/foo")
+      user_present = get(conn, "/#{user.nickname}")
 
-    assert conn
-           |> get("/foo")
-           |> html_response(200) =~ "<!--server-generated-meta-->"
+      assert html_response(user_missing, 200) =~ "<!--server-generated-meta-->"
+      refute html_response(user_present, 200) =~ "<!--server-generated-meta-->"
 
-    refute conn
-           |> get("/" <> user.nickname)
-           |> html_response(200) =~ "<!--server-generated-meta-->"
+      assert html_response(user_missing, 200) =~ "<!--server-generated-initial-data-->"
+      refute html_response(user_present, 200) =~ "<!--server-generated-initial-data-->"
+    end
+  end
+
+  describe "preloaded data only attached to" do
+    test "GET /*path", %{conn: conn} do
+      public_page = get(conn, "/main/public")
+
+      assert html_response(public_page, 200) =~ "<!--server-generated-meta-->"
+      refute html_response(public_page, 200) =~ "<!--server-generated-initial-data-->"
+    end
   end
 
   test "GET /api*path", %{conn: conn} do
diff --git a/test/web/preload/instance_test.exs b/test/web/preload/instance_test.exs
new file mode 100644 (file)
index 0000000..52f9bab
--- /dev/null
@@ -0,0 +1,37 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Preload.Providers.InstanceTest do
+  use Pleroma.DataCase
+  alias Pleroma.Web.Preload.Providers.Instance
+
+  setup do: {:ok, Instance.generate_terms(nil)}
+
+  test "it renders the info", %{"/api/v1/instance": info} do
+    assert %{
+             description: description,
+             email: "admin@example.com",
+             registrations: true
+           } = info
+
+    assert String.equivalent?(description, "A Pleroma instance, an alternative fediverse server")
+  end
+
+  test "it renders the panel", %{"/instance/panel.html": panel} do
+    assert String.contains?(
+             panel,
+             "<p>Welcome to <a href=\"https://pleroma.social\" target=\"_blank\">Pleroma!</a></p>"
+           )
+  end
+
+  test "it renders the node_info", %{"/nodeinfo/2.0": nodeinfo} do
+    %{
+      metadata: metadata,
+      version: "2.0"
+    } = nodeinfo
+
+    assert metadata.private == false
+    assert metadata.suggestions == %{enabled: false}
+  end
+end
diff --git a/test/web/preload/timeline_test.exs b/test/web/preload/timeline_test.exs
new file mode 100644 (file)
index 0000000..00b10d0
--- /dev/null
@@ -0,0 +1,74 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Preload.Providers.TimelineTest do
+  use Pleroma.DataCase
+  import Pleroma.Factory
+
+  alias Pleroma.Web.CommonAPI
+  alias Pleroma.Web.Preload.Providers.Timelines
+
+  @public_url :"/api/v1/timelines/public"
+
+  describe "unauthenticated timeliness when restricted" do
+    setup do
+      svd_config = Pleroma.Config.get([:restrict_unauthenticated, :timelines])
+      Pleroma.Config.put([:restrict_unauthenticated, :timelines], %{local: true, federated: true})
+
+      on_exit(fn ->
+        Pleroma.Config.put([:restrict_unauthenticated, :timelines], svd_config)
+      end)
+
+      :ok
+    end
+
+    test "return nothing" do
+      tl_data = Timelines.generate_terms(%{})
+
+      refute Map.has_key?(tl_data, "/api/v1/timelines/public")
+    end
+  end
+
+  describe "unauthenticated timeliness when unrestricted" do
+    setup do
+      svd_config = Pleroma.Config.get([:restrict_unauthenticated, :timelines])
+
+      Pleroma.Config.put([:restrict_unauthenticated, :timelines], %{
+        local: false,
+        federated: false
+      })
+
+      on_exit(fn ->
+        Pleroma.Config.put([:restrict_unauthenticated, :timelines], svd_config)
+      end)
+
+      {:ok, user: insert(:user)}
+    end
+
+    test "returns the timeline when not restricted" do
+      assert Timelines.generate_terms(%{})
+             |> Map.has_key?(@public_url)
+    end
+
+    test "returns public items", %{user: user} do
+      {:ok, _} = CommonAPI.post(user, %{"status" => "it's post 1!"})
+      {:ok, _} = CommonAPI.post(user, %{"status" => "it's post 2!"})
+      {:ok, _} = CommonAPI.post(user, %{"status" => "it's post 3!"})
+
+      assert Timelines.generate_terms(%{})
+             |> Map.fetch!(@public_url)
+             |> Enum.count() == 3
+    end
+
+    test "does not return non-public items", %{user: user} do
+      {:ok, _} = CommonAPI.post(user, %{"status" => "it's post 1!", "visibility" => "unlisted"})
+      {:ok, _} = CommonAPI.post(user, %{"status" => "it's post 2!", "visibility" => "direct"})
+      {:ok, _} = CommonAPI.post(user, %{"status" => "it's post 3!"})
+
+      assert Timelines.generate_terms(%{})
+             |> Map.fetch!(@public_url)
+             |> Enum.count() == 1
+    end
+  end
+end
diff --git a/test/web/preload/user_test.exs b/test/web/preload/user_test.exs
new file mode 100644 (file)
index 0000000..99232cd
--- /dev/null
@@ -0,0 +1,33 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Preload.Providers.UserTest do
+  use Pleroma.DataCase
+  import Pleroma.Factory
+  alias Pleroma.Web.Preload.Providers.User
+
+  describe "returns empty when user doesn't exist" do
+    test "nil user specified" do
+      refute User.generate_terms(%{user: nil})
+             |> Map.has_key?("/api/v1/accounts")
+    end
+
+    test "missing user specified" do
+      refute User.generate_terms(%{user: :not_a_user})
+             |> Map.has_key?("/api/v1/accounts")
+    end
+  end
+
+  describe "specified user exists" do
+    setup do
+      user = insert(:user)
+
+      {:ok, User.generate_terms(%{user: user})}
+    end
+
+    test "account is rendered", %{"/api/v1/accounts": accounts} do
+      assert %{acct: user, username: user} = accounts
+    end
+  end
+end