@velaro/cli 1.4.72 → 1.4.73
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/velaro.js
CHANGED
|
@@ -40,6 +40,7 @@ import { appointmentsCommand } from '../lib/commands/appointments.js';
|
|
|
40
40
|
import { bookingCommand } from '../lib/commands/booking.js';
|
|
41
41
|
import { reportCommand } from '../lib/commands/report.js';
|
|
42
42
|
import { scheduleAdherenceCommand } from '../lib/commands/schedule-adherence.js';
|
|
43
|
+
import { reportSubscriptionCommand } from '../lib/commands/report-subscription.js';
|
|
43
44
|
import { experienceImpactCommand } from '../lib/commands/experience-impact.js';
|
|
44
45
|
import { reportBackfillCommand } from '../lib/commands/report-backfill.js';
|
|
45
46
|
import { staffCommand } from '../lib/commands/staff.js';
|
|
@@ -148,6 +149,7 @@ await yargs(hideBin(process.argv))
|
|
|
148
149
|
.command(conversationEfficiencyCommand)
|
|
149
150
|
.command(scheduleAdherenceCommand)
|
|
150
151
|
.command(experienceImpactCommand)
|
|
152
|
+
.command(reportSubscriptionCommand)
|
|
151
153
|
.command(reportBackfillCommand)
|
|
152
154
|
.command({ command: 'staff', desc: 'Velaro staff: cross-site tools (backfill)', builder: staffCommand, handler: () => {} })
|
|
153
155
|
.command(reportExplainCommand)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { messagingRequest } from '../api.js';
|
|
2
|
+
import { runCommand } from '../run.js';
|
|
3
|
+
import { buildSubscriptionUpdateBody, formatSubscriptionLine } from '../report-subscription.js';
|
|
4
|
+
|
|
5
|
+
// -- velaro report-subscription list | update | delete ------------------------------
|
|
6
|
+
// Backend: velaro-messaging GET/PUT/DELETE /report-subscriptions (the caller's own subscriptions).
|
|
7
|
+
|
|
8
|
+
const listCmd = {
|
|
9
|
+
command: 'list',
|
|
10
|
+
describe: 'List your report email subscriptions (incl. delivery hour, format, extra recipients)',
|
|
11
|
+
builder: (y) => y.option('json', { type: 'boolean', default: false }),
|
|
12
|
+
handler: runCommand(async (argv) => {
|
|
13
|
+
const rows = await messagingRequest('GET', '/report-subscriptions');
|
|
14
|
+
if (argv.json) { console.log(JSON.stringify(rows, null, 2)); return; }
|
|
15
|
+
if (!Array.isArray(rows) || !rows.length) { console.log('No report subscriptions.'); return; }
|
|
16
|
+
rows.forEach((s) => console.log(formatSubscriptionLine(s)));
|
|
17
|
+
}),
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const updateCmd = {
|
|
21
|
+
command: 'update <id>',
|
|
22
|
+
describe: 'Update one subscription by id (only passed fields change)',
|
|
23
|
+
builder: (y) => y
|
|
24
|
+
.positional('id', { type: 'number' })
|
|
25
|
+
.option('frequency', { type: 'string', describe: 'daily | weekly | bi-monthly | monthly' })
|
|
26
|
+
.option('delivery-hour', { type: 'number', describe: 'Site-local hour 0-23 to deliver at or after' })
|
|
27
|
+
.option('clear-delivery-hour', { type: 'boolean', default: false })
|
|
28
|
+
.option('format', { type: 'string', choices: ['pdf', 'html'] })
|
|
29
|
+
.option('extra-recipients', { type: 'string', describe: 'Comma-separated emails of other users on this account ("" clears)' })
|
|
30
|
+
.option('active', { type: 'boolean', describe: 'true to resume, false to pause' }),
|
|
31
|
+
handler: runCommand(async (argv) => {
|
|
32
|
+
const body = buildSubscriptionUpdateBody({
|
|
33
|
+
frequency: argv.frequency, deliveryHour: argv.deliveryHour, clearDeliveryHour: argv.clearDeliveryHour,
|
|
34
|
+
format: argv.format, extraRecipients: argv.extraRecipients, active: argv.active,
|
|
35
|
+
});
|
|
36
|
+
await messagingRequest('PUT', `/report-subscriptions/${argv.id}`, body);
|
|
37
|
+
console.log(`Subscription #${argv.id} updated.`);
|
|
38
|
+
}),
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const deleteCmd = {
|
|
42
|
+
command: 'delete <id>',
|
|
43
|
+
describe: 'Delete one subscription by id',
|
|
44
|
+
builder: (y) => y.positional('id', { type: 'number' }),
|
|
45
|
+
handler: runCommand(async (argv) => {
|
|
46
|
+
await messagingRequest('DELETE', `/report-subscriptions/${argv.id}`);
|
|
47
|
+
console.log(`Subscription #${argv.id} deleted.`);
|
|
48
|
+
}),
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const reportSubscriptionCommand = {
|
|
52
|
+
command: 'report-subscription',
|
|
53
|
+
describe: 'Manage your scheduled report email subscriptions',
|
|
54
|
+
builder: (y) => y.command(listCmd).command(updateCmd).command(deleteCmd).demandCommand(1),
|
|
55
|
+
handler: () => {},
|
|
56
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Pure helpers for `velaro report-subscription` (backend: velaro-messaging /report-subscriptions).
|
|
2
|
+
// Site + user scope come from the caller's auth, never an argument.
|
|
3
|
+
|
|
4
|
+
/** Partial-update body: only fields the caller actually passed are included. */
|
|
5
|
+
export function buildSubscriptionUpdateBody(opts = {}) {
|
|
6
|
+
const body = {};
|
|
7
|
+
if (opts.frequency != null && opts.frequency !== '') body.frequency = String(opts.frequency);
|
|
8
|
+
if (opts.deliveryHour != null) {
|
|
9
|
+
const h = Number(opts.deliveryHour);
|
|
10
|
+
if (!Number.isInteger(h) || h < 0 || h > 23) throw new Error('deliveryHour must be an integer 0-23');
|
|
11
|
+
body.deliveryHour = h;
|
|
12
|
+
}
|
|
13
|
+
if (opts.clearDeliveryHour === true) body.clearDeliveryHour = true;
|
|
14
|
+
if (opts.format != null && opts.format !== '') {
|
|
15
|
+
const f = String(opts.format).toLowerCase();
|
|
16
|
+
if (f !== 'pdf' && f !== 'html') throw new Error('format must be pdf or html');
|
|
17
|
+
body.format = f;
|
|
18
|
+
}
|
|
19
|
+
if (opts.extraRecipients != null) body.extraRecipients = String(opts.extraRecipients);
|
|
20
|
+
if (typeof opts.active === 'boolean') body.isActive = opts.active;
|
|
21
|
+
if (Object.keys(body).length === 0) throw new Error('nothing to update: pass at least one field');
|
|
22
|
+
return body;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function formatSubscriptionLine(s) {
|
|
26
|
+
const hour = s.deliveryHour == null ? 'any hour' : `${String(s.deliveryHour).padStart(2, '0')}:00`;
|
|
27
|
+
const extra = s.extraRecipients ? ` | also to ${s.extraRecipients}` : '';
|
|
28
|
+
return `#${s.id} ${s.reportType}: ${s.isActive ? 'active' : 'paused'}, ${s.frequency}, ${hour}, ${s.format ?? 'pdf'}${extra}`;
|
|
29
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { test } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { buildSubscriptionUpdateBody, formatSubscriptionLine } from './report-subscription.js';
|
|
4
|
+
|
|
5
|
+
test('update body includes only provided fields', () => {
|
|
6
|
+
assert.deepEqual(buildSubscriptionUpdateBody({ deliveryHour: 7, format: 'HTML', extraRecipients: 'a@x.com,b@x.com' }),
|
|
7
|
+
{ deliveryHour: 7, format: 'html', extraRecipients: 'a@x.com,b@x.com' });
|
|
8
|
+
});
|
|
9
|
+
test('empty extraRecipients string is sent so it clears the list', () => {
|
|
10
|
+
assert.deepEqual(buildSubscriptionUpdateBody({ extraRecipients: '' }), { extraRecipients: '' });
|
|
11
|
+
});
|
|
12
|
+
test('active=false pauses, hour 0 is valid', () => {
|
|
13
|
+
assert.deepEqual(buildSubscriptionUpdateBody({ active: false, deliveryHour: 0 }), { isActive: false, deliveryHour: 0 });
|
|
14
|
+
});
|
|
15
|
+
test('rejects bad hour, bad format, empty update', () => {
|
|
16
|
+
assert.throws(() => buildSubscriptionUpdateBody({ deliveryHour: 24 }));
|
|
17
|
+
assert.throws(() => buildSubscriptionUpdateBody({ format: 'docx' }));
|
|
18
|
+
assert.throws(() => buildSubscriptionUpdateBody({}));
|
|
19
|
+
});
|
|
20
|
+
test('formats a line with hour, format and extras', () => {
|
|
21
|
+
assert.equal(formatSubscriptionLine({ id: 5, reportType: 'experience-impact', isActive: true, frequency: 'weekly', deliveryHour: 7, format: 'pdf', extraRecipients: 'a@x.com' }),
|
|
22
|
+
'#5 experience-impact: active, weekly, 07:00, pdf | also to a@x.com');
|
|
23
|
+
assert.equal(formatSubscriptionLine({ id: 6, reportType: 'x', isActive: false, frequency: 'daily' }), '#6 x: paused, daily, any hour, pdf');
|
|
24
|
+
});
|
package/package.json
CHANGED