@impl Plug
@doc """
- If marked as skipped, returns `conn`, otherwise calls `perform/2`.
+ Before-plug hook that
+ * ensures the plug is not skipped
+ * processes `:if_func` / `:unless_func` functional pre-run conditions
+ * adds plug to the list of called plugs and calls `perform/2` if checks are passed
+
Note: multiple invocations of the same plug (with different or same options) are allowed.
"""
def call(%Plug.Conn{} = conn, options) do
- if PlugHelper.plug_skipped?(conn, __MODULE__) do
+ if PlugHelper.plug_skipped?(conn, __MODULE__) ||
+ (options[:if_func] && !options[:if_func].(conn)) ||
+ (options[:unless_func] && options[:unless_func].(conn)) do
conn
else
conn =
--- /dev/null
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PlugTest do
+ @moduledoc "Tests for the functionality added via `use Pleroma.Web, :plug`"
+
+ alias Pleroma.Plugs.ExpectAuthenticatedCheckPlug
+ alias Pleroma.Plugs.ExpectPublicOrAuthenticatedCheckPlug
+ alias Pleroma.Plugs.PlugHelper
+
+ import Mock
+
+ use Pleroma.Web.ConnCase
+
+ describe "when plug is skipped, " do
+ setup_with_mocks(
+ [
+ {ExpectPublicOrAuthenticatedCheckPlug, [:passthrough], []}
+ ],
+ %{conn: conn}
+ ) do
+ conn = ExpectPublicOrAuthenticatedCheckPlug.skip_plug(conn)
+ %{conn: conn}
+ end
+
+ test "it neither adds plug to called plugs list nor calls `perform/2`, " <>
+ "regardless of :if_func / :unless_func options",
+ %{conn: conn} do
+ for opts <- [%{}, %{if_func: fn _ -> true end}, %{unless_func: fn _ -> false end}] do
+ ret_conn = ExpectPublicOrAuthenticatedCheckPlug.call(conn, opts)
+
+ refute called(ExpectPublicOrAuthenticatedCheckPlug.perform(:_, :_))
+ refute PlugHelper.plug_called?(ret_conn, ExpectPublicOrAuthenticatedCheckPlug)
+ end
+ end
+ end
+
+ describe "when plug is NOT skipped, " do
+ setup_with_mocks([{ExpectAuthenticatedCheckPlug, [:passthrough], []}]) do
+ :ok
+ end
+
+ test "with no pre-run checks, adds plug to called plugs list and calls `perform/2`", %{
+ conn: conn
+ } do
+ ret_conn = ExpectAuthenticatedCheckPlug.call(conn, %{})
+
+ assert called(ExpectAuthenticatedCheckPlug.perform(ret_conn, :_))
+ assert PlugHelper.plug_called?(ret_conn, ExpectAuthenticatedCheckPlug)
+ end
+
+ test "when :if_func option is given, calls the plug only if provided function evals tru-ish",
+ %{conn: conn} do
+ ret_conn = ExpectAuthenticatedCheckPlug.call(conn, %{if_func: fn _ -> false end})
+
+ refute called(ExpectAuthenticatedCheckPlug.perform(:_, :_))
+ refute PlugHelper.plug_called?(ret_conn, ExpectAuthenticatedCheckPlug)
+
+ ret_conn = ExpectAuthenticatedCheckPlug.call(conn, %{if_func: fn _ -> true end})
+
+ assert called(ExpectAuthenticatedCheckPlug.perform(ret_conn, :_))
+ assert PlugHelper.plug_called?(ret_conn, ExpectAuthenticatedCheckPlug)
+ end
+
+ test "if :unless_func option is given, calls the plug only if provided function evals falsy",
+ %{conn: conn} do
+ ret_conn = ExpectAuthenticatedCheckPlug.call(conn, %{unless_func: fn _ -> true end})
+
+ refute called(ExpectAuthenticatedCheckPlug.perform(:_, :_))
+ refute PlugHelper.plug_called?(ret_conn, ExpectAuthenticatedCheckPlug)
+
+ ret_conn = ExpectAuthenticatedCheckPlug.call(conn, %{unless_func: fn _ -> false end})
+
+ assert called(ExpectAuthenticatedCheckPlug.perform(ret_conn, :_))
+ assert PlugHelper.plug_called?(ret_conn, ExpectAuthenticatedCheckPlug)
+ end
+
+ test "allows a plug to be called multiple times (even if it's in called plugs list)", %{
+ conn: conn
+ } do
+ conn = ExpectAuthenticatedCheckPlug.call(conn, %{an_option: :value1})
+ assert called(ExpectAuthenticatedCheckPlug.perform(conn, %{an_option: :value1}))
+
+ assert PlugHelper.plug_called?(conn, ExpectAuthenticatedCheckPlug)
+
+ conn = ExpectAuthenticatedCheckPlug.call(conn, %{an_option: :value2})
+ assert called(ExpectAuthenticatedCheckPlug.perform(conn, %{an_option: :value2}))
+ end
+ end
+end