mirror of
https://github.com/ash-project/ash.git
synced 2024-09-20 13:33:20 +12:00
fix: handle atomic_ref templates and changing_attributes/1
This commit is contained in:
parent
e9d2d8c575
commit
f23f0a29fe
5 changed files with 96 additions and 44 deletions
|
@ -904,7 +904,7 @@ defmodule Ash.Api do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp alter_source({:ok, true, query}, api, actor, %Ash.Changeset{} = subject, opts) do
|
defp alter_source({:ok, true, query}, api, actor, %Ash.Changeset{} = subject, opts) do
|
||||||
case alter_source({:ok, true}, api, actor, subject, opts) do
|
case alter_source({:ok, true}, api, actor, subject, Keyword.put(opts, :base_query, query)) do
|
||||||
{:ok, true, new_subject} -> {:ok, true, new_subject, query}
|
{:ok, true, new_subject} -> {:ok, true, new_subject, query}
|
||||||
other -> other
|
other -> other
|
||||||
end
|
end
|
||||||
|
@ -939,6 +939,45 @@ defmodule Ash.Api do
|
||||||
|
|
||||||
case subject do
|
case subject do
|
||||||
%Ash.Query{} = query ->
|
%Ash.Query{} = query ->
|
||||||
|
alter_query(query, authorizer, authorizer_state, context)
|
||||||
|
|
||||||
|
%Ash.Changeset{} = changeset ->
|
||||||
|
context = Map.put(context, :changeset, changeset)
|
||||||
|
|
||||||
|
with {:ok, changeset, authorizer_state} <-
|
||||||
|
Ash.Authorizer.add_calculations(
|
||||||
|
authorizer,
|
||||||
|
changeset,
|
||||||
|
authorizer_state,
|
||||||
|
context
|
||||||
|
) do
|
||||||
|
if opts[:base_query] do
|
||||||
|
case alter_query(opts[:base_query], authorizer, authorizer_state, context) do
|
||||||
|
{:ok, true, query} ->
|
||||||
|
{:ok, true, changeset, query}
|
||||||
|
|
||||||
|
other ->
|
||||||
|
other
|
||||||
|
end
|
||||||
|
else
|
||||||
|
{:ok, true, changeset}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
%Ash.ActionInput{} = subject ->
|
||||||
|
{:ok, true, subject}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
{:ok, true}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp alter_source(other, _, _, _, _), do: other
|
||||||
|
|
||||||
|
defp alter_query(query, authorizer, authorizer_state, context) do
|
||||||
context = Map.put(context, :query, query)
|
context = Map.put(context, :query, query)
|
||||||
|
|
||||||
with {:ok, query, _} <-
|
with {:ok, query, _} <-
|
||||||
|
@ -969,33 +1008,8 @@ defmodule Ash.Api do
|
||||||
) do
|
) do
|
||||||
{:ok, true, %{query | filter: hydrated, sort: new_sort}}
|
{:ok, true, %{query | filter: hydrated, sort: new_sort}}
|
||||||
end
|
end
|
||||||
|
|
||||||
%Ash.Changeset{} = changeset ->
|
|
||||||
context = Map.put(context, :changeset, changeset)
|
|
||||||
|
|
||||||
with {:ok, changeset, _} <-
|
|
||||||
Ash.Authorizer.add_calculations(
|
|
||||||
authorizer,
|
|
||||||
changeset,
|
|
||||||
authorizer_state,
|
|
||||||
context
|
|
||||||
) do
|
|
||||||
{:ok, true, changeset}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
%Ash.ActionInput{} = subject ->
|
|
||||||
{:ok, true, subject}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
{:ok, true}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defp alter_source(other, _, _, _, _), do: other
|
|
||||||
|
|
||||||
defp run_check(api, actor, subject, opts) do
|
defp run_check(api, actor, subject, opts) do
|
||||||
authorizers =
|
authorizers =
|
||||||
Ash.Resource.Info.authorizers(subject.resource)
|
Ash.Resource.Info.authorizers(subject.resource)
|
||||||
|
|
|
@ -601,6 +601,8 @@ defmodule Ash.Filter do
|
||||||
{:_atomic_ref, field} when is_atom(field) ->
|
{:_atomic_ref, field} when is_atom(field) ->
|
||||||
if changeset do
|
if changeset do
|
||||||
Ash.Changeset.atomic_ref(changeset, field)
|
Ash.Changeset.atomic_ref(changeset, field)
|
||||||
|
else
|
||||||
|
{:_atomic_ref, field}
|
||||||
end
|
end
|
||||||
|
|
||||||
{:_context, fields} when is_list(fields) ->
|
{:_context, fields} when is_list(fields) ->
|
||||||
|
|
|
@ -720,6 +720,15 @@ defmodule Ash.Filter.Runtime do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp resolve_expr({:_actor, _}, _, _, _, _), do: :unknown
|
||||||
|
defp resolve_expr({:_arg, _}, _, _, _, _), do: :unknown
|
||||||
|
defp resolve_expr({:_ref, _}, _, _, _, _), do: :unknown
|
||||||
|
defp resolve_expr({:_ref, _, _}, _, _, _, _), do: :unknown
|
||||||
|
defp resolve_expr({:_parent, _}, _, _, _, _), do: :unknown
|
||||||
|
defp resolve_expr({:_parent, _, _}, _, _, _, _), do: :unknown
|
||||||
|
defp resolve_expr({:_atomic_ref, _}, _, _, _, _), do: :unknown
|
||||||
|
defp resolve_expr({:_context, _}, _, _, _, _), do: :unknown
|
||||||
|
|
||||||
defp resolve_expr(other, _, _, _, _), do: {:ok, other}
|
defp resolve_expr(other, _, _, _, _), do: {:ok, other}
|
||||||
|
|
||||||
defp try_cast_arguments(:var_args, args) do
|
defp try_cast_arguments(:var_args, args) do
|
||||||
|
|
|
@ -1051,7 +1051,7 @@ defmodule Ash.Policy.Authorizer do
|
||||||
{{check_module, check_opts}, true} ->
|
{{check_module, check_opts}, true} ->
|
||||||
result =
|
result =
|
||||||
try do
|
try do
|
||||||
check_module.auto_filter(authorizer.actor, authorizer, check_opts)
|
nil_to_false(check_module.auto_filter(authorizer.actor, authorizer, check_opts))
|
||||||
rescue
|
rescue
|
||||||
e ->
|
e ->
|
||||||
reraise Ash.Error.to_ash_error(e, __STACKTRACE__,
|
reraise Ash.Error.to_ash_error(e, __STACKTRACE__,
|
||||||
|
@ -1071,9 +1071,16 @@ defmodule Ash.Policy.Authorizer do
|
||||||
result =
|
result =
|
||||||
try do
|
try do
|
||||||
if :erlang.function_exported(check_module, :auto_filter_not, 3) do
|
if :erlang.function_exported(check_module, :auto_filter_not, 3) do
|
||||||
|
nil_to_false(
|
||||||
check_module.auto_filter_not(authorizer.actor, authorizer, check_opts)
|
check_module.auto_filter_not(authorizer.actor, authorizer, check_opts)
|
||||||
|
)
|
||||||
else
|
else
|
||||||
[not: check_module.auto_filter(authorizer.actor, authorizer, check_opts)]
|
[
|
||||||
|
not:
|
||||||
|
nil_to_false(
|
||||||
|
check_module.auto_filter(authorizer.actor, authorizer, check_opts)
|
||||||
|
)
|
||||||
|
]
|
||||||
end
|
end
|
||||||
rescue
|
rescue
|
||||||
e ->
|
e ->
|
||||||
|
@ -1103,6 +1110,9 @@ defmodule Ash.Policy.Authorizer do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp nil_to_false(nil), do: false
|
||||||
|
defp nil_to_false(v), do: v
|
||||||
|
|
||||||
def print_tuple_boolean({op, l, r}) when op in [:and, :or] do
|
def print_tuple_boolean({op, l, r}) when op in [:and, :or] do
|
||||||
"(#{print_tuple_boolean(l)} #{op} #{print_tuple_boolean(r)})"
|
"(#{print_tuple_boolean(l)} #{op} #{print_tuple_boolean(r)})"
|
||||||
end
|
end
|
||||||
|
@ -1148,12 +1158,15 @@ defmodule Ash.Policy.Authorizer do
|
||||||
{{check_module, check_opts}, required_status} ->
|
{{check_module, check_opts}, required_status} ->
|
||||||
additional_filter =
|
additional_filter =
|
||||||
if required_status do
|
if required_status do
|
||||||
check_module.auto_filter(authorizer.actor, authorizer, check_opts)
|
nil_to_false(check_module.auto_filter(authorizer.actor, authorizer, check_opts))
|
||||||
else
|
else
|
||||||
if :erlang.function_exported(check_module, :auto_filter_not, 3) do
|
if :erlang.function_exported(check_module, :auto_filter_not, 3) do
|
||||||
check_module.auto_filter_not(authorizer.actor, authorizer, check_opts)
|
nil_to_false(check_module.auto_filter_not(authorizer.actor, authorizer, check_opts))
|
||||||
else
|
else
|
||||||
[not: check_module.auto_filter(authorizer.actor, authorizer, check_opts)]
|
[
|
||||||
|
not:
|
||||||
|
nil_to_false(check_module.auto_filter(authorizer.actor, authorizer, check_opts))
|
||||||
|
]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -40,16 +40,30 @@ defmodule Ash.Policy.Check.ChangingAttributes do
|
||||||
{:cont, expr}
|
{:cont, expr}
|
||||||
|
|
||||||
{{:ok, from}, {:ok, to}} ->
|
{{:ok, from}, {:ok, to}} ->
|
||||||
|
if expr == true do
|
||||||
|
{:cont,
|
||||||
|
Ash.Expr.expr(not (ref(attribute) == ^from and ^atomic_ref(attribute) == ^to))}
|
||||||
|
else
|
||||||
|
{:cont,
|
||||||
Ash.Expr.expr(
|
Ash.Expr.expr(
|
||||||
^expr and not (ref(attribute) == ^from and ^atomic_ref(attribute) == ^to)
|
^expr and not (ref(attribute) == ^from and ^atomic_ref(attribute) == ^to)
|
||||||
)
|
)}
|
||||||
|
end
|
||||||
|
|
||||||
{{:ok, from}, :error} ->
|
{{:ok, from}, :error} ->
|
||||||
|
if expr == true do
|
||||||
|
{:cont, Ash.Expr.expr(ref(attribute) != ^from)}
|
||||||
|
else
|
||||||
{:cont, Ash.Expr.expr(^expr and ref(attribute) != ^from)}
|
{:cont, Ash.Expr.expr(^expr and ref(attribute) != ^from)}
|
||||||
|
end
|
||||||
|
|
||||||
{:error, {:ok, to}} ->
|
{:error, {:ok, to}} ->
|
||||||
|
if expr == true do
|
||||||
|
{:cont, Ash.Expr.expr(^atomic_ref(attribute) != ^to)}
|
||||||
|
else
|
||||||
{:cont, Ash.Expr.expr(^expr and ^atomic_ref(attribute) != ^to)}
|
{:cont, Ash.Expr.expr(^expr and ^atomic_ref(attribute) != ^to)}
|
||||||
end
|
end
|
||||||
|
end
|
||||||
else
|
else
|
||||||
{:cont, expr}
|
{:cont, expr}
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue