@trycourier/cli 2.5.0 → 2.6.1
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/README.md +9 -12
- package/dist/commands/TenantsGetMembership.d.ts +3 -0
- package/dist/commands/TenantsGetMembership.js +127 -0
- package/dist/mappings.js +10 -0
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -55,6 +55,7 @@ For more details, run `courier` to see a list of commands and their arguments &
|
|
|
55
55
|
|
|
56
56
|
```
|
|
57
57
|
courier --help
|
|
58
|
+
courier --version
|
|
58
59
|
courier upgrade
|
|
59
60
|
|
|
60
61
|
courier send --tel 555-867-5309 --body "Hey Jenny\!"
|
|
@@ -66,10 +67,7 @@ courier send --user="1" --tenant-context=kewl --title=hello --body="hello world"
|
|
|
66
67
|
courier users:get user123
|
|
67
68
|
courier users:set user123 --email user@example.com
|
|
68
69
|
courier users:bulk examples/users.csv --replace
|
|
69
|
-
courier users:bulk
|
|
70
|
-
courier users:bulk "examples/*.json" --remove-nulls
|
|
71
|
-
courier users:bulk examples/users.parquet --list new-list-id
|
|
72
|
-
courier users:bulk examples/users.xlsx --tenant new-tenant-id
|
|
70
|
+
courier users:bulk examples/users.parquet --list new-list-id --tenant new-tenant-id
|
|
73
71
|
|
|
74
72
|
courier track EXAMPLE_EVENT user123 --name "Pip the Pigeon"
|
|
75
73
|
|
|
@@ -85,16 +83,15 @@ courier config --apikey MY_API_KEY --draft
|
|
|
85
83
|
|
|
86
84
|
There are a number flags you can use for any command
|
|
87
85
|
|
|
88
|
-
| Flags
|
|
89
|
-
|
|
|
90
|
-
| -M --mock
|
|
91
|
-
| -P --production
|
|
92
|
-
| -D --draft
|
|
93
|
-
| -S --submitted
|
|
94
|
-
| --apikey <Courier API Key> | Use the provided Courier API key, otherwise use the approprate environment variable
|
|
86
|
+
| Flags | Description |
|
|
87
|
+
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
88
|
+
| -M --mock | Use the API key that simulates sending using the simulating routing |
|
|
89
|
+
| -P --production | Use the production environment API key |
|
|
90
|
+
| -D --draft | Use the draft document scope API key. Use draft or submitted, will default to published key if neither are provided |
|
|
91
|
+
| -S --submitted | Use the submitted document scope API key |
|
|
92
|
+
| --apikey <Courier API Key> | Use the provided Courier API key, otherwise use the approprate environment variable |
|
|
95
93
|
| --apiurl <Courier API URL> | Use the provided Courier API URL, otherwise use COURIER_API_URL environment variable. Default is https://api.courier.com |
|
|
96
94
|
|
|
97
|
-
|
|
98
95
|
## Misc
|
|
99
96
|
|
|
100
97
|
- If you need to change the Courier API URL, you can set COURIER_API_URL in .courier or other methods to set the environment variables.
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { Alert } from '@inkjs/ui';
|
|
2
|
+
import { stringify } from 'csv-stringify/sync';
|
|
3
|
+
import fs from 'fs/promises';
|
|
4
|
+
import _ from 'lodash';
|
|
5
|
+
import { DateTime } from 'luxon';
|
|
6
|
+
import React, { useEffect, useState } from 'react';
|
|
7
|
+
import { useBoolean, useCounter } from 'usehooks-ts';
|
|
8
|
+
import { useCliContext } from '../components/Context.js';
|
|
9
|
+
import Spinner from '../components/Spinner.js';
|
|
10
|
+
import UhOh from '../components/UhOh.js';
|
|
11
|
+
const FILENAME = 'tenent_members';
|
|
12
|
+
const TenantsGetMembership = () => {
|
|
13
|
+
const { parsedParams, courier } = useCliContext();
|
|
14
|
+
const processing = useBoolean(true);
|
|
15
|
+
const running = useBoolean(true);
|
|
16
|
+
const counter = useCounter(0);
|
|
17
|
+
const [members, setMembers] = useState([]);
|
|
18
|
+
const [error, setError] = useState();
|
|
19
|
+
const { maxPages, json, csv, webhook, filename, _: [tenant_id], } = parsedParams;
|
|
20
|
+
const out_file = (filename?.length
|
|
21
|
+
? filename.substring(0, filename.includes('.') ? filename.lastIndexOf('.') : filename.length)
|
|
22
|
+
: FILENAME) + (csv ? '.csv' : '.json');
|
|
23
|
+
const MAX_PAGES = Number(maxPages) || 100;
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (!processing.value) {
|
|
26
|
+
if (json || csv || webhook?.length) {
|
|
27
|
+
runExport();
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
running.setFalse();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}, [processing.value]);
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
getTenantMemberships();
|
|
36
|
+
}, []);
|
|
37
|
+
const getTenantMemberships = async (cursor, count = 0) => {
|
|
38
|
+
if (!tenant_id) {
|
|
39
|
+
setError('No Tenant Specified');
|
|
40
|
+
processing.setFalse();
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
counter.increment();
|
|
44
|
+
const r = await courier.tenants.getUsersByTenant(tenant_id, {
|
|
45
|
+
cursor,
|
|
46
|
+
limit: 100,
|
|
47
|
+
}, {
|
|
48
|
+
maxRetries: 3,
|
|
49
|
+
timeoutInSeconds: 10,
|
|
50
|
+
});
|
|
51
|
+
let items = r.items;
|
|
52
|
+
if (items?.length) {
|
|
53
|
+
setMembers(previous => {
|
|
54
|
+
return [
|
|
55
|
+
...previous,
|
|
56
|
+
...items.map(({ tenant_id, type, ...rest }) => rest),
|
|
57
|
+
];
|
|
58
|
+
});
|
|
59
|
+
if (r.has_more && count < MAX_PAGES) {
|
|
60
|
+
await getTenantMemberships(r.cursor, count + 1);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
processing.setFalse();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
processing.setFalse();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const runExport = async () => {
|
|
72
|
+
const flat = csv ? flattenData(members) : members;
|
|
73
|
+
if (csv) {
|
|
74
|
+
await fs.writeFile(out_file, stringify(flat, { header: true }));
|
|
75
|
+
}
|
|
76
|
+
else if (json) {
|
|
77
|
+
await fs.writeFile(out_file, JSON.stringify(flat, null, 2), {
|
|
78
|
+
encoding: 'utf-8',
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
if (webhook?.length) {
|
|
82
|
+
try {
|
|
83
|
+
await fetch(webhook, {
|
|
84
|
+
method: 'POST',
|
|
85
|
+
headers: {
|
|
86
|
+
'Content-Type': 'application/json',
|
|
87
|
+
},
|
|
88
|
+
body: JSON.stringify(flat),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
catch (e) {
|
|
92
|
+
setError(e instanceof Error ? e.message : String(e));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
running.setFalse();
|
|
96
|
+
};
|
|
97
|
+
if (error?.length) {
|
|
98
|
+
return React.createElement(UhOh, { text: error });
|
|
99
|
+
}
|
|
100
|
+
else if (running.value) {
|
|
101
|
+
return React.createElement(Spinner, { text: `Fetching tenent_members - page ${counter.count}` });
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
return (React.createElement(React.Fragment, null,
|
|
105
|
+
React.createElement(Alert, { variant: "success", title: `Finished ${counter.count} pages` }, csv || json
|
|
106
|
+
? `Output ${members.length} tenent_members to ${out_file}`
|
|
107
|
+
: JSON.stringify(members, null, 2))));
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
const flattenData = (data) => {
|
|
111
|
+
return data.map(row => {
|
|
112
|
+
return Object.keys(row).reduce((p, key) => {
|
|
113
|
+
const v = _.get(row, [key]);
|
|
114
|
+
if (typeof v === 'number') {
|
|
115
|
+
p[key] = DateTime.fromMillis(v, { zone: 'utc' }).toISO();
|
|
116
|
+
}
|
|
117
|
+
else if (typeof v === 'object') {
|
|
118
|
+
p[key] = JSON.stringify(v);
|
|
119
|
+
}
|
|
120
|
+
else if (v) {
|
|
121
|
+
p[key] = v;
|
|
122
|
+
}
|
|
123
|
+
return p;
|
|
124
|
+
}, {});
|
|
125
|
+
});
|
|
126
|
+
};
|
|
127
|
+
export default TenantsGetMembership;
|
package/dist/mappings.js
CHANGED
|
@@ -22,6 +22,7 @@ import MessagesSearch from './commands/MessagesSearch.js';
|
|
|
22
22
|
import TenantsMembershipBulk from './commands/TenantsMembershipBulk.js';
|
|
23
23
|
import AudienceSearch from './commands/AudienceSearch.js';
|
|
24
24
|
import UsersTokensBulk from './commands/UsersTokensBulk.js';
|
|
25
|
+
import TenantsGetMembership from './commands/TenantsGetMembership.js';
|
|
25
26
|
const mappings = new Map();
|
|
26
27
|
export const COMMON_OPTIONS = [
|
|
27
28
|
{
|
|
@@ -369,6 +370,15 @@ mappings.set('tenants:bulk', {
|
|
|
369
370
|
},
|
|
370
371
|
],
|
|
371
372
|
});
|
|
373
|
+
mappings.set('tenants:get:membership', {
|
|
374
|
+
params: '<tenant_id>',
|
|
375
|
+
instructions: 'Retrieve the users in the tenant',
|
|
376
|
+
component: () => React.createElement(TenantsGetMembership, null),
|
|
377
|
+
options: [...OUTPUT_OPTIONS],
|
|
378
|
+
example: [
|
|
379
|
+
'courier tenants:membership tenant123 --json --filename=tenant123.json',
|
|
380
|
+
],
|
|
381
|
+
});
|
|
372
382
|
mappings.set('tenants:membership:bulk', {
|
|
373
383
|
params: '<filename>',
|
|
374
384
|
instructions: 'Bulk add or remove tenant memberships from file(s). Requires at a minumum a user_id column. You can provide the tenant as a column (tenant_id) or via, other columns are merged into the users tenant specific profile. Supports csv, json, jsonl, xls, xlsx, .parquet. Supports wildcard syntax for multiple files, must surround with quotes (see examples)',
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
let VERSION = '2.
|
|
1
|
+
let VERSION = '2.6.1';
|
|
2
2
|
export default VERSION;
|