@contentstack/cli-cm-export-to-csv 0.1.0-beta.1 → 1.0.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/LICENSE +21 -0
- package/oclif.manifest.json +1 -1
- package/package.json +14 -10
- package/src/commands/cm/export-to-csv.js +233 -49
- package/src/util/config.js +9 -6
- package/src/util/index.js +466 -326
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Contentstack
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/oclif.manifest.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"
|
|
1
|
+
{"version":"1.0.0","commands":{"cm:export-to-csv":{"id":"cm:export-to-csv","description":"Export entries or organization users to csv using this command","pluginName":"@contentstack/cli-cm-export-to-csv","pluginType":"core","aliases":[],"examples":["csdx cm:export-to-csv","","Exporting entries to csv","csdx cm:export-to-csv --action <entries> --locale <locale> --alias <management-token-alias> --content-type <content-type>","","Exporting entries to csv with stack name provided","csdx cm:export-to-csv --action <entries> --locale <locale> --alias <management-token-alias> --content-type <content-type> --stack-name <stack-name>","","Exporting organization users to csv","csdx cm:export-to-csv --action <users> --org <org-uid>","","Exporting organization users to csv with organization name provided","csdx cm:export-to-csv --action <users> --org <org-uid> --org-name <org-name>"],"flags":{"action":{"name":"action","type":"option","description":"Option to export data (entries, users)","required":false,"options":["entries","users"]},"alias":{"name":"alias","type":"option","char":"a","description":"Alias of the management token"},"org":{"name":"org","type":"option","description":"Provide organization UID to clone org users","required":false},"stack-name":{"name":"stack-name","type":"option","char":"n","description":"Name of the stack that needs to be created as csv filename.","required":false},"org-name":{"name":"org-name","type":"option","description":"Name of the organization that needs to be created as csv filename.","required":false},"locale":{"name":"locale","type":"option","description":"Locale for which entries need to be exported","required":false},"content-type":{"name":"content-type","type":"option","description":"Content type for which entries needs to be exported","required":false}},"args":[]}}}
|
package/package.json
CHANGED
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentstack/cli-cm-export-to-csv",
|
|
3
3
|
"description": "Export entities to csv",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "1.0.0",
|
|
5
5
|
"author": "Abhinav Gupta @abhinav-from-contentstack",
|
|
6
6
|
"bugs": "https://github.com/contentstack/cli/issues",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@contentstack/cli-command": "^
|
|
9
|
-
"@contentstack/
|
|
10
|
-
"@
|
|
11
|
-
"@oclif/
|
|
12
|
-
"
|
|
8
|
+
"@contentstack/cli-command": "^1.0.0",
|
|
9
|
+
"@contentstack/cli-utilities": "^1.0.0",
|
|
10
|
+
"@contentstack/management": "^1.3.0",
|
|
11
|
+
"@oclif/command": "^1.8.16",
|
|
12
|
+
"@oclif/config": "^1.18.3",
|
|
13
13
|
"chalk": "^4.1.0",
|
|
14
14
|
"fast-csv": "^4.3.6",
|
|
15
15
|
"inquirer": "^7.3.3",
|
|
16
|
+
"inquirer-checkbox-plus-prompt": "^1.0.1",
|
|
16
17
|
"mkdirp": "^1.0.4"
|
|
17
18
|
},
|
|
18
19
|
"devDependencies": {
|
|
19
20
|
"@oclif/dev-cli": "^1.26.0",
|
|
20
|
-
"@oclif/plugin-help": "^
|
|
21
|
+
"@oclif/plugin-help": "^5.1.12",
|
|
21
22
|
"@oclif/test": "^1.2.8",
|
|
22
23
|
"chai": "^4.2.0",
|
|
23
24
|
"debug": "^4.3.1",
|
|
24
|
-
"eslint": "^
|
|
25
|
-
"eslint-config-oclif": "^
|
|
25
|
+
"eslint": "^8.18.0",
|
|
26
|
+
"eslint-config-oclif": "^4.0.0",
|
|
26
27
|
"globby": "^10.0.2",
|
|
27
|
-
"mocha": "^
|
|
28
|
+
"mocha": "^10.0.0",
|
|
28
29
|
"nyc": "^14.1.1"
|
|
29
30
|
},
|
|
30
31
|
"engines": {
|
|
@@ -50,6 +51,9 @@
|
|
|
50
51
|
"@oclif/plugin-help"
|
|
51
52
|
]
|
|
52
53
|
},
|
|
54
|
+
"csdxConfig": {
|
|
55
|
+
"expiredCommands": {}
|
|
56
|
+
},
|
|
53
57
|
"repository": "contentstack/cli",
|
|
54
58
|
"scripts": {
|
|
55
59
|
"postpack": "rm -f oclif.manifest.json",
|
|
@@ -1,62 +1,246 @@
|
|
|
1
|
-
const {Command} = require('@contentstack/cli-command')
|
|
2
|
-
const
|
|
3
|
-
const ContentstackManagementSDK = require('@contentstack/management')
|
|
4
|
-
const
|
|
1
|
+
const { Command, flags } = require('@contentstack/cli-command');
|
|
2
|
+
const { configHandler } = require('@contentstack/cli-utilities');
|
|
3
|
+
const ContentstackManagementSDK = require('@contentstack/management');
|
|
4
|
+
const util = require('../../util');
|
|
5
|
+
const config = require('../../util/config');
|
|
5
6
|
|
|
6
7
|
class ExportToCsvCommand extends Command {
|
|
8
|
+
static flags = {
|
|
9
|
+
action: flags.string({
|
|
10
|
+
required: false,
|
|
11
|
+
multiple: false,
|
|
12
|
+
options: ['entries', 'users'],
|
|
13
|
+
description: `Option to export data (entries, users)`,
|
|
14
|
+
}),
|
|
15
|
+
alias: flags.string({
|
|
16
|
+
char: 'a',
|
|
17
|
+
description: 'Alias of the management token',
|
|
18
|
+
}),
|
|
19
|
+
org: flags.string({
|
|
20
|
+
multiple: false,
|
|
21
|
+
required: false,
|
|
22
|
+
description: 'Provide organization UID to clone org users',
|
|
23
|
+
}),
|
|
24
|
+
'stack-name': flags.string({
|
|
25
|
+
char: 'n',
|
|
26
|
+
multiple: false,
|
|
27
|
+
required: false,
|
|
28
|
+
description: 'Name of the stack that needs to be created as csv filename.',
|
|
29
|
+
}),
|
|
30
|
+
'org-name': flags.string({
|
|
31
|
+
multiple: false,
|
|
32
|
+
required: false,
|
|
33
|
+
description: 'Name of the organization that needs to be created as csv filename.',
|
|
34
|
+
}),
|
|
35
|
+
locale: flags.string({
|
|
36
|
+
required: false,
|
|
37
|
+
multiple: false,
|
|
38
|
+
description: 'Locale for which entries need to be exported',
|
|
39
|
+
}),
|
|
40
|
+
'content-type': flags.string({
|
|
41
|
+
description: 'Content type for which entries needs to be exported',
|
|
42
|
+
required: false,
|
|
43
|
+
multiple: false,
|
|
44
|
+
}),
|
|
45
|
+
};
|
|
7
46
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
47
|
+
get getAuthToken() {
|
|
48
|
+
try {
|
|
49
|
+
return this.authToken;
|
|
50
|
+
} catch (error) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
get managementAPIClient() {
|
|
56
|
+
debugger;
|
|
57
|
+
this._managementAPIClient = ContentstackManagementSDK.client({ host: this.cmaHost, authtoken: this.getAuthToken });
|
|
58
|
+
return this._managementAPIClient;
|
|
59
|
+
}
|
|
13
60
|
|
|
14
61
|
async run() {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
util.write(this, flatEntries, fileName) // write to file
|
|
34
|
-
}
|
|
35
|
-
break;
|
|
62
|
+
try {
|
|
63
|
+
let action;
|
|
64
|
+
const {
|
|
65
|
+
flags: {
|
|
66
|
+
org,
|
|
67
|
+
action: actionFlag,
|
|
68
|
+
'org-name': orgName,
|
|
69
|
+
'stack-name': stackName,
|
|
70
|
+
locale: locale,
|
|
71
|
+
'content-type': contentTypesFlag,
|
|
72
|
+
alias: managementTokenAlias,
|
|
73
|
+
},
|
|
74
|
+
} = this.parse(ExportToCsvCommand);
|
|
75
|
+
|
|
76
|
+
if (actionFlag) {
|
|
77
|
+
action = actionFlag;
|
|
78
|
+
} else {
|
|
79
|
+
action = await util.startupQuestions();
|
|
36
80
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
81
|
+
|
|
82
|
+
switch (action) {
|
|
83
|
+
case config.exportEntries:
|
|
84
|
+
case 'entries': {
|
|
85
|
+
try {
|
|
86
|
+
let stack;
|
|
87
|
+
let stackClient;
|
|
88
|
+
let language;
|
|
89
|
+
let contentTypes = [];
|
|
90
|
+
const listOfTokens = configHandler.get('tokens');
|
|
91
|
+
|
|
92
|
+
if (managementTokenAlias && listOfTokens[managementTokenAlias]) {
|
|
93
|
+
stack = {
|
|
94
|
+
name: stackName || managementTokenAlias,
|
|
95
|
+
apiKey: listOfTokens[managementTokenAlias].apiKey,
|
|
96
|
+
token: listOfTokens[managementTokenAlias].token,
|
|
97
|
+
};
|
|
98
|
+
} else if (managementTokenAlias) {
|
|
99
|
+
this.error('Provided management token alias not found in your config.!');
|
|
100
|
+
} else {
|
|
101
|
+
let organization;
|
|
102
|
+
|
|
103
|
+
if (!this.getAuthToken) {
|
|
104
|
+
this.error(config.CLI_EXPORT_CSV_ENTRIES_ERROR, {
|
|
105
|
+
exit: 2,
|
|
106
|
+
suggestions: ['https://www.contentstack.com/docs/developers/cli/authentication/'],
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (org) {
|
|
111
|
+
organization = { uid: org };
|
|
112
|
+
} else {
|
|
113
|
+
organization = await util.chooseOrganization(this.managementAPIClient); // prompt for organization
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
stack = await util.chooseStack(this.managementAPIClient, organization.uid); // prompt for stack
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
stackClient = this.getStackClient(stack);
|
|
120
|
+
const contentTypeCount = await util.getContentTypeCount(stackClient);
|
|
121
|
+
const environments = await util.getEnvironments(stackClient); // fetch environments, because in publish details only env uid are available and we need env names
|
|
122
|
+
|
|
123
|
+
if (contentTypesFlag) {
|
|
124
|
+
contentTypes = contentTypesFlag.split(',').map(this.snakeCase);
|
|
125
|
+
} else {
|
|
126
|
+
for (let index = 0; index <= contentTypeCount / 100; index++) {
|
|
127
|
+
const contentTypesMap = await util.getContentTypes(stackClient, index);
|
|
128
|
+
contentTypes = contentTypes.concat(Object.values(contentTypesMap)); // prompt for content Type
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (contentTypes.length <= 0) {
|
|
133
|
+
this.log('No content types found for the given stack');
|
|
134
|
+
this.exit();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (!contentTypesFlag) {
|
|
138
|
+
contentTypes = await util.chooseInMemContentTypes(contentTypes);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (locale) {
|
|
142
|
+
language = { code: locale };
|
|
143
|
+
} else {
|
|
144
|
+
language = await util.chooseLanguage(stackClient); // prompt for language
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
while (contentTypes.length > 0) {
|
|
148
|
+
let contentType = contentTypes.pop();
|
|
149
|
+
|
|
150
|
+
const entriesCount = await util.getEntriesCount(stackClient, contentType, language.code);
|
|
151
|
+
let flatEntries = [];
|
|
152
|
+
for (let index = 0; index < entriesCount / 100; index++) {
|
|
153
|
+
const entriesResult = await util.getEntries(stackClient, contentType, language.code, index);
|
|
154
|
+
const flatEntriesResult = util.cleanEntries(
|
|
155
|
+
entriesResult.items,
|
|
156
|
+
language.code,
|
|
157
|
+
environments,
|
|
158
|
+
contentType,
|
|
159
|
+
);
|
|
160
|
+
flatEntries = flatEntries.concat(flatEntriesResult);
|
|
161
|
+
}
|
|
162
|
+
let fileName = `${stack.name}_${contentType}_${language.code}_entries_export.csv`;
|
|
163
|
+
|
|
164
|
+
util.write(this, flatEntries, fileName, 'entries'); // write to file
|
|
165
|
+
}
|
|
166
|
+
} catch (error) {
|
|
167
|
+
this.log(util.formatError(error));
|
|
168
|
+
}
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
case config.exportUsers:
|
|
172
|
+
case 'users': {
|
|
173
|
+
try {
|
|
174
|
+
if (!this.getAuthToken) {
|
|
175
|
+
this.error(config.CLI_EXPORT_CSV_LOGIN_FAILED, {
|
|
176
|
+
exit: 2,
|
|
177
|
+
suggestions: ['https://www.contentstack.com/docs/developers/cli/authentication/'],
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
let organization;
|
|
181
|
+
|
|
182
|
+
if (org) {
|
|
183
|
+
organization = { uid: org, name: orgName || org };
|
|
184
|
+
} else {
|
|
185
|
+
organization = await util.chooseOrganization(this.managementAPIClient, action); // prompt for organization
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const orgUsers = await util.getOrgUsers(this.managementAPIClient, organization.uid, this);
|
|
189
|
+
const orgRoles = await util.getOrgRoles(this.managementAPIClient, organization.uid, this);
|
|
190
|
+
const mappedUsers = util.getMappedUsers(orgUsers);
|
|
191
|
+
const mappedRoles = util.getMappedRoles(orgRoles);
|
|
192
|
+
const listOfUsers = util.cleanOrgUsers(orgUsers, mappedUsers, mappedRoles);
|
|
193
|
+
const fileName = `${util.kebabize(
|
|
194
|
+
organization.name.replace(config.organizationNameRegex, ''),
|
|
195
|
+
)}_users_export.csv`;
|
|
196
|
+
|
|
197
|
+
util.write(this, listOfUsers, fileName, 'organization details');
|
|
198
|
+
} catch (error) {
|
|
199
|
+
if (error.message) {
|
|
200
|
+
this.log(util.formatError(error));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
break;
|
|
52
204
|
}
|
|
53
|
-
|
|
205
|
+
}
|
|
206
|
+
} catch (error) {
|
|
207
|
+
if (error.message) {
|
|
208
|
+
this.log(util.formatError(error));
|
|
54
209
|
}
|
|
55
210
|
}
|
|
56
211
|
}
|
|
212
|
+
|
|
213
|
+
snakeCase(string) {
|
|
214
|
+
return (string || '').split(' ').join('_').toLowerCase();
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
getStackClient(stack) {
|
|
218
|
+
if (stack.token) {
|
|
219
|
+
return ContentstackManagementSDK.client({ host: this.cmaHost }).stack({
|
|
220
|
+
api_key: stack.apiKey,
|
|
221
|
+
management_token: stack.token,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
return this.managementAPIClient.stack({ api_key: stack.apiKey });
|
|
225
|
+
}
|
|
57
226
|
}
|
|
58
227
|
|
|
59
|
-
ExportToCsvCommand.description = `Export entries or organization users to csv using this command
|
|
60
|
-
|
|
228
|
+
ExportToCsvCommand.description = `Export entries or organization users to csv using this command`;
|
|
229
|
+
|
|
230
|
+
ExportToCsvCommand.examples = [
|
|
231
|
+
'csdx cm:export-to-csv',
|
|
232
|
+
'',
|
|
233
|
+
'Exporting entries to csv',
|
|
234
|
+
'csdx cm:export-to-csv --action <entries> --locale <locale> --alias <management-token-alias> --content-type <content-type>',
|
|
235
|
+
'',
|
|
236
|
+
'Exporting entries to csv with stack name provided',
|
|
237
|
+
'csdx cm:export-to-csv --action <entries> --locale <locale> --alias <management-token-alias> --content-type <content-type> --stack-name <stack-name>',
|
|
238
|
+
'',
|
|
239
|
+
'Exporting organization users to csv',
|
|
240
|
+
'csdx cm:export-to-csv --action <users> --org <org-uid>',
|
|
241
|
+
'',
|
|
242
|
+
'Exporting organization users to csv with organization name provided',
|
|
243
|
+
'csdx cm:export-to-csv --action <users> --org <org-uid> --org-name <org-name>',
|
|
244
|
+
];
|
|
61
245
|
|
|
62
|
-
module.exports = ExportToCsvCommand
|
|
246
|
+
module.exports = ExportToCsvCommand;
|
package/src/util/config.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
module.exports = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
cancelString: 'Cancel and Exit',
|
|
3
|
+
exportEntries: 'Export entries to a .CSV file',
|
|
4
|
+
exportUsers: "Export organization users' data to a .CSV file",
|
|
5
|
+
adminError: "Unable to export data. Make sure you're an admin or owner of this organization",
|
|
6
|
+
organizationNameRegex: /\'/,
|
|
7
|
+
CLI_EXPORT_CSV_LOGIN_FAILED: "You need to login to execute this command. See: auth:login --help",
|
|
8
|
+
CLI_EXPORT_CSV_ENTRIES_ERROR: "You need to either login or provide a management token to execute this command"
|
|
9
|
+
|
|
10
|
+
};
|
package/src/util/index.js
CHANGED
|
@@ -1,401 +1,536 @@
|
|
|
1
|
-
const inquirer = require('inquirer')
|
|
2
|
-
const
|
|
3
|
-
const os = require('os')
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
1
|
+
const inquirer = require('inquirer');
|
|
2
|
+
const { HttpClient } = require('@contentstack/cli-utilities');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const checkboxPlus = require('inquirer-checkbox-plus-prompt');
|
|
5
|
+
const config = require('./config.js');
|
|
6
|
+
const fastcsv = require('fast-csv');
|
|
7
|
+
const mkdirp = require('mkdirp');
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const debug = require('debug')('export-to-csv');
|
|
10
|
+
const directory = './data';
|
|
11
|
+
const delimeter = os.platform() === 'win32' ? '\\' : '/';
|
|
12
|
+
|
|
13
|
+
// Register checkbox-plus here.
|
|
14
|
+
inquirer.registerPrompt('checkbox-plus', checkboxPlus);
|
|
11
15
|
|
|
12
16
|
function chooseOrganization(managementAPIClient, action) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
17
|
+
return new Promise(async (resolve, reject) => {
|
|
18
|
+
try {
|
|
19
|
+
let organizations;
|
|
20
|
+
if (action === config.exportUsers) {
|
|
21
|
+
organizations = await getOrganizationsWhereUserIsAdmin(managementAPIClient);
|
|
22
|
+
} else {
|
|
23
|
+
organizations = await getOrganizations(managementAPIClient);
|
|
24
|
+
}
|
|
25
|
+
let orgList = Object.keys(organizations);
|
|
26
|
+
orgList.push(config.cancelString);
|
|
27
|
+
let _chooseOrganization = [
|
|
28
|
+
{
|
|
29
|
+
type: 'list',
|
|
30
|
+
name: 'chosenOrg',
|
|
31
|
+
message: 'Choose an Organization',
|
|
32
|
+
choices: orgList,
|
|
33
|
+
loop: false,
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
inquirer.prompt(_chooseOrganization).then(({ chosenOrg }) => {
|
|
37
|
+
if (chosenOrg === config.cancelString) exitProgram();
|
|
38
|
+
resolve({ name: chosenOrg, uid: organizations[chosenOrg] });
|
|
39
|
+
});
|
|
40
|
+
} catch (error) {
|
|
41
|
+
reject(error);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
35
44
|
}
|
|
36
45
|
|
|
37
46
|
function getOrganizations(managementAPIClient) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
return new Promise((resolve, reject) => {
|
|
48
|
+
let result = {};
|
|
49
|
+
|
|
50
|
+
managementAPIClient
|
|
51
|
+
.organization()
|
|
52
|
+
.fetchAll()
|
|
53
|
+
.then((organizations) => {
|
|
54
|
+
organizations.items.forEach((org) => {
|
|
55
|
+
result[org.name] = org.uid;
|
|
56
|
+
});
|
|
57
|
+
resolve(result);
|
|
58
|
+
})
|
|
59
|
+
.catch((error) => reject(error));
|
|
60
|
+
});
|
|
48
61
|
}
|
|
49
62
|
|
|
50
63
|
function getOrganizationsWhereUserIsAdmin(managementAPIClient) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
})
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
let result = {};
|
|
66
|
+
managementAPIClient
|
|
67
|
+
.getUser({ include_orgs_roles: true })
|
|
68
|
+
.then((response) => {
|
|
69
|
+
let organizations = response.organizations.filter((org) => {
|
|
70
|
+
if (org.org_roles) {
|
|
71
|
+
const org_role = org.org_roles.shift();
|
|
72
|
+
return org_role.admin;
|
|
73
|
+
}
|
|
74
|
+
return org.is_owner === true;
|
|
75
|
+
});
|
|
76
|
+
organizations.forEach((org) => {
|
|
77
|
+
result[org.name] = org.uid;
|
|
78
|
+
});
|
|
79
|
+
resolve(result);
|
|
80
|
+
})
|
|
81
|
+
.catch((error) => reject(error));
|
|
82
|
+
});
|
|
71
83
|
}
|
|
72
84
|
|
|
73
85
|
function chooseStack(managementAPIClient, orgUid) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
86
|
+
return new Promise(async (resolve, reject) => {
|
|
87
|
+
try {
|
|
88
|
+
let stacks = await getStacks(managementAPIClient, orgUid);
|
|
89
|
+
let stackList = Object.keys(stacks);
|
|
90
|
+
stackList.push(config.cancelString);
|
|
91
|
+
|
|
92
|
+
let _chooseStack = [
|
|
93
|
+
{
|
|
94
|
+
type: 'list',
|
|
95
|
+
name: 'chosenStack',
|
|
96
|
+
message: 'Choose a Stack',
|
|
97
|
+
choices: stackList,
|
|
98
|
+
},
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
inquirer.prompt(_chooseStack).then(({ chosenStack }) => {
|
|
102
|
+
if (chosenStack === config.cancelString) exitProgram();
|
|
103
|
+
resolve({ name: chosenStack, apiKey: stacks[chosenStack] });
|
|
104
|
+
});
|
|
105
|
+
} catch (error) {
|
|
106
|
+
reject(error);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
92
109
|
}
|
|
93
110
|
|
|
94
111
|
function getStacks(managementAPIClient, orgUid) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
112
|
+
// Adding a query object in query, because it throws an error
|
|
113
|
+
// the error is coming from query function lib/entity.js, @contentstack/management pacakge
|
|
114
|
+
// where params.query is being set
|
|
115
|
+
return new Promise((resolve, reject) => {
|
|
116
|
+
let result = {};
|
|
117
|
+
managementAPIClient
|
|
118
|
+
.stack({ organization_uid: orgUid })
|
|
119
|
+
.query({ query: {} })
|
|
120
|
+
.find()
|
|
121
|
+
.then((stacks) => {
|
|
122
|
+
stacks.items.forEach((stack) => {
|
|
123
|
+
result[stack.name] = stack.api_key;
|
|
124
|
+
});
|
|
125
|
+
resolve(result);
|
|
126
|
+
})
|
|
127
|
+
.catch((error) => {
|
|
128
|
+
reject(error);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function chooseContentType(stack, skip) {
|
|
134
|
+
return new Promise(async (resolve) => {
|
|
135
|
+
let contentTypes = await getContentTypes(stack, skip);
|
|
136
|
+
let contentTypesList = Object.values(contentTypes);
|
|
137
|
+
// contentTypesList.push(config.cancelString)
|
|
138
|
+
|
|
139
|
+
let _chooseContentType = [
|
|
140
|
+
{
|
|
141
|
+
type: 'checkbox',
|
|
142
|
+
message: 'Choose Content Type',
|
|
143
|
+
choices: contentTypesList,
|
|
144
|
+
name: 'chosenContentTypes',
|
|
145
|
+
loop: false,
|
|
146
|
+
},
|
|
147
|
+
];
|
|
148
|
+
|
|
149
|
+
inquirer.prompt(_chooseContentType).then(({ chosenContentTypes }) => {
|
|
150
|
+
resolve(chosenContentTypes);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function chooseInMemContentTypes(contentTypesList) {
|
|
156
|
+
return new Promise(async (resolve, reject) => {
|
|
157
|
+
let _chooseContentType = [
|
|
158
|
+
{
|
|
159
|
+
type: 'checkbox-plus',
|
|
160
|
+
message: 'Choose Content Type',
|
|
161
|
+
choices: contentTypesList,
|
|
162
|
+
name: 'chosenContentTypes',
|
|
163
|
+
loop: false,
|
|
164
|
+
highlight: true,
|
|
165
|
+
searchable: true,
|
|
166
|
+
source: (_, input) => {
|
|
167
|
+
input = input || '';
|
|
168
|
+
const inputArray = input.split(' ');
|
|
169
|
+
return new Promise((resolveSource) => {
|
|
170
|
+
const contentTypes = contentTypesList.filter((contentType) => {
|
|
171
|
+
let shouldInclude = true;
|
|
172
|
+
inputArray.forEach((inputChunk) => {
|
|
173
|
+
// if any term to filter by doesn't exist, exclude
|
|
174
|
+
if (!contentType.toLowerCase().includes(inputChunk.toLowerCase())) {
|
|
175
|
+
shouldInclude = false;
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
return shouldInclude;
|
|
179
|
+
});
|
|
180
|
+
resolveSource(contentTypes);
|
|
181
|
+
});
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
];
|
|
185
|
+
inquirer.prompt(_chooseContentType).then(({ chosenContentTypes }) => {
|
|
186
|
+
if (chosenContentTypes.length === 0) {
|
|
187
|
+
reject('Please select atleast one content type.');
|
|
188
|
+
}
|
|
189
|
+
resolve(chosenContentTypes);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function getContentTypes(stack, skip) {
|
|
195
|
+
return new Promise((resolve, reject) => {
|
|
196
|
+
let result = {};
|
|
197
|
+
stack
|
|
198
|
+
.contentType()
|
|
199
|
+
.query({ skip: skip * 100 })
|
|
200
|
+
.find()
|
|
201
|
+
.then((contentTypes) => {
|
|
202
|
+
contentTypes.items.forEach((contentType) => {
|
|
203
|
+
result[contentType.title] = contentType.uid;
|
|
204
|
+
});
|
|
205
|
+
resolve(result);
|
|
206
|
+
})
|
|
207
|
+
.catch((error) => reject(error));
|
|
208
|
+
});
|
|
107
209
|
}
|
|
108
210
|
|
|
109
|
-
function
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
211
|
+
function chooseLanguage(stack) {
|
|
212
|
+
return new Promise(async (resolve) => {
|
|
213
|
+
let languages = await getLanguages(stack);
|
|
214
|
+
let languagesList = Object.keys(languages);
|
|
215
|
+
languagesList.push(config.cancelString);
|
|
216
|
+
|
|
217
|
+
let _chooseLanguage = [
|
|
218
|
+
{
|
|
219
|
+
type: 'list',
|
|
220
|
+
message: 'Choose Language',
|
|
221
|
+
choices: languagesList,
|
|
222
|
+
name: 'chosenLanguage',
|
|
223
|
+
},
|
|
224
|
+
];
|
|
225
|
+
|
|
226
|
+
inquirer.prompt(_chooseLanguage).then(({ chosenLanguage }) => {
|
|
227
|
+
if (chosenLanguage === config.cancelString) exitProgram();
|
|
228
|
+
resolve({ name: chosenLanguage, code: languages[chosenLanguage] });
|
|
229
|
+
});
|
|
230
|
+
});
|
|
129
231
|
}
|
|
130
232
|
|
|
131
|
-
function
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
233
|
+
function getLanguages(stack) {
|
|
234
|
+
return new Promise((resolve, reject) => {
|
|
235
|
+
let result = {};
|
|
236
|
+
stack
|
|
237
|
+
.locale()
|
|
238
|
+
.query()
|
|
239
|
+
.find()
|
|
240
|
+
.then((languages) => {
|
|
241
|
+
languages.items.forEach((language) => {
|
|
242
|
+
result[language.name] = language.code;
|
|
243
|
+
});
|
|
244
|
+
resolve(result);
|
|
245
|
+
})
|
|
246
|
+
.catch((error) => reject(error));
|
|
247
|
+
});
|
|
141
248
|
}
|
|
142
249
|
|
|
143
|
-
function
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
name: 'chosenLanguage'
|
|
154
|
-
}]
|
|
155
|
-
|
|
156
|
-
inquirer.prompt(chooseLanguage).then(({chosenLanguage}) => {
|
|
157
|
-
if (chosenLanguage === config.cancelString)
|
|
158
|
-
exitProgram()
|
|
159
|
-
resolve({ name: chosenLanguage, code: languages[chosenLanguage] })
|
|
160
|
-
})
|
|
161
|
-
})
|
|
250
|
+
function getEntries(stack, contentType, language, skip) {
|
|
251
|
+
return new Promise((resolve, reject) => {
|
|
252
|
+
stack
|
|
253
|
+
.contentType(contentType)
|
|
254
|
+
.entry()
|
|
255
|
+
.query({ include_publish_details: true, locale: language, skip: skip * 100 })
|
|
256
|
+
.find()
|
|
257
|
+
.then((entries) => resolve(entries))
|
|
258
|
+
.catch((error) => reject(error));
|
|
259
|
+
});
|
|
162
260
|
}
|
|
163
261
|
|
|
164
|
-
function
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
262
|
+
function getEntriesCount(stack, contentType, language) {
|
|
263
|
+
return new Promise((resolve, reject) => {
|
|
264
|
+
stack
|
|
265
|
+
.contentType(contentType)
|
|
266
|
+
.entry()
|
|
267
|
+
.query({ include_publish_details: true, locale: language })
|
|
268
|
+
.count()
|
|
269
|
+
.then((entriesData) => resolve(entriesData.entries))
|
|
270
|
+
.catch((error) => reject(formatError(error)));
|
|
271
|
+
});
|
|
174
272
|
}
|
|
175
273
|
|
|
176
|
-
function
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
274
|
+
function getEnvironments(stack) {
|
|
275
|
+
let result = {};
|
|
276
|
+
return stack
|
|
277
|
+
.environment()
|
|
278
|
+
.query()
|
|
279
|
+
.find()
|
|
280
|
+
.then((environments) => {
|
|
281
|
+
environments.items.forEach((env) => {
|
|
282
|
+
result[env['uid']] = env['name'];
|
|
283
|
+
});
|
|
284
|
+
return result;
|
|
285
|
+
});
|
|
186
286
|
}
|
|
187
287
|
|
|
188
|
-
function
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
288
|
+
function getContentTypeCount(stack) {
|
|
289
|
+
return new Promise((resolve, reject) => {
|
|
290
|
+
stack
|
|
291
|
+
.contentType()
|
|
292
|
+
.query()
|
|
293
|
+
.count()
|
|
294
|
+
.then((contentTypes) => {
|
|
295
|
+
resolve(contentTypes.content_types);
|
|
296
|
+
})
|
|
297
|
+
.catch((error) => reject(error));
|
|
298
|
+
});
|
|
194
299
|
}
|
|
195
300
|
|
|
196
301
|
function exitProgram() {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
302
|
+
debug('Exiting');
|
|
303
|
+
// eslint-disable-next-line no-undef
|
|
304
|
+
process.exit();
|
|
200
305
|
}
|
|
201
306
|
|
|
202
307
|
function cleanEntries(entries, language, environments, contentTypeUid) {
|
|
203
|
-
const filteredEntries = entries.filter(entry => {
|
|
204
|
-
return
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
let workflow = ''
|
|
209
|
-
const envArr = []
|
|
210
|
-
entry.publish_details.forEach(env => {
|
|
211
|
-
envArr.push(JSON.stringify([environments[env['environment']], env['locale']]))
|
|
212
|
-
})
|
|
213
|
-
delete entry.publish_details
|
|
308
|
+
const filteredEntries = entries.filter((entry) => {
|
|
309
|
+
return entry['locale'] === language && entry.publish_details.length > 0;
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
return filteredEntries.map((entry) => {
|
|
313
|
+
let workflow = '';
|
|
314
|
+
const envArr = [];
|
|
315
|
+
entry.publish_details.forEach((env) => {
|
|
316
|
+
envArr.push(JSON.stringify([environments[env['environment']], env['locale']]));
|
|
317
|
+
});
|
|
318
|
+
delete entry.publish_details;
|
|
214
319
|
if ('_workflow' in entry) {
|
|
215
|
-
workflow = entry['_workflow']['name']
|
|
216
|
-
delete entry['_workflow']
|
|
320
|
+
workflow = entry['_workflow']['name'];
|
|
321
|
+
delete entry['_workflow'];
|
|
217
322
|
}
|
|
218
|
-
entry = flatten(entry)
|
|
219
|
-
entry['publish_details'] = envArr
|
|
220
|
-
entry['_workflow'] = workflow
|
|
221
|
-
entry['ACL'] = JSON.stringify({}) // setting ACL to empty obj
|
|
222
|
-
entry['content_type_uid'] = contentTypeUid // content_type_uid is being returned as 'uid' from the sdk for some reason
|
|
323
|
+
entry = flatten(entry);
|
|
324
|
+
entry['publish_details'] = envArr;
|
|
325
|
+
entry['_workflow'] = workflow;
|
|
326
|
+
entry['ACL'] = JSON.stringify({}); // setting ACL to empty obj
|
|
327
|
+
entry['content_type_uid'] = contentTypeUid; // content_type_uid is being returned as 'uid' from the sdk for some reason
|
|
223
328
|
// entry['url'] might also be wrong
|
|
224
|
-
delete entry.stackHeaders
|
|
225
|
-
delete entry.update
|
|
226
|
-
delete entry.delete
|
|
227
|
-
delete entry.fetch
|
|
228
|
-
delete entry.publish
|
|
229
|
-
delete entry.unpublish
|
|
230
|
-
delete entry.import
|
|
231
|
-
delete entry.publishRequest
|
|
232
|
-
return entry
|
|
233
|
-
})
|
|
234
|
-
|
|
235
|
-
return flatEntries
|
|
329
|
+
delete entry.stackHeaders;
|
|
330
|
+
delete entry.update;
|
|
331
|
+
delete entry.delete;
|
|
332
|
+
delete entry.fetch;
|
|
333
|
+
delete entry.publish;
|
|
334
|
+
delete entry.unpublish;
|
|
335
|
+
delete entry.import;
|
|
336
|
+
delete entry.publishRequest;
|
|
337
|
+
return entry;
|
|
338
|
+
});
|
|
236
339
|
}
|
|
237
340
|
|
|
238
341
|
function getDateTime() {
|
|
239
|
-
let date = new Date()
|
|
240
|
-
let dateTime = date.toLocaleString().split(',')
|
|
241
|
-
dateTime[0] = dateTime[0].split('/').join('-')
|
|
242
|
-
dateTime[1] = dateTime[1].trim() // trim the space before time
|
|
243
|
-
dateTime[1] = dateTime[1].split(' ').join('')
|
|
244
|
-
return dateTime.join('_')
|
|
342
|
+
let date = new Date();
|
|
343
|
+
let dateTime = date.toLocaleString().split(',');
|
|
344
|
+
dateTime[0] = dateTime[0].split('/').join('-');
|
|
345
|
+
dateTime[1] = dateTime[1].trim(); // trim the space before time
|
|
346
|
+
dateTime[1] = dateTime[1].split(' ').join('');
|
|
347
|
+
return dateTime.join('_');
|
|
245
348
|
}
|
|
246
349
|
|
|
247
|
-
function write(command, entries, fileName) {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
// eslint-disable-next-line no-undef
|
|
253
|
-
if (process.cwd().split(delimeter).pop() !== 'data') {
|
|
254
|
-
// eslint-disable-next-line no-undef
|
|
255
|
-
process.chdir(directory)
|
|
256
|
-
}
|
|
350
|
+
function write(command, entries, fileName, message) {
|
|
351
|
+
// eslint-disable-next-line no-undef
|
|
352
|
+
if (process.cwd().split(delimeter).pop() !== 'data' && !fs.existsSync(directory)) {
|
|
353
|
+
mkdirp.sync(directory);
|
|
354
|
+
}
|
|
257
355
|
// eslint-disable-next-line no-undef
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
356
|
+
if (process.cwd().split(delimeter).pop() !== 'data') {
|
|
357
|
+
// eslint-disable-next-line no-undef
|
|
358
|
+
process.chdir(directory);
|
|
359
|
+
}
|
|
360
|
+
// eslint-disable-next-line no-undef
|
|
361
|
+
command.log(`Writing ${message} to file: ${process.cwd()}${delimeter}${fileName}`);
|
|
362
|
+
fastcsv.writeToPath(fileName, entries, { headers: true });
|
|
261
363
|
}
|
|
262
364
|
|
|
263
365
|
function startupQuestions() {
|
|
264
|
-
return new Promise(resolve => {
|
|
265
|
-
let actions = [
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
366
|
+
return new Promise((resolve) => {
|
|
367
|
+
let actions = [
|
|
368
|
+
{
|
|
369
|
+
type: 'list',
|
|
370
|
+
name: 'action',
|
|
371
|
+
message: 'Choose Action',
|
|
372
|
+
choices: [config.exportEntries, config.exportUsers, 'Exit'],
|
|
373
|
+
},
|
|
374
|
+
];
|
|
375
|
+
inquirer.prompt(actions).then((answers) => {
|
|
376
|
+
if (answers.action === 'Exit') exitProgram();
|
|
377
|
+
resolve(answers.action);
|
|
378
|
+
});
|
|
379
|
+
});
|
|
277
380
|
}
|
|
278
381
|
|
|
279
382
|
function getOrgUsers(managementAPIClient, orgUid, ecsv) {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
383
|
+
return new Promise((resolve, reject) => {
|
|
384
|
+
managementAPIClient
|
|
385
|
+
.getUser({ include_orgs_roles: true })
|
|
386
|
+
.then((response) => {
|
|
387
|
+
let organization = response.organizations.filter((org) => org.uid === orgUid).pop();
|
|
388
|
+
if (organization.is_owner === true) {
|
|
389
|
+
let cma = ecsv.region.cma;
|
|
390
|
+
let authtoken = ecsv.authToken;
|
|
391
|
+
return HttpClient.create()
|
|
392
|
+
.headers({ authtoken: authtoken })
|
|
393
|
+
.get(`${cma}/v3/organizations/${organization.uid}/share`)
|
|
394
|
+
.then((_response) => resolve({ items: _response.data.shares }));
|
|
395
|
+
}
|
|
396
|
+
if (!organization.getInvitations) {
|
|
397
|
+
return reject(new Error(config.adminError));
|
|
398
|
+
}
|
|
399
|
+
organization.getInvitations().then((users) => resolve(users));
|
|
400
|
+
})
|
|
401
|
+
.catch((error) => reject(error));
|
|
402
|
+
});
|
|
297
403
|
}
|
|
298
404
|
|
|
299
405
|
function getMappedUsers(users) {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
406
|
+
let mappedUsers = {};
|
|
407
|
+
users.items.forEach((user) => {
|
|
408
|
+
mappedUsers[user.user_uid] = user.email;
|
|
409
|
+
});
|
|
410
|
+
mappedUsers['System'] = 'System';
|
|
411
|
+
return mappedUsers;
|
|
304
412
|
}
|
|
305
413
|
|
|
306
414
|
function getMappedRoles(roles) {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
415
|
+
let mappedRoles = {};
|
|
416
|
+
roles.items.forEach((role) => {
|
|
417
|
+
mappedRoles[role.uid] = role.name;
|
|
418
|
+
});
|
|
419
|
+
return mappedRoles;
|
|
310
420
|
}
|
|
311
421
|
|
|
312
422
|
function getOrgRoles(managementAPIClient, orgUid, ecsv) {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
423
|
+
return new Promise((resolve, reject) => {
|
|
424
|
+
managementAPIClient
|
|
425
|
+
.getUser({ include_orgs_roles: true })
|
|
426
|
+
.then((response) => {
|
|
427
|
+
let organization = response.organizations.filter((org) => org.uid === orgUid).pop();
|
|
428
|
+
if (organization.is_owner === true) {
|
|
429
|
+
let cma = ecsv.region.cma;
|
|
430
|
+
let authtoken = ecsv.authToken;
|
|
431
|
+
return axios
|
|
432
|
+
.get(`${cma}/v3/organizations/${organization.uid}/roles`, { headers: { authtoken: authtoken } })
|
|
433
|
+
.then((_response) => resolve({ items: _response.data.roles }));
|
|
434
|
+
}
|
|
435
|
+
if (!organization.roles) {
|
|
436
|
+
return reject(new Error(config.adminError));
|
|
437
|
+
}
|
|
438
|
+
organization.roles().then((roles) => resolve(roles));
|
|
439
|
+
})
|
|
440
|
+
.catch((error) => reject(error));
|
|
441
|
+
});
|
|
330
442
|
}
|
|
331
443
|
|
|
332
444
|
function determineUserOrgRole(user, roles) {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
445
|
+
let roleName = 'No Role';
|
|
446
|
+
let roleUid = user.org_roles || [];
|
|
447
|
+
if (roleUid.length > 0) {
|
|
448
|
+
roleUid = roleUid.shift();
|
|
449
|
+
roleName = roles[roleUid];
|
|
450
|
+
}
|
|
451
|
+
if (user.is_owner) {
|
|
452
|
+
roleName = 'Owner';
|
|
453
|
+
}
|
|
454
|
+
return roleName;
|
|
343
455
|
}
|
|
344
456
|
|
|
345
457
|
function cleanOrgUsers(orgUsers, mappedUsers, mappedRoles) {
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
458
|
+
const userList = [];
|
|
459
|
+
orgUsers.items.forEach((user) => {
|
|
460
|
+
let invitedBy;
|
|
461
|
+
let formattedUser = {};
|
|
462
|
+
try {
|
|
463
|
+
invitedBy = mappedUsers[user['invited_by']];
|
|
464
|
+
} catch (error) {
|
|
465
|
+
invitedBy = 'System';
|
|
466
|
+
}
|
|
467
|
+
formattedUser['Email'] = user['email'];
|
|
468
|
+
formattedUser['User UID'] = user['user_uid'];
|
|
469
|
+
formattedUser['Organization Role'] = determineUserOrgRole(user, mappedRoles);
|
|
470
|
+
formattedUser['Status'] = user['status'];
|
|
471
|
+
formattedUser['Invited By'] = invitedBy;
|
|
472
|
+
formattedUser['Created Time'] = user['created_at'];
|
|
473
|
+
formattedUser['Updated Time'] = user['updated_at'];
|
|
474
|
+
userList.push(formattedUser);
|
|
475
|
+
});
|
|
476
|
+
return userList;
|
|
365
477
|
}
|
|
366
478
|
|
|
367
479
|
function kebabize(str) {
|
|
368
|
-
|
|
480
|
+
return str
|
|
481
|
+
.split(' ')
|
|
482
|
+
.map((word) => word.toLowerCase())
|
|
483
|
+
.join('-');
|
|
369
484
|
}
|
|
370
485
|
|
|
371
486
|
// https://stackoverflow.com/questions/19098797/fastest-way-to-flatten-un-flatten-nested-json-objects
|
|
372
487
|
function flatten(data) {
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
488
|
+
let result = {};
|
|
489
|
+
function recurse(cur, prop) {
|
|
490
|
+
if (Object(cur) !== cur) {
|
|
491
|
+
result[prop] = cur;
|
|
492
|
+
} else if (Array.isArray(cur)) {
|
|
493
|
+
let i, l;
|
|
494
|
+
for (i = 0, l = cur.length; i < l; i++) recurse(cur[i], prop + '[' + i + ']');
|
|
495
|
+
if (l == 0) result[prop] = [];
|
|
496
|
+
} else {
|
|
497
|
+
let isEmpty = true;
|
|
498
|
+
for (let p in cur) {
|
|
499
|
+
isEmpty = false;
|
|
500
|
+
recurse(cur[p], prop ? prop + '.' + p : p);
|
|
501
|
+
}
|
|
502
|
+
if (isEmpty && prop) result[prop] = {};
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
recurse(data, '');
|
|
506
|
+
return result;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
function formatError(error) {
|
|
510
|
+
try {
|
|
511
|
+
if (typeof error === 'string') {
|
|
512
|
+
error = JSON.parse(error);
|
|
513
|
+
} else {
|
|
514
|
+
error = JSON.parse(error.message);
|
|
391
515
|
}
|
|
392
|
-
|
|
393
|
-
|
|
516
|
+
} catch (e) {}
|
|
517
|
+
let message = error.errorMessage || error.error_message || error.message || error;
|
|
518
|
+
if (error.errors && Object.keys(error.errors).length > 0) {
|
|
519
|
+
Object.keys(error.errors).forEach((e) => {
|
|
520
|
+
let entity = e;
|
|
521
|
+
if (e === 'authorization') entity = 'Management Token';
|
|
522
|
+
if (e === 'api_key') entity = 'Stack API key';
|
|
523
|
+
if (e === 'uid') entity = 'Content Type';
|
|
524
|
+
if (e === 'access_token') entity = 'Delivery Token';
|
|
525
|
+
message += ' ' + [entity, error.errors[e]].join(' ');
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
return message;
|
|
394
529
|
}
|
|
395
530
|
|
|
396
531
|
module.exports = {
|
|
397
|
-
|
|
398
|
-
|
|
532
|
+
chooseOrganization: chooseOrganization,
|
|
533
|
+
chooseStack: chooseStack,
|
|
399
534
|
chooseContentType: chooseContentType,
|
|
400
535
|
chooseLanguage: chooseLanguage,
|
|
401
536
|
getEntries: getEntries,
|
|
@@ -413,4 +548,9 @@ module.exports = {
|
|
|
413
548
|
getOrganizationsWhereUserIsAdmin: getOrganizationsWhereUserIsAdmin,
|
|
414
549
|
kebabize: kebabize,
|
|
415
550
|
flatten: flatten,
|
|
416
|
-
|
|
551
|
+
getContentTypeCount: getContentTypeCount,
|
|
552
|
+
getContentTypes: getContentTypes,
|
|
553
|
+
chooseInMemContentTypes: chooseInMemContentTypes,
|
|
554
|
+
getEntriesCount: getEntriesCount,
|
|
555
|
+
formatError: formatError,
|
|
556
|
+
};
|