MishkaCmsCore.Runtime.Setting (Mishka CMS Core v0.0.1)

Copy Markdown View Source

Durable key/value CMS settings, multitenant like MishkaCmsCore.Runtime.Layout (global? true): a row with site_id = nil is a GLOBAL setting (one value for every site, master-managed); a row with a site_id is a PER-SITE setting owned by that tenant (site title, SEO, …). Both live in the one cms_settings table, keyed by [:key, :site_id].

Values are stored as JSON maps; the facade MishkaCmsCore.Settings wraps/unwraps scalars and the ETS cache MishkaCmsCore.Runtime.States.SettingsState serves them lock-free (site value → global default) on every request. Reads are open (non-secret config); a tenant writes only its own rows (the tenant :set auto-stamps site_id), the master writes any site or the global via :master_set.

That split is enforced by the policies below, not by convention or by the caller. A write takes the permission the setting's definition declares, or admin:dashboard:setting when it declares none (MishkaCmsCore.Runtime.Resources.Checks.SettingPermission). Because every site's rows share one table, that permission alone cannot decide a write — every site's settings admin holds it — so a second policy pins the row to actor.site_id unless the actor is a master. Write through MishkaCmsCore.Settings.put_as/4 to get that; put/3 is the trusted infra path for boot seeding and passes authorize?: false, which skips all of it.

PubSub topics: a nil site_id publishes to "setting:updated" only; a uuid site_id publishes to both "setting:updated" AND "setting:{uuid}:updated", so a master watching the global topic sees every change while a tenant watches only its own.

See MishkaCmsCore.Settings, MishkaCmsCore.Runtime.States.SettingsState, MishkaCmsCore.Runtime.Layout (the global? true reference) and MishkaCmsCore.Runtime.Resources.Validations.TenantContext.

Summary

Functions

Validates that the keys in the provided input are valid for at least one action on the resource.

Same as input/1, except restricts the keys to values accepted by the action provided.

Types

t()

@type t() :: %MishkaCmsCore.Runtime.Setting{
  __lateral_join_source__: term(),
  __meta__: term(),
  __metadata__: term(),
  __order__: term(),
  aggregates: term(),
  calculations: term(),
  category: term(),
  created_at: term(),
  description: term(),
  editable?: term(),
  id: term(),
  key: term(),
  site: term(),
  site_id: term(),
  source: term(),
  updated_at: term(),
  value: term()
}

Functions

default_short_name()

input(opts)

@spec input(values :: map() | Keyword.t()) :: map() | no_return()

Validates that the keys in the provided input are valid for at least one action on the resource.

Raises a KeyError error at compile time if not. This exists because generally a struct should only ever be created by Ash as a result of a successful action. You should not be creating records manually in code, e.g %MyResource{value: 1, value: 2}. Generally that is fine, but often with embedded resources it is nice to be able to validate the keys that are being provided, e.g

Resource
|> Ash.Changeset.for_create(:create, %{embedded: EmbeddedResource.input(foo: 1, bar: 2)})
|> Ash.create()

input(opts, action)

@spec input(values :: map() | Keyword.t(), action :: atom()) :: map() | no_return()

Same as input/1, except restricts the keys to values accepted by the action provided.

primary_key_matches?(left, right)