# `Sekisho`
[🔗](https://github.com/hattoriai/sekisho/blob/v0.1.0-dev/lib/sekisho.ex#L1)

Permissions for Phoenix.

Your app has one permissions module, which lists its policies:

    defmodule MyApp.Permissions do
      use Sekisho,
        repo: MyApp.Repo,
        policies: [MyApp.Blog.PostPolicy, MyApp.Docs.DocumentPolicy, MyApp.Orgs.OrgPolicy],
        sources: MyApp.Permissions.Sources,
        groups: [MyApp.Teams.Team]

      @impl Sekisho
      def actor(%MyApp.Accounts.Scope{user: user}), do: user
      def actor(nil), do: nil
    end

and every question goes through it, with your scope (Phoenix's
`%Scope{}`) first:

    MyApp.Permissions.allowed?(scope, :update, post)        # true | false
    MyApp.Permissions.authorize(scope, :update, post)       # :ok | {:error, %Sekisho.Denied{}}
    MyApp.Permissions.authorize!(scope, :update, post)      # raises Sekisho.Denied, a 403

    Post |> MyApp.Permissions.where_allowed(scope, :read) |> Repo.all()
    MyApp.Permissions.with_permissions(posts, scope, [:update, :delete])

    MyApp.Permissions.allowed_fields(scope, user)
    MyApp.Permissions.redact(scope, user)
    MyApp.Permissions.explain(scope, :update, document)

    MyApp.Permissions.grant(scope, ana, :editor, on: document)
    MyApp.Permissions.grant(scope, :link, :viewer, on: document)
    MyApp.Permissions.revoke(scope, ana, :editor, on: document)
    MyApp.Permissions.grants(scope, document)

    {:ok, support} = MyApp.Permissions.create_role(scope, org, "Support", [:"investigations.view"])
    MyApp.Permissions.grant(scope, ana, "Support", on: org)

The rules are in policies (`Sekisho.Policy`), and roles held in your own
tables in sources (`Sekisho.Sources`).

## Options

  * `:repo`: your Ecto repo (required).
  * `:policies`: your policies (required). They are read when the module
    is first asked, not when it compiles, so a change to one recompiles no
    other; `validate!/0` checks them together (in a test, or at boot).
  * `:sources`: your `Sekisho.Sources` module.
  * `:groups`: the schemas of groups that may be granted roles (teams);
    their members come from `c:Sekisho.Sources.members/1`.
  * `:pubsub`: your `Phoenix.PubSub`, on which grants and revocations are
    broadcast (topic `"sekisho"`).
  * `:deny_as`: `:forbidden` (403, the default) or `:not_found` (404).

## Checks of a record

A check of a record asks the database: the record as it is there, with
one query on its primary key. A rule about the actor alone (`true`,
`false`) needs none. To ask about many records at once, use
`with_permissions/3`.

# `actor`

```elixir
@callback actor(scope :: term()) :: struct() | nil
```

The actor your scope is: a user struct, or `nil` for a visitor.

# `link_tokens`

```elixir
@callback link_tokens(scope :: term()) :: [String.t()]
```

The link tokens your scope holds (from a link a visitor followed): `[]` by
default.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
