domma-cms 0.66.0 → 0.69.4
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/CLAUDE.md +64 -1
- package/README.md +14 -10
- package/admin/css/admin.css +1 -1
- package/admin/index.html +1 -0
- package/admin/js/api.js +1 -1
- package/admin/js/app.js +4 -4
- package/admin/js/lib/analytics-shape.js +1 -0
- package/admin/js/lib/contacts-arrange.js +1 -0
- package/admin/js/lib/help-popover.js +1 -0
- package/admin/js/lib/notes-arrange.js +1 -0
- package/admin/js/lib/plugin-accent.js +1 -1
- package/admin/js/lib/plugin-chrome.js +1 -1
- package/admin/js/lib/sidebar-grouping.js +1 -1
- package/admin/js/lib/sidebar-grouping.test.js +1 -1
- package/admin/js/lib/sidebar-renderer.js +3 -3
- package/admin/js/lib/todo-arrange.js +1 -0
- package/admin/js/lib/tool-kit.js +1 -0
- package/admin/js/templates/analytics.html +138 -0
- package/admin/js/templates/contacts.html +156 -0
- package/admin/js/templates/notes.html +137 -0
- package/admin/js/templates/plugin-marketplace.html +17 -4
- package/admin/js/templates/plugins.html +13 -7
- package/admin/js/templates/theme.html +38 -0
- package/admin/js/templates/todo.html +113 -0
- package/admin/js/views/analytics.js +62 -0
- package/admin/js/views/contacts.js +174 -0
- package/admin/js/views/index.js +1 -1
- package/admin/js/views/notes.js +104 -0
- package/admin/js/views/plugin-marketplace.js +1 -1
- package/admin/js/views/plugins.js +24 -22
- package/admin/js/views/theme.js +1 -1
- package/admin/js/views/todo.js +96 -0
- package/bin/cli.js +4 -10
- package/bin/lib/plugin-version.js +28 -0
- package/bin/update.js +14 -0
- package/config/menus/admin-sidebar.json +1 -1
- package/config/server.json +3 -1
- package/package.json +3 -7
- package/plugins/_lib/admin/mail/reader-view.js +20 -0
- package/plugins/_lib/mail/store.js +21 -1
- package/plugins/blog/CLAUDE.md +237 -0
- package/plugins/blog/admin/css/index.css +178 -1
- package/plugins/blog/admin/templates/blog.html +35 -53
- package/plugins/blog/admin/templates/categories.html +19 -6
- package/plugins/blog/admin/templates/comments.html +26 -9
- package/plugins/blog/admin/templates/post-editor.html +36 -13
- package/plugins/blog/admin/templates/settings.html +2 -11
- package/plugins/blog/admin/views/blog.js +288 -162
- package/plugins/blog/admin/views/categories.js +212 -201
- package/plugins/blog/admin/views/comments.js +207 -158
- package/plugins/blog/admin/views/kit.js +372 -0
- package/plugins/blog/admin/views/post-editor.js +269 -21
- package/plugins/blog/admin/views/settings-cog.js +56 -0
- package/plugins/blog/admin/views/settings.js +16 -86
- package/plugins/blog/blocks/blog-card-compact.css +17 -0
- package/plugins/blog/blocks/blog-card-compact.html +8 -0
- package/plugins/blog/blocks/blog-card-row.css +22 -0
- package/plugins/blog/blocks/blog-card-row.html +11 -0
- package/plugins/blog/blocks/blog-card.css +35 -0
- package/plugins/blog/blocks/blog-card.html +16 -0
- package/plugins/blog/blocks/blog-post-classic.css +15 -0
- package/plugins/blog/blocks/blog-post-classic.html +28 -0
- package/plugins/blog/blocks/blog-post-feature.css +20 -0
- package/plugins/blog/blocks/blog-post-feature.html +30 -0
- package/plugins/blog/blocks/blog-post-minimal.css +10 -0
- package/plugins/blog/blocks/blog-post-minimal.html +23 -0
- package/plugins/blog/blocks/blog-post-sidebar.css +22 -0
- package/plugins/blog/blocks/blog-post-sidebar.html +36 -0
- package/plugins/blog/collections/posts/schema.json +3 -1
- package/plugins/blog/config.js +6 -0
- package/plugins/blog/lib/layouts.js +304 -0
- package/plugins/blog/lib/page.js +158 -0
- package/plugins/blog/lib/render.js +119 -0
- package/plugins/blog/lib/samples.js +234 -0
- package/plugins/blog/plugin.js +225 -15
- package/plugins/blog/plugin.json +21 -81
- package/plugins/blog/plugin.public.js +115 -210
- package/plugins/blog/public/blog.css +177 -0
- package/plugins/blog/public/blog.js +586 -0
- package/plugins/blog/public/samples/aurora.svg +7 -0
- package/plugins/blog/public/samples/dusk.svg +7 -0
- package/plugins/blog/public/samples/ember.svg +7 -0
- package/plugins/blog/public/samples/harbour.svg +7 -0
- package/plugins/blog/public/samples/meadow.svg +7 -0
- package/plugins/blog/public/samples/rosewood.svg +7 -0
- package/plugins/blog/templates/index.html +9 -8
- package/plugins/blog/templates/post.html +4 -17
- package/plugins/blog/tests/layouts.test.js +97 -0
- package/plugins/blog/tests/public.test.js +71 -0
- package/plugins/free-tier.lock.json +74 -0
- package/plugins/mail-reader/CLAUDE.md +78 -0
- package/plugins/mail-reader/plugin.json +2 -1
- package/public/css/theme-switcher.css +1 -0
- package/public/js/analytics.js +1 -0
- package/public/js/theme-switcher.js +1 -0
- package/scripts/build.js +41 -2
- package/scripts/run-tests.mjs +94 -0
- package/{plugins/analytics/plugin.js → server/routes/api/analytics.js} +89 -41
- package/{plugins/contacts/plugin.js → server/routes/api/contacts.js} +71 -43
- package/server/routes/api/dashboard.js +8 -2
- package/{plugins/notes/plugin.js → server/routes/api/notes.js} +61 -17
- package/server/routes/api/plugin-marketplace.js +78 -23
- package/server/routes/api/plugins.js +148 -3
- package/server/routes/api/todo.js +178 -0
- package/server/server.js +61 -1
- package/server/services/collections.js +13 -3
- package/server/services/managerClient.js +72 -136
- package/server/services/markdown.js +54 -1
- package/server/services/permissionRegistry.js +50 -0
- package/server/services/pluginEntitlement.js +171 -0
- package/server/services/pluginEnvelope.js +242 -0
- package/server/services/pluginInstaller.js +246 -26
- package/server/services/pluginScaffold.js +5 -0
- package/server/services/plugins.js +117 -7
- package/server/services/presetCollections.js +344 -0
- package/server/services/promoted-plugins-migration.js +254 -0
- package/server/services/publicCors.js +46 -0
- package/server/services/renderer.js +83 -3
- package/server/services/sidebarBadges.js +37 -0
- package/server/services/siteGitignore.js +310 -0
- package/server/services/themeSettings.js +39 -0
- package/config/theme.json +0 -18
- package/plugins/analytics/admin/css/index.css +0 -1
- package/plugins/analytics/admin/templates/analytics.html +0 -70
- package/plugins/analytics/admin/views/analytics.js +0 -176
- package/plugins/analytics/config.js +0 -14
- package/plugins/analytics/plugin.json +0 -60
- package/plugins/analytics/public/inject-body.html +0 -60
- package/plugins/analytics/public/inject-head.html +0 -1
- package/plugins/blog/templates/author.html +0 -9
- package/plugins/blog/templates/category.html +0 -9
- package/plugins/blog/templates/tag.html +0 -9
- package/plugins/contacts/admin/templates/contacts.html +0 -254
- package/plugins/contacts/admin/views/contacts.js +0 -943
- package/plugins/contacts/collections/user-contact-groups/schema.json +0 -35
- package/plugins/contacts/collections/user-contacts/schema.json +0 -179
- package/plugins/contacts/config.js +0 -6
- package/plugins/contacts/plugin.json +0 -36
- package/plugins/demo-viewer/config.js +0 -4
- package/plugins/demo-viewer/plugin.js +0 -36
- package/plugins/demo-viewer/plugin.json +0 -9
- package/plugins/invoice/admin/css/index.css +0 -1
- package/plugins/invoice/admin/templates/editor.html +0 -220
- package/plugins/invoice/admin/templates/index.html +0 -173
- package/plugins/invoice/admin/templates/issuers.html +0 -2
- package/plugins/invoice/admin/templates/receivers.html +0 -2
- package/plugins/invoice/admin/views/contacts-source.js +0 -266
- package/plugins/invoice/admin/views/editor.js +0 -434
- package/plugins/invoice/admin/views/export.js +0 -199
- package/plugins/invoice/admin/views/help-content.js +0 -61
- package/plugins/invoice/admin/views/index.js +0 -643
- package/plugins/invoice/admin/views/issuers.js +0 -30
- package/plugins/invoice/admin/views/media.js +0 -172
- package/plugins/invoice/admin/views/party-view.js +0 -386
- package/plugins/invoice/admin/views/payments.js +0 -127
- package/plugins/invoice/admin/views/print.js +0 -130
- package/plugins/invoice/admin/views/receivers.js +0 -55
- package/plugins/invoice/admin/views/send.js +0 -212
- package/plugins/invoice/admin/views/settings.js +0 -594
- package/plugins/invoice/admin/views/view-lifecycle.js +0 -33
- package/plugins/invoice/collections/invoice-issuers/schema.json +0 -82
- package/plugins/invoice/collections/invoice-receivers/schema.json +0 -16
- package/plugins/invoice/collections/invoices/schema.json +0 -33
- package/plugins/invoice/config.js +0 -37
- package/plugins/invoice/pdf.js +0 -164
- package/plugins/invoice/plugin.js +0 -1456
- package/plugins/invoice/plugin.json +0 -86
- package/plugins/invoice/templates/_base.css +0 -1
- package/plugins/invoice/templates/classic-nologo.html +0 -100
- package/plugins/invoice/templates/classic.html +0 -91
- package/plugins/invoice/templates/invoice-print.html +0 -237
- package/plugins/invoice/templates/minimal.html +0 -99
- package/plugins/invoice/templates/modern-nologo.html +0 -114
- package/plugins/invoice/templates/modern.html +0 -113
- package/plugins/invoice/templates/templates.json +0 -11
- package/plugins/notes/admin/templates/notes.html +0 -83
- package/plugins/notes/admin/views/notes.js +0 -281
- package/plugins/notes/collections/user-notes/schema.json +0 -54
- package/plugins/notes/config.js +0 -6
- package/plugins/notes/plugin.json +0 -33
- package/plugins/surveys/admin/templates/audience.html +0 -47
- package/plugins/surveys/admin/templates/results.html +0 -58
- package/plugins/surveys/admin/templates/survey-editor.html +0 -141
- package/plugins/surveys/admin/templates/surveys.html +0 -25
- package/plugins/surveys/admin/views/audience.js +0 -301
- package/plugins/surveys/admin/views/results.js +0 -172
- package/plugins/surveys/admin/views/survey-editor.js +0 -211
- package/plugins/surveys/admin/views/surveys.js +0 -161
- package/plugins/surveys/collections/survey-contacts/schema.json +0 -13
- package/plugins/surveys/collections/survey-groups/schema.json +0 -11
- package/plugins/surveys/collections/survey-invites/schema.json +0 -16
- package/plugins/surveys/collections/surveys/schema.json +0 -23
- package/plugins/surveys/config.js +0 -8
- package/plugins/surveys/lib/audience.js +0 -37
- package/plugins/surveys/lib/campaigns.js +0 -43
- package/plugins/surveys/lib/ledger.js +0 -110
- package/plugins/surveys/lib/sending.js +0 -106
- package/plugins/surveys/lib/stats.js +0 -62
- package/plugins/surveys/lib/submit.js +0 -95
- package/plugins/surveys/lib/tokens.js +0 -28
- package/plugins/surveys/plugin.js +0 -174
- package/plugins/surveys/plugin.json +0 -65
- package/plugins/surveys/plugin.public.js +0 -149
- package/plugins/surveys/public/dist-shared.mjs +0 -1
- package/plugins/surveys/public/survey.css +0 -1
- package/plugins/surveys/public/survey.mjs +0 -1
- package/plugins/surveys/templates/survey-page.html +0 -63
- package/plugins/theme-switcher/admin/templates/theme-switcher.html +0 -86
- package/plugins/theme-switcher/admin/views/theme-switcher.js +0 -65
- package/plugins/theme-switcher/config.js +0 -10
- package/plugins/theme-switcher/plugin.js +0 -26
- package/plugins/theme-switcher/plugin.json +0 -74
- package/plugins/theme-switcher/public/inject-body.html +0 -153
- package/plugins/theme-switcher/public/inject-head.html +0 -260
- package/plugins/todo/admin/templates/todo.html +0 -158
- package/plugins/todo/admin/views/todo.js +0 -343
- package/plugins/todo/collections/todos/schema.json +0 -60
- package/plugins/todo/config.js +0 -7
- package/plugins/todo/plugin.js +0 -102
- package/plugins/todo/plugin.json +0 -33
- /package/{plugins/contacts/admin/css/index.css → admin/css/contacts.css} +0 -0
|
@@ -24,12 +24,47 @@ import {
|
|
|
24
24
|
registerTransform
|
|
25
25
|
} from './hooks.js';
|
|
26
26
|
import {registerPluginResource, unregisterPluginResourcesByPlugin} from './permissionRegistry.js';
|
|
27
|
+
import {classifyEntitlement, mayLoad} from './pluginEntitlement.js';
|
|
27
28
|
import {createCollection, getCollection} from './collections.js';
|
|
28
29
|
|
|
29
30
|
const PLUGINS_DIR = path.resolve('plugins');
|
|
30
31
|
|
|
31
32
|
const REQUIRED_MANIFEST_FIELDS = ['name', 'displayName', 'version', 'description', 'author', 'date', 'icon'];
|
|
32
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Validate a candidate plugin directory the way discoverPlugins() would.
|
|
36
|
+
*
|
|
37
|
+
* Exported so an UPGRADE can check what it extracted before swapping it over a
|
|
38
|
+
* working installation. Validating after the swap would mean discovering the
|
|
39
|
+
* new version is broken with the old one already gone.
|
|
40
|
+
*
|
|
41
|
+
* @param {string} dir - absolute directory
|
|
42
|
+
* @param {string} slug
|
|
43
|
+
* @returns {Promise<{ok: boolean, reason?: string, manifest?: object}>}
|
|
44
|
+
*/
|
|
45
|
+
export async function validatePluginDir(dir, slug) {
|
|
46
|
+
let manifest;
|
|
47
|
+
try {
|
|
48
|
+
manifest = JSON.parse(await fs.readFile(path.join(dir, 'plugin.json'), 'utf8'));
|
|
49
|
+
} catch {
|
|
50
|
+
return {ok: false, reason: 'no readable plugin.json'};
|
|
51
|
+
}
|
|
52
|
+
for (const field of REQUIRED_MANIFEST_FIELDS) {
|
|
53
|
+
if (!manifest[field]) return {ok: false, reason: `missing required field "${field}"`};
|
|
54
|
+
}
|
|
55
|
+
if (manifest.name !== slug) {
|
|
56
|
+
return {ok: false, reason: `manifest name is "${manifest.name}", not "${slug}"`};
|
|
57
|
+
}
|
|
58
|
+
for (const file of ['plugin.js', 'config.js']) {
|
|
59
|
+
try {
|
|
60
|
+
await fs.access(path.join(dir, file));
|
|
61
|
+
} catch {
|
|
62
|
+
return {ok: false, reason: `missing required file ${file}`};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return {ok: true, manifest};
|
|
66
|
+
}
|
|
67
|
+
|
|
33
68
|
const failedLoads = [];
|
|
34
69
|
|
|
35
70
|
/**
|
|
@@ -60,6 +95,23 @@ export function getPluginLoadFailures() {
|
|
|
60
95
|
*/
|
|
61
96
|
const _loadedPlugins = {};
|
|
62
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Entitlement state per licensed plugin, as of the last registerPlugins().
|
|
100
|
+
* Reported by GET /api/plugins so the screen can explain an absence rather than
|
|
101
|
+
* simply not showing a plugin the operator knows they installed.
|
|
102
|
+
*
|
|
103
|
+
* @type {Object.<string, string>}
|
|
104
|
+
*/
|
|
105
|
+
const _entitlementStates = {};
|
|
106
|
+
|
|
107
|
+
/** Entitlement states that still let a plugin load. Mirrors pluginEntitlement. */
|
|
108
|
+
const ENTITLEMENT_LOADABLE = new Set(['valid', 'grace', 'support-ended', 'not-required']);
|
|
109
|
+
|
|
110
|
+
/** @returns {Object.<string, string>} */
|
|
111
|
+
export function getEntitlementStates() {
|
|
112
|
+
return {..._entitlementStates};
|
|
113
|
+
}
|
|
114
|
+
|
|
63
115
|
/**
|
|
64
116
|
* Core plugins - always loaded regardless of plugins.json enabled state.
|
|
65
117
|
* These are considered first-class CMS features, not optional add-ons: they
|
|
@@ -70,12 +122,15 @@ const _loadedPlugins = {};
|
|
|
70
122
|
* for these, so a site that had one switched off still gets it on the next
|
|
71
123
|
* start - which is the point of promoting one.
|
|
72
124
|
*
|
|
73
|
-
* It is also a waiting room rather than a destination
|
|
74
|
-
* until search
|
|
75
|
-
* a feature nobody may switch off has no
|
|
76
|
-
* toggled as though it were an add-on.
|
|
125
|
+
* It is also a waiting room rather than a destination, and as of 0.67.0 it is
|
|
126
|
+
* EMPTY. site-search sat here until search moved into the CMS proper, and
|
|
127
|
+
* analytics until it did the same - a feature nobody may switch off has no
|
|
128
|
+
* business being discovered, listed and toggled as though it were an add-on.
|
|
129
|
+
*
|
|
130
|
+
* Kept rather than deleted because the mechanism is the right one for the next
|
|
131
|
+
* promotion: a plugin lands here while its replacement is built, then leaves.
|
|
77
132
|
*/
|
|
78
|
-
const CORE_PLUGINS = new Set([
|
|
133
|
+
const CORE_PLUGINS = new Set([]);
|
|
79
134
|
|
|
80
135
|
/** Is this plugin a built-in feature rather than an optional add-on? */
|
|
81
136
|
export function isCorePlugin(name) { return CORE_PLUGINS.has(name); }
|
|
@@ -300,11 +355,29 @@ export async function registerPlugins(fastify) {
|
|
|
300
355
|
const manifests = await discoverPlugins();
|
|
301
356
|
const states = getPluginStates();
|
|
302
357
|
|
|
358
|
+
// Entitlement is settled BEFORE supersession, not after, and the ordering is
|
|
359
|
+
// load-bearing. `email-pro` supersedes `mail-reader`; if an unentitled
|
|
360
|
+
// email-pro still counted as active it would displace mail-reader and then
|
|
361
|
+
// fail to load itself, leaving a customer whose licence lapsed with NEITHER -
|
|
362
|
+
// worse off than someone who never paid at all.
|
|
363
|
+
for (const manifest of manifests) {
|
|
364
|
+
if (manifest.closedSource !== true) continue;
|
|
365
|
+
const verdict = mayLoad(manifest);
|
|
366
|
+
_entitlementStates[manifest.name] = verdict.state;
|
|
367
|
+
if (!verdict.allowed) {
|
|
368
|
+
fastify.log.warn(`[plugins] "${manifest.name}" not loaded: ${verdict.state} (${verdict.reason})`);
|
|
369
|
+
} else if (verdict.state !== 'valid') {
|
|
370
|
+
fastify.log.info(`[plugins] "${manifest.name}": ${verdict.state} (${verdict.reason})`);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
const entitled = (name) => _entitlementStates[name] === undefined
|
|
374
|
+
|| ENTITLEMENT_LOADABLE.has(_entitlementStates[name]);
|
|
375
|
+
|
|
303
376
|
// Which plugins would load on their own account, before anything displaces
|
|
304
377
|
// one another.
|
|
305
378
|
const activeNames = new Set(
|
|
306
379
|
manifests
|
|
307
|
-
.filter(m => states[m.name]?.enabled || CORE_PLUGINS.has(m.name))
|
|
380
|
+
.filter(m => (states[m.name]?.enabled || CORE_PLUGINS.has(m.name)) && entitled(m.name))
|
|
308
381
|
.map(m => m.name)
|
|
309
382
|
);
|
|
310
383
|
const superseded = resolveSupersessions(manifests, activeNames, {
|
|
@@ -327,6 +400,12 @@ export async function registerPlugins(fastify) {
|
|
|
327
400
|
continue;
|
|
328
401
|
}
|
|
329
402
|
|
|
403
|
+
// Already classified above, before supersession was resolved. A refusal
|
|
404
|
+
// is NOT written into plugins.json: a lapse recorded as stored state
|
|
405
|
+
// would mean a renewal could not simply restore it, the same reasoning
|
|
406
|
+
// resolveSupersessions() uses for a superseded plugin.
|
|
407
|
+
if (!entitled(manifest.name)) continue;
|
|
408
|
+
|
|
330
409
|
const entryPath = path.join(PLUGINS_DIR, manifest.name, 'plugin.js');
|
|
331
410
|
try {
|
|
332
411
|
const { default: plugin } = await import(entryPath);
|
|
@@ -801,6 +880,34 @@ export function pluginLicence(manifest) {
|
|
|
801
880
|
return 'Included with Domma CMS';
|
|
802
881
|
}
|
|
803
882
|
|
|
883
|
+
/**
|
|
884
|
+
* The expiry shown beside the licence on a plugin's admin banner, or null.
|
|
885
|
+
*
|
|
886
|
+
* Only a licensed plugin has one, and what "expires" means depends on how it
|
|
887
|
+
* was bought (see pluginEntitlement.js): a rental STOPS at its end date, a
|
|
888
|
+
* perpetual licence never does and only its support lapses. The banner says
|
|
889
|
+
* which, because "Expires" on something bought outright would frighten a
|
|
890
|
+
* customer about a thing that is not going to happen.
|
|
891
|
+
*
|
|
892
|
+
* An owner wildcard, or a perpetual licence with no support date, has nothing
|
|
893
|
+
* to show and returns null rather than a chip with no date in it.
|
|
894
|
+
*
|
|
895
|
+
* @param {object} manifest
|
|
896
|
+
* @param {object|null} [given] - injectable for testing; read from disk when omitted
|
|
897
|
+
* @returns {{kind: 'rental'|'support', date: string, state: string}|null}
|
|
898
|
+
*/
|
|
899
|
+
export function pluginExpiry(manifest, given) {
|
|
900
|
+
if (manifest?.closedSource !== true) return null;
|
|
901
|
+
const {state, entitlement} = classifyEntitlement(manifest.name, given);
|
|
902
|
+
if (!entitlement || state === 'unlicensed') return null;
|
|
903
|
+
if (entitlement.model === 'rental') {
|
|
904
|
+
return entitlement.expiresAt ? {kind: 'rental', date: entitlement.expiresAt, state} : null;
|
|
905
|
+
}
|
|
906
|
+
return entitlement.supportExpiresAt
|
|
907
|
+
? {kind: 'support', date: entitlement.supportExpiresAt, state}
|
|
908
|
+
: null;
|
|
909
|
+
}
|
|
910
|
+
|
|
804
911
|
export async function getAdminPluginConfig() {
|
|
805
912
|
const manifests = await discoverPlugins();
|
|
806
913
|
const states = getPluginStates();
|
|
@@ -830,6 +937,8 @@ export async function getAdminPluginConfig() {
|
|
|
830
937
|
// browser fetching the same URL and serving the previous build of
|
|
831
938
|
// everything behind it. That presents as a feature that worked
|
|
832
939
|
// yesterday and does not today, on one machine.
|
|
940
|
+
// Once per plugin, not per view: it verifies a signature.
|
|
941
|
+
const expiry = pluginExpiry(manifest);
|
|
833
942
|
const sharedStamp = Math.max(
|
|
834
943
|
await newestAdminMtime(path.join(PLUGINS_DIR, '_lib', 'admin')),
|
|
835
944
|
await newestAdminMtime(path.join(PLUGINS_DIR, manifest.name, 'admin'))
|
|
@@ -851,7 +960,8 @@ export async function getAdminPluginConfig() {
|
|
|
851
960
|
author: manifest.author || '',
|
|
852
961
|
icon: manifest.icon || 'package',
|
|
853
962
|
core: CORE_PLUGINS.has(manifest.name),
|
|
854
|
-
licence: pluginLicence(manifest)
|
|
963
|
+
licence: pluginLicence(manifest),
|
|
964
|
+
expiry
|
|
855
965
|
};
|
|
856
966
|
}
|
|
857
967
|
|
|
@@ -115,6 +115,350 @@ const PRESETS = [
|
|
|
115
115
|
delete: {enabled: false, access: 'admin'}
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
|
+
,
|
|
119
|
+
// ---- Tools promoted out of plugins/ (0.67.0) --------------------------
|
|
120
|
+
// The slugs are what setupPlugin() created from `schema.slug`, NOT the
|
|
121
|
+
// directories the schemas used to live in (`user-notes`, `todos`). Keeping
|
|
122
|
+
// them exactly preserves every existing entry; changing one would seed an
|
|
123
|
+
// empty collection beside a site's real one.
|
|
124
|
+
//
|
|
125
|
+
// seedAll() rewrites schema.json on every boot, so `storage` is declared
|
|
126
|
+
// exactly as the plugins declared it - a site that had these in Mongo must
|
|
127
|
+
// not silently switch to files and lose sight of its rows. Sites with no
|
|
128
|
+
// connections.json fall back to the file adapter as they always did.
|
|
129
|
+
{
|
|
130
|
+
"slug": "notes-notes",
|
|
131
|
+
"title": "Notes",
|
|
132
|
+
"description": "Personal notes, one row per note, scoped to its author.",
|
|
133
|
+
"preset": true,
|
|
134
|
+
"fields": [
|
|
135
|
+
{
|
|
136
|
+
"name": "title",
|
|
137
|
+
"label": "Title",
|
|
138
|
+
"type": "text",
|
|
139
|
+
"required": false
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"name": "content",
|
|
143
|
+
"label": "Content",
|
|
144
|
+
"type": "textarea",
|
|
145
|
+
"required": false
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"name": "categories",
|
|
149
|
+
"label": "Categories",
|
|
150
|
+
"type": "text",
|
|
151
|
+
"required": false
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"name": "userId",
|
|
155
|
+
"label": "User ID",
|
|
156
|
+
"type": "text",
|
|
157
|
+
"required": false
|
|
158
|
+
}
|
|
159
|
+
],
|
|
160
|
+
"api": {
|
|
161
|
+
"create": {
|
|
162
|
+
"enabled": true,
|
|
163
|
+
"access": "admin"
|
|
164
|
+
},
|
|
165
|
+
"read": {
|
|
166
|
+
"enabled": true,
|
|
167
|
+
"access": "admin"
|
|
168
|
+
},
|
|
169
|
+
"update": {
|
|
170
|
+
"enabled": false,
|
|
171
|
+
"access": "admin"
|
|
172
|
+
},
|
|
173
|
+
"delete": {
|
|
174
|
+
"enabled": false,
|
|
175
|
+
"access": "admin"
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
"storage": {
|
|
179
|
+
"adapter": "mongodb",
|
|
180
|
+
"connection": "default"
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"slug": "todo-items",
|
|
185
|
+
"title": "Todo Items",
|
|
186
|
+
"description": "Personal tasks, one row per task, scoped to its owner.",
|
|
187
|
+
"preset": true,
|
|
188
|
+
"fields": [
|
|
189
|
+
{
|
|
190
|
+
"name": "text",
|
|
191
|
+
"label": "Text",
|
|
192
|
+
"type": "text",
|
|
193
|
+
"required": true
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"name": "status",
|
|
197
|
+
"label": "Status",
|
|
198
|
+
"type": "text",
|
|
199
|
+
"required": false
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"name": "priority",
|
|
203
|
+
"label": "Priority",
|
|
204
|
+
"type": "text",
|
|
205
|
+
"required": false
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"name": "dueAt",
|
|
209
|
+
"label": "Due At",
|
|
210
|
+
"type": "text",
|
|
211
|
+
"required": false
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
"name": "userId",
|
|
215
|
+
"label": "User ID",
|
|
216
|
+
"type": "text",
|
|
217
|
+
"required": false
|
|
218
|
+
}
|
|
219
|
+
],
|
|
220
|
+
"api": {
|
|
221
|
+
"create": {
|
|
222
|
+
"enabled": true,
|
|
223
|
+
"access": "admin"
|
|
224
|
+
},
|
|
225
|
+
"read": {
|
|
226
|
+
"enabled": true,
|
|
227
|
+
"access": "admin"
|
|
228
|
+
},
|
|
229
|
+
"update": {
|
|
230
|
+
"enabled": false,
|
|
231
|
+
"access": "admin"
|
|
232
|
+
},
|
|
233
|
+
"delete": {
|
|
234
|
+
"enabled": false,
|
|
235
|
+
"access": "admin"
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
"storage": {
|
|
239
|
+
"adapter": "mongodb",
|
|
240
|
+
"connection": "default"
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
// ---- Contacts, promoted out of plugins/ (0.67.0) ----------------------
|
|
244
|
+
// Slugs are contacts-contacts and contacts-groups - NOT the directories the
|
|
245
|
+
// schemas lived in (user-contacts, user-contact-groups). Taken verbatim from
|
|
246
|
+
// those files so none of the 25 contact fields is lost in transcription, and
|
|
247
|
+
// `storage` stays `file` exactly as it was.
|
|
248
|
+
{
|
|
249
|
+
"slug": "contacts-contacts",
|
|
250
|
+
"title": "Contacts",
|
|
251
|
+
"description": "Contacts managed by the Contacts plugin.",
|
|
252
|
+
"fields": [
|
|
253
|
+
{
|
|
254
|
+
"name": "name",
|
|
255
|
+
"label": "Name",
|
|
256
|
+
"type": "text",
|
|
257
|
+
"required": true
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
"name": "email",
|
|
261
|
+
"label": "Email",
|
|
262
|
+
"type": "text",
|
|
263
|
+
"required": false
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"name": "phone",
|
|
267
|
+
"label": "Phone",
|
|
268
|
+
"type": "text",
|
|
269
|
+
"required": false
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
"name": "groups",
|
|
273
|
+
"label": "Groups",
|
|
274
|
+
"type": "text",
|
|
275
|
+
"required": false
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
"name": "notes",
|
|
279
|
+
"label": "Notes",
|
|
280
|
+
"type": "textarea",
|
|
281
|
+
"required": false
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
"name": "favourite",
|
|
285
|
+
"label": "Favourite",
|
|
286
|
+
"type": "text",
|
|
287
|
+
"required": false
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
"name": "company",
|
|
291
|
+
"label": "Company",
|
|
292
|
+
"type": "text",
|
|
293
|
+
"required": false
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
"name": "jobTitle",
|
|
297
|
+
"label": "Job Title",
|
|
298
|
+
"type": "text",
|
|
299
|
+
"required": false
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
"name": "website",
|
|
303
|
+
"label": "Website",
|
|
304
|
+
"type": "text",
|
|
305
|
+
"required": false
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
"name": "vatNumber",
|
|
309
|
+
"label": "VAT Number",
|
|
310
|
+
"type": "text",
|
|
311
|
+
"required": false
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
"name": "companyNumber",
|
|
315
|
+
"label": "Company Number",
|
|
316
|
+
"type": "text",
|
|
317
|
+
"required": false
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
"name": "reference",
|
|
321
|
+
"label": "Their Reference",
|
|
322
|
+
"type": "text",
|
|
323
|
+
"required": false
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
"name": "billingEmail",
|
|
327
|
+
"label": "Billing Email",
|
|
328
|
+
"type": "text",
|
|
329
|
+
"required": false
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
"name": "paymentTerms",
|
|
333
|
+
"label": "Payment Terms (days)",
|
|
334
|
+
"type": "number",
|
|
335
|
+
"required": false
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
"name": "currency",
|
|
339
|
+
"label": "Preferred Currency",
|
|
340
|
+
"type": "text",
|
|
341
|
+
"required": false
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
"name": "addresses",
|
|
345
|
+
"label": "Addresses",
|
|
346
|
+
"type": "json",
|
|
347
|
+
"required": false
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
"name": "emails",
|
|
351
|
+
"label": "Additional Emails",
|
|
352
|
+
"type": "json",
|
|
353
|
+
"required": false
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
"name": "phones",
|
|
357
|
+
"label": "Additional Phones",
|
|
358
|
+
"type": "json",
|
|
359
|
+
"required": false
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
"name": "accountName",
|
|
363
|
+
"label": "Account Name",
|
|
364
|
+
"type": "text",
|
|
365
|
+
"required": false
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
"name": "bankName",
|
|
369
|
+
"label": "Bank",
|
|
370
|
+
"type": "text",
|
|
371
|
+
"required": false
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
"name": "sortCode",
|
|
375
|
+
"label": "Sort Code",
|
|
376
|
+
"type": "text",
|
|
377
|
+
"required": false
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
"name": "accountNumber",
|
|
381
|
+
"label": "Account Number",
|
|
382
|
+
"type": "text",
|
|
383
|
+
"required": false
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
"name": "iban",
|
|
387
|
+
"label": "IBAN",
|
|
388
|
+
"type": "text",
|
|
389
|
+
"required": false
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
"name": "bic",
|
|
393
|
+
"label": "BIC / SWIFT",
|
|
394
|
+
"type": "text",
|
|
395
|
+
"required": false
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
"name": "userId",
|
|
399
|
+
"label": "User ID",
|
|
400
|
+
"type": "text",
|
|
401
|
+
"required": false
|
|
402
|
+
}
|
|
403
|
+
],
|
|
404
|
+
"api": {
|
|
405
|
+
"create": {
|
|
406
|
+
"enabled": true,
|
|
407
|
+
"access": "admin"
|
|
408
|
+
},
|
|
409
|
+
"read": {
|
|
410
|
+
"enabled": true,
|
|
411
|
+
"access": "admin"
|
|
412
|
+
},
|
|
413
|
+
"update": {
|
|
414
|
+
"enabled": false,
|
|
415
|
+
"access": "admin"
|
|
416
|
+
},
|
|
417
|
+
"delete": {
|
|
418
|
+
"enabled": false,
|
|
419
|
+
"access": "admin"
|
|
420
|
+
}
|
|
421
|
+
},
|
|
422
|
+
"storage": {
|
|
423
|
+
"adapter": "file"
|
|
424
|
+
},
|
|
425
|
+
"preset": true
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
"slug": "contacts-groups",
|
|
429
|
+
"title": "Contact Groups",
|
|
430
|
+
"description": "Groups for the Contacts plugin.",
|
|
431
|
+
"fields": [
|
|
432
|
+
{
|
|
433
|
+
"name": "name",
|
|
434
|
+
"label": "Group Name",
|
|
435
|
+
"type": "text",
|
|
436
|
+
"required": true
|
|
437
|
+
}
|
|
438
|
+
],
|
|
439
|
+
"api": {
|
|
440
|
+
"create": {
|
|
441
|
+
"enabled": true,
|
|
442
|
+
"access": "admin"
|
|
443
|
+
},
|
|
444
|
+
"read": {
|
|
445
|
+
"enabled": true,
|
|
446
|
+
"access": "admin"
|
|
447
|
+
},
|
|
448
|
+
"update": {
|
|
449
|
+
"enabled": false,
|
|
450
|
+
"access": "admin"
|
|
451
|
+
},
|
|
452
|
+
"delete": {
|
|
453
|
+
"enabled": false,
|
|
454
|
+
"access": "admin"
|
|
455
|
+
}
|
|
456
|
+
},
|
|
457
|
+
"storage": {
|
|
458
|
+
"adapter": "file"
|
|
459
|
+
},
|
|
460
|
+
"preset": true
|
|
461
|
+
}
|
|
118
462
|
];
|
|
119
463
|
|
|
120
464
|
/** Slugs exported for use in adapterRegistry and the delete guard. */
|