AshDispatch.EventResolver (AshDispatch v0.5.0)

View Source

Centralized event resolution and callback execution for AshDispatch events.

Handles the logic for finding event modules and safely calling their callbacks with consistent error handling.

Finding Events

# Find an event module by ID
{:ok, module} = EventResolver.find_module("orders.created")

# Get all registered events
events = EventResolver.all_events()

Safe Callback Execution

All callback functions handle errors gracefully and return sensible defaults:

# Get sample data with fallback to empty map
data = EventResolver.sample_data(module)

# Get subject with fallback
subject = EventResolver.subject(module, context, channel, default: "No subject")

# Check if callback exists and call it
{:ok, result} = EventResolver.call_if_exported(module, :custom_callback, [arg1, arg2])

Context Building

# Build a sample context for previews
context = EventResolver.build_sample_context(event_id, module)

Summary

Functions

Get action label for in-app notifications.

Check if the event requires action from the user.

Get action URL for in-app notifications.

Get all registered event modules as a list of {event_id, module} tuples.

Check if the event is applicable for a specific user.

Get HTML body for email (for test modules without templates). Returns nil if callback not exported.

Get text body for email (for test modules without templates). Returns nil if callback not exported.

Build a sample context for previews and testing.

Call a function on the module if it's exported, with error handling.

Get the event category for preferences.

Get counters for broadcasting.

Get the data key from an event module.

Get the domain from an event module.

Get the event ID from a module, if it implements id/0.

Check if a module exports a specific function.

Find an event module by its event ID.

Get the from address for a channel.

Generate send variables for actual delivery.

Check if module exports both body_html and body_text callbacks. Used to determine if we should use callbacks instead of templates.

Get notification message for in-app notifications.

Get notification title for in-app notifications.

Get the notification type from an event module.

Prepare data from changeset (for resource-triggered events).

Prepare template assigns for a channel.

Get recipients for a channel.

Get required resources for manual trigger.

Get the resource from an event module.

Get sample data from an event module.

Get source URL for linking receipts to source resources.

Get the email subject for a channel.

Get the template variant for a channel.

Check if the event is user configurable.

Functions

action_label(module, context, channel)

@spec action_label(module(), AshDispatch.Context.t(), AshDispatch.Channel.t()) ::
  String.t() | nil

Get action label for in-app notifications.

action_required?(module, context)

@spec action_required?(module(), AshDispatch.Context.t()) :: boolean()

Check if the event requires action from the user.

action_url(module, context, channel)

@spec action_url(module(), AshDispatch.Context.t(), AshDispatch.Channel.t()) ::
  String.t() | nil

Get action URL for in-app notifications.

all_events()

@spec all_events() :: [{String.t(), module()}]

Get all registered event modules as a list of {event_id, module} tuples.

Uses the EventRegistry which auto-discovers events from configured domains.

applicable_for_user?(module, user)

@spec applicable_for_user?(module(), any()) :: boolean()

Check if the event is applicable for a specific user.

body_html(module, context, channel)

@spec body_html(module(), AshDispatch.Context.t(), AshDispatch.Channel.t()) ::
  String.t() | nil

Get HTML body for email (for test modules without templates). Returns nil if callback not exported.

body_text(module, context, channel)

@spec body_text(module(), AshDispatch.Context.t(), AshDispatch.Channel.t()) ::
  String.t() | nil

Get text body for email (for test modules without templates). Returns nil if callback not exported.

build_sample_context(event_id, module)

@spec build_sample_context(String.t(), module()) :: AshDispatch.Context.t()

Build a sample context for previews and testing.

Uses the module's sample_data/0 callback if available.

call_if_exported(module, function, args, opts \\ [])

@spec call_if_exported(module(), atom(), list(), keyword()) :: any()

Call a function on the module if it's exported, with error handling.

Options

  • :default - Value to return if function not exported or raises (default: nil)

Examples

# Returns result or default
value = EventResolver.call_if_exported(module, :domain, [], default: :unknown)

# With arguments
subject = EventResolver.call_if_exported(module, :subject, [context, channel])

category(module, context)

@spec category(module(), AshDispatch.Context.t()) :: atom() | nil

Get the event category for preferences.

counters(module, context, channel)

@spec counters(module(), AshDispatch.Context.t(), AshDispatch.Channel.t()) :: [atom()]

Get counters for broadcasting.

data_key(module)

@spec data_key(module()) :: atom() | nil

Get the data key from an event module.

domain(module)

@spec domain(module()) :: atom() | nil

Get the domain from an event module.

event_id(module)

@spec event_id(module()) :: String.t() | nil

Get the event ID from a module, if it implements id/0.

exports?(module, function, arity)

@spec exports?(module(), atom(), non_neg_integer()) :: boolean()

Check if a module exports a specific function.

find_module(event_id)

@spec find_module(String.t()) :: {:ok, module()} | {:error, :not_found}

Find an event module by its event ID.

Returns

  • {:ok, module} if found
  • {:error, :not_found} if no event with that ID exists

from(module, context, channel)

Get the from address for a channel.

generate_send_variables(module, context, variables)

@spec generate_send_variables(module(), AshDispatch.Context.t(), map()) ::
  {:ok, map()} | {:error, term()}

Generate send variables for actual delivery.

has_body_callbacks?(module)

@spec has_body_callbacks?(module()) :: boolean()

Check if module exports both body_html and body_text callbacks. Used to determine if we should use callbacks instead of templates.

notification_message(module, context, channel)

@spec notification_message(module(), AshDispatch.Context.t(), AshDispatch.Channel.t()) ::
  String.t() | nil

Get notification message for in-app notifications.

Falls back to DSL content from the registry if the module returns the default value.

notification_title(module, context, channel)

@spec notification_title(module(), AshDispatch.Context.t(), AshDispatch.Channel.t()) ::
  String.t() | nil

Get notification title for in-app notifications.

Falls back to DSL content from the registry if the module returns the default value.

notification_type(module, context)

@spec notification_type(module(), AshDispatch.Context.t()) :: atom()

Get the notification type from an event module.

prepare_data(module, changeset, record)

@spec prepare_data(module(), Ash.Changeset.t(), any()) :: map()

Prepare data from changeset (for resource-triggered events).

prepare_template_assigns(module, context, channel)

@spec prepare_template_assigns(
  module(),
  AshDispatch.Context.t(),
  AshDispatch.Channel.t()
) :: map()

Prepare template assigns for a channel.

recipients(module, context, channel)

@spec recipients(module(), AshDispatch.Context.t(), AshDispatch.Channel.t()) :: [
  String.t()
]

Get recipients for a channel.

required_resources(module)

@spec required_resources(module()) :: keyword()

Get required resources for manual trigger.

resource(module)

@spec resource(module()) :: module() | nil

Get the resource from an event module.

sample_data(module)

@spec sample_data(module()) :: map()

Get sample data from an event module.

source_url(module, context, channel)

@spec source_url(module(), AshDispatch.Context.t(), AshDispatch.Channel.t()) ::
  String.t() | nil

Get source URL for linking receipts to source resources.

subject(module, context, channel, opts \\ [])

@spec subject(module(), AshDispatch.Context.t(), AshDispatch.Channel.t(), keyword()) ::
  String.t() | nil

Get the email subject for a channel.

Falls back to DSL content from the registry if the module returns the default value.

template_variant(module, context, channel)

@spec template_variant(module(), AshDispatch.Context.t(), AshDispatch.Channel.t()) ::
  String.t() | nil

Get the template variant for a channel.

user_configurable?(module, context)

@spec user_configurable?(module(), AshDispatch.Context.t()) :: boolean()

Check if the event is user configurable.