defmodule AshAuthentication.Strategy.MagicLink.Transformer do
@moduledoc """
DSL transformer for magic links.
"""
alias Ash.Resource
alias AshAuthentication.Strategy.MagicLink
alias Spark.Dsl.Transformer
import AshAuthentication.Utils
import AshAuthentication.Validations
import AshAuthentication.Strategy.Custom.Helpers
@doc false
@spec transform(MagicLink.t(), dsl_state) :: {:ok, MagicLink.t() | dsl_state} | {:error, any}
when dsl_state: map
def transform(strategy, dsl_state) do
with :ok <-
validate_token_generation_enabled(
dsl_state,
"Token generation must be enabled for magic links to work."
),
strategy <- maybe_set_sign_in_action_name(strategy),
strategy <- maybe_set_request_action_name(strategy),
{:ok, dsl_state} <-
maybe_build_action(
dsl_state,
strategy.sign_in_action_name,
&build_sign_in_action(&1, strategy)
),
{:ok, dsl_state} <-
maybe_build_action(
dsl_state,
strategy.request_action_name,
&build_request_action(&1, strategy)
) do
dsl_state =
dsl_state
|> then(
®ister_strategy_actions(
[strategy.sign_in_action_name, strategy.request_action_name],
&1,
strategy
)
)
|> put_strategy(strategy)
{:ok, dsl_state}
end
end
defp maybe_set_sign_in_action_name(strategy) when is_nil(strategy.sign_in_action_name),
do: %{strategy | sign_in_action_name: :"sign_in_with_#{strategy.name}"}
defp maybe_set_sign_in_action_name(strategy), do: strategy
defp maybe_set_request_action_name(strategy) when is_nil(strategy.request_action_name),
do: %{strategy | request_action_name: :"request_#{strategy.name}"}
defp maybe_set_request_action_name(strategy), do: strategy
defp build_sign_in_action(_dsl_state, strategy) do
arguments = [
Transformer.build_entity!(Resource.Dsl, [:actions, :read], :argument,
name: strategy.token_param_name,
type: :string,
allow_nil?: false
)
]
preparations = [
Transformer.build_entity!(Resource.Dsl, [:actions, :read], :prepare,
preparation: MagicLink.SignInPreparation
)
]
metadata = [
Transformer.build_entity!(Resource.Dsl, [:actions, :read], :metadata,
name: :token,
type: :string,
allow_nil?: false
)
]
Transformer.build_entity(Resource.Dsl, [:actions], :read,
name: strategy.sign_in_action_name,
arguments: arguments,
preparations: preparations,
metadata: metadata,
get?: true
)
end
defp build_request_action(dsl_state, strategy) do
identity_attribute = Resource.Info.attribute(dsl_state, strategy.identity_field)
arguments = [
Transformer.build_entity!(Resource.Dsl, [:actions, :read], :argument,
name: strategy.identity_field,
type: identity_attribute.type,
allow_nil?: false
)
]
preparations = [
Transformer.build_entity!(Resource.Dsl, [:actions, :read], :prepare,
preparation: MagicLink.RequestPreparation
)
]
Transformer.build_entity(Resource.Dsl, [:actions], :read,
name: strategy.request_action_name,
arguments: arguments,
preparations: preparations
)
end
end