Current section

Files

Jump to
authorize lib authorize.ex
Raw

lib/authorize.ex

defmodule Authorize do
defmacro __using__(_options) do
quote do
import unquote(__MODULE__)
Module.register_attribute(__MODULE__, :rules, accumulate: true)
@before_compile unquote(__MODULE__)
end
end
def authorize(do: block) do
block
end
def create_authorize() do
quote do
def is_changeset?(%{__struct__: :"Elixir.Ecto.Changeset"}), do: true
def is_changeset?(_), do: false
def get_struct(%{__struct__: :"Elixir.Ecto.Changeset"} = changeset), do: changeset.data
def get_struct(struct), do: struct
def authorize_fields(struct_or_changeset, actor, actions, field, options \\ [])
def authorize_fields(struct_or_changeset, actor, actions, field, options)
when is_atom(field) do
authorize(struct_or_changeset, actor, actions, Keyword.put(options, :fields, [field]))
end
def authorize_fields(struct_or_changeset, actor, actions, fields, options) do
authorize(struct_or_changeset, actor, actions, Keyword.put(options, :fields, fields))
end
def authorize(struct_or_changeset, actor, action, options \\ []) do
@rules
|> Enum.reverse()
# filter based on actions
|> Enum.filter(fn
{acts, _, _} when is_atom(acts) -> acts == :all || acts == action
{acts, _, _} -> Enum.member?(acts, :all) || Enum.member?(acts, action)
end)
|> Enum.reduce(:next, fn
{_actions, description, rule_func}, :next ->
apply(__MODULE__, rule_func, [
struct_or_changeset,
Keyword.get(options, :fields, []),
actor
])
_fun, other ->
other
end)
|> case do
:next ->
{:error, "no authorization rule found"}
:ok ->
:ok
{:ok, reason} ->
if Keyword.get(options, :include_reason, false) do
{:ok, reason}
else
:ok
end
{:error, reason} ->
{:error, reason}
other ->
other
end
end
def authorize(struct_or_changeset, actor), do: authorize(struct_or_changeset, actor, :all)
end
end
defmacro __before_compile__(_env) do
create_authorize()
end
def create_rule(actions, description, struct_or_changeset, fields, actor, do: rule_block) do
rule_func = String.to_atom(description)
quote do
@rules {unquote(actions), unquote(description), unquote(rule_func)}
def unquote(rule_func)(unquote(struct_or_changeset), unquote(fields), unquote(actor)) do
case unquote(rule_block) do
:next ->
:next
:ok ->
{:ok, unquote(description)}
:error ->
{:error, unquote(description)}
# make composition of authorization functions possible
{:ok, description} ->
{:ok, description}
{:error, "no authorization rule found"} ->
:next
{:error, description} ->
{:error, description}
end
end
end
end
defmacro rule(description, struct_or_changeset, actor, do: rule_block)
when is_binary(description) do
create_rule(:all, description, struct_or_changeset, quote(do: field), actor, do: rule_block)
end
defmacro rule(description, changeset, fields, actor, do: rule_block)
when is_binary(description) do
create_rule(:all, description, changeset, fields, actor, do: rule_block)
end
defmacro rule(actions, description, struct_or_changeset, actor, do: rule_block)
when is_binary(description) do
create_rule(
actions,
description,
struct_or_changeset,
quote(do: field),
actor,
do: rule_block
)
end
defmacro rule(actions, description, struct_or_changeset, fields, actor, do: rule_block)
when is_binary(description) do
create_rule(actions, description, struct_or_changeset, fields, actor, do: rule_block)
end
end