domma-cms 0.93.0 → 0.94.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin/css/admin.css +1 -1
- package/admin/js/app.js +2 -2
- package/admin/js/templates/docs/api-actions.html +86 -64
- package/admin/js/templates/docs/api-authentication.html +159 -123
- package/admin/js/templates/docs/api-builder.html +197 -0
- package/admin/js/templates/docs/api-collections.html +199 -259
- package/admin/js/templates/docs/api-external.html +225 -0
- package/admin/js/templates/docs/api-forms.html +268 -0
- package/admin/js/templates/docs/api-layouts.html +70 -45
- package/admin/js/templates/docs/api-media.html +57 -80
- package/admin/js/templates/docs/api-navigation.html +66 -22
- package/admin/js/templates/docs/api-pages.html +109 -129
- package/admin/js/templates/docs/api-plugins.html +123 -61
- package/admin/js/templates/docs/api-scaffold.html +185 -0
- package/admin/js/templates/docs/api-settings.html +72 -64
- package/admin/js/templates/docs/api-users.html +74 -107
- package/admin/js/templates/docs/api-views.html +68 -54
- package/admin/js/templates/docs/components-howto.html +20 -17
- package/admin/js/templates/docs/components-reference.html +13 -16
- package/admin/js/templates/docs/components-rules.html +7 -6
- package/admin/js/templates/docs/components-walkthrough.html +19 -19
- package/admin/js/templates/docs/tutorial-crud.html +68 -38
- package/admin/js/templates/docs/tutorial-forms.html +51 -35
- package/admin/js/templates/docs/tutorial-plugin.html +132 -56
- package/admin/js/templates/docs/usage-actions.html +55 -14
- package/admin/js/templates/docs/usage-collections.html +108 -0
- package/admin/js/templates/docs/usage-cta-shortcode.html +14 -3
- package/admin/js/templates/docs/usage-dconfig.html +0 -3
- package/admin/js/templates/docs/usage-editions.html +213 -0
- package/admin/js/templates/docs/usage-media.html +22 -6
- package/admin/js/templates/docs/usage-navigation.html +74 -18
- package/admin/js/templates/docs/usage-pages.html +60 -20
- package/admin/js/templates/docs/usage-plugins.html +89 -17
- package/admin/js/templates/docs/usage-shortcodes.html +123 -70
- package/admin/js/templates/docs/usage-site-settings.html +50 -18
- package/admin/js/templates/docs/usage-tools.html +73 -0
- package/admin/js/templates/docs/usage-users-roles.html +99 -20
- package/admin/js/templates/docs/usage-views.html +36 -19
- package/admin/js/templates/documentation.html +153 -32
- package/admin/js/templates/plugin-guide.html +15 -0
- package/admin/js/templates/plugin-guides.html +21 -0
- package/admin/js/templates/pro-docs.html +53 -234
- package/admin/js/templates/tutorials.html +5 -4
- package/admin/js/views/doc-pages.js +1 -1
- package/admin/js/views/index.js +1 -1
- package/admin/js/views/plugin-guides.js +5 -0
- package/bin/cli.js +6 -6
- package/package.json +1 -1
- package/plugins/blog/docs/guide.md +205 -0
- package/plugins/blog/plugin.json +1 -1
- package/plugins/feedback/docs/guide.md +95 -0
- package/plugins/feedback/plugin.json +1 -1
- package/plugins/free-tier.lock.json +16 -11
- package/plugins/mail-reader/docs/guide.md +147 -0
- package/plugins/mail-reader/plugin.json +1 -1
- package/plugins/security/docs/guide.md +170 -0
- package/plugins/security/plugin.json +1 -1
- package/plugins/shopping-cart/docs/guide.md +191 -0
- package/plugins/shopping-cart/plugin.json +1 -1
- package/server/routes/api/documentation.js +42 -0
- package/server/server.js +12 -0
- package/server/services/docs.js +13 -2
- package/server/services/pluginGuides.js +255 -0
- package/server/services/plugins.js +8 -0
|
@@ -69,67 +69,129 @@
|
|
|
69
69
|
<div class="col-12">
|
|
70
70
|
<div class="docs-body">
|
|
71
71
|
|
|
72
|
-
<
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
{
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
{
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
72
|
+
<p>These endpoints drive the <strong>Marketplace</strong> screen (System > Plugins, <code>#/plugins</code>). They
|
|
73
|
+
need the <code>plugins</code> permission for the action named: <code>read</code>, <code>create</code> (install),
|
|
74
|
+
<code>update</code> (switch on or off, settings) or <code>develop</code> (the source editor, export and restart).
|
|
75
|
+
Installing from, and uninstalling through, the managed catalogue needs an admin (role level 0 or 1).</p>
|
|
76
|
+
<p><strong>Restarts.</strong> A plugin's routes and screens are read when the server starts, so switching a plugin
|
|
77
|
+
or a built-in Tool on or off restarts the server by itself, about a second and a half after the reply, when
|
|
78
|
+
something will bring it back (the fleet manager, or pm2) and <code>restartOnPluginToggle</code> in
|
|
79
|
+
<code>config/server.json</code> is not <code>false</code>. The reply says what happened:
|
|
80
|
+
<code>restartRequired</code>, <code>supervised</code>, <code>restarting</code>. Installing, updating and
|
|
81
|
+
uninstalling do not restart; the new code runs after the next restart.</p>
|
|
82
|
+
|
|
83
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/plugins</span></h3>
|
|
84
|
+
<p class="auth-note">Requires Bearer token + <code>plugins</code> read permission.</p>
|
|
85
|
+
<p>Every installed plugin, with its state.</p>
|
|
86
|
+
<pre class="code-block"><code>// Response 200
|
|
87
|
+
[ { "name": "blog", "displayName": "Blog", "version": "1.9.0", "description": "...", "author": "...", "icon": "edit",
|
|
88
|
+
"core": false, "enabled": true, "closedSource": false, "licence": "...",
|
|
89
|
+
"entitlement": null, // for a licensed plugin: valid, grace, expired, support-ended, unlicensed...
|
|
90
|
+
"supersededBy": null, // enabled but replaced by another plugin (a Pro edition)
|
|
91
|
+
"blockedBy": null, // enabled but not running: something it requires is off
|
|
92
|
+
"locked": false, // the site's manager holds this switch
|
|
93
|
+
"requires": [], "uses": {},
|
|
94
|
+
"settings": {}, "settingsSchema": null, "effectiveSettings": {} } ]</code></pre>
|
|
95
|
+
<p>Secret settings come back masked; sending the mask back keeps the stored value.</p>
|
|
96
|
+
|
|
97
|
+
<h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/plugins/:name</span></h3>
|
|
98
|
+
<p class="auth-note">Requires Bearer token + <code>plugins</code> update permission.</p>
|
|
99
|
+
<p>Switch a plugin on or off, or save its settings. A switch goes through the same check as the screen: a switch
|
|
100
|
+
the site's manager has locked is refused with 423, and one that changes other Tools or plugins (a plugin that
|
|
101
|
+
requires this one goes off with it; switching one on brings on what it requires) answers 409 with the
|
|
102
|
+
<code>plan</code> until repeated with <code>"cascade": true</code>. A built-in plugin cannot be switched off.</p>
|
|
103
|
+
<table class="table table-sm">
|
|
104
|
+
<thead><tr><th>Field</th><th>Type</th><th>Description</th></tr></thead>
|
|
105
|
+
<tbody>
|
|
106
|
+
<tr><td><code>enabled</code></td><td>boolean</td><td>On or off</td></tr>
|
|
107
|
+
<tr><td><code>settings</code></td><td>object</td><td>The plugin's settings</td></tr>
|
|
108
|
+
<tr><td><code>cascade</code></td><td>boolean</td><td>Confirm the knock-on changes in a 409's plan</td></tr>
|
|
109
|
+
</tbody>
|
|
110
|
+
</table>
|
|
111
|
+
<pre class="code-block"><code>// Response 200 - a switch
|
|
112
|
+
{ "success": true, "restartRequired": true, "supervised": true, "restarting": true }
|
|
113
|
+
// Error 409 - confirm first
|
|
114
|
+
{ "error": "This switch changes other Tools too.", "needsConfirm": true, "plan": { ... } }</code></pre>
|
|
115
|
+
|
|
116
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/tools</span></h3>
|
|
117
|
+
<p class="auth-note">Requires Bearer token + <code>plugins</code> read permission.</p>
|
|
118
|
+
<p>The built-in Tools that can be switched off - Contacts, Notes, Todo, Analytics and SEO - with their state and the
|
|
119
|
+
plugins that depend on each. <code>GET /api/tools/enabled</code> (any signed-in user) answers just
|
|
120
|
+
<code>{"notes": true, ...}</code>.</p>
|
|
121
|
+
<pre class="code-block"><code>// Response 200
|
|
122
|
+
[ { "name": "contacts", "displayName": "Contacts", "enabled": true, "locked": false,
|
|
123
|
+
"requiredBy": [ { "name": "contacts-pro", "displayName": "Contacts Pro" } ],
|
|
124
|
+
"usedBy": [ { "name": "calendar", "displayName": "Calendar", "reason": "Invite a contact group" } ] } ]</code></pre>
|
|
125
|
+
|
|
126
|
+
<h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/tools/:name</span></h3>
|
|
127
|
+
<p class="auth-note">Requires Bearer token + <code>plugins</code> update permission.</p>
|
|
128
|
+
<p>Switch a built-in Tool on or off (<code>{"enabled": false}</code>). Nothing is deleted; switched back on,
|
|
129
|
+
everything is where it was. The same 423 / 409-with-plan / <code>cascade</code> rules and restart as a plugin.</p>
|
|
130
|
+
|
|
131
|
+
<h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/plugins/install-upload</span></h3>
|
|
132
|
+
<p class="auth-note">Requires Bearer token + <code>plugins</code> create permission. Content-Type:
|
|
133
|
+
<code>multipart/form-data</code>.</p>
|
|
134
|
+
<p>Install or update a plugin from a <code>.dcmsplugin</code> file (Install from file). The plugin is named by the
|
|
135
|
+
manifest inside, not the file name. Refusals come back as questions to confirm with form fields set to
|
|
136
|
+
<code>true</code>: <code>confirmUpgrade</code> (it is already installed - 409, <code>code: "already-installed"</code>),
|
|
137
|
+
<code>confirmDowngrade</code> and <code>confirmUnsigned</code> (a file not signed by the Marketplace; a site
|
|
138
|
+
with <code>requireSignedPlugins</code> refuses those outright). A plugin whose <code>minCmsVersion</code> is newer
|
|
139
|
+
than this site is refused, naming both versions, and an update leaves the installed version in place. A
|
|
140
|
+
licensed plugin's licence travels in the file. A new plugin arrives switched off.</p>
|
|
141
|
+
<pre class="code-block"><code>// Response 200
|
|
142
|
+
{ "success": true, "name": "invoices", "action": "install", "from": null, "version": "1.6.1", "restartRequired": true }
|
|
143
|
+
// Error 400
|
|
144
|
+
{ "error": "Invoices needs Domma CMS 0.93.0 or later; this site runs 0.92.2. Update the CMS first." }</code></pre>
|
|
145
|
+
|
|
146
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/plugins/marketplace</span></h3>
|
|
147
|
+
<p class="auth-note">Requires Bearer token + an admin role (level 0 or 1).</p>
|
|
148
|
+
<p>The Browse tab: what this site can get from its manager, with what is installed and what can be updated. A
|
|
149
|
+
site that is not managed answers <code>{"available": false, "catalogue": []}</code> and installs from a file
|
|
150
|
+
instead.</p>
|
|
151
|
+
<pre class="code-block"><code>// Response 200
|
|
152
|
+
{ "available": true, "site": "my-site",
|
|
153
|
+
"catalogue": [ { "slug": "invoices", "version": "1.6.1", "installed": true, "installedVersion": "1.6.0", "updatable": true, ... } ] }</code></pre>
|
|
154
|
+
|
|
155
|
+
<h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/plugins/marketplace/install</span></h3>
|
|
156
|
+
<p class="auth-note">Requires Bearer token + an admin role (level 0 or 1). Managed sites only.</p>
|
|
157
|
+
<p>Fetch a plugin from the manager and install it, licensed to this site; <code>"update": true</code> updates one
|
|
158
|
+
already installed. If the update fails, the installed version is put back. A refusal from the manager (no
|
|
159
|
+
licence) answers 403 with its reason; 503 when the manager cannot be reached.</p>
|
|
160
|
+
<pre class="code-block"><code>// Request body
|
|
161
|
+
{ "slug": "invoices", "version": "1.6.1", "update": true }
|
|
162
|
+
// Response 200
|
|
163
|
+
{ "success": true, "name": "invoices", "action": "upgrade", "from": "1.6.0", "version": "1.6.1", "restartRequired": true }</code></pre>
|
|
164
|
+
|
|
165
|
+
<h3><span class="method-badge method-delete">DELETE</span><span class="endpoint-path">/api/plugins/marketplace/:slug</span></h3>
|
|
166
|
+
<p class="auth-note">Requires Bearer token + an admin role (level 0 or 1).</p>
|
|
167
|
+
<p>Uninstall a plugin. Its files and its <code>data/</code> folder are removed, roles it added are removed and their
|
|
168
|
+
users moved to <code>user</code>. Restart to finish.</p>
|
|
169
|
+
<pre class="code-block"><code>// Response 200
|
|
170
|
+
{ "success": true }</code></pre>
|
|
171
|
+
|
|
172
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/plugins/admin-config</span></h3>
|
|
173
|
+
<p class="auth-note">Requires Bearer token (any role).</p>
|
|
174
|
+
<p>What the admin needs from the running plugins: sidebar items, screens (routes) and the scripts behind them.</p>
|
|
175
|
+
<pre class="code-block"><code>// Response 200
|
|
176
|
+
{ "sidebar": [ { "id": "blog", "text": "Blog", "icon": "edit", "url": "#/plugins/blog" } ],
|
|
177
|
+
"routes": [ { "path": "/plugins/blog", "view": "plugin-blog", "title": "Blog - Domma CMS" } ],
|
|
178
|
+
"views": { "plugin-blog": { "entry": "blog/admin/views/blog.js", "exportName": "blogView" } } }</code></pre>
|
|
179
|
+
|
|
180
|
+
<h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/plugins/scaffold</span></h3>
|
|
181
|
+
<p class="auth-note">Requires Bearer token + <code>plugins</code> create permission.</p>
|
|
182
|
+
<p>Start a new plugin from the template (New plugin). It is created switched on and runs after the next restart.</p>
|
|
183
|
+
<pre class="code-block"><code>// Request body
|
|
184
|
+
{ "slug": "my-plugin", "displayName": "My Plugin", "description": "...", "author": "...", "icon": "package" }
|
|
185
|
+
// Response 200
|
|
186
|
+
{ "success": true, "name": "my-plugin", "files": [ ... ], "restartRequired": true }</code></pre>
|
|
187
|
+
|
|
188
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/plugins/:name/export</span></h3>
|
|
189
|
+
<p class="auth-note">Requires Bearer token + <code>plugins</code> develop permission.</p>
|
|
190
|
+
<p>Download a plugin as an unsigned <code>.dcmsplugin</code> file (<code>?includeData=1</code> adds its data).
|
|
191
|
+
Licensed plugins cannot be exported (403). The source editor uses <code>GET /api/plugins/:name/files</code> and
|
|
192
|
+
<code>GET</code>, <code>PUT</code>, <code>DELETE /api/plugins/:name/file</code>, and
|
|
193
|
+
<code>POST /api/plugins/restart</code> restarts the server to run edited code; a licensed plugin's source is open
|
|
194
|
+
only to the level-0 role.</p>
|
|
133
195
|
|
|
134
196
|
</div>
|
|
135
197
|
</div>
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
<div class="view-header">
|
|
2
|
+
<h1><span data-icon="code"></span> API · Scaffold API</h1>
|
|
3
|
+
<a href="#/api-reference" class="btn btn-ghost btn-sm"><span data-icon="arrow-left"></span> API overview</a>
|
|
4
|
+
</div>
|
|
5
|
+
<style>
|
|
6
|
+
.method-badge {
|
|
7
|
+
display: inline-block;
|
|
8
|
+
font-size: 11px;
|
|
9
|
+
font-weight: 700;
|
|
10
|
+
letter-spacing: 0.5px;
|
|
11
|
+
padding: 2px 7px;
|
|
12
|
+
border-radius: 4px;
|
|
13
|
+
font-family: var(--dm-font-mono, monospace);
|
|
14
|
+
margin-right: 6px;
|
|
15
|
+
vertical-align: middle;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.method-get {
|
|
19
|
+
background: color-mix(in srgb, var(--dm-success) 15%, transparent);
|
|
20
|
+
color: var(--dm-success);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.method-post {
|
|
24
|
+
background: color-mix(in srgb, var(--dm-primary) 15%, transparent);
|
|
25
|
+
color: var(--dm-primary);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.method-put {
|
|
29
|
+
background: color-mix(in srgb, var(--dm-warning) 15%, transparent);
|
|
30
|
+
color: var(--dm-warning-dark);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.method-patch {
|
|
34
|
+
background: color-mix(in srgb, var(--dm-info) 15%, transparent);
|
|
35
|
+
color: var(--dm-info);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.method-delete {
|
|
39
|
+
background: color-mix(in srgb, var(--dm-danger) 15%, transparent);
|
|
40
|
+
color: var(--dm-danger);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.endpoint-path {
|
|
44
|
+
font-family: var(--dm-font-mono, monospace);
|
|
45
|
+
font-size: 14px;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.auth-note {
|
|
49
|
+
font-size: 12px;
|
|
50
|
+
color: var(--dm-text-muted, #6b7280);
|
|
51
|
+
margin: 4px 0 12px;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.auth-note code {
|
|
55
|
+
font-size: 11px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.docs-body h3 {
|
|
59
|
+
margin-top: 24px;
|
|
60
|
+
margin-bottom: 8px;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.docs-body h3:first-child {
|
|
64
|
+
margin-top: 0;
|
|
65
|
+
}
|
|
66
|
+
</style>
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
<div class="row">
|
|
70
|
+
<div class="col-12">
|
|
71
|
+
<div class="docs-body">
|
|
72
|
+
|
|
73
|
+
<p>The scaffolder builds a working system - collection, form, Actions and optionally a project, roles, users, menus,
|
|
74
|
+
API tokens and API Builder endpoints - from a bundled <strong>recipe</strong> in one call. In the admin it is
|
|
75
|
+
the "scaffold a working system in one click" panel in the page editor's CRUD shortcut slideover and on the
|
|
76
|
+
Building a CRUD App tutorial. Full recipe format: <code>docs/scaffolding.md</code>.</p>
|
|
77
|
+
|
|
78
|
+
<h2>Endpoints</h2>
|
|
79
|
+
|
|
80
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/scaffold/recipes</span></h3>
|
|
81
|
+
<p class="auth-note">Requires: <code>collections.create</code></p>
|
|
82
|
+
<p>List the bundled recipes with just what a picker needs.</p>
|
|
83
|
+
<pre class="code-block"><code class="language-json">// Response 200
|
|
84
|
+
{ "recipes": [
|
|
85
|
+
{ "slug": "contact-list", "name": "Contact list (CRM-lite)", "description": "...", "icon": "...",
|
|
86
|
+
"options": [
|
|
87
|
+
{ "name": "collectionSlug", "label": "Collection slug", "default": "contacts", "hint": "..." },
|
|
88
|
+
{ "name": "formSlug", "label": "Form slug", "default": "contact-quick-add" },
|
|
89
|
+
{ "name": "actionPrefix", "label": "Action slug prefix", "default": "contact" }
|
|
90
|
+
] }
|
|
91
|
+
] }</code></pre>
|
|
92
|
+
|
|
93
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/scaffold/recipes/:slug</span></h3>
|
|
94
|
+
<p class="auth-note">Requires: <code>collections.create</code></p>
|
|
95
|
+
<p>The whole recipe document, unresolved (placeholders such as <code>{{collectionSlug}}</code> still in place) -
|
|
96
|
+
the preview of what apply will create. <code>404</code> for an unknown recipe. There is no separate dry-run
|
|
97
|
+
endpoint.</p>
|
|
98
|
+
|
|
99
|
+
<h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/scaffold/apply</span></h3>
|
|
100
|
+
<p class="auth-note">Requires: <code>collections.create</code></p>
|
|
101
|
+
<p>Apply a recipe. <code>options</code> overrides the recipe's option defaults by name; anything omitted or blank
|
|
102
|
+
keeps its default.</p>
|
|
103
|
+
<pre class="code-block"><code class="language-bash">curl -X POST https://example.com/api/scaffold/apply \
|
|
104
|
+
-H 'Authorization: Bearer <access_token>' \
|
|
105
|
+
-H 'Content-Type: application/json' \
|
|
106
|
+
-d '{"recipe":"contact-list","options":{"collectionSlug":"leads","formSlug":"lead-form"}}'</code></pre>
|
|
107
|
+
<pre class="code-block"><code class="language-json">// Response 200
|
|
108
|
+
{
|
|
109
|
+
"created": {
|
|
110
|
+
"collection": "leads",
|
|
111
|
+
"form": "lead-form",
|
|
112
|
+
"actions": ["contact-followup"],
|
|
113
|
+
"roles": [], "users": [], "menus": [],
|
|
114
|
+
"apiTokens": [],
|
|
115
|
+
"apiEndpoints": []
|
|
116
|
+
},
|
|
117
|
+
"skipped": [],
|
|
118
|
+
"warnings": [],
|
|
119
|
+
"snippet": "[form name=\"lead-form\" /]\n\n## Contacts\n\n[collection slug=\"leads\" ...]"
|
|
120
|
+
}
|
|
121
|
+
// Error 400
|
|
122
|
+
{ "error": "recipe slug is required" }
|
|
123
|
+
// Error 409 - something the recipe would create already exists
|
|
124
|
+
{ "error": "Cannot apply recipe - conflicts: ...", "conflicts": ["Collection \"leads\" already exists"] }</code></pre>
|
|
125
|
+
<p><code>snippet</code> is Markdown ready to paste into a page - usually the form embed plus a collection
|
|
126
|
+
display.</p>
|
|
127
|
+
|
|
128
|
+
<h2>What apply creates</h2>
|
|
129
|
+
<p>In this order, with every option value substituted into the recipe first:</p>
|
|
130
|
+
<ol>
|
|
131
|
+
<li><strong>Project</strong> - when the recipe has a <code>project</code> block, the <code>namespace</code>
|
|
132
|
+
option is the project slug. Created if missing, left alone if it exists. A failure here aborts with
|
|
133
|
+
<code>400</code>.</li>
|
|
134
|
+
<li><strong>Pre-flight</strong> - the collection, form, each Action and each menu must not exist yet;
|
|
135
|
+
otherwise <code>409</code> with the full list and nothing below runs.</li>
|
|
136
|
+
<li><strong>Roles</strong> - an existing role name is skipped with a warning (its permissions are not
|
|
137
|
+
changed).</li>
|
|
138
|
+
<li><strong>Menus</strong> - written, and mapped to their <code>locations</code> slots unless a slot is already
|
|
139
|
+
taken (warning) or the menu says <code>force: true</code>.</li>
|
|
140
|
+
<li><strong>Collection</strong> - schema, API access rules and <code>rowAccess</code>.</li>
|
|
141
|
+
<li><strong>Form</strong> - its collection action points at the new collection.</li>
|
|
142
|
+
<li><strong>Users</strong> - only when the recipe supplies a password; an existing email or a missing password
|
|
143
|
+
is skipped with a warning. Users in a project recipe get <code>projects: [namespace]</code>.</li>
|
|
144
|
+
<li><strong>Actions</strong> - need MongoDB; without it each is skipped with the warning
|
|
145
|
+
<code>MongoDB not configured - action "..." skipped (Pro feature)</code>. When the form's
|
|
146
|
+
<code>settings.actionSlug</code> is <code>""</code>, it is wired to the first Action created.</li>
|
|
147
|
+
<li><strong>API tokens</strong> (<code>apiTokens: [{name, scopes?, expiresAt?}]</code>) - bound to the recipe's
|
|
148
|
+
project (else the <code>namespace</code> option, else <code>core</code>). The plaintext is returned once
|
|
149
|
+
in <code>created.apiTokens[].token</code>; a token with the same name in that project is skipped and never
|
|
150
|
+
re-issued. See <a href="#/docs/api/external">External API</a>.</li>
|
|
151
|
+
<li><strong>API endpoints</strong> (<code>apiEndpoints: [{path, collection, filter, ...}]</code>) - same project
|
|
152
|
+
rule; a definition with the same path shape is skipped. See
|
|
153
|
+
<a href="#/docs/api/builder">API Builder</a>.</li>
|
|
154
|
+
</ol>
|
|
155
|
+
<p>Everything a project recipe creates is tagged <code>meta.project: <namespace></code>. Recipes cannot create
|
|
156
|
+
pages, blocks or views.</p>
|
|
157
|
+
|
|
158
|
+
<h2>Partial results</h2>
|
|
159
|
+
<p>Apply is not a transaction. Pre-flight keeps the main pieces from colliding, but after it a failing role, menu,
|
|
160
|
+
user, Action, token or endpoint becomes a warning and the rest carries on. Read <code>skipped</code> (entries
|
|
161
|
+
such as <code>role:hr</code>, <code>user:hr@example.com</code>, <code>apiToken:mobile</code>,
|
|
162
|
+
<code>apiEndpoint:/latest</code> or an Action slug) and <code>warnings</code> to see what did not land. A
|
|
163
|
+
project created in step 1 stays even when pre-flight then refuses.</p>
|
|
164
|
+
|
|
165
|
+
<h2>Recipes and options</h2>
|
|
166
|
+
<p>Recipes are JSON files in <code>server/services/recipes/</code> (bundled: <code>contact-list</code> and
|
|
167
|
+
<code>onboarding</code>); a new file is listed on the next request. Each <code>options[]</code> entry has a
|
|
168
|
+
<code>name</code>, <code>label</code>, <code>default</code> and <code>hint</code>. A default may refer to an
|
|
169
|
+
earlier option (<code>"default": "{{namespace}}-form"</code>).</p>
|
|
170
|
+
<ul>
|
|
171
|
+
<li><code>{{optionName}}</code> is replaced throughout the recipe at apply time.</li>
|
|
172
|
+
<li>Runtime placeholders such as <code>{{entry.data.email}}</code>, <code>{{user.id}}</code> and
|
|
173
|
+
<code>{{now}}</code> are left for the Action to resolve when it runs.</li>
|
|
174
|
+
<li>Every value supplied in <code>options</code> is slugified (lower case, anything other than letters and
|
|
175
|
+
digits becomes a hyphen) - including options that are not slugs.</li>
|
|
176
|
+
</ul>
|
|
177
|
+
|
|
178
|
+
<h2>Permissions</h2>
|
|
179
|
+
<p>All three endpoints need a signed-in user whose role holds <code>collections.create</code>. No other permission
|
|
180
|
+
is checked, although a recipe can also create roles, users, menus, API tokens and endpoints - grant
|
|
181
|
+
<code>collections.create</code> only to roles you would trust with those.</p>
|
|
182
|
+
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
</div>
|
|
@@ -69,80 +69,88 @@
|
|
|
69
69
|
<div class="col-12">
|
|
70
70
|
<div class="docs-body">
|
|
71
71
|
|
|
72
|
-
<
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
72
|
+
<p>Site settings live in <code>config/site.json</code> and are edited at System > Site Settings. They need the
|
|
73
|
+
<code>settings</code> permission (read or update). The theme has its own endpoints, under Theme below.</p>
|
|
74
|
+
|
|
75
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/settings</span></h3>
|
|
76
|
+
<p class="auth-note">Requires Bearer token + <code>settings</code> read permission.</p>
|
|
77
|
+
<p>The site settings. The SMTP password is always sent back empty.</p>
|
|
78
|
+
<pre class="code-block"><code>// Response 200
|
|
79
|
+
{ "title": "My Site", "tagline": "...", "baseUrl": "https://example.com", "adminHome": "/",
|
|
80
|
+
"smtp": { "host": "...", "pass": "", ... }, "footer": { ... }, "seo": { ... }, ... }</code></pre>
|
|
81
|
+
|
|
82
|
+
<h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/settings</span></h3>
|
|
83
|
+
<p class="auth-note">Requires Bearer token + <code>settings</code> update permission.</p>
|
|
84
|
+
<p>Save settings. Send only what changes: top-level keys are merged into the stored settings, and objects such as
|
|
85
|
+
<code>smtp</code> or <code>footer</code> are merged one level deep. An empty <code>smtp.pass</code> keeps the
|
|
86
|
+
stored password. An unknown key is refused with 400, so a typo cannot be saved silently. The public pages'
|
|
87
|
+
cache is cleared.</p>
|
|
88
|
+
<table class="table table-sm">
|
|
89
|
+
<thead><tr><th>Key</th><th>What it is</th></tr></thead>
|
|
90
|
+
<tbody>
|
|
91
|
+
<tr><td><code>title</code>, <code>tagline</code>, <code>description</code>, <code>logo</code>,
|
|
92
|
+
<code>favicon</code></td><td>The site's name and identity</td></tr>
|
|
93
|
+
<tr><td><code>baseUrl</code></td><td>Site URL - an origin only (<code>https://example.com</code>, no path). Canonical
|
|
94
|
+
links, the sitemap and password reset links are built on it.</td></tr>
|
|
95
|
+
<tr><td><code>adminHome</code></td><td>The admin screen <code>#/</code> opens, e.g. <code>/plugins/blog</code>;
|
|
96
|
+
empty for the Dashboard</td></tr>
|
|
97
|
+
<tr><td><code>smtp</code></td><td>Mail server: <code>host</code>, <code>port</code>, <code>user</code>,
|
|
98
|
+
<code>pass</code>, <code>secure</code>, <code>fromAddress</code>, <code>fromName</code></td></tr>
|
|
99
|
+
<tr><td><code>seo</code>, <code>footer</code>, <code>social</code>, <code>backToTop</code>,
|
|
100
|
+
<code>cookieConsent</code>, <code>breadcrumbs</code>, <code>layoutOptions</code></td><td>The Site Settings
|
|
101
|
+
tabs of the same names</td></tr>
|
|
102
|
+
<tr><td><code>theme</code>, <code>adminTheme</code>, <code>autoTheme</code>, <code>fontFamily</code>,
|
|
103
|
+
<code>fontSize</code>, <code>adminBrand</code>, <code>locale</code>, <code>analytics</code>, <code>brand</code>,
|
|
104
|
+
<code>url</code>, <code>baseTheme</code></td><td>Also accepted; most are set from Theme or kept for older
|
|
105
|
+
sites</td></tr>
|
|
106
|
+
</tbody>
|
|
107
|
+
</table>
|
|
108
|
+
<pre class="code-block"><code>// Request body
|
|
109
|
+
{ "tagline": "Fresh bread daily", "smtp": { "port": 465, "secure": true } }
|
|
87
110
|
// Response 200
|
|
88
|
-
{ "success": true }
|
|
111
|
+
{ "success": true }
|
|
112
|
+
// Error 400
|
|
113
|
+
{ "error": "Unknown settings keys: siteName" }</code></pre>
|
|
89
114
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
<tr>
|
|
97
|
-
<th>Field</th>
|
|
98
|
-
<th>Type</th>
|
|
99
|
-
<th>Description</th>
|
|
100
|
-
</tr>
|
|
101
|
-
</thead>
|
|
102
|
-
<tbody>
|
|
103
|
-
<tr>
|
|
104
|
-
<td><code>to</code></td>
|
|
105
|
-
<td>string</td>
|
|
106
|
-
<td>Optional. Recipient address. Defaults to the configured From Address.</td>
|
|
107
|
-
</tr>
|
|
108
|
-
</tbody>
|
|
109
|
-
</table>
|
|
110
|
-
<pre class="code-block"><code>// Response 200
|
|
115
|
+
<h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/settings/test-email</span></h3>
|
|
116
|
+
<p class="auth-note">Requires Bearer token + <code>settings</code> read permission.</p>
|
|
117
|
+
<p>Send a test email with the saved SMTP settings.</p>
|
|
118
|
+
<pre class="code-block"><code>// Request body (optional - defaults to the From address)
|
|
119
|
+
{ "to": "alice@example.com" }
|
|
120
|
+
// Response 200
|
|
111
121
|
{ "success": true, "message": "Test email sent to alice@example.com" }
|
|
112
|
-
|
|
113
122
|
// Error 400
|
|
114
123
|
{ "error": "SMTP is not configured. Save your SMTP settings first." }</code></pre>
|
|
115
124
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
125
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/settings/db-status</span></h3>
|
|
126
|
+
<p class="auth-note">Requires Bearer token + <code>settings</code> read permission.</p>
|
|
127
|
+
<p>Whether any MongoDB connection is set up (<code>config/connections.json</code>).</p>
|
|
128
|
+
<pre class="code-block"><code>// Response 200
|
|
129
|
+
{ "configured": true, "connections": ["default"] }</code></pre>
|
|
130
|
+
|
|
131
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/settings/custom-css</span></h3>
|
|
132
|
+
<p class="auth-note">Requires Bearer token + <code>settings</code> update permission.</p>
|
|
133
|
+
<p>The site-wide custom CSS (<code>content/custom.css</code>), which is inlined into every public page.</p>
|
|
134
|
+
<pre class="code-block"><code>// Response 200
|
|
121
135
|
{ "css": "body { font-family: sans-serif; }" }</code></pre>
|
|
122
136
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
<tr>
|
|
130
|
-
<th>Field</th>
|
|
131
|
-
<th>Type</th>
|
|
132
|
-
<th>Description</th>
|
|
133
|
-
</tr>
|
|
134
|
-
</thead>
|
|
135
|
-
<tbody>
|
|
136
|
-
<tr>
|
|
137
|
-
<td><code>css</code></td>
|
|
138
|
-
<td>string</td>
|
|
139
|
-
<td>CSS string (max 100 KB)</td>
|
|
140
|
-
</tr>
|
|
141
|
-
</tbody>
|
|
142
|
-
</table>
|
|
143
|
-
<pre class="code-block"><code>// Response 200
|
|
137
|
+
<h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/settings/custom-css</span></h3>
|
|
138
|
+
<p class="auth-note">Requires Bearer token + <code>settings</code> update permission.</p>
|
|
139
|
+
<p>Replace the custom CSS (at most 100 KB). The public pages' cache is cleared.</p>
|
|
140
|
+
<pre class="code-block"><code>// Request body
|
|
141
|
+
{ "css": "..." }
|
|
142
|
+
// Response 200
|
|
144
143
|
{ "success": true }</code></pre>
|
|
145
144
|
|
|
145
|
+
<h3 style="margin-top:24px;font-size:15px;text-transform:uppercase;letter-spacing:.5px;opacity:.6">Theme</h3>
|
|
146
|
+
|
|
147
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/theme</span></h3>
|
|
148
|
+
<p class="auth-note">Requires Bearer token + <code>theme</code> read permission.</p>
|
|
149
|
+
<p>The site's theme settings (<code>config/theme.json</code>): the public and admin themes, day/night switching,
|
|
150
|
+
fonts and any custom themes. <code>PUT /api/theme</code> (update permission) saves them, answering 400 with the
|
|
151
|
+
problems if they do not validate. <code>GET /api/theme/catalog</code> lists the themes and colour tokens
|
|
152
|
+
available, and <code>GET /api/theme/themes/:id</code> one theme's token values.</p>
|
|
153
|
+
|
|
146
154
|
</div>
|
|
147
155
|
</div>
|
|
148
156
|
</div>
|