improvement: allow turning new authorization behavior off

This commit is contained in:
Zach Daniel 2024-02-20 13:28:32 -05:00
parent 2b8a6926ae
commit 27d0ebb154
5 changed files with 75 additions and 31 deletions

View file

@ -22,7 +22,7 @@ if Mix.env() == :test do
triggered_say_hello: 10 triggered_say_hello: 10
] ]
config :ash_oban, :actor_persister, AshOban.Test.ActorPersister config :ash_oban, actor_persister: AshOban.Test.ActorPersister
config :ash_oban, AshOban.Test.Repo, config :ash_oban, AshOban.Test.Repo,
username: "postgres", username: "postgres",

View file

@ -114,6 +114,23 @@ and
} }
``` ```
## Authorizing actions
As of v0.2, `authorize?: true` is passed into every action that is called. This may be a breaking change for some users that are using policies. There are two ways to get around this:
1. you can set `config :ash_oban, authorize?: false` (easiest, reverts to old behavior, but not recommended)
2. you can install the bypass at the top of your policies in any resource that you have triggers on that has policies:
```elixir
policies do
bypass AshOban.Checks.AshObanInteraction do
authorize_if always()
end
...the rest of your policies
end
```
## Persisting the actor along with a job ## Persisting the actor along with a job
Create a module that is responsible for translating the current user to a value that will be JSON encoded, and for turning that encoded value back into an actor. Create a module that is responsible for translating the current user to a value that will be JSON encoded, and for turning that encoded value back into an actor.

View file

@ -394,22 +394,27 @@ defmodule AshOban do
|> case do |> case do
%AshOban.Schedule{worker: worker} -> %AshOban.Schedule{worker: worker} ->
%{} %{}
|> persist_actor(opts[:actor]) |> store_actor(opts[:actor])
|> worker.new() |> worker.new()
|> Oban.insert!() |> Oban.insert!()
%AshOban.Trigger{scheduler: scheduler} -> %AshOban.Trigger{scheduler: scheduler} ->
%{} %{}
|> persist_actor(opts[:actor]) |> store_actor(opts[:actor])
|> scheduler.new() |> scheduler.new()
|> Oban.insert!() |> Oban.insert!()
end end
end end
@spec persist_actor(args :: map, actor :: any) :: any @spec authorize? :: boolean
def persist_actor(args, nil), do: args def authorize? do
Application.get_env(:ash_oban, :authorize?, true)
end
def persist_actor(args, actor) do @spec store_actor(args :: map, actor :: any) :: any
def store_actor(args, nil), do: args
def store_actor(args, actor) do
case Application.get_env(:ash_oban, :actor_persister) do case Application.get_env(:ash_oban, :actor_persister) do
nil -> nil ->
args args
@ -463,7 +468,7 @@ defmodule AshOban do
end end
%{primary_key: Map.take(record, primary_key), metadata: metadata} %{primary_key: Map.take(record, primary_key), metadata: metadata}
|> AshOban.persist_actor(opts[:actor]) |> AshOban.store_actor(opts[:actor])
|> trigger.worker.new(oban_job_opts) |> trigger.worker.new(oban_job_opts)
|> Oban.insert!() |> Oban.insert!()
end end

View file

@ -73,27 +73,39 @@ defmodule AshOban.Transformers.DefineActionWorkers do
require Logger require Logger
@impl unquote(worker) @impl unquote(worker)
def unquote(function_name)(%Oban.Job{} = job) do def unquote(function_name)(%Oban.Job{args: args} = job) do
AshOban.debug( case AshOban.lookup_actor(args["actor"]) do
"Scheduled action #{unquote(inspect(resource))}.#{unquote(scheduled_action.name)} triggered.", {:ok, actor} ->
unquote(scheduled_action.debug?) authorize? = AshOban.authorize?()
)
input = unquote(Macro.escape(scheduled_action.action_input || %{})) AshOban.debug(
"Scheduled action #{unquote(inspect(resource))}.#{unquote(scheduled_action.name)} triggered.",
unquote(scheduled_action.debug?)
)
input = input = unquote(Macro.escape(scheduled_action.action_input || %{}))
if job.max_attempts == job.attempt do
Map.put(input, :last_oban_attempt?, true)
else
Map.put(input, :last_oban_attempt?, false)
end
unquote(resource) input =
|> Ash.ActionInput.for_action( if job.max_attempts == job.attempt do
unquote(scheduled_action.action), Map.put(input, :last_oban_attempt?, true)
input else
) Map.put(input, :last_oban_attempt?, false)
|> unquote(api).run_action() end
unquote(resource)
|> Ash.ActionInput.for_action(
unquote(scheduled_action.action),
input,
authorize?: authorize?,
actor: actor
)
|> unquote(api).run_action!()
:ok
{:error, error} ->
raise Ash.Error.to_ash_error(error)
end
end end
end, end,
Macro.Env.location(__ENV__) Macro.Env.location(__ENV__)

