Packages
ash_authentication
3.11.7
5.0.0-rc.12
5.0.0-rc.11
5.0.0-rc.10
5.0.0-rc.9
5.0.0-rc.8
5.0.0-rc.7
5.0.0-rc.6
5.0.0-rc.5
5.0.0-rc.4
5.0.0-rc.3
5.0.0-rc.2
5.0.0-rc.1
5.0.0-rc.0
4.14.1
4.14.0
4.13.7
4.13.6
4.13.5
4.13.4
4.13.3
4.13.2
retired
4.13.1
retired
4.13.0
4.12.0
4.11.0
4.10.0
4.9.9
4.9.8
4.9.7
4.9.6
4.9.5
4.9.4
4.9.3
4.9.2
4.9.1
4.9.0
4.8.7
4.8.6
4.8.5
4.8.3
4.8.2
4.8.1
4.8.0
4.7.6
4.7.5
4.7.4
4.7.3
4.7.2
4.7.1
4.7.0
4.6.4
4.6.3
4.6.2
4.6.1
4.6.0
4.5.6
4.5.5
4.5.4
4.5.3
4.5.2
4.5.1
4.5.0
4.4.9
4.4.8
4.4.7
4.4.6
4.4.5
4.4.4
4.4.3
4.4.2
4.4.1
4.4.0
4.3.12
4.3.11
4.3.10
4.3.9
4.3.8
4.3.7
4.3.6
4.3.5
4.3.4
4.3.3
4.3.2
4.3.1
4.3.0
4.2.7
4.2.6
4.2.5
4.2.4
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.4
4.0.3
4.0.2
4.0.1
4.0.0
4.0.0-rc.6
4.0.0-rc.5
4.0.0-rc.3
4.0.0-rc.2
4.0.0-rc.1
4.0.0-rc.0
3.12.4
3.12.3
3.12.2
3.12.1
3.12.0
3.11.16
3.11.15
3.11.14
3.11.13
3.11.12
3.11.11
3.11.10
3.11.9
3.11.8
3.11.7
3.11.6
3.11.5
3.11.4
3.11.3
3.11.2
3.11.1
3.11.0
3.10.8
3.10.7
3.10.6
3.10.5
3.10.4
3.10.3
3.10.2
3.10.1
3.10.0
3.9.6
3.9.5
3.9.4
3.9.3
3.9.2
3.9.1
3.9.0
3.8.0
3.7.9
3.7.8
3.7.6
3.7.5
3.7.4
3.7.3
3.7.2
3.7.1
3.7.0
3.6.1
3.6.0
3.5.3
3.5.2
3.5.1
3.5.0
3.3.1
3.3.0
3.2.2
3.2.1
3.2.0
3.1.0
3.0.3
Authentication extension for the Ash Framework.
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/ash_authentication/utils.ex
defmodule AshAuthentication.Utils do
@moduledoc false
alias Ash.{Api, Resource}
alias Spark.{Dsl, Dsl.Transformer}
@doc """
Returns `true` if `falsy` is either `nil` or `false`.
"""
@spec is_falsy(any) :: Macro.t()
defguard is_falsy(falsy) when falsy in [nil, false]
@doc """
Returns `false` if `truthy` is either `nil` or `false`.
"""
@spec is_truthy(any) :: Macro.t()
defguard is_truthy(truthy) when truthy not in [nil, false]
@doc """
Convert a list of `String.Chars.t` into a sentence.
## Example
iex> ~w[Marty Doc Einstein] |> to_sentence()
"Marty, Doc and Einstein"
"""
@spec to_sentence(Enum.t(), [
{:separator, String.t()} | {:final, String.t()} | {:whitespace, boolean}
]) :: String.t()
def to_sentence(elements, opts \\ []) do
opts =
[separator: ",", final: "and", whitespace: true]
|> Keyword.merge(opts)
|> Map.new()
elements
|> Enum.to_list()
|> case do
[] ->
""
[element] ->
to_string(element)
[_ | _] = elements ->
elements
|> Enum.reverse()
|> convert_to_sentence("", opts.separator, opts.final, opts.whitespace)
end
end
defp convert_to_sentence([last], result, _, final, true), do: "#{result} #{final} #{last}"
defp convert_to_sentence([last], result, _, final, false), do: "#{result}#{final}#{last}"
defp convert_to_sentence([next | rest], "", sep, final, ws),
do: convert_to_sentence(rest, to_string(next), sep, final, ws)
defp convert_to_sentence([next | rest], result, sep, final, true),
do: convert_to_sentence(rest, "#{result}#{sep} #{next}", sep, final, true)
defp convert_to_sentence([next | rest], result, sep, final, false),
do: convert_to_sentence(rest, "#{result}#{sep}#{next}", sep, final, false)
@doc """
Optionally append an element to a collection.
When `test` is truthy, append `element` to the collection.
"""
@spec maybe_append(Enum.t(), test :: any, element :: any) :: Enum.t()
def maybe_append(collection, test, _element) when is_falsy(test), do: collection
def maybe_append(collection, _test, element), do: Enum.concat(collection, [element])
@doc """
Optionally concat a collection to another collection.
When `test` is truthy, concat the collections together.
"""
@spec maybe_concat(Enum.t(), test :: any, Enum.t()) :: Enum.t()
def maybe_concat(collection, test, _new_elements) when is_falsy(test), do: collection
def maybe_concat(collection, _test, new_elements), do: Enum.concat(collection, new_elements)
@doc """
Used within transformers to optionally build actions as needed.
"""
@spec maybe_build_action(Dsl.t(), atom, (map -> map)) :: {:ok, atom | map} | {:error, any}
def maybe_build_action(dsl_state, action_name, builder) when is_function(builder, 1) do
with nil <- Resource.Info.action(dsl_state, action_name),
{:ok, action} <- builder.(dsl_state) do
{:ok, Transformer.add_entity(dsl_state, [:actions], action)}
else
action when is_map(action) -> {:ok, dsl_state}
{:error, reason} -> {:error, reason}
end
end
@doc """
Used within transformers to optionally build attributes as needed.
"""
@spec maybe_build_attribute(Dsl.t(), atom, atom | module, keyword) :: {:ok, Dsl.t()}
def maybe_build_attribute(dsl_state, name, type, options) do
if Resource.Info.attribute(dsl_state, name) do
{:ok, dsl_state}
else
options =
options
|> Keyword.put(:name, name)
|> Keyword.put(:type, type)
attribute = Transformer.build_entity!(Resource.Dsl, [:attributes], :attribute, options)
{:ok, Transformer.add_entity(dsl_state, [:attributes], attribute)}
end
end
@doc """
Used within transformers to optionally build relationships as needed.
"""
@spec maybe_build_relationship(
Dsl.t(),
relationship_name :: atom,
(Dsl.t() -> {:ok, Resource.Relationships.relationship()})
) :: {:ok, Dsl.t()} | {:error, Exception.t()}
def maybe_build_relationship(dsl_state, relationship_name, builder)
when is_function(builder, 1) do
with :error <- find_relationship(dsl_state, relationship_name),
{:ok, relationship} <- builder.(dsl_state) do
{:ok, Transformer.add_entity(dsl_state, [:relationships], relationship)}
else
{:ok, _relationship} -> {:ok, dsl_state}
{:error, reason} -> {:error, reason}
end
end
@doc """
Find a relationship from a resource.
"""
@spec find_relationship(Dsl.t(), relationship_name :: atom) ::
{:ok, Resource.Relationships.relationship()} | :error
def find_relationship(dsl_state, relationship_name) do
dsl_state
|> Resource.Info.relationships()
|> Enum.find(&(&1.name == relationship_name))
|> case do
nil -> :error
relationship -> {:ok, relationship}
end
end
@doc """
Optionally set a field in a map.
Like `Map.put_new/3` except that it overwrites fields if their contents are
falsy.
"""
@spec maybe_set_field(map, any, any) :: map
def maybe_set_field(map, field, value) when is_falsy(:erlang.map_get(field, map)),
do: Map.put(map, field, value)
def maybe_set_field(map, _field, _value), do: map
@doc """
Like `maybe_set_field/3` except that the value is lazily generated.
"""
@spec maybe_set_field_lazy(input, any, (input -> value)) :: map when input: map, value: any
def maybe_set_field_lazy(map, field, generator)
when is_falsy(:erlang.map_get(field, map)) and is_function(generator, 1),
do: Map.put(map, field, generator.(map))
def maybe_set_field_lazy(map, _field, _generator), do: map
@doc """
Asserts that `resource` is an Ash resource and `extension` is a Spark DSL
extension.
"""
@spec assert_resource_has_extension(Resource.t(), Spark.Dsl.Extension.t()) ::
:ok | {:error, term}
def assert_resource_has_extension(resource, extension) do
with :ok <- assert_is_resource(resource) do
assert_has_extension(resource, extension)
end
end
@doc """
Asserts that `module` is actually an Ash resource.
"""
@spec assert_is_resource(Resource.t()) :: :ok | {:error, term}
def assert_is_resource(module) do
with :ok <- assert_is_module(module),
true <- function_exported?(module, :spark_is, 0),
Resource <- module.spark_is() do
:ok
else
_ ->
{:error, "Module `#{inspect(module)}` is not an Ash resource"}
end
end
@doc """
Asserts that `module` is actually an Ash API.
"""
@spec assert_is_api(Api.t()) :: :ok | {:error, term}
def assert_is_api(module) do
with :ok <- assert_is_module(module),
true <- function_exported?(module, :spark_is, 0),
Api <- module.spark_is() do
:ok
else
_ -> {:error, "Module `#{inspect(module)}` is not an Ash API"}
end
end
@doc """
Asserts that `module` is a Spark DSL extension.
"""
@spec assert_is_extension(Spark.Dsl.Extension.t()) :: :ok | {:error, term}
def assert_is_extension(extension) do
with :ok <- assert_is_module(extension) do
assert_has_behaviour(extension, Spark.Dsl.Extension)
end
end
@doc """
Asserts that `module` is actually a module.
"""
@spec assert_is_module(module) :: :ok | {:error, term}
def assert_is_module(module) when is_atom(module) do
case Code.ensure_compiled(module) do
{:module, _} -> :ok
_ -> {:error, "Argument `#{inspect(module)}` is not a valid module"}
end
end
def assert_is_module(module),
do: {:error, "Argument `#{inspect(module)}` is not a valid module"}
@doc """
Asserts that `module` is extended by `extension`.
"""
@spec assert_has_extension(Resource.t(), Spark.Dsl.Extension.t()) :: :ok | {:error, term}
def assert_has_extension(module, extension) do
if extension in Spark.extensions(module) do
:ok
else
{:error, "Module `#{inspect(module)}` is not extended by `#{inspect(extension)}`"}
end
end
@doc """
Asserts that `module` implements `behaviour`.
"""
@spec assert_has_behaviour(module, module) :: :ok | {:error, term}
def assert_has_behaviour(module, behaviour) do
if Spark.implements_behaviour?(module, behaviour) do
:ok
else
{:error,
"Module `#{inspect(module)}` does not implement the `#{inspect(behaviour)}` behaviour"}
end
end
end