PhoenixKitKnowledgeBase.Vaults (PhoenixKitKnowledgeBase v0.1.0)

Copy Markdown View Source

Vault CRUD, membership, and the access model the whole module funnels through.

Who can see what

Reaching any knowledge-base page at all requires the knowledge_base permission — that is core's job, enforced by the admin tab. What this module decides is which vaults you then see, and what you may do inside each one.

Access resolves to one of four values, computed by role_for/2:

RoleMay
"owner"everything, including membership and deleting the vault
"editor"create, edit, move and delete notes and folders
"viewer"read
nilnot see the vault exists

Two roles are implicit, held without a membership row:

  • a personal vault's owner_uuid is always its "owner" — so a vault can never end up with nobody able to administer it;
  • anyone holding knowledge_base.manage_system_vaults (and any org Owner) is "owner" of every system vault.

That second rule stops at system vaults on purpose. An admin does not get implicit access to other people's personal vaults: a private notebook that silently isn't private is worse than no private notebook. To read someone's personal vault, they add you as a member.

Summary

Functions

Absolute path to a vault's directory, for showing the operator where its files are.

Whether a role permits an action.

Whether this user may create system vaults (as opposed to personal ones).

A blank changeset for the create/edit form.

Create a vault owned by this user.

Remove a vault from the app.

Fetch a vault for a user, resolving their role in the same step.

Fetch a vault by uuid, or nil. Returns nil for a malformed uuid rather than raising.

Fetch a vault by its URL slug, or nil.

Fetch a membership row scoped to its vault, or nil.

Members of a vault with their user records, owners first.

Every vault this user may open, system vaults first, then alphabetical.

list_visible/1 with each vault's role resolved, as {vault, role}.

The sub-permission key that confers ownership of every system vault.

Add a user to a vault, or change their role if already a member.

Remove a membership row. The implicit owner of a personal vault is unaffected.

The role scope's user holds on vault, or nil if they cannot see it.

A role, for showing — the stored value stays English (owner / editor / viewer).

Users matching term who are not already members, for the "add member" picker. Delegates the search to core so it stays consistent with the rest of the admin.

Update a vault's name, slug, description or icon. Scope and owner are fixed at creation.

A display label for a user record from search_candidates/2 or list_members/1.

Functions

absolute_path(vault)

Absolute path to a vault's directory, for showing the operator where its files are.

can?(role, arg2)

@spec can?(String.t() | nil, :read | :write | :manage) :: boolean()

Whether a role permits an action.

  • :read — viewer and up
  • :write — editor and up (notes, folders)
  • :manage — owner only (membership, vault settings, deletion)

can_manage_system_vaults?(scope)

@spec can_manage_system_vaults?(PhoenixKit.Users.Auth.Scope.t() | nil) :: boolean()

Whether this user may create system vaults (as opposed to personal ones).

change(vault \\ %Vault{}, attrs \\ %{})

A blank changeset for the create/edit form.

create(attrs, scope, scope_kind \\ :user)

@spec create(map(), PhoenixKit.Users.Auth.Scope.t() | nil, :user | :system) ::
  {:ok, PhoenixKitKnowledgeBase.Schemas.Vault.t()}
  | {:error, Ecto.Changeset.t()}
  | {:error, :unauthorized}
  | {:error, term()}

Create a vault owned by this user.

scope_kind is :user for a personal vault or :system for an org-wide one; :system is rejected without knowledge_base.manage_system_vaults, here rather than only in the UI, so the check can't be skipped by a crafted form submission.

delete(vault)

Remove a vault from the app.

Deletes the vault row and, by FK cascade, its members and its whole index — but not the files. Notes are the durable artifact here; a mis-click in a web UI should not be able to rm -rf somebody's writing. The directory stays on disk, and re-creating a vault with the same slug and pressing Rescan brings every note back.

fetch_for(slug, scope)

@spec fetch_for(String.t(), PhoenixKit.Users.Auth.Scope.t() | nil) ::
  {:ok, PhoenixKitKnowledgeBase.Schemas.Vault.t(), String.t()}
  | {:error, :not_found}

Fetch a vault for a user, resolving their role in the same step.

{:error, :not_found} covers both "no such slug" and "you may not see it" — telling those apart would leak the existence of other people's vaults.

get(uuid)

Fetch a vault by uuid, or nil. Returns nil for a malformed uuid rather than raising.

get_by_slug(slug)

@spec get_by_slug(String.t()) :: PhoenixKitKnowledgeBase.Schemas.Vault.t() | nil

Fetch a vault by its URL slug, or nil.

get_member(vault, member_uuid)

Fetch a membership row scoped to its vault, or nil.

list_members(vault)

@spec list_members(PhoenixKitKnowledgeBase.Schemas.Vault.t()) :: [
  %{member: PhoenixKitKnowledgeBase.Schemas.VaultMember.t(), user: map() | nil}
]

Members of a vault with their user records, owners first.

The user is loaded by a join rather than a preload because PhoenixKit.Users.Auth.User belongs to core: joining on uuid uses the documented schema contract without this module declaring an association into another package's schema.

list_visible(scope)

Every vault this user may open, system vaults first, then alphabetical.

Runs as one query rather than a filter over all vaults, so a host with many personal vaults doesn't load them all to throw most away.

list_visible_with_roles(scope)

@spec list_visible_with_roles(PhoenixKit.Users.Auth.Scope.t() | nil) :: [
  {PhoenixKitKnowledgeBase.Schemas.Vault.t(), String.t()}
]

list_visible/1 with each vault's role resolved, as {vault, role}.

One membership query for the whole list rather than role_for/2 per vault — the list page would otherwise issue a query per card.

manage_system_permission()

@spec manage_system_permission() :: String.t()

The sub-permission key that confers ownership of every system vault.

put_member(vault, user_uuid, role)

Add a user to a vault, or change their role if already a member.

remove_member(member)

Remove a membership row. The implicit owner of a personal vault is unaffected.

role_for(vault, scope)

The role scope's user holds on vault, or nil if they cannot see it.

Takes the highest of the implicit roles and any membership row, so being added as a viewer of a system vault you already administer does not reduce your access.

role_label(other)

@spec role_label(String.t() | nil) :: String.t()

A role, for showing — the stored value stays English (owner / editor / viewer).

search_candidates(vault, term)

@spec search_candidates(PhoenixKitKnowledgeBase.Schemas.Vault.t(), String.t()) :: [
  map()
]

Users matching term who are not already members, for the "add member" picker. Delegates the search to core so it stays consistent with the rest of the admin.

update(vault, attrs)

Update a vault's name, slug, description or icon. Scope and owner are fixed at creation.

user_label(user)

@spec user_label(map() | nil) :: String.t()

A display label for a user record from search_candidates/2 or list_members/1.