diff --git a/CHANGELOG.md b/CHANGELOG.md index cf579bc..6527105 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,14 @@ All notable changes to this project will be documented in this file. * This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) ## [Unreleased] +### Changed +- [Breaking] Require explicitly specified `:actions_module` on `use Permit` rather than fetching it through permissions module to avoid compile-time dependency. ## [v0.3.0] ### Changed - [Breaking] Change order of args in `Permit.verify_record/3` and add delegation as `do?/3` when doing `use Permit`. - This way, permisisons to perform a dynamically computed action can be checked like this: + This way, permissions to perform a dynamically computed action can be checked like this: ```elixir action = :read can(user) |> do?(action, %Item{id: 1}) diff --git a/lib/permit.ex b/lib/permit.ex index 9f0b7df..e4162bb 100644 --- a/lib/permit.ex +++ b/lib/permit.ex @@ -69,7 +69,7 @@ defmodule Permit do end defmodule MyApp.Permissions do - use Permit.Permissions, actions_module: Permit.Actions.CrudActions + use Permit.Permissions def can(%{role: :admin} = user) do permit() @@ -85,7 +85,6 @@ defmodule Permit do def can(user), do: permit() end ``` - Note that in the permission definitions module the `read` function is generated based on configuration provided as the `:actions_module` option - in this case, `CrudActions` generates `create`, `read`, `update` and `delete`. For more on this, see `Permit.Actions` and `Permit.Permissions`. ### Check a user's authorization to perform an action on a resource ```elixir @@ -99,7 +98,22 @@ defmodule Permit do iex(4)> can(%MyApp.User{role: :admin}) |> delete?(%MyApp.Article{author_id: 2}) true ``` - Functions such as `MyApp.Authorization.read?/2`, `MyApp.Authorization.update?/2`, etc. are also generated based on the `:actions_module` option. See more in `Permit.Actions`. + + ### Configure further actions + By default, Permit will generate predicate functions for the 4 common CRUD actions. If you need further actions, + you can define a custom actions module and configure it in both your `Authorization` and your `Permissions` module. + See `Permit.Actions` for more information. + ```elixir + defmodule MyApp.Authorization do + use Permit, + actions_module: MyApp.Actions, + permissions_module: MyApp.Permissions + end + + defmodule MyApp.Permissions do + use Permit.Permissions, actions_module: MyApp.Actions + # ... + end """ alias Permit.Permissions @@ -114,7 +128,9 @@ defmodule Permit do permissions_module = Keyword.fetch!(opts, :permissions_module) predicates = - Macro.expand(permissions_module, __CALLER__).actions_module() + opts + |> Keyword.get(:actions_module, Permit.Actions.CrudActions) + |> Macro.expand(__CALLER__) |> Permit.Actions.list_groups() |> Enum.map(&add_predicate_name/1) |> Enum.map(fn {predicate, name} -> diff --git a/lib/permit/permissions.ex b/lib/permit/permissions.ex index 93f3fb6..4ee9f31 100644 --- a/lib/permit/permissions.ex +++ b/lib/permit/permissions.ex @@ -11,7 +11,7 @@ defmodule Permit.Permissions do A very simple usage example: ``` defmodule MyApp.Permissions do - use Permit.Permissions, actions_module: Permit.Actions.CrudActions + use Permit.Permissions @impl true def can(%MyApp.User{role: :admin}) do @@ -31,6 +31,14 @@ defmodule Permit.Permissions do ## Named action functions + By default, Permit will generate actions functions for the 4 common CRUD actions. If you need further actions, you can define a custom actions module .and configure it in both your `Authorization` and your `Permissions` module. See `Permit.Actions` for more information. + + ```elixir + defmodule MyApp.Permissions do + # actions_module defaults to Permit.Actions.CrudActions. + use Permit.Permissions, actions_module: MyApp.Actions + ``` + Each action defined in the `:actions_module` results in a 2-, 3-, and 4-arity function being generated. For instance, if a `:read` action is defined, there are the following calls available to grant the `:read` permission on a given resource type: @@ -97,7 +105,7 @@ defmodule Permit.Permissions do condition_parser = opts[:condition_parser] || (&ConditionParser.build/2) condition_types_module = opts[:condition_types_module] || Permit.Types.ConditionTypes - actions_module = opts |> Keyword.get(:actions_module, Permit.Actions.CrudActions) + actions_module = Keyword.get(opts, :actions_module, Permit.Actions.CrudActions) # Unnamed action macro permission_to = PermissionTo.mixin(condition_parser, condition_types_module) diff --git a/test/permit/permit_test.exs b/test/permit/permit_test.exs index 9f7adcf..f5d982c 100644 --- a/test/permit/permit_test.exs +++ b/test/permit/permit_test.exs @@ -35,6 +35,7 @@ defmodule Permit.PermitTest do defmodule TestAuthorization do @moduledoc false use Permit, + actions_module: TestActions, permissions_module: Permit.PermitTest.TestPermissions end