Packages

ash

3.7.6
3.29.3 3.29.2 3.29.1 3.29.0 3.28.0 3.27.8 3.27.7 3.27.6 3.27.5 3.27.4 3.27.3 3.27.2 3.27.1 3.27.0 3.26.0 3.25.2 3.25.1 3.25.0 retired 3.24.7 3.24.6 3.24.5 3.24.4 3.24.3 3.24.2 3.24.1 3.24.0 3.23.1 3.23.0 3.22.2 3.22.1 3.22.0 3.21.3 3.21.2 3.21.1 3.21.0 3.20.0 3.19.3 3.19.2 3.19.1 3.19.0 3.18.0 3.17.1 3.17.0 3.16.0 3.15.0 3.14.1 3.14.0 retired 3.13.2 3.13.1 3.13.0 3.12.0 3.11.3 3.11.2 3.11.1 3.11.0 3.10.1 3.10.0 3.9.0 3.8.0 3.7.6 3.7.5 3.7.4 3.7.3 3.7.2 3.7.1 3.7.0 retired 3.6.3 retired 3.6.2 3.6.1 3.6.0 3.5.43 3.5.42 3.5.41 3.5.40 3.5.39 3.5.38 3.5.37 3.5.36 3.5.35 3.5.34 3.5.33 3.5.32 3.5.31 3.5.30 3.5.29 3.5.28 3.5.27 3.5.26 3.5.25 3.5.24 3.5.23 3.5.22 3.5.21 3.5.20 3.5.19 3.5.18 3.5.17 3.5.16 3.5.15 3.5.14 3.5.13 3.5.12 3.5.11 3.5.10 3.5.9 3.5.8 3.5.7 3.5.6 3.5.5 3.5.4 3.5.3 3.5.2 3.5.1 3.5.0 3.4.74 retired 3.4.73 3.4.72 3.4.71 3.4.70 3.4.69 3.4.68 3.4.67 3.4.66 3.4.65 3.4.64 3.4.63 3.4.62 3.4.61 3.4.60 3.4.59 3.4.58 3.4.57 3.4.56 3.4.55 3.4.54 3.4.53 3.4.52 3.4.51 3.4.50 3.4.49 3.4.48 3.4.47 3.4.46 3.4.45 3.4.44 3.4.43 3.4.42 3.4.41 3.4.40 3.4.39 3.4.38 3.4.37 3.4.36 3.4.35 3.4.34 3.4.33 3.4.32 3.4.31 3.4.30 3.4.29 3.4.28 3.4.27 3.4.26 3.4.25 3.4.24 3.4.23 3.4.22 3.4.21 3.4.20 3.4.19 3.4.18 3.4.17 3.4.16 3.4.15 3.4.14 3.4.13 3.4.12 3.4.11 3.4.10 3.4.9 3.4.8 3.4.7 3.4.6 3.4.5 3.4.4 3.4.3 3.4.2 3.4.1 3.4.0 3.3.3 3.3.2 3.3.1 3.3.0 3.2.6 3.2.5 3.2.4 3.2.3 3.2.2 3.2.1 3.2.0 3.1.8 3.1.7 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.16 3.0.15 3.0.14 3.0.13 3.0.12 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.4 3.0.3 3.0.2 3.0.1 3.0.0 3.0.0-rc.46 3.0.0-rc.45 3.0.0-rc.44 3.0.0-rc.43 3.0.0-rc.42 3.0.0-rc.41 3.0.0-rc.40 3.0.0-rc.39 3.0.0-rc.38 3.0.0-rc.37 3.0.0-rc.36 3.0.0-rc.35 3.0.0-rc.34 3.0.0-rc.33 3.0.0-rc.32 3.0.0-rc.31 3.0.0-rc.29 3.0.0-rc.28 3.0.0-rc.27 3.0.0-rc.26 3.0.0-rc.25 3.0.0-rc.24 3.0.0-rc.23 3.0.0-rc.22 3.0.0-rc.21 3.0.0-rc.20 3.0.0-rc.19 3.0.0-rc.18 3.0.0-rc.17 3.0.0-rc.16 3.0.0-rc.15 3.0.0-rc.14 3.0.0-rc.13 3.0.0-rc.12 3.0.0-rc.11 3.0.0-rc.10 3.0.0-rc.9 3.0.0-rc.8 3.0.0-rc.7 3.0.0-rc.6 3.0.0-rc.5 3.0.0-rc.4 3.0.0-rc.3 3.0.0-rc.1 3.0.0-rc.0 2.21.15 2.21.14 2.21.13 2.21.12 2.21.11 2.21.10 2.21.9 2.21.8 2.21.7 2.21.6 2.21.5 2.21.4 2.21.3 2.21.2 2.21.1 2.21.0 2.20.3 2.20.2 2.20.1 2.20.0 2.19.14 2.19.13 2.19.12 2.19.11 2.19.10 2.19.9 2.19.8 2.19.7 2.19.6 2.19.5 2.19.4 2.19.3 retired 2.19.2 retired 2.19.1 retired 2.19.0 retired 2.18.2 2.18.1 2.18.0 2.17.24 2.17.23 2.17.22 2.17.21 2.17.20 2.17.19 2.17.18 2.17.17 2.17.16 2.17.15 2.17.14 2.17.13 2.17.12 2.17.11 2.17.10 2.17.9 2.17.8 2.17.7 2.17.6 2.17.5 2.17.4 2.17.3 2.17.2 2.17.1 2.17.0 2.16.1 2.16.0 2.15.20 2.15.19 2.15.18 2.15.17 2.15.16 2.15.15 2.15.14 2.15.13 2.15.12 2.15.11 2.15.10 2.15.9 2.15.8 2.15.7 2.15.6 2.15.5 2.15.4 2.15.2 2.15.1 2.15.0 2.14.21 2.14.20 2.14.19 2.14.18 2.14.17 2.14.16 2.14.15 2.14.14 2.14.13 2.14.12 2.14.11 2.14.10 2.14.9 2.14.8 2.14.7 2.14.6 2.14.5 2.14.4 2.14.3 2.14.2 2.14.1 2.14.0 2.13.4 retired 2.13.3 2.13.2 2.13.1 2.13.0 2.12.1 2.12.0 2.11.11 2.11.10 2.11.9 2.11.8 2.11.7 2.11.6 2.11.5 2.11.4 2.11.3 2.11.2 2.11.1 2.11.0 2.11.0-rc.3 2.11.0-rc.2 2.11.0-rc.1 2.11.0-rc.0 2.10.2 2.10.1 2.10.0 2.9.29 2.9.28 2.9.27 2.9.26 2.9.25 2.9.24 2.9.23 2.9.22 2.9.21 2.9.20 2.9.19 2.9.18 2.9.17 2.9.16 2.9.15 2.9.14 2.9.13 2.9.12 2.9.11 2.9.10 2.9.9 2.9.8 2.9.7 2.9.6 2.9.5 2.9.4 2.9.3 2.9.2 2.9.1 2.9.0 2.8.1 2.8.0 2.7.1 2.7.0 2.6.31 2.6.30 2.6.29 2.6.28 2.6.27 2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 2.6.4 2.6.3 2.6.2 2.6.1 2.6.0 2.5.16 2.5.15 2.5.14 2.5.13 2.5.12 2.5.11 2.5.10 2.5.9 2.5.8 2.5.7 2.5.6 2.5.5 2.5.4 2.5.3 2.5.2 2.5.1 2.5.0 2.5.0-rc.6 2.5.0-rc.5 2.5.0-rc.4 2.5.0-rc.3 2.5.0-rc.2 2.5.0-rc.1 2.5.0-rc.0 2.4.30 2.4.29 2.4.28 2.4.27 2.4.26 2.4.25 2.4.24 2.4.23 2.4.22 2.4.21 2.4.20 2.4.19 2.4.18 2.4.17 2.4.16 2.4.15 2.4.14 2.4.13 2.4.12 2.4.11 2.4.10 2.4.9 2.4.8 2.4.7 2.4.6 2.4.5 2.4.4 2.4.3 2.4.2 2.4.1 2.4.0 2.3.0 2.2.0 2.1.0 2.0.0 2.0.0-rc.15 2.0.0-rc.14 2.0.0-rc.13 2.0.0-rc.12 2.0.0-rc.11 2.0.0-rc.10 2.0.0-rc.9 2.0.0-rc.8 2.0.0-rc.7 2.0.0-rc.6 2.0.0-rc.5 2.0.0-rc.4 2.0.0-rc.3 2.0.0-rc.2 2.0.0-rc.1 2.0.0-rc.0 2.0.0-pre.8 2.0.0-pre.7 2.0.0-pre.6 2.0.0-pre.5 2.0.0-pre.4 2.0.0-pre.3 2.0.0-pre.2 2.0.0-pre.1 2.0.0-pre.0 1.53.3 1.53.2 1.53.0 1.52.0-rc.22 1.52.0-rc.21 1.52.0-rc.20 1.52.0-rc.19 1.52.0-rc.18 1.52.0-rc.17 1.52.0-rc.16 1.52.0-rc.15 1.52.0-rc.14 1.52.0-rc.13 1.52.0-rc.12 1.52.0-rc.11 1.52.0-rc.10 1.52.0-rc.9 1.52.0-rc.8 1.52.0-rc.7 1.52.0-rc.6 1.52.0-rc.5 1.52.0-rc.4 1.52.0-rc.3 1.52.0-rc.2 1.52.0-rc.1 1.52.0-rc.0 1.51.2 1.51.1 retired 1.51.0 1.50.21 1.50.20 1.50.19 1.50.18 1.50.17 1.50.16 1.50.15 1.50.14 1.50.13 1.50.12 1.50.11 1.50.10 1.50.9 1.50.8 1.50.7 1.50.6 1.50.5 1.50.4 1.50.3 1.50.2 1.50.1 1.50.0 1.49.0 1.48.0-rc.30 1.48.0-rc.29 1.48.0-rc.28 1.48.0-rc.27 1.48.0-rc.26 1.48.0-rc.25 1.48.0-rc.24 1.48.0-rc.23 1.48.0-rc.22 1.48.0-rc.21 1.48.0-rc.20 1.48.0-rc.19 1.48.0-rc.18 1.48.0-rc.17 1.48.0-rc.16 1.48.0-rc.15 1.48.0-rc.14 1.48.0-rc.13 1.48.0-rc.12 1.48.0-rc.11 1.48.0-rc.10 1.48.0-rc.9 1.48.0-rc.8 1.48.0-rc.7 1.48.0-rc.6 1.48.0-rc.5 1.48.0-rc.4 1.48.0-rc.3 1.48.0-rc.2 1.48.0-rc.1 1.48.0-rc.0 1.47.12 1.47.11 1.47.10 1.47.9 1.47.8 1.47.7 1.47.6 1.47.5 1.47.4 1.47.3 1.47.2 1.47.1 1.47.0 1.46.13 1.46.12 1.46.11 1.46.10 1.46.9 1.46.8 1.46.7 1.46.6 1.46.5 1.46.4 1.46.3 1.46.2 1.46.1 1.46.0 1.45.0-rc9 1.45.0-rc8 1.45.0-rc7 1.45.0-rc6 1.45.0-rc5 1.45.0-rc4 1.45.0-rc3 1.45.0-rc20 1.45.0-rc2 1.45.0-rc19 1.45.0-rc18 1.45.0-rc17 1.45.0-rc16 1.45.0-rc15 1.45.0-rc14 1.45.0-rc13 1.45.0-rc12 1.45.0-rc11 1.45.0-rc10 1.45.0-rc1 1.45.0-rc0 1.44.13 1.44.12 1.44.11 1.44.10 1.44.9 1.44.8 1.44.7 1.44.6 1.44.5 1.44.4 1.44.3 1.44.2 1.44.1 1.44.0 1.43.12 1.43.11 1.43.10 1.43.9 1.43.8 1.43.7 1.43.6 1.43.5 1.43.4 1.43.3 1.43.2 1.43.1 1.43.0 1.42.0 1.41.12 1.41.11 1.41.10 1.41.9 1.41.8 1.41.7 1.41.6 1.41.5 1.41.4 1.41.3 1.41.2 1.41.1 1.41.0 1.40.0 1.39.7 1.39.6 1.39.5 1.39.4 1.39.3 1.39.2 1.39.1 1.39.0 1.38.0 1.37.2 1.37.1 1.37.0 1.36.22 1.36.21 1.36.19 1.36.18 1.36.17 1.36.16 1.36.15 1.36.14 1.36.13 1.36.12 1.36.11 1.36.10 1.36.9 1.36.8 1.36.7 1.36.6 1.36.5 1.36.4 1.36.3 1.36.2 1.36.0 1.35.1 1.35.0 1.34.9 1.34.8 1.34.7 1.34.6 1.34.5 1.34.4 1.34.3 1.34.2 1.34.1 1.34.0 1.33.0 1.32.2 1.32.1 1.32.0 1.31.1 1.31.0 1.30.2 1.30.1 1.29.0-rc1 1.29.0-rc0 1.28.1 1.28.0 1.27.1 1.27.0 1.26.13 1.26.12 1.26.11 1.26.10 1.26.9 1.26.8 1.26.7 1.26.6 1.26.5 1.26.4 1.26.2 1.26.1 1.26.0 1.25.8 1.25.7 1.25.6 1.25.5 1.25.4 1.25.3 1.25.2 1.25.1 1.25.0 1.24.2 1.24.1 1.24.0 1.23.3 1.23.2 1.23.1 1.23.0 1.22.1 1.22.0 1.20.1 1.20.0 1.19.1 1.19.0 1.18.1 1.18.0 1.17.1 1.17.0 1.16.2 1.15.1 1.15.0 1.14.0 1.13.4 1.13.3 1.13.2 1.13.1 1.13.0 1.12.0 1.11.1 1.11.0 1.10.0 1.9.0 1.8.0 1.7.0 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.1 1.5.0 1.4.1 1.4.0 1.3.1 1.3.0 1.2.1 1.2.0 1.1.3 1.1.2 1.1.0 1.0.3 1.0.2 1.0.1 1.0.0 0.13.1 0.13.0 0.12.0 0.10.0 0.9.1 0.9.0 0.8.0 0.7.0 0.6.5 0.6.4 0.6.3 0.6.2 0.6.1 0.6.0 0.5.2 0.5.1 0.5.0 0.4.0 0.3.0 0.2.0 0.1.9 0.1.8 0.1.3 0.1.1 0.1.0

