Show the kiosk label prefix, and let a plugin declare the settings it owns
Three defects, all found on printedparts_label_prefix, all one root cause: nothing in the framework knew that setting existed. The parts kiosk runs logged out. An unauthenticated read of a setting is limited to an allowlist, the key was not on it, so the kiosk got a 404 and fell back to no prefix. An admin previewing the same page while logged in saw the prefix, which is why it looked like it worked. The same setting also looked like it would not save. The row did not exist on a site that installed the plugin before the setting was added, so the first save created it - under the placeholder category the settings API uses for keys it does not recognise, where the plugin's settings page, which lists by category, could no longer see it. The value was in the database the whole time. And the row was missing in the first place because seeding ran from on_install / on_enable, which fire only on a state transition. Neither runs again on an upgrade, so a setting added in a later plugin version never reached a site that installed an earlier one. The comment claiming enable ran every upgrade cycle was simply wrong. A plugin now declares the settings it owns in get_settings_defaults(): key, default, type, category, description, and whether a logged-out page may read it. The framework seeds declared keys at install, at enable, and on every flask plugin upgrade-all; files a first-time write under the declared category; re-homes any row left in the placeholder category, value untouched; and answers an anonymous read for keys marked public. Core carries no list of any plugin's keys. Contract 0.16.0 (additive optional hook). printedparts and printers move to the hook and floor their core_version at 0.16.0. The dev database had two rows in the misfiled state (printedparts_alert_email, employee_db_host); the first repairs itself on the next upgrade pass.
This commit is contained in:
@@ -9,7 +9,7 @@ The contract is locked in [ADR-001](../docs/adr/ADR-001-asset-as-platform-contra
|
||||
The framework declares its contract version in `shopdb/__init__.py`:
|
||||
|
||||
```python
|
||||
__contract_version__ = '0.15.0'
|
||||
__contract_version__ = '0.16.0'
|
||||
```
|
||||
|
||||
Each plugin's `manifest.json` declares the range of contract versions it supports:
|
||||
@@ -415,6 +415,46 @@ class PrintersPlugin(BasePlugin):
|
||||
]
|
||||
```
|
||||
|
||||
### `get_settings_defaults() -> List[Dict]` (0.16.0)
|
||||
|
||||
Declares the `Setting` rows this plugin owns. Return `[]` (the default) if it
|
||||
owns none. Each entry is a dict:
|
||||
|
||||
| Key | Meaning |
|
||||
|-----|---------|
|
||||
| `key` | the Setting key |
|
||||
| `value` | default value in string form |
|
||||
| `valuetype` | `'string'` / `'boolean'` / `'integer'` / `'json'` |
|
||||
| `category` | grouping the plugin's settings page filters on |
|
||||
| `description` | what the setting does |
|
||||
| `public` | `True` if an unauthenticated caller may read it; default `False` |
|
||||
|
||||
```python
|
||||
class PrintedpartsPlugin(BasePlugin):
|
||||
def get_settings_defaults(self):
|
||||
return [
|
||||
{'key': 'printedparts_label_prefix', 'value': '', 'valuetype': 'string',
|
||||
'category': 'printedparts', 'public': True,
|
||||
'description': 'Leading text on the physical labels, shown at the kiosk'},
|
||||
]
|
||||
```
|
||||
|
||||
The framework seeds declared keys at install, at enable, and on every
|
||||
`flask plugin upgrade-all`, so a key added in a later plugin version reaches a
|
||||
site that installed an earlier one. Existing values are never overwritten.
|
||||
|
||||
Declaring a key is also what tells the settings API which category and type to
|
||||
use when an admin's save creates the row for the first time. Do not seed
|
||||
settings by hand in `on_install` / `on_enable`: those hooks fire only on a state
|
||||
transition, so a hand-seeded key added later never reaches an existing site, and
|
||||
the row the first save creates lands in the placeholder `plugin` category where
|
||||
the plugin's own settings page (which filters by category) cannot see it.
|
||||
|
||||
`public: True` puts the key on the unauthenticated read allowlist of
|
||||
`GET /api/settings/<key>` and `GET /api/settings`. Use it only for cosmetic
|
||||
values that a page rendering before login needs (a kiosk, a print page). Never
|
||||
mark a credential, a hostname, or an integration URL public.
|
||||
|
||||
### `get_collector_schema() -> Optional[Dict]`
|
||||
|
||||
Declares the JSON Schema for an external collector pushing to `/api/collector/<pluginname>`. See [ADR-006](../docs/adr/ADR-006-collector-contract.md) for the contract.
|
||||
|
||||
Reference in New Issue
Block a user