improvement: add dynamic allow list

improvement: uniqify list_references
This commit is contained in:
Zach Daniel 2022-04-07 22:33:48 -04:00
parent 5bf8c39975
commit c98910add6
6 changed files with 35 additions and 5 deletions

View file

@ -3,6 +3,7 @@
locals_without_parens = [ locals_without_parens = [
accept: 1, accept: 1,
action: 1, action: 1,
allow: 1,
allow_async?: 1, allow_async?: 1,
allow_nil?: 1, allow_nil?: 1,
allow_nil_input: 1, allow_nil_input: 1,

View file

@ -549,11 +549,25 @@ defmodule Ash.Api do
|> Enum.find(&(&1 == resource)) |> Enum.find(&(&1 == resource))
end end
|> case do |> case do
nil -> {:error, NoSuchResource.exception(resource: resource)} nil ->
resource -> {:ok, resource} if allowed?(allow(api), resource) do
{:ok, resource}
else
{:error, NoSuchResource.exception(resource: resource)}
end
resource ->
{:ok, resource}
end end
end end
@spec allowed?(mfa | nil, module()) :: boolean
defp allowed?({m, f, a}, resource) do
apply(m, f, List.wrap(a) ++ [resource])
end
defp allowed?(_, _), do: false
@spec resources(Ash.Api.t()) :: list(Ash.Resource.t()) @spec resources(Ash.Api.t()) :: list(Ash.Resource.t())
def resources(api) do def resources(api) do
api api
@ -577,7 +591,12 @@ defmodule Ash.Api do
Extension.get_opt(api, [:resources], :registry, nil, true) Extension.get_opt(api, [:resources], :registry, nil, true)
end end
@spec timeout(atom) :: :timeout | integer() @spec allow(atom) :: mfa() | nil
def allow(api) do
Extension.get_opt(api, [:resources], :allow, nil, true)
end
@spec timeout(atom) :: nil | :infinity | integer()
def timeout(api) do def timeout(api) do
Extension.get_opt(api, [:execution], :timeout, 30_000, true) Extension.get_opt(api, [:execution], :timeout, 30_000, true)
end end

View file

@ -31,12 +31,16 @@ defmodule Ash.Api.Dsl do
""" """
], ],
schema: [ schema: [
allow: [
type: :mfa,
doc: """
Support a dynamic resource list by providing a callback that checks wether or not the resource should be allowed.
"""
],
allow_unregistered?: [ allow_unregistered?: [
type: :boolean, type: :boolean,
default: false, default: false,
doc: """ doc: """
This is still experimental, but will be supported if you run into any issues.
By default, an api will only work with resources that are explicitly included in the provided registry. In order to separate your By default, an api will only work with resources that are explicitly included in the provided registry. In order to separate your
application into multiple domains, you may wish to "mix and match" your resources across contexts. Specifying this option allows you application into multiple domains, you may wish to "mix and match" your resources across contexts. Specifying this option allows you
to refer to resources in different apis in your resources, and allows providing any resource to api actions (to facilitate that requirement). to refer to resources in different apis in your resources, and allows providing any resource to api actions (to facilitate that requirement).

View file

@ -54,6 +54,10 @@ defmodule Ash.EmbeddableType do
resources do resources do
allow_unregistered? true allow_unregistered? true
end end
execution do
timeout :infinity
end
end end
@doc false @doc false

View file

@ -791,6 +791,7 @@ defmodule Ash.Filter do
else else
Enum.map(refs, & &1.attribute) Enum.map(refs, & &1.attribute)
end end
|> Enum.uniq()
end end
def put_at_path(value, []), do: value def put_at_path(value, []), do: value

View file

@ -129,6 +129,7 @@ defmodule Ash.Query.Aggregate do
|> Enum.map(fn {key, value} -> |> Enum.map(fn {key, value} ->
{key, Enum.uniq_by(Enum.map(value, &elem(&1, 1)), & &1.name)} {key, Enum.uniq_by(Enum.map(value, &elem(&1, 1)), & &1.name)}
end) end)
|> Enum.uniq()
|> Enum.reduce({[], [], []}, fn {{aggregate_resource, relationship_path, ref_path}, |> Enum.reduce({[], [], []}, fn {{aggregate_resource, relationship_path, ref_path},
aggregates}, aggregates},
{auth_requests, value_requests, aggregates_in_query} -> {auth_requests, value_requests, aggregates_in_query} ->