View Source Permit.Actions behaviour (permit v0.2.0)

Overview

The Permit.Actions behaviour defines an exhaustive set of actions that can be performed on resources in the business domain.

Actions can be grouped using the grouping_schema/0 callback, which is useful when the developer intends to define permissions that imply that multiple actions will be authorized. For instance, in the Permit.Phoenix library, granting the :read permission results in the :index and :show actions being authorized.

Permit includes a predefined Permit.Actions.CrudActions module that defines four basic CRUD actions: create, read, update and delete.

Permit.Permissions generates functions for each of defined CRUD action names, as shorthands to define permissions to perform them - as well as an all function to permit all possible actions.

Moreover, the singular_actions/0 callback can be implemented to declare which actions are of singular nature, and which are of plural nature - for instance, an :index action is typically plural and a :show action is typically singular. This means that if automatic preloading mechanisms are in place, :index will load many records, and :show will load a single record.

Example

For instance, to make an :index action separate from a :read action, you may define an additional :open action and define :index as requiring only :read, and :show as requiring both :open and :read.

defmodule MyApp.Actions do
  use Permit.Actions

  @impl Permit.Actions
  def grouping_schema do
    crud_grouping() # Includes :create, :read, :update and :delete
    |> Map.merge(%{
      index: [:read],

      # This is a 'plain' action not dependent on any other one, i.e. permission to these can be assigned directly
      open: []

      # This indicates that for the :show action to be performed, the :read AND open permissions must be granted.
      show: [:read, :open]
    })
  end
end

Declaring permissions basing on defined actions:

defmodule MyApp.Permissions do
  use Permit.Permissions, actions_module: MyApp.Actions

  # An admin will be able to perform all actions on Note
  def can(%User{role: :admin} = _user) do
    permit()
    |> all(Note)
  end

  # A user will be able
  def can(%User{id: user_id} = _user) do
    permit()
    |> read(Note)
    |> open(Note, user_id: user_id)
  end

  def can(_), do: permit()
end

Summary

Callbacks

Used for mapping business domain actions to conjunctions of permissions required to perform them.

Declares which actions are singular, and which are plural.

Callbacks

@callback grouping_schema() :: %{
  required(Permit.Types.action_group()) => [Permit.Types.action_group()]
}

Used for mapping business domain actions to conjunctions of permissions required to perform them.

In the example below, granting :read and :open means that :show action can be performed. Note, though, that this is a one-way implication - :show permission can be granted, but it does not imply that :read or :open are granted.

Example

@impl Permit.Actions
def grouping_schema do
  crud_grouping() # Includes :create, :read, :update and :delete
  |> Map.merge(%{
    index: [:read],

    # This is a 'plain' action not dependent on any other one, i.e. permission to these can be assigned directly
    open: []

    # This indicates that for the :show action to be performed, the :read AND :open permissions must be granted.
    show: [:read, :open]
  })
end
@callback singular_actions() :: [Permit.Types.action_group()]

Declares which actions are singular, and which are plural.

For instance, an :index action is typically plural and a :show action is typically singular. This means that if automatic preloading mechanisms are in place, :index will load many records, and :show will load a single record.

Example

@impl Permit.Actions
def singular_actions do
  crud_singular() ++ [:show, :open]
end