Sigra.Plug.PutActiveOrganization (Sigra v1.20.0)

Copy Markdown View Source

The single authoritative write site for "set the active organization".

Every Phase 14+ call site that needs to set, clear, or change the active organization funnels through this function: login (Plan 03), the switcher controller (Phase 16), invitation accept (Phase 17), stale-pointer recovery inside Sigra.Plug.LoadActiveOrganization, and the backfill upgrade (Phase 18). No ad-hoc Plug-session writes. No direct ecto updates on user_sessions. No shortcuts.

This function is not a Plug call/2 — it is a function-call contract invoked from controllers, other plugs, and the login entry point. It takes a Plug.Conn, an Organization struct (or nil to clear), and an opts keyword list, and returns {:ok, updated_conn} or {:error, reason}.

Writes performed

  1. user_sessions.active_organization_id column (via the configured Sigra.SessionStore implementation's update_active_organization/3 callback).
  2. conn.private[:sigra_session] (refreshed with the updated struct).
  3. conn.assigns[:current_scope] (via the host scope module's put_active_organization/3 — D-15).

Writes explicitly NOT performed

  • Plug session cookie writes — no mirror of the DB column into the cookie session (D-03/D-17).
  • Session token rotation / session renewal — a scope transition is NOT a trust transition (D-18).

Authorization (T-14-06)

Before any write, call/3 verifies the user's membership in the target organization via Sigra.Organizations.get_membership/3. If nil, the function returns {:error, :not_a_member} without calling the SessionStore's update_active_organization/3 callback. The SessionStore callback itself does not enforce authz (see Phase 14 T-14-04).

Options

  • :organizations — required. The host's use Sigra.Organizations module exposing __sigra_org_config__/0.
  • :session_store — required. Module implementing Sigra.SessionStore.
  • :scope_module — required. The host scope module whose put_active_organization/3 builds the updated scope struct (D-15).
  • :session_store_opts — optional keyword list forwarded to the session store callback (e.g. [repo: MyApp.Repo]). Defaults to [].

Summary

Functions

Set, change, or clear the active organization on the caller's session. Returns {:ok, updated_conn} on success or {:error, reason} on failure.

Types

call_error()

@type call_error() :: :not_a_member | :no_session | :no_scope | term()

Functions

call(conn, org, opts)

(since 0.8.0)
@spec call(Plug.Conn.t(), struct() | nil, keyword()) ::
  {:ok, Plug.Conn.t()} | {:error, call_error()}

Set, change, or clear the active organization on the caller's session. Returns {:ok, updated_conn} on success or {:error, reason} on failure.

Returns {:error, :no_session} if no %Sigra.Session{} has been stashed at conn.private[:sigra_session] (the FetchSession plug has not run, or the user is not logged in). Returns {:error, :no_scope} if conn.assigns[:current_scope] is missing or has a nil :user. Both errors are fail-closed: the request does not crash and no write is performed.