AshDispatch.UserPreference behaviour (AshDispatch v0.5.1)
View SourceBehaviour for checking user notification preferences.
Allows consuming apps to control which notifications users receive based on their preferences. Users can opt out of specific event categories, transports, or both.
Configuration
Configure your preference checker in config:
# config/config.exs
config :ash_dispatch,
user_preference: MyApp.NotificationPreferencesImplementing the Behaviour
defmodule MyApp.NotificationPreferences do
@behaviour AshDispatch.UserPreference
@impl true
def user_allows?(user_id, event_id, transport, opts) do
# Query your preference system
case Ash.get(UserPreference, user_id) do
{:ok, prefs} ->
category = opts[:category]
# Check if user disabled this category
if category in prefs.disabled_categories do
false
# Check if user disabled this transport
else if transport in prefs.disabled_transports do
false
else
true
end
_ ->
true # Allow if no preferences found
end
end
endUsage in Events
Events should specify their category for preference filtering:
dispatch do
event :promotional_offer,
trigger_on: :create,
channels: [[transport: :email, audience: :user]],
metadata: [
category: :marketing # Users can opt out of :marketing
]
endPreference Granularity
Users can control notifications at three levels:
- By Category - Opt out of entire categories (e.g., :marketing, :billing)
- By Transport - Opt out of specific transports (e.g., no :email, yes :in_app)
- Both - Opt out of category+transport combinations
Default Behavior
If no preference checker is configured, all notifications are sent. This ensures AshDispatch works out-of-the-box without requiring preference setup.
Security
Only check preferences for :user audience events. Admin/team/system
notifications typically shouldn't be user-configurable.
Summary
Callbacks
Checks if a user allows a specific notification.
Functions
Checks if user allows notification based on context and channel.
Callbacks
@callback user_allows?( user_id :: any(), event_id :: String.t(), transport :: atom(), opts :: keyword() ) :: boolean()
Checks if a user allows a specific notification.
Parameters
user_id- User identifier (can be any type)event_id- Event identifier string (e.g., "orders.created")transport- Transport atom (e.g., :email, :in_app)opts- Options keyword list with::category- Event category atom (e.g., :billing, :marketing):audience- Channel audience (e.g., :user, :admin)
Returns
true- User allows this notificationfalse- User has opted out
Examples
# User allows order emails
iex> user_allows?(123, "orders.created", :email, category: :transactional)
true
# User opted out of marketing emails
iex> user_allows?(123, "promo.new", :email, category: :marketing)
false
# User allows marketing in-app (only opted out of marketing emails)
iex> user_allows?(123, "promo.new", :in_app, category: :marketing)
true
Functions
@spec allows?(AshDispatch.Context.t(), AshDispatch.Channel.t(), keyword()) :: boolean()
Checks if user allows notification based on context and channel.
This is a convenience wrapper around the callback that extracts relevant data from Context and Channel structs.
Returns
true- User allows or no user in context or preferences not configuredfalse- User has opted out