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
|
||||
|
||||
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}
|
||||
other -> other
|
||||
end
|
||||
|
@ -939,48 +939,29 @@ defmodule Ash.Api do
|
|||
|
||||
case subject do
|
||||
%Ash.Query{} = query ->
|
||||
context = Map.put(context, :query, query)
|
||||
|
||||
with {:ok, query, _} <-
|
||||
Ash.Authorizer.add_calculations(
|
||||
authorizer,
|
||||
query,
|
||||
authorizer_state,
|
||||
context
|
||||
),
|
||||
{:ok, new_filter} <-
|
||||
Ash.Authorizer.alter_filter(
|
||||
authorizer,
|
||||
authorizer_state,
|
||||
query.filter,
|
||||
context
|
||||
),
|
||||
{:ok, hydrated} <-
|
||||
Ash.Filter.hydrate_refs(new_filter, %{
|
||||
resource: query.resource,
|
||||
public?: false
|
||||
}),
|
||||
{:ok, new_sort} <-
|
||||
Ash.Authorizer.alter_sort(
|
||||
authorizer,
|
||||
authorizer_state,
|
||||
query.sort,
|
||||
context
|
||||
) do
|
||||
{:ok, true, %{query | filter: hydrated, sort: new_sort}}
|
||||
end
|
||||
alter_query(query, authorizer, authorizer_state, context)
|
||||
|
||||
%Ash.Changeset{} = changeset ->
|
||||
context = Map.put(context, :changeset, changeset)
|
||||
|
||||
with {:ok, changeset, _} <-
|
||||
with {:ok, changeset, authorizer_state} <-
|
||||
Ash.Authorizer.add_calculations(
|
||||
authorizer,
|
||||
changeset,
|
||||
authorizer_state,
|
||||
context
|
||||
) do
|
||||
{:ok, true, changeset}
|
||||
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 ->
|
||||
|
@ -996,6 +977,39 @@ defmodule Ash.Api do
|
|||
|
||||
defp alter_source(other, _, _, _, _), do: other
|
||||
|
||||
defp alter_query(query, authorizer, authorizer_state, context) do
|
||||
context = Map.put(context, :query, query)
|
||||
|
||||
with {:ok, query, _} <-
|
||||
Ash.Authorizer.add_calculations(
|
||||
authorizer,
|
||||
query,
|
||||
authorizer_state,
|
||||
context
|
||||
),
|
||||
{:ok, new_filter} <-
|
||||
Ash.Authorizer.alter_filter(
|
||||
authorizer,
|
||||
authorizer_state,
|
||||
query.filter,
|
||||
context
|
||||
),
|
||||
{:ok, hydrated} <-
|
||||
Ash.Filter.hydrate_refs(new_filter, %{
|
||||
resource: query.resource,
|
||||
public?: false
|
||||
}),
|
||||
{:ok, new_sort} <-
|
||||
Ash.Authorizer.alter_sort(
|
||||
authorizer,
|
||||
authorizer_state,
|
||||
query.sort,
|
||||
context
|
||||
) do
|
||||
{:ok, true, %{query | filter: hydrated, sort: new_sort}}
|
||||
end
|
||||
end
|
||||
|
||||
defp run_check(api, actor, subject, opts) do
|
||||
authorizers =
|
||||
Ash.Resource.Info.authorizers(subject.resource)
|
||||
|
|
|
@ -601,6 +601,8 @@ defmodule Ash.Filter do
|
|||
{:_atomic_ref, field} when is_atom(field) ->
|
||||
if changeset do
|
||||
Ash.Changeset.atomic_ref(changeset, field)
|
||||
else
|
||||
{:_atomic_ref, field}
|
||||
end
|
||||
|
||||
{:_context, fields} when is_list(fields) ->
|
||||
|
|
|
@ -720,6 +720,15 @@ defmodule Ash.Filter.Runtime do
|
|||
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 try_cast_arguments(:var_args, args) do
|
||||
|
|
|
@ -1051,7 +1051,7 @@ defmodule Ash.Policy.Authorizer do
|
|||
{{check_module, check_opts}, true} ->
|
||||
result =
|
||||
try do
|
||||
check_module.auto_filter(authorizer.actor, authorizer, check_opts)
|
||||
nil_to_false(check_module.auto_filter(authorizer.actor, authorizer, check_opts))
|
||||
rescue
|
||||
e ->
|
||||
reraise Ash.Error.to_ash_error(e, __STACKTRACE__,
|
||||
|
@ -1071,9 +1071,16 @@ defmodule Ash.Policy.Authorizer do
|
|||
result =
|
||||
try 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
|
||||
[not: check_module.auto_filter(authorizer.actor, authorizer, check_opts)]
|
||||
[
|
||||
not:
|
||||
nil_to_false(
|
||||
check_module.auto_filter(authorizer.actor, authorizer, check_opts)
|
||||
)
|
||||
]
|
||||
end
|
||||
rescue
|
||||
e ->
|
||||
|
@ -1103,6 +1110,9 @@ defmodule Ash.Policy.Authorizer do
|
|||
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
|
||||
"(#{print_tuple_boolean(l)} #{op} #{print_tuple_boolean(r)})"
|
||||
end
|
||||
|
@ -1148,12 +1158,15 @@ defmodule Ash.Policy.Authorizer do
|
|||
{{check_module, check_opts}, required_status} ->
|
||||
additional_filter =
|
||||
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
|
||||
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
|
||||
[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
|
||||
|
||||
|
|
|
@ -40,15 +40,29 @@ defmodule Ash.Policy.Check.ChangingAttributes do
|
|||
{:cont, expr}
|
||||
|
||||
{{:ok, from}, {:ok, to}} ->
|
||||
Ash.Expr.expr(
|
||||
^expr and not (ref(attribute) == ^from and ^atomic_ref(attribute) == ^to)
|
||||
)
|
||||
if expr == true do
|
||||
{:cont,
|
||||
Ash.Expr.expr(not (ref(attribute) == ^from and ^atomic_ref(attribute) == ^to))}
|
||||
else
|
||||
{:cont,
|
||||
Ash.Expr.expr(
|
||||
^expr and not (ref(attribute) == ^from and ^atomic_ref(attribute) == ^to)
|
||||
)}
|
||||
end
|
||||
|
||||
{{:ok, from}, :error} ->
|
||||
{:cont, Ash.Expr.expr(^expr and ref(attribute) != ^from)}
|
||||
if expr == true do
|
||||
{:cont, Ash.Expr.expr(ref(attribute) != ^from)}
|
||||
else
|
||||
{:cont, Ash.Expr.expr(^expr and ref(attribute) != ^from)}
|
||||
end
|
||||
|
||||
{:error, {:ok, to}} ->
|
||||
{:cont, Ash.Expr.expr(^expr and ^atomic_ref(attribute) != ^to)}
|
||||
if expr == true do
|
||||
{:cont, Ash.Expr.expr(^atomic_ref(attribute) != ^to)}
|
||||
else
|
||||
{:cont, Ash.Expr.expr(^expr and ^atomic_ref(attribute) != ^to)}
|
||||
end
|
||||
end
|
||||
else
|
||||
{:cont, expr}
|
||||
|
|
Loading…
Reference in a new issue