Current section

Files

Jump to
ash_authentication lib ash_authentication strategies magic_link request.ex
Raw

lib/ash_authentication/strategies/magic_link/request.ex

# SPDX-FileCopyrightText: 2022 Alembic Pty Ltd
#
# SPDX-License-Identifier: MIT
defmodule AshAuthentication.Strategy.MagicLink.Request do
@moduledoc """
Requests a magic link for the given identity field.
"""
use Ash.Resource.Actions.Implementation
alias Ash.{ActionInput, Query}
alias AshAuthentication.{Errors.SenderFailed, Info, Strategy.MagicLink}
# require Ash.Query
@doc false
@impl true
def run(input, _opts, context) do
strategy = Info.strategy_for_action!(input.resource, input.action.name)
identity = ActionInput.get_argument(input, strategy.identity_field)
context_opts = Ash.Context.to_opts(context)
input.resource
|> Query.set_context(%{
private: %{
ash_authentication?: true
}
})
|> Ash.Query.for_read(
strategy.lookup_action_name,
%{strategy.identity_field => identity},
context_opts
)
|> Ash.read_one()
|> case do
{:error, error} ->
{:error, error}
{:ok, nil} ->
with true <- strategy.registration_enabled?,
{sender, send_opts} <- strategy.sender,
{:ok, token} <-
MagicLink.request_token_for_identity(strategy, identity, context_opts, context),
build_opts =
Keyword.merge(send_opts,
tenant: context.tenant,
source_context: context.source_context
),
:ok <- sender.send(to_string(identity), token, build_opts) do
:ok
else
{:error, reason} when not is_struct(reason) ->
{sender, _} = strategy.sender
{:error,
SenderFailed.exception(sender: sender, reason: reason, strategy: strategy.name)}
{:error, _} = error ->
error
_ ->
:ok
end
{:ok, user} ->
with {sender, send_opts} <- strategy.sender,
{:ok, token} <-
MagicLink.request_token_for_identity(strategy, identity, context_opts, context),
build_opts =
Keyword.merge(send_opts,
tenant: context.tenant,
source_context: context.source_context
),
:ok <- sender.send(user, token, build_opts) do
:ok
else
{:error, reason} when not is_struct(reason) ->
{sender, _} = strategy.sender
{:error,
SenderFailed.exception(sender: sender, reason: reason, strategy: strategy.name)}
{:error, _} = error ->
error
_ ->
:ok
end
end
end
end