mirror of
https://github.com/ash-project/ash.git
synced 2024-09-19 21:13:10 +12:00
WIP
This commit is contained in:
parent
afdd294e7f
commit
ef2f828250
6 changed files with 33 additions and 19 deletions
|
@ -19,3 +19,4 @@
|
|||
* all actions need to be performed in a transaction
|
||||
* document authorization thoroughly. *batch* (default) checks need to return a list of `ids` for which the check passed.
|
||||
* So many parts of the system are reliant on things having an `id` key explicitly. THis will need to be addressed some day, and will be a huge pain in the ass
|
||||
* Validate that the user resource has a get action
|
||||
|
|
21
lib/ash.ex
21
lib/ash.ex
|
@ -58,14 +58,14 @@ defmodule Ash do
|
|||
resource.data_layer()
|
||||
end
|
||||
|
||||
def get(resource, id, params \\ %{}, action \\ nil) do
|
||||
def get(resource, id, params \\ %{}, action \\ %{}) do
|
||||
# TODO: Figure out this interface
|
||||
params_with_filter =
|
||||
params
|
||||
|> Map.put_new(:filter, %{})
|
||||
|> Map.update!(:filter, &Map.put(&1, :id, id))
|
||||
|
||||
case read(resource, params_with_filter, action) do
|
||||
case read(resource, params_with_filter) do
|
||||
{:ok, %{results: [single_result]}} ->
|
||||
{:ok, single_result}
|
||||
|
||||
|
@ -81,26 +81,27 @@ defmodule Ash do
|
|||
end
|
||||
|
||||
# TODO: params
|
||||
def read(resource, user, params \\ %{}, action \\ nil) do
|
||||
action = action || primary_action(resource, :read)
|
||||
def read(resource, params \\ %{}) do
|
||||
action = Map.get(params, :action) || primary_action(resource, :read)
|
||||
params = Map.put_new(params, :user, :__none__)
|
||||
Ash.DataLayer.Actions.run_read_action(resource, action, params)
|
||||
end
|
||||
|
||||
# TODO: auth
|
||||
def create(resource, attributes, relationships, params \\ %{}, action \\ nil) do
|
||||
action = action || primary_action(resource, :create)
|
||||
def create(resource, attributes, relationships, params \\ %{}) do
|
||||
action = Map.get(params, :action) || primary_action(resource, :create)
|
||||
Ash.DataLayer.Actions.run_create_action(resource, action, attributes, relationships, params)
|
||||
end
|
||||
|
||||
# TODO: auth
|
||||
def update(%resource{} = record, attributes, relationships, params \\ %{}, action \\ nil) do
|
||||
action = action || primary_action(resource, :update)
|
||||
def update(%resource{} = record, attributes, relationships, params \\ %{}) do
|
||||
action = Map.get(params, :action) || primary_action(resource, :update)
|
||||
Ash.DataLayer.Actions.run_update_action(record, action, attributes, relationships, params)
|
||||
end
|
||||
|
||||
# TODO: auth
|
||||
def destroy(%resource{} = record, params \\ %{}, action \\ nil) do
|
||||
action = action || primary_action(resource, :destroy)
|
||||
def destroy(%resource{} = record, params \\ %{}) do
|
||||
action = Map.get(params, :action) || primary_action(resource, :destroy)
|
||||
Ash.DataLayer.Actions.run_destroy_action(record, action, params)
|
||||
end
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
defmodule Ash.Authorization.Authorizer do
|
||||
alias Ash.Authorization.Rule
|
||||
|
||||
def authorize_precheck(:__none__, rules, _context),
|
||||
do: {%{prediction: :allow}, Enum.map(rules, fn _ -> %{} end)}
|
||||
|
||||
def authorize_precheck(user, rules, context) do
|
||||
rules
|
||||
|> Enum.reduce({%{}, []}, fn rule, {instructions, per_check_data} ->
|
||||
|
@ -17,6 +20,8 @@ defmodule Ash.Authorization.Authorizer do
|
|||
|
||||
# Never call authorize w/o first calling authorize_precheck before
|
||||
# the operation
|
||||
def authorize(:__none__, _, _, _, _), do: :allow
|
||||
|
||||
def authorize(user, data, rules, context, per_check_data) do
|
||||
{_decision, remaining_records} =
|
||||
rules
|
||||
|
|
|
@ -9,6 +9,7 @@ defmodule Ash.Authorization.BuiltIn do
|
|||
item
|
||||
|> Map.get(relationship_name)
|
||||
|> Kernel.||([])
|
||||
|> List.wrap()
|
||||
|> Enum.find(fn related ->
|
||||
Map.get(related, relationship.destination_field) == user.id
|
||||
end)
|
||||
|
|
|
@ -51,7 +51,7 @@ defmodule Ash.Authorization.Rule do
|
|||
end
|
||||
|
||||
def run_check(
|
||||
%{check: check, extra_context: extra_context, kind: kind},
|
||||
%{check: check, extra_context: extra_context, kind: kind} = rule,
|
||||
user,
|
||||
data,
|
||||
context
|
||||
|
|
|
@ -2,7 +2,7 @@ defmodule Ash.DataLayer.Actions do
|
|||
def run_create_action(resource, action, attributes, relationships, params) do
|
||||
case Ash.Data.create(resource, action, attributes, relationships, params) do
|
||||
{:ok, record} ->
|
||||
Ash.Data.side_load(record, Map.get(params, :include, []), resource)
|
||||
Ash.Data.side_load(record, Map.get(params, :side_load, []), resource)
|
||||
|
||||
{:error, error} ->
|
||||
{:error, error}
|
||||
|
@ -11,7 +11,8 @@ defmodule Ash.DataLayer.Actions do
|
|||
|
||||
def run_update_action(%resource{} = record, action, attributes, relationships, params) do
|
||||
with {:ok, record} <- Ash.Data.update(record, action, attributes, relationships, params),
|
||||
{:ok, [record]} <- Ash.Data.side_load([record], Map.get(params, :include, []), resource) do
|
||||
{:ok, [record]} <-
|
||||
Ash.Data.side_load([record], Map.get(params, :side_load, []), resource) do
|
||||
{:ok, record}
|
||||
else
|
||||
{:error, error} -> {:error, error}
|
||||
|
@ -29,27 +30,32 @@ defmodule Ash.DataLayer.Actions do
|
|||
params: params
|
||||
}
|
||||
|
||||
user = Map.get(params, :user)
|
||||
user = Map.get(params || %{}, :user)
|
||||
|
||||
with {%{prediction: prediction} = instructions, per_check_data}
|
||||
when prediction != :unauthorized <-
|
||||
Ash.Authorization.Authorizer.authorize_precheck(user, action.rules, auth_context),
|
||||
params <- add_auth_side_loads(params, instructions),
|
||||
{:ok, query} <- Ash.Data.resource_to_query(resource),
|
||||
{:ok, filtered_query} <- Ash.Data.filter(resource, query, params),
|
||||
{:ok, paginator} <-
|
||||
Ash.DataLayer.Paginator.paginate(resource, action, filtered_query, params),
|
||||
{:ok, found} <- Ash.Data.get_many(paginator.query, resource),
|
||||
side_load_param <-
|
||||
deep_merge_side_loads(
|
||||
Map.get(params, :side_load, []),
|
||||
Map.get(instructions, :side_load, [])
|
||||
),
|
||||
{:ok, side_loaded} <-
|
||||
Ash.Data.side_load(found, side_load_param, resource),
|
||||
:allow <-
|
||||
Ash.Authorization.Authorizer.authorize(
|
||||
user,
|
||||
found,
|
||||
side_loaded,
|
||||
action.rules,
|
||||
auth_context,
|
||||
per_check_data
|
||||
),
|
||||
{:ok, result} <- Ash.Data.side_load(found, Map.get(params, :include, []), resource) do
|
||||
{:ok, %{paginator | results: result}}
|
||||
) do
|
||||
{:ok, %{paginator | results: side_loaded}}
|
||||
else
|
||||
{%{prediction: :unauthorized}, _} ->
|
||||
# TODO: Nice errors here!
|
||||
|
|
Loading…
Reference in a new issue