View file

@ -100,7 +100,7 @@ defmodule AshOban.Transformers.DefineSchedulers do
|> Ash.Query.select(unquote(primary_key)) |> Ash.Query.select(unquote(primary_key))
|> limit_stream() |> limit_stream()
|> Ash.Query.for_read(unquote(trigger.read_action), %{}, |> Ash.Query.for_read(unquote(trigger.read_action), %{},
authorize?: true, authorize?: AshOban.authorize?(),
actor: actor actor: actor
) )
|> unquote(api).stream!(unquote(batch_opts)) |> unquote(api).stream!(unquote(batch_opts))
@ -115,7 +115,7 @@ defmodule AshOban.Transformers.DefineSchedulers do
|> limit_stream() |> limit_stream()
|> filter() |> filter()
|> Ash.Query.for_read(unquote(trigger.read_action), %{}, |> Ash.Query.for_read(unquote(trigger.read_action), %{},
authorize?: true, authorize?: AshOban.authorize?(),
actor: actor actor: actor
) )
|> unquote(api).stream!() |> unquote(api).stream!()
@ -432,12 +432,17 @@ defmodule AshOban.Transformers.DefineSchedulers do
primary_key, primary_key,
stacktrace stacktrace
) do ) do
authorize? = AshOban.authorize?()
case AshOban.lookup_actor(args["actor"]) do case AshOban.lookup_actor(args["actor"]) do
{:ok, actor} -> {:ok, actor} ->
query() query()
|> Ash.Query.do_filter(primary_key) |> Ash.Query.do_filter(primary_key)
|> Ash.Query.set_context(%{private: %{ash_oban?: true}}) |> Ash.Query.set_context(%{private: %{ash_oban?: true}})
|> Ash.Query.for_read(unquote(read_action), %{}, authorize?: true, actor: actor) |> Ash.Query.for_read(unquote(read_action), %{},
authorize?: authorize?,
actor: actor
)
|> unquote(api).read_one() |> unquote(api).read_one()
|> case do |> case do
{:error, error} -> {:error, error} ->
@ -468,7 +473,7 @@ defmodule AshOban.Transformers.DefineSchedulers do
|> prepare_error(primary_key) |> prepare_error(primary_key)
|> Ash.Changeset.set_context(%{private: %{ash_oban?: true}}) |> Ash.Changeset.set_context(%{private: %{ash_oban?: true}})
|> Ash.Changeset.for_action(unquote(trigger.on_error), %{error: error}, |> Ash.Changeset.for_action(unquote(trigger.on_error), %{error: error},
authorize?: true, authorize?: authorize?,
actor: actor actor: actor
) )
|> AshOban.update_or_destroy(unquote(api)) |> AshOban.update_or_destroy(unquote(api))
@ -546,10 +551,15 @@ defmodule AshOban.Transformers.DefineSchedulers do
case AshOban.lookup_actor(args["actor"]) do case AshOban.lookup_actor(args["actor"]) do
{:ok, actor} -> {:ok, actor} ->
authorize? = AshOban.authorize?()
query() query()
|> Ash.Query.do_filter(primary_key) |> Ash.Query.do_filter(primary_key)
|> Ash.Query.set_context(%{private: %{ash_oban?: true}}) |> Ash.Query.set_context(%{private: %{ash_oban?: true}})
|> Ash.Query.for_read(unquote(read_action), %{}, authorize?: true, actor: actor) |> Ash.Query.for_read(unquote(read_action), %{},
authorize?: authorize?,
actor: actor
)
|> unquote(api).read_one() |> unquote(api).read_one()
|> case do |> case do
{:ok, nil} -> {:ok, nil} ->
@ -575,7 +585,7 @@ defmodule AshOban.Transformers.DefineSchedulers do
|> Ash.Changeset.for_action( |> Ash.Changeset.for_action(
unquote(trigger.action), unquote(trigger.action),
Map.merge(unquote(Macro.escape(trigger.action_input || %{})), args), Map.merge(unquote(Macro.escape(trigger.action_input || %{})), args),
authorize?: true, authorize?: authorize?,
actor: actor actor: actor
) )
|> AshOban.update_or_destroy(unquote(api)) |> AshOban.update_or_destroy(unquote(api))