ExEssentials.Web.Plugs.DisableServices behaviour (ExEssentials v0.8.0)
View SourceA Plug that conditionally disables specific controller actions based on a feature flag,
with optional support for group-based evaluation using FunWithFlags.
Overview
This plug allows developers to temporarily disable specific Phoenix actions
(e.g., :create, :delete) by checking if a feature flag is enabled for the current context (typically, the current user or realm).
It works by intercepting the connection and returning a 503 Service Unavailable
response if the feature flag is enabled and the requested action is among the disabled ones.
Group-based targeting is supported through FunWithFlags, using a struct that includes
the current user as current_user.
Configuration
You must provide the following options when using the plug:
:disabled_actions– a list of controller actions (atoms) that should be disabled if the flag is active.:flag_name– the name of the feature flag to check (defaults to:disable_services_enabled).
This plug uses FunWithFlags.enabled?/2 with a custom context struct that supports group checks via FunWithFlags.Group.
Dependencies
To use this plug, your application must be configured with:
{:fun_with_flags, "~> 1.13"},
{:ecto_sql, "~> 3.4"},
{:postgrex, ">= 0.0.0"},And you must configure the FunWithFlags adapter to use Ecto with a repo.
Usage
Simple usage (default behavior)
By default, the plug uses conn.assigns.user_name or conn.params["user_name"] to resolve the group.
plug ExEssentials.Web.Plugs.DisableServices,
disabled_actions: [:create, :delete],
flag_name: :services_disabledCustomized usage with use and @impl
To change how the group name is extracted from the connection (e.g., use realm instead of user_name),
you can define your own module and override the get_current_user/1 callback:
defmodule MyApp.Web.Plugs.DisableServices do
use ExEssentials.Web.Plugs.DisableServices
@impl ExEssentials.Web.Plugs.DisableServices
def get_current_user(%Plug.Conn{assigns: %{realm: realm}}), do: realm
def get_current_user(%Plug.Conn{params: params}), do: Map.get(params, "realm")
def get_current_user(_), do: nil
endAnd in your router or endpoint:
plug MyApp.Web.Plugs.DisableServices,
disabled_actions: [:create, :delete],
flag_name: :services_disabledExample with FunWithFlags
To enable or disable the flag at runtime:
FunWithFlags.enable(:services_disabled)
FunWithFlags.disable(:services_disabled, for_group: "admin")This will enable the flag globally, but disable it for users in the "admin" group.
Notes
- If
FunWithFlagsis not available at runtime (e.g., not installed), the plug assumes the flag is enabled by default and proceeds with normal request handling. - The
ExEssentials.Web.Plugs.DisableServicesstruct implements theFunWithFlags.Groupprotocol to support group-based targeting.
Summary
Functions
Callback implementation for Plug.call/2.
Extracts the current user identifier from the connection for use in group-based flag evaluation.
Callback implementation for Plug.init/1.
Callbacks
@callback get_current_user(Plug.Conn.t()) :: String.t() | nil
Functions
Callback implementation for Plug.call/2.
Extracts the current user identifier from the connection for use in group-based flag evaluation.
This function looks first in conn.assigns[:user_name], and if not found, in conn.params["user_name"].
Examples
iex> conn = %Plug.Conn{assigns: %{user_name: "admin"}}
iex> ExEssentials.Web.Plugs.DisableServices.get_current_user(conn)
"admin"
iex> conn = %Plug.Conn{params: %{"user_name" => "admin"}}
iex> ExEssentials.Web.Plugs.DisableServices.get_current_user(conn)
"admin"
iex> ExEssentials.Web.Plugs.DisableServices.get_current_user(%Plug.Conn{})
nil
Callback implementation for Plug.init/1.