domma-cms 0.115.1 → 0.115.3
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/bin/cli.js +6 -4
- package/bin/update.js +2 -1
- package/config/plugins.json +5 -0
- package/package.json +1 -1
- package/plugins/free-tier.lock.json +9 -9
- package/plugins/support/admin/views/support.js +1 -1
- package/plugins/support/config.js +2 -2
- package/plugins/support/lib/mail.js +3 -2
- package/plugins/support/plugin.js +4 -2
- package/plugins/support/plugin.json +27 -7
- package/plugins/support/tests/api.test.js +3 -1
- package/plugins/support/tests/shape.test.js +2 -2
package/bin/cli.js
CHANGED
|
@@ -249,9 +249,11 @@ const DEFAULT_NAV = {
|
|
|
249
249
|
position: 'sticky'
|
|
250
250
|
};
|
|
251
251
|
|
|
252
|
-
// Discover the bundled plugins and list them in plugins.json, all switched off
|
|
253
|
-
// a fresh project enables what it wants from the Marketplace
|
|
254
|
-
//
|
|
252
|
+
// Discover the bundled plugins and list them in plugins.json, all switched off -
|
|
253
|
+
// a fresh project enables what it wants from the Marketplace - except the ones
|
|
254
|
+
// every site has on arrival: Support (how a customer reaches Domma, whatever
|
|
255
|
+
// their tier). (Analytics, the theme switcher and the effects are core now.)
|
|
256
|
+
const ON_ARRIVAL = new Set(['support']);
|
|
255
257
|
const DEFAULT_PLUGINS = {};
|
|
256
258
|
try {
|
|
257
259
|
const pluginsRoot = path.join(target, 'plugins');
|
|
@@ -262,7 +264,7 @@ try {
|
|
|
262
264
|
const manifestPath = path.join(pluginsRoot, name, 'plugin.json');
|
|
263
265
|
try {
|
|
264
266
|
JSON.parse(readFileSync(manifestPath, 'utf8')); // validate manifest exists
|
|
265
|
-
DEFAULT_PLUGINS[name] = {enabled:
|
|
267
|
+
DEFAULT_PLUGINS[name] = {enabled: ON_ARRIVAL.has(name), settings: {}};
|
|
266
268
|
} catch { /* no valid plugin.json - skip */
|
|
267
269
|
}
|
|
268
270
|
}
|
package/bin/update.js
CHANGED
|
@@ -441,7 +441,8 @@ export default async function update(_positional, flags) {
|
|
|
441
441
|
// left off protects nobody. Only the FIRST time: a site that switched it
|
|
442
442
|
// off keeps it off.)
|
|
443
443
|
// -------------------------------------------------------------------------
|
|
444
|
-
|
|
444
|
+
// support: every site can reach Domma, whatever its tier (2026-10-04).
|
|
445
|
+
const ON_ARRIVAL = new Set(['security', 'support']);
|
|
445
446
|
|
|
446
447
|
const pluginsJsonPath = path.join(cwd, 'config/plugins.json');
|
|
447
448
|
if (newPlugins.length > 0 && existsSync(pluginsJsonPath)) {
|
package/config/plugins.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"note": "Written by `make sync-free-tier` in dcms-marketplace. Do not edit these plugins here - edit them there and sync.",
|
|
3
|
-
"source": "dcms-marketplace@
|
|
3
|
+
"source": "dcms-marketplace@9b9543d",
|
|
4
4
|
"plugins": {
|
|
5
5
|
"blog": {
|
|
6
6
|
"version": "1.9.4",
|
|
@@ -224,7 +224,7 @@
|
|
|
224
224
|
}
|
|
225
225
|
},
|
|
226
226
|
"support": {
|
|
227
|
-
"version": "1.0.
|
|
227
|
+
"version": "1.0.1",
|
|
228
228
|
"files": {
|
|
229
229
|
"CLAUDE.md": "a54f3af90bc273622e67d0da0502da39a9e0962633d43d82eebf1228cf996f79",
|
|
230
230
|
"admin/css/index.css": "43a792dbc08acafc9f79757ac96c3675a49abb39aab05a553c6871f6f2050a1e",
|
|
@@ -232,17 +232,17 @@
|
|
|
232
232
|
"admin/templates/support.html": "2bb69d0443a367a402e6160fe68f4af3e8983b578cfff9575b4df9a534fcb480",
|
|
233
233
|
"admin/views/desk.js": "f0770c750dd340b83438c8f41b222b814c0937081201cb06b851a3fdea2952fd",
|
|
234
234
|
"admin/views/inbox.js": "fac961363a827ce5139689464a6b9a65c685752b0771f4bf956fb1dcd8d95ccb",
|
|
235
|
-
"admin/views/support.js": "
|
|
235
|
+
"admin/views/support.js": "f5621fd99782e40d9faeeddf187c5c8b0412ee621ab53f03fb96d60b3f144478",
|
|
236
236
|
"collections/support-tickets.json": "aa1e6b4814fdfbbcd46d097edd93dfb838cc49f5232a86ba76b54c9b29d82ac5",
|
|
237
|
-
"config.js": "
|
|
238
|
-
"lib/mail.js": "
|
|
237
|
+
"config.js": "eb7ccc1169fa8b2be52a213536825492fedaec5fa73fd749cba9f498dd54b503",
|
|
238
|
+
"lib/mail.js": "d14aae3a59aad6af61451863cdaaf94fc4a87810b16e1dcb9c655dda6c803b3b",
|
|
239
239
|
"lib/receiver.js": "ef958be2a8fadcec10169ff76f10404d395f9c6b401a51642ede9218547d6262",
|
|
240
240
|
"lib/sender.js": "71e9146729e443df401a1b84e9778e9243d057012462e48a05e32a73f7309aa2",
|
|
241
241
|
"lib/shape.js": "7bef95c823ee4c6d4041152a58fdb2279dbe6797710a89e1339f8aca60cd0f89",
|
|
242
|
-
"plugin.js": "
|
|
243
|
-
"plugin.json": "
|
|
244
|
-
"tests/api.test.js": "
|
|
245
|
-
"tests/shape.test.js": "
|
|
242
|
+
"plugin.js": "240cd2e0f0cd26037e7bcc76ce376caa29a54323a3bab4a96abc5e0558a9be06",
|
|
243
|
+
"plugin.json": "239630f28577b687cdafb53b6f4be3e0dc0c48fb24a20092d094bfab68cb6f7b",
|
|
244
|
+
"tests/api.test.js": "f2d3632fce50e926e1d0d6f965e1d10358f13a71cfcece0bdee8150d7dc70c07",
|
|
245
|
+
"tests/shape.test.js": "6d7b7a23dcb1933e4ed6e2f4b9fce2bf0b50125073f6ec60d15d6f2e6d7f8aa1"
|
|
246
246
|
}
|
|
247
247
|
}
|
|
248
248
|
}
|
|
@@ -46,7 +46,7 @@ export const supportView = {
|
|
|
46
46
|
try {
|
|
47
47
|
[mode, meta] = await Promise.all([api.mode(), api.meta()]);
|
|
48
48
|
} catch (err) {
|
|
49
|
-
fail(`Support could not load: ${err.message || err}. You can always email support@
|
|
49
|
+
fail(`Support could not load: ${err.message || err}. You can always email support@domma-cms.com.`);
|
|
50
50
|
return;
|
|
51
51
|
}
|
|
52
52
|
if (!here()) return;
|
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
* perSiteMinutes the window for perSiteMax
|
|
18
18
|
*/
|
|
19
19
|
export default {
|
|
20
|
-
email: 'support@
|
|
20
|
+
email: 'support@domma-cms.com',
|
|
21
21
|
phone: '',
|
|
22
22
|
hours: 'Monday to Friday, 9am to 5pm (UK time)',
|
|
23
23
|
responseTime: 'We answer within one working day, and urgent requests first.',
|
|
24
24
|
syncMinutes: 5,
|
|
25
|
-
notifyEmail: 'support@
|
|
25
|
+
notifyEmail: 'support@domma-cms.com',
|
|
26
26
|
perSiteMax: 20,
|
|
27
27
|
perSiteMinutes: 10
|
|
28
28
|
};
|
|
@@ -31,7 +31,7 @@ export function siteUrl() {
|
|
|
31
31
|
* must never fail the request that caused it, and callers do not await it - an
|
|
32
32
|
* unhandled rejection stops the whole server.
|
|
33
33
|
*
|
|
34
|
-
* @param {{to: string, subject: string, html: string, text: string, replyTo?: string}} msg
|
|
34
|
+
* @param {{to: string, subject: string, html: string, text: string, replyTo?: string, from?: string}} msg
|
|
35
35
|
* @returns {Promise<boolean>}
|
|
36
36
|
*/
|
|
37
37
|
export async function send(msg, {log} = {}) {
|
|
@@ -44,7 +44,8 @@ export async function send(msg, {log} = {}) {
|
|
|
44
44
|
const key = JSON.stringify([smtp.host, smtp.port, smtp.user, smtp.secure]);
|
|
45
45
|
if (!transport || transportFor !== key) { transport = await createTransport(smtp); transportFor = key; }
|
|
46
46
|
await sendEmail(transport, {
|
|
47
|
-
|
|
47
|
+
// `msg.from`: the support mailbox, for mail TO a customer (a reply then reaches it).
|
|
48
|
+
from: msg.from || smtp.fromAddress || 'noreply@example.com',
|
|
48
49
|
fromName: 'Domma Support',
|
|
49
50
|
to: msg.to, subject: msg.subject, html: msg.html, text: msg.text,
|
|
50
51
|
...(msg.replyTo && {replyTo: msg.replyTo})
|
|
@@ -327,8 +327,10 @@ async function receiverRoutes(fastify, {can, notify, mail, receiverMod, settings
|
|
|
327
327
|
const d = next.data;
|
|
328
328
|
// The customer hears of a reply, and of their request being resolved - not of a quiet status change back to open.
|
|
329
329
|
if (d.userEmail && (body || (d.status === 'closed' && e.data.status !== 'closed'))) {
|
|
330
|
-
|
|
331
|
-
|
|
330
|
+
// From the support mailbox and replying to it: a customer who answers the email reaches Domma Support.
|
|
331
|
+
const support = contactCard(settings).email;
|
|
332
|
+
mail.send({to: d.userEmail, ...(support && {from: support, replyTo: support}),
|
|
333
|
+
...toCustomerEmail({ticket: d, siteName: siteOf(d.site).name, link: siteLink(d.site, d.ref), body, resolved: d.status === 'closed'})}, {log});
|
|
332
334
|
}
|
|
333
335
|
return row(next);
|
|
334
336
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "support",
|
|
3
3
|
"displayName": "Support",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.1",
|
|
5
5
|
"tier": "free",
|
|
6
6
|
"description": "Get help from Domma straight from your admin: our email, phone and hours always to hand, and a conversation with the Domma team for anything you need - urgent requests first.",
|
|
7
7
|
"author": "Domma CMS",
|
|
@@ -15,14 +15,26 @@
|
|
|
15
15
|
"icon": "headphones",
|
|
16
16
|
"description": "Ask Domma for help and follow the conversation (send). On the Domma server itself: the inbox of every site's requests (manage).",
|
|
17
17
|
"actions": [
|
|
18
|
-
{
|
|
19
|
-
|
|
18
|
+
{
|
|
19
|
+
"key": "send",
|
|
20
|
+
"label": "Send",
|
|
21
|
+
"description": "Ask Domma for help and read this site's requests and replies"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"key": "manage",
|
|
25
|
+
"label": "Manage",
|
|
26
|
+
"description": "On the Domma server: read and answer every site's requests"
|
|
27
|
+
}
|
|
20
28
|
],
|
|
21
|
-
"grant": [
|
|
29
|
+
"grant": [
|
|
30
|
+
"admin"
|
|
31
|
+
]
|
|
22
32
|
}
|
|
23
33
|
],
|
|
24
34
|
"admin": {
|
|
25
|
-
"css": [
|
|
35
|
+
"css": [
|
|
36
|
+
"admin/css/index.css"
|
|
37
|
+
],
|
|
26
38
|
"sidebar": [
|
|
27
39
|
{
|
|
28
40
|
"id": "support",
|
|
@@ -35,8 +47,16 @@
|
|
|
35
47
|
}
|
|
36
48
|
],
|
|
37
49
|
"routes": [
|
|
38
|
-
{
|
|
39
|
-
|
|
50
|
+
{
|
|
51
|
+
"path": "/plugins/support",
|
|
52
|
+
"view": "plugin-support",
|
|
53
|
+
"title": "Support - Domma CMS"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"path": "/plugins/support/:id",
|
|
57
|
+
"view": "plugin-support",
|
|
58
|
+
"title": "Support - Domma CMS"
|
|
59
|
+
}
|
|
40
60
|
],
|
|
41
61
|
"views": {
|
|
42
62
|
"plugin-support": {
|
|
@@ -108,6 +108,8 @@ test('Domma replies: the customer is emailed a link to their own admin, and the
|
|
|
108
108
|
assert.equal(r.body.status, 'answered');
|
|
109
109
|
const toAnn = mails.find(x => x.to === 'ann@acme.test');
|
|
110
110
|
assert.equal(toAnn.subject, 'Re: How do I add a page?');
|
|
111
|
+
assert.equal(toAnn.from, 'support@domma-cms.com', 'from the support mailbox');
|
|
112
|
+
assert.equal(toAnn.replyTo, 'support@domma-cms.com', 'so answering the email reaches support');
|
|
111
113
|
assert.ok(toAnn.text.includes(`https://acme.example.test/admin/#/plugins/support/${s.ref}`));
|
|
112
114
|
|
|
113
115
|
const list = await call(acme, 'GET', '/tickets');
|
|
@@ -179,7 +181,7 @@ test('the contact card: the manager\'s reaches every site; a standalone site sti
|
|
|
179
181
|
const alone = await site({env: {}});
|
|
180
182
|
const mode = (await call(alone, 'GET', '/mode')).body;
|
|
181
183
|
assert.equal(mode.connected, false);
|
|
182
|
-
assert.equal(mode.contact.email, 'support@
|
|
184
|
+
assert.equal(mode.contact.email, 'support@domma-cms.com');
|
|
183
185
|
assert.equal((await call(alone, 'POST', '/tickets', {subject: 's', body: 'b'})).status, 409);
|
|
184
186
|
});
|
|
185
187
|
|
|
@@ -74,8 +74,8 @@ test('inbox updates are checked', () => {
|
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
test('the contact card lets through only what is well-formed', () => {
|
|
77
|
-
assert.deepEqual(contactCard({email: 'support@
|
|
78
|
-
{email: 'support@
|
|
77
|
+
assert.deepEqual(contactCard({email: 'support@domma-cms.com', phone: '+44 (0)1234 567890', hours: 'Mon\nFri', responseTime: 'Soon'}),
|
|
78
|
+
{email: 'support@domma-cms.com', phone: '+44 (0)1234 567890', hours: 'Mon Fri', responseTime: 'Soon'});
|
|
79
79
|
assert.deepEqual(contactCard({email: 'javascript:alert(1)', phone: 'call me'}), {email: '', phone: '', hours: '', responseTime: ''});
|
|
80
80
|
assert.equal(telHref('+44 (0)1234 567890'), 'tel:+4401234567890');
|
|
81
81
|
});
|