# SPDX-FileCopyrightText: 2019 ash contributors # # SPDX-License-Identifier: MIT defmodule Ash.Resource.Validation.Confirm do @moduledoc false use Ash.Resource.Validation alias Ash.Changeset alias Ash.Error.Changes.InvalidAttribute require Ash.Expr @impl true def init(opts) do case opts[:field] do nil -> {:error, "Field is required"} field when is_atom(field) -> case opts[:confirmation] do nil -> {:error, "Confirmation is required"} confirmation when is_atom(confirmation) -> {:ok, [confirmation: confirmation, field: field]} confirmation -> {:error, "Expected an atom for confirmation, got: #{inspect(confirmation)}"} end field -> {:error, "Expected an atom for field, got: #{inspect(field)}"} end end @impl true def supports(_opts), do: [Ash.Changeset, Ash.Query, Ash.ActionInput] @impl true def validate(subject, opts, _context) do confirmation_value = Ash.Subject.get_argument_or_attribute(subject, opts[:confirmation]) value = Ash.Subject.get_argument_or_attribute(subject, opts[:field]) if Comp.equal?(confirmation_value, value) do :ok else {:error, [field: opts[:confirmation], value: confirmation_value] |> with_description(opts) |> InvalidAttribute.exception()} end end @impl true def atomic(changeset, opts, context) do confirmation = case Changeset.fetch_argument_or_change(changeset, opts[:confirmation]) do {:ok, value} -> value :error -> Changeset.atomic_ref(changeset, opts[:confirmation]) end value = case Changeset.fetch_argument_or_change(changeset, opts[:field]) do {:ok, value} -> value :error -> Changeset.atomic_ref(changeset, opts[:field]) end {:atomic, [opts[:confirmation], opts[:field]], Ash.Expr.expr(^confirmation != ^value), Ash.Expr.expr( error(^InvalidAttribute, %{ field: ^opts[:confirmation], value: ^value, message: ^(context.message || "confirmation did not match value") }) )} end @impl true def describe(_opts) do [ message: "confirmation did not match value", vars: [] ] end end