A declarative, extensible framework for building Elixir applications.

Security advisory: This version has known vulnerabilities. View advisories

Current section

Files

Jump to
ash lib ash actions action.ex
Raw

lib/ash/actions/action.ex

# SPDX-FileCopyrightText: 2019 ash contributors <https://github.com/ash-project/ash/graphs.contributors>
#
# SPDX-License-Identifier: MIT
defmodule Ash.Actions.Action do
@moduledoc false
require Ash.Tracer
def run(_domain, %{valid?: false, errors: errors}, _opts) do
{:error, Ash.Error.to_error_class(errors)}
end
def run(domain, input, opts) do
{input, opts} = Ash.Actions.Helpers.set_context_and_get_opts(domain, input, opts)
if input.valid? do
run_with_lifecycle(domain, input, opts)
else
{:error, Ash.Error.to_error_class(input.errors)}
end
end
defp run_with_lifecycle(domain, input, opts) do
context =
%Ash.Resource.Actions.Implementation.Context{
actor: opts[:actor],
tenant: opts[:tenant],
tracer: opts[:tracer],
source_context: input.context,
authorize?: opts[:authorize?],
domain: opts[:domain]
}
{module, run_opts} = input.action.run
Ash.Tracer.span :action,
fn ->
Ash.Domain.Info.span_name(
domain,
input.resource,
input.action.name
)
end,
opts[:tracer] do
metadata = fn ->
%{
domain: domain,
resource: input.resource,
resource_short_name: Ash.Resource.Info.short_name(input.resource),
actor: opts[:actor],
tenant: opts[:tenant],
action: input.action.name,
authorize?: opts[:authorize?]
}
end
Ash.Tracer.set_metadata(opts[:tracer], :action, metadata)
Ash.Tracer.telemetry_span [:ash, Ash.Domain.Info.short_name(domain), :action],
metadata do
# Run around_transaction hooks if any exist, or proceed directly
Ash.ActionInput.run_around_transaction_hooks(input, fn input ->
if input.action.transaction? do
run_with_transaction(domain, input, module, run_opts, context, opts)
else
run_without_transaction(domain, input, module, run_opts, context, opts)
end
end)
end
end
end
defp run_with_transaction(domain, input, module, run_opts, context, opts) do
# Run before_transaction hooks first
case Ash.ActionInput.run_before_transaction_hooks(input) do
{:ok, input} ->
notify? = !Process.put(:ash_started_transaction?, true)
try do
resources =
input.action.touches_resources
|> Enum.reject(&Ash.DataLayer.in_transaction?/1)
|> Enum.concat([input.resource])
|> Enum.uniq()
resources
|> Ash.DataLayer.transaction(
fn ->
case authorize(domain, opts[:actor], input) do
:ok ->
case run_with_hooks(module, input, run_opts, context, true) do
{:ok, result, notifications} ->
{:ok, result, notifications}
{:error, error} ->
Ash.DataLayer.rollback(resources, error)
end
{:error, error} ->
Ash.DataLayer.rollback(resources, error)
end
end,
nil,
%{
type: :generic,
metadata: %{
resource: input.resource,
action: input.action.name,
input: input,
actor: opts[:actor]
},
data_layer_context: input.context[:data_layer] || %{}
},
rollback_on_error?: false
)
|> case do
{:ok, {:ok, result, notifications}} ->
notifications =
if notify? && !opts[:return_notifications?] do
Enum.concat(
notifications || [],
Process.delete(:ash_notifications) || []
)
else
notifications || []
end
remaining = Ash.Notifier.notify(notifications)
Ash.Actions.Helpers.warn_missed!(input.resource, input.action, %{
resource_notifications: remaining
})
final_result =
if input.action.returns do
{:ok, result}
else
:ok
end
# Run after_transaction hooks
Ash.ActionInput.run_after_transaction_hooks(final_result, input)
{:error, error} ->
error_result = {:error, Ash.Error.to_ash_error(error)}
# Run after_transaction hooks even on error
Ash.ActionInput.run_after_transaction_hooks(error_result, input)
end
after
if notify? do
Process.delete(:ash_started_transaction?)
end
end
{:error, error} ->
{:error, error}
end
end
defp run_without_transaction(domain, input, module, run_opts, context, opts) do
# Run before_transaction hooks even for non-transactional actions
case Ash.ActionInput.run_before_transaction_hooks(input) do
{:ok, input} ->
result =
case authorize(domain, opts[:actor], input) do
:ok ->
case run_with_hooks(module, input, run_opts, context, false) do
{:ok, result, notifications} ->
remaining = Ash.Notifier.notify(notifications)
Ash.Actions.Helpers.warn_missed!(input.resource, input.action, %{
resource_notifications: remaining
})
if input.action.returns do
{:ok, result}
else
:ok
end
{:error, error} ->
{:error, error}
end
{:error, error} ->
{:error, error}
end
# Run after_transaction hooks
Ash.ActionInput.run_after_transaction_hooks(result, input)
{:error, error} ->
{:error, error}
end
end
defp is_reactor?(module) when is_atom(module) do
module.spark_is() == Reactor
rescue
UndefinedFunctionError -> false
end
defp call_run_function(module, input, run_opts, context, in_transaction?) do
if is_reactor?(module) do
run_opts =
if in_transaction?,
do: Keyword.put(run_opts, :async?, false),
else: run_opts
context =
context
|> Ash.Context.to_opts()
|> Map.new()
arguments =
Enum.reduce(module.reactor().inputs, input.arguments, fn input, arguments ->
Map.put_new(arguments, input, nil)
end)
Reactor.run(
module,
arguments,
context,
run_opts
)
else
Ash.Resource.Actions.Implementation.run(module, input, run_opts, context)
end
end
defp raise_invalid_generic_action_return!(input, other) do
ok_or_ok_tuple = if input.action.returns, do: "{:ok, result}", else: ":ok"
raise Ash.Error.Framework.InvalidReturnType,
message: """
Invalid return from generic action #{input.resource}.#{input.action.name}.
Expected #{ok_or_ok_tuple} or {:error, error}, got:
#{inspect(other)}
"""
end
defp authorize(_domain, _actor, %{context: %{private: %{authorize?: false}}}) do
:ok
end
defp authorize(domain, actor, input) do
input.resource
|> Ash.Resource.Info.authorizers()
|> Enum.reduce_while(
:ok,
fn authorizer, :ok ->
authorizer_state =
authorizer.initial_state(
actor,
input.resource,
input.action,
input.domain
)
context = %{
domain: domain,
action_input: input,
query: nil,
changeset: nil
}
case authorizer.strict_check(authorizer_state, context) do
{:error, %{class: :forbidden} = e} when is_exception(e) ->
{:halt, {:error, e}}
{:error, error} ->
{:halt, {:error, error}}
{:authorized, _} ->
{:cont, :ok}
{:filter, _authorizer, filter} ->
raise """
Cannot use filter checks with generic actions
Received #{inspect(filter)} when authorizing #{inspect(input.resource)}.#{input.action.name}
"""
{:filter, filter} ->
raise """
Cannot use filter checks with generic actions
Received #{inspect(filter)} when authorizing #{inspect(input.resource)}.#{input.action.name}
"""
{:continue, _state} ->
raise """
Cannot use runtime checks with generic actions
Must use only simple checks or other checks that can be resolved without returning results #{inspect(input.resource)}.#{input.action.name}
"""
{:filter_and_continue, filter, _} ->
raise """
Cannot use filter checks with generic actions
Received #{inspect(filter)} when authorizing #{inspect(input.resource)}.#{input.action.name}
"""
:forbidden ->
{:halt, {:error, Ash.Authorizer.exception(authorizer, :forbidden, authorizer_state)}}
end
end
)
end
defp run_with_hooks(module, input, run_opts, context, in_transaction?) do
# Run before_action hooks
case Ash.ActionInput.run_before_actions(input) do
{:error, error} ->
if in_transaction? do
Ash.DataLayer.rollback([input.resource], error)
else
{:error, error}
end
{input, %{notifications: before_action_notifications}} ->
# Run the actual action
case call_run_function(module, input, run_opts, context, in_transaction?) do
:ok when is_nil(input.action.returns) ->
# Run after_action hooks
case Ash.ActionInput.run_after_actions(nil, input, before_action_notifications) do
{:ok, result, _input, %{notifications: all_notifications}} ->
{:ok, result, all_notifications}
{:error, error} ->
if in_transaction? do
Ash.DataLayer.rollback([input.resource], error)
else
{:error, error}
end
end
{:ok, result} ->
if input.action.returns do
# Run after_action hooks
case Ash.ActionInput.run_after_actions(result, input, before_action_notifications) do
{:ok, result, _input, %{notifications: all_notifications}} ->
{:ok, result, all_notifications}
{:error, error} ->
if in_transaction? do
Ash.DataLayer.rollback([input.resource], error)
else
{:error, error}
end
end
else
raise_invalid_generic_action_return!(input, result)
end
{:ok, result, notifications} ->
# Run after_action hooks
case Ash.ActionInput.run_after_actions(
result,
input,
before_action_notifications ++ notifications
) do
{:ok, result, _input, %{notifications: all_notifications}} ->
{:ok, result, all_notifications}
{:error, error} ->
if in_transaction? do
Ash.DataLayer.rollback([input.resource], error)
else
{:error, error}
end
end
{:error, error} ->
if in_transaction? do
Ash.DataLayer.rollback([input.resource], error)
else
{:error, error}
end
other ->
raise_invalid_generic_action_return!(input, other)
end
end
end
end