Your app's answer to "may this actor do this here?", and to "what is this document?". Issho has no roles and no user model: it asks, and your app answers with whatever it already uses.
defmodule MyApp.Collaboration do
@behaviour Issho.Policy
@impl true
def authorize(%Issho.Identity{} = who, "board:" <> id, action) do
if MyApp.Boards.allowed?(who.claims["user_id"], id, action),
do: :ok,
else: {:error, :forbidden}
end
@impl true
def document(_who, "board:" <> id) do
board = MyApp.Boards.get!(id)
{:ok, %{engine: Issho.Engine.Map, initial: board.content}}
end
endActions
authorize/3 gets the room (the topic, such as "board:42") and one of:
:join: to enter the room, see its people and their places;:read: to receive its documents and their changes, asked again for the changes others make, so that a person whose access you take away stops receiving them;:write: to change its documents;:lock: to hold an advisory lock on a place.
Issho asks on join and on every message in both directions, so keep it
fast: put what it needs in the identity's claims when you sign the
token (Issho.Token.sign/4), or cache.
Documents
document/2 says what a document is when it opens for the first time on
a node: its engine (Issho.Engine), its initial content from your
server (a browser never seeds a document), and the engine's options. A
room's documents are the room itself ("board:42") and paths under it
("board:42/n7/body"), so the nested documents of a canvas share the
room's people and authorization.
Summary
Types
What a document is: its engine, its initial content (given to the
engine's Issho.Engine.init/2 when the store has nothing), and the
engine's options.
Callbacks
Whether the actor may do the action in the room.
What a document is, when it opens for the first time on a node.
Types
@type action() :: :join | :read | :write | :lock
@type document() :: %{ :engine => module(), optional(:initial) => term(), optional(:opts) => keyword() }
What a document is: its engine, its initial content (given to the
engine's Issho.Engine.init/2 when the store has nothing), and the
engine's options.
Callbacks
@callback authorize(Issho.Identity.t(), room :: String.t(), action()) :: :ok | {:error, term()}
Whether the actor may do the action in the room.
@callback document(Issho.Identity.t() | nil, document_id :: String.t()) :: {:ok, document()} | {:error, term()}
What a document is, when it opens for the first time on a node.