Skip to content

Commit

Permalink
fix: throw validation error when trying to set public arguments in pr…
Browse files Browse the repository at this point in the history
…ivate_arguments (#1663)
  • Loading branch information
StephanH90 authored Dec 17, 2024
1 parent 6d75a34 commit e9d4c42
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 5 deletions.
30 changes: 29 additions & 1 deletion lib/ash/action_input.ex
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ defmodule Ash.ActionInput do

input =
Enum.reduce(opts[:private_arguments] || %{}, input, fn {k, v}, input ->
Ash.ActionInput.set_argument(input, k, v)
Ash.ActionInput.set_private_argument(input, k, v)
end)

input
Expand Down Expand Up @@ -252,6 +252,34 @@ defmodule Ash.ActionInput do
end
end

@doc """
Sets a private argument value
"""
@spec set_private_argument(input :: t(), name :: atom, value :: term()) :: t()
def set_private_argument(input, name, value) do
argument =
Enum.find(
input.action.arguments,
&(&1.name == name || to_string(&1.name) == name)
)

cond do
is_nil(argument) ->
input

argument.public? ->
add_invalid_errors(
value,
input,
argument,
"can't set public arguments with set_private_argument/3"
)

true ->
set_argument(input, name, value)
end
end

@doc """
Deep merges the provided map into the input context that can be used later
Expand Down
51 changes: 49 additions & 2 deletions lib/ash/changeset/changeset.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1587,7 +1587,7 @@ defmodule Ash.Changeset do

changeset =
Enum.reduce(opts[:private_arguments] || %{}, changeset, fn {k, v}, changeset ->
Ash.Changeset.set_argument(changeset, k, v)
set_private_argument_for_action(changeset, k, v)
end)

changeset
Expand Down Expand Up @@ -1928,7 +1928,7 @@ defmodule Ash.Changeset do

changeset =
Enum.reduce(opts[:private_arguments] || %{}, changeset, fn {k, v}, changeset ->
Ash.Changeset.set_argument(changeset, k, v)
set_private_argument_for_action(changeset, k, v)
end)

changeset =
Expand Down Expand Up @@ -5080,6 +5080,53 @@ defmodule Ash.Changeset do
do_set_argument(changeset, argument, value)
end

@doc """
Add a private argument to the changeset, which will be provided to the action.
"""
@spec set_private_argument(t(), atom, term) :: t()
def set_private_argument(changeset, argument, value) do
do_set_private_argument(
changeset,
argument,
value,
"can't set public arguments with set_private_argument/3"
)
end

defp set_private_argument_for_action(changeset, argument, value) do
do_set_private_argument(
changeset,
argument,
value,
"can't set public arguments using the private_arguments option."
)
end

defp do_set_private_argument(changeset, name, value, error_msg) do
argument =
Enum.find(
changeset.action.arguments,
&(&1.name == name || to_string(&1.name) == name)
)

cond do
is_nil(argument) ->
changeset

argument.public? ->
add_invalid_errors(
value,
:argument,
changeset,
argument,
error_msg
)

true ->
set_argument(changeset, name, value)
end
end

@doc """
Add an argument to the changeset, which will be provided to the action.
Expand Down
4 changes: 2 additions & 2 deletions test/actions/create_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ defmodule Ash.Test.Actions.CreateTest do
end

create :create_with_private_argument do
argument :private_name, :string, allow_nil?: false
argument :private_name, :string, allow_nil?: false, public?: false
accept [:title]

change set_attribute(:private_name, arg(:private_name))
Expand Down Expand Up @@ -584,7 +584,7 @@ defmodule Ash.Test.Actions.CreateTest do
end

test "allows setting private arguments" do
assert %Post{title: "title", private_name: "private"} =
assert %Post{title: "title"} =
Post
|> Ash.Changeset.for_create(:create_with_private_argument, %{title: "title"},
private_arguments: %{private_name: "private"}
Expand Down
40 changes: 40 additions & 0 deletions test/changeset/changeset_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ defmodule Ash.Test.Changeset.ChangesetTest do
create :with_name_validation do
validate present(:name), message: "this validates the name is present"
end

create :create_with_private_argument do
argument :ip_address_public, :string, allow_nil?: false, public?: true
end
end

attributes do
Expand Down Expand Up @@ -1220,6 +1224,42 @@ defmodule Ash.Test.Changeset.ChangesetTest do
}).errors
end

test "private_arguments are validated" do
assert [
%Ash.Error.Changes.InvalidArgument{
class: :invalid,
field: :ip_address_public,
message: "can't set public arguments using the private_arguments option."
}
] =
Ash.Changeset.for_create(Category, :create_with_private_argument, %{},
private_arguments: %{ip_address_public: "123"}
).errors

assert [
%Ash.Error.Changes.InvalidArgument{
class: :invalid,
field: :ip_address_public,
message: "can't set public arguments with set_private_argument/3"
},
%Ash.Error.Changes.Required{
class: :invalid,
field: :ip_address_public
}
] =
Ash.Changeset.for_create(Category, :create_with_private_argument, %{})
|> Ash.Changeset.set_private_argument(:ip_address_public, "123")
|> Map.get(:errors)

assert [] =
Ash.Changeset.for_create(
Category,
:create_with_private_argument,
%{ip_address_public: "123"},
private_arguments: %{}
).errors
end

test "for_action works the same as calling for_<action>" do
changeset_1 =
Category
Expand Down

0 comments on commit e9d4c42

Please sign in to comment.