mirror of
https://github.com/ash-project/ash_state_machine.git
synced 2024-09-21 22:03:12 +12:00
66 lines
2.2 KiB
Elixir
66 lines
2.2 KiB
Elixir
defmodule AshStateMachine.Checks.ValidNextState do
|
|
@moduledoc """
|
|
A policy for pre_flight checking if a state transition is allowed.
|
|
"""
|
|
use Ash.Policy.FilterCheck
|
|
|
|
def describe(_) do
|
|
"allowed to make state transition"
|
|
end
|
|
|
|
def filter(
|
|
_actor,
|
|
%{changeset: %Ash.Changeset{action_type: :create} = changeset} = _context,
|
|
_options
|
|
) do
|
|
attribute = AshStateMachine.Info.state_machine_state_attribute!(changeset.resource)
|
|
|
|
if changeset.context[:private][:pre_flight_authorization?] do
|
|
new_state =
|
|
Ash.Changeset.get_attribute(changeset, attribute) ||
|
|
AshStateMachine.Info.state_machine_default_initial_state!(changeset.resource)
|
|
|
|
{:ok, new_state in AshStateMachine.Info.state_machine_initial_states!(changeset.resource)}
|
|
else
|
|
{:ok, true}
|
|
end
|
|
end
|
|
|
|
def filter(
|
|
_actor,
|
|
%{changeset: %Ash.Changeset{action_type: :update} = changeset} = _context,
|
|
_options
|
|
) do
|
|
attribute = AshStateMachine.Info.state_machine_state_attribute!(changeset.resource)
|
|
|
|
if changeset.context[:private][:pre_flight_authorization?] &&
|
|
(Ash.Changeset.changing_attribute?(changeset, attribute) ||
|
|
get_in(changeset.context, [:state_machine, :attempted_change])) do
|
|
transitions =
|
|
AshStateMachine.Info.state_machine_transitions(changeset.resource, changeset.action.name)
|
|
|
|
old_state = expr(^ref(attribute))
|
|
target = Ash.Changeset.get_attribute(changeset, attribute)
|
|
all_states = AshStateMachine.Info.state_machine_all_states(changeset.resource)
|
|
|
|
if not is_nil(target) && !Ash.Expr.expr?(target) && target not in all_states do
|
|
{:ok, false}
|
|
else
|
|
states_expr =
|
|
Enum.reduce(transitions, nil, fn transition, expr ->
|
|
state_expr =
|
|
expr(
|
|
^old_state in ^List.wrap(transition.from) and ^target in ^List.wrap(transition.to)
|
|
)
|
|
|
|
expr(^state_expr or ^expr)
|
|
end)
|
|
|
|
expr(is_nil(^target) || (^target in ^all_states and ^states_expr))
|
|
end
|
|
else
|
|
# state transitions are checked in validations when using `transition_state`
|
|
{:ok, true}
|
|
end
|
|
end
|
|
end
|