Permit.Phoenix.LiveView behaviour (permit_phoenix v0.3.0)

View Source

A live view module using the authorization mechanism should mix in the LiveViewAuthorization module:

defmodule MyAppWeb.DocumentLive.Index
  use Permit.Phoenix.LiveView

  @impl true
  def resource_module, do: Document

  # Override default action groupings if needed
  @impl true
  def action_grouping do
    %{
      new: [:create],
      index: [:read],
      show: [:read],
      edit: [:update],
      create: [:create],
      update: [:update],
      delete: [:delete]
    }
  end

  # Override singular actions if needed
  @impl true
  def singular_actions do
    [:show, :edit, :new, :delete, :update]
  end
end

which adds the LiveViewAuthorization behavior with the following callbacks to be implemented - for example:

# The related schema

@impl true
def resource_module, do: Document

# Loader function for a singular resource in appropriate actions (:show, etc.); usually a context
# function. If not defined, Repo.get is used by default.

@impl true
def loader, do: fn id -> get_organization!(id) end

# How to fetch the current user from session - for instance:

@impl true
def fetch_subject(socket, session) do
  with token when not is_nil(token) <- session["token"],
       %User{} = current_user <- get_user(token) do
    current_user
  else
    _ -> nil
  end
end

Optionally, p handle_unauthorized/2 optional callback can be implemented, returning {:cont, socket} or {:halt, socket}. The default implementation returns:

{:halt, socket(socket, to: socket.view.fallback_path())}

Summary

Callbacks

Defines the action grouping schema for this live view. This can be overridden in individual live views to customize the action mapping.

Defines which actions are considered singular (operating on a single resource). This can be overridden in individual live views to customize the singular actions.

Functions

Returns true if inside mount/1, false otherwise. Useful for distinguishing between rendering directly via router or being in a handle_params lifecycle.

Callbacks

action_grouping()

@callback action_grouping() :: map()

Defines the action grouping schema for this live view. This can be overridden in individual live views to customize the action mapping.

authorization_module()

@callback authorization_module() :: Permit.Types.authorization_module()

base_query(resolution_context)

(optional)
@callback base_query(Permit.Types.resolution_context()) :: Ecto.Query.t()

event_mapping()

@callback event_mapping() :: map()

except()

(optional)
@callback except() :: [Permit.Types.action_group()]

fallback_path(action_group, socket)

(optional)
@callback fallback_path(Permit.Types.action_group(), Permit.Phoenix.Types.socket()) ::
  binary()

fetch_subject(socket, map)

@callback fetch_subject(Permit.Phoenix.Types.socket(), map()) :: Permit.Types.subject()

finalize_query(t, resolution_context)

(optional)
@callback finalize_query(Ecto.Query.t(), Permit.Types.resolution_context()) ::
  Ecto.Query.t()

handle_not_found(socket)

(optional)

handle_unauthorized(action_group, socket)

(optional)

id_param_name(action_group, socket)

(optional)
@callback id_param_name(Permit.Types.action_group(), Permit.Phoenix.Types.socket()) ::
  binary()

id_struct_field_name(action_group, socket)

(optional)
@callback id_struct_field_name(Permit.Types.action_group(), Permit.Phoenix.Types.socket()) ::
  atom()

loader(resolution_context)

(optional)
@callback loader(Permit.Types.resolution_context()) :: Permit.Types.object() | nil

preload_actions()

(optional)
@callback preload_actions() :: [Permit.Types.action_group()]

resource_module()

(optional)
@callback resource_module() :: module()

singular_actions()

@callback singular_actions() :: [atom()]

Defines which actions are considered singular (operating on a single resource). This can be overridden in individual live views to customize the singular actions.

unauthorized_message(socket, map)

(optional)
@callback unauthorized_message(Permit.Phoenix.Types.socket(), map()) :: binary()

use_stream?(socket)

(optional)
@callback use_stream?(Permit.Phoenix.Types.socket()) :: boolean()

Functions

handle_not_found(socket, opts)

mounting?(socket)

@spec mounting?(Permit.Phoenix.Types.socket()) :: boolean()

Returns true if inside mount/1, false otherwise. Useful for distinguishing between rendering directly via router or being in a handle_params lifecycle.

For example, a handle_unauthorized/1 implementation must redirect when halting during mounting, while it needn't redirect when halting during the handle_params lifecycle.

Example

@impl true
    def handle_unauthorized(socket) do
      if mounting?(socket) do
        {:halt, push_redirect(socket, to: "/foo")}
      else
        {:halt, assign(socket, :unauthorized, true)}
      end
    end

unauthorized_message(action, socket, opts)