Packages

Event-driven notification system for Ash Framework with multiple transport types

Current section

Files

Jump to
ash_dispatch lib calculations admin_url.ex
Raw

lib/calculations/admin_url.ex

defmodule AshDispatch.Calculations.AdminUrl do
@moduledoc """
Calculates admin-specific URL for source resource, regardless of receipt audience.
Unlike `source_url` which uses the receipt's audience to determine the URL path,
this calculation always uses `audience: :admin`. This is useful for admin dashboards
that need to link to admin views regardless of who the notification was sent to.
## Configuration
config :ash_dispatch, url_builder: MyApp.UrlBuilder
The UrlBuilder must implement `build_resource_url/3` with support for `audience: :admin`.
"""
use Ash.Resource.Calculation
alias AshDispatch.{Config, EventResolver}
@impl true
def load(_query, _opts, _context), do: [:event_id, :source_type, :source_id]
@impl true
def calculate(records, _opts, _context) do
url_builder = Config.url_builder()
Enum.map(records, &compute_admin_url(&1, url_builder))
end
defp compute_admin_url(record, url_builder) do
# Use EventResolver for consistent event lookup and callback execution
with {:ok, event_module} <- EventResolver.find_module(record.event_id),
{:ok, data_key} <- get_data_key(event_module),
{:ok, source_id} <- get_source_id(record),
true <- not is_nil(url_builder) do
mock_resource = %{id: source_id}
try do
url_builder.build_resource_url(data_key, mock_resource, audience: :admin, path_only: true)
rescue
ArgumentError -> nil
end
else
_ -> nil
end
end
# Use EventResolver for safe data_key callback execution
defp get_data_key(event_module) do
case EventResolver.data_key(event_module) do
key when is_atom(key) and not is_nil(key) -> {:ok, key}
_ -> :error
end
end
defp get_source_id(%{source_id: nil}), do: :error
defp get_source_id(%{source_id: id}), do: {:ok, id}
end