@contentstack/cli-cm-export-to-csv 0.1.0-beta.3 → 1.0.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/LICENSE +21 -0
- package/oclif.manifest.json +1 -1
- package/package.json +13 -9
- package/src/commands/cm/export-to-csv.js +230 -53
- package/src/util/config.js +9 -6
- package/src/util/index.js +464 -337
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.1","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.1",
|
|
5
5
|
"author": "Abhinav Gupta @abhinav-from-contentstack",
|
|
6
6
|
"bugs": "https://github.com/contentstack/cli/issues",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@contentstack/cli-command": "^0.1
|
|
8
|
+
"@contentstack/cli-command": "^1.0.1",
|
|
9
|
+
"@contentstack/cli-utilities": "^1.0.2",
|
|
9
10
|
"@contentstack/management": "^1.3.0",
|
|
10
|
-
"@oclif/command": "^1.8.
|
|
11
|
-
"@oclif/config": "^1.
|
|
12
|
-
"axios": "^0.21.1",
|
|
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,68 +1,245 @@
|
|
|
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
|
+
this._managementAPIClient = ContentstackManagementSDK.client({ host: this.cmaHost, authtoken: this.getAuthToken });
|
|
57
|
+
return this._managementAPIClient;
|
|
58
|
+
}
|
|
13
59
|
|
|
14
60
|
async run() {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
61
|
+
try {
|
|
62
|
+
let action;
|
|
63
|
+
const {
|
|
64
|
+
flags: {
|
|
65
|
+
org,
|
|
66
|
+
action: actionFlag,
|
|
67
|
+
'org-name': orgName,
|
|
68
|
+
'stack-name': stackName,
|
|
69
|
+
locale: locale,
|
|
70
|
+
'content-type': contentTypesFlag,
|
|
71
|
+
alias: managementTokenAlias,
|
|
72
|
+
},
|
|
73
|
+
} = this.parse(ExportToCsvCommand);
|
|
74
|
+
|
|
75
|
+
if (actionFlag) {
|
|
76
|
+
action = actionFlag;
|
|
77
|
+
} else {
|
|
78
|
+
action = await util.startupQuestions();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
switch (action) {
|
|
82
|
+
case config.exportEntries:
|
|
83
|
+
case 'entries': {
|
|
84
|
+
try {
|
|
85
|
+
let stack;
|
|
86
|
+
let stackClient;
|
|
87
|
+
let language;
|
|
88
|
+
let contentTypes = [];
|
|
89
|
+
const listOfTokens = configHandler.get('tokens');
|
|
90
|
+
|
|
91
|
+
if (managementTokenAlias && listOfTokens[managementTokenAlias]) {
|
|
92
|
+
stack = {
|
|
93
|
+
name: stackName || managementTokenAlias,
|
|
94
|
+
apiKey: listOfTokens[managementTokenAlias].apiKey,
|
|
95
|
+
token: listOfTokens[managementTokenAlias].token,
|
|
96
|
+
};
|
|
97
|
+
} else if (managementTokenAlias) {
|
|
98
|
+
this.error('Provided management token alias not found in your config.!');
|
|
99
|
+
} else {
|
|
100
|
+
let organization;
|
|
101
|
+
|
|
102
|
+
if (!this.getAuthToken) {
|
|
103
|
+
this.error(config.CLI_EXPORT_CSV_ENTRIES_ERROR, {
|
|
104
|
+
exit: 2,
|
|
105
|
+
suggestions: ['https://www.contentstack.com/docs/developers/cli/authentication/'],
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (org) {
|
|
110
|
+
organization = { uid: org };
|
|
111
|
+
} else {
|
|
112
|
+
organization = await util.chooseOrganization(this.managementAPIClient); // prompt for organization
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
stack = await util.chooseStack(this.managementAPIClient, organization.uid); // prompt for stack
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
stackClient = this.getStackClient(stack);
|
|
119
|
+
const contentTypeCount = await util.getContentTypeCount(stackClient);
|
|
120
|
+
const environments = await util.getEnvironments(stackClient); // fetch environments, because in publish details only env uid are available and we need env names
|
|
121
|
+
|
|
122
|
+
if (contentTypesFlag) {
|
|
123
|
+
contentTypes = contentTypesFlag.split(',').map(this.snakeCase);
|
|
124
|
+
} else {
|
|
125
|
+
for (let index = 0; index <= contentTypeCount / 100; index++) {
|
|
126
|
+
const contentTypesMap = await util.getContentTypes(stackClient, index);
|
|
127
|
+
contentTypes = contentTypes.concat(Object.values(contentTypesMap)); // prompt for content Type
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (contentTypes.length <= 0) {
|
|
132
|
+
this.log('No content types found for the given stack');
|
|
133
|
+
this.exit();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (!contentTypesFlag) {
|
|
137
|
+
contentTypes = await util.chooseInMemContentTypes(contentTypes);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (locale) {
|
|
141
|
+
language = { code: locale };
|
|
142
|
+
} else {
|
|
143
|
+
language = await util.chooseLanguage(stackClient); // prompt for language
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
while (contentTypes.length > 0) {
|
|
147
|
+
let contentType = contentTypes.pop();
|
|
148
|
+
|
|
149
|
+
const entriesCount = await util.getEntriesCount(stackClient, contentType, language.code);
|
|
150
|
+
let flatEntries = [];
|
|
151
|
+
for (let index = 0; index < entriesCount / 100; index++) {
|
|
152
|
+
const entriesResult = await util.getEntries(stackClient, contentType, language.code, index);
|
|
153
|
+
const flatEntriesResult = util.cleanEntries(
|
|
154
|
+
entriesResult.items,
|
|
155
|
+
language.code,
|
|
156
|
+
environments,
|
|
157
|
+
contentType,
|
|
158
|
+
);
|
|
159
|
+
flatEntries = flatEntries.concat(flatEntriesResult);
|
|
160
|
+
}
|
|
161
|
+
let fileName = `${stack.name}_${contentType}_${language.code}_entries_export.csv`;
|
|
162
|
+
|
|
163
|
+
util.write(this, flatEntries, fileName, 'entries'); // write to file
|
|
164
|
+
}
|
|
165
|
+
} catch (error) {
|
|
166
|
+
this.log(util.formatError(error));
|
|
34
167
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
case config.exportUsers:
|
|
171
|
+
case 'users': {
|
|
172
|
+
try {
|
|
173
|
+
if (!this.getAuthToken) {
|
|
174
|
+
this.error(config.CLI_EXPORT_CSV_LOGIN_FAILED, {
|
|
175
|
+
exit: 2,
|
|
176
|
+
suggestions: ['https://www.contentstack.com/docs/developers/cli/authentication/'],
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
let organization;
|
|
180
|
+
|
|
181
|
+
if (org) {
|
|
182
|
+
organization = { uid: org, name: orgName || org };
|
|
183
|
+
} else {
|
|
184
|
+
organization = await util.chooseOrganization(this.managementAPIClient, action); // prompt for organization
|
|
185
|
+
}
|
|
38
186
|
|
|
39
|
-
|
|
187
|
+
const orgUsers = await util.getOrgUsers(this.managementAPIClient, organization.uid, this);
|
|
188
|
+
const orgRoles = await util.getOrgRoles(this.managementAPIClient, organization.uid, this);
|
|
189
|
+
const mappedUsers = util.getMappedUsers(orgUsers);
|
|
190
|
+
const mappedRoles = util.getMappedRoles(orgRoles);
|
|
191
|
+
const listOfUsers = util.cleanOrgUsers(orgUsers, mappedUsers, mappedRoles);
|
|
192
|
+
const fileName = `${util.kebabize(
|
|
193
|
+
organization.name.replace(config.organizationNameRegex, ''),
|
|
194
|
+
)}_users_export.csv`;
|
|
195
|
+
|
|
196
|
+
util.write(this, listOfUsers, fileName, 'organization details');
|
|
197
|
+
} catch (error) {
|
|
198
|
+
if (error.message) {
|
|
199
|
+
this.log(util.formatError(error));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
break;
|
|
40
203
|
}
|
|
41
|
-
break;
|
|
42
204
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const orgUsers = await util.getOrgUsers(this.managementAPIClient, organization.uid, this)
|
|
47
|
-
const orgRoles = await util.getOrgRoles(this.managementAPIClient, organization.uid, this)
|
|
48
|
-
const mappedUsers = util.getMappedUsers(orgUsers)
|
|
49
|
-
const mappedRoles = util.getMappedRoles(orgRoles)
|
|
50
|
-
const listOfUsers = util.cleanOrgUsers(orgUsers, mappedUsers, mappedRoles)
|
|
51
|
-
// const dateTime = util.getDateTime()
|
|
52
|
-
// const fileName = `${util.kebabize(organization.name.replace(config.organizationNameRegex, ''))}_users_export_${dateTime}.csv`
|
|
53
|
-
const fileName = `${util.kebabize(organization.name.replace(config.organizationNameRegex, ''))}_users_export.csv`
|
|
54
|
-
|
|
55
|
-
util.write(this, listOfUsers, fileName)
|
|
56
|
-
} catch(error) {
|
|
57
|
-
this.error(error)
|
|
58
|
-
}
|
|
59
|
-
break;
|
|
205
|
+
} catch (error) {
|
|
206
|
+
if (error.message) {
|
|
207
|
+
this.log(util.formatError(error));
|
|
60
208
|
}
|
|
61
209
|
}
|
|
62
210
|
}
|
|
211
|
+
|
|
212
|
+
snakeCase(string) {
|
|
213
|
+
return (string || '').split(' ').join('_').toLowerCase();
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
getStackClient(stack) {
|
|
217
|
+
if (stack.token) {
|
|
218
|
+
return ContentstackManagementSDK.client({ host: this.cmaHost }).stack({
|
|
219
|
+
api_key: stack.apiKey,
|
|
220
|
+
management_token: stack.token,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
return this.managementAPIClient.stack({ api_key: stack.apiKey });
|
|
224
|
+
}
|
|
63
225
|
}
|
|
64
226
|
|
|
65
|
-
ExportToCsvCommand.description = `Export entries or organization users to csv using this command
|
|
66
|
-
|
|
227
|
+
ExportToCsvCommand.description = `Export entries or organization users to csv using this command`;
|
|
228
|
+
|
|
229
|
+
ExportToCsvCommand.examples = [
|
|
230
|
+
'csdx cm:export-to-csv',
|
|
231
|
+
'',
|
|
232
|
+
'Exporting entries to csv',
|
|
233
|
+
'csdx cm:export-to-csv --action <entries> --locale <locale> --alias <management-token-alias> --content-type <content-type>',
|
|
234
|
+
'',
|
|
235
|
+
'Exporting entries to csv with stack name provided',
|
|
236
|
+
'csdx cm:export-to-csv --action <entries> --locale <locale> --alias <management-token-alias> --content-type <content-type> --stack-name <stack-name>',
|
|
237
|
+
'',
|
|
238
|
+
'Exporting organization users to csv',
|
|
239
|
+
'csdx cm:export-to-csv --action <users> --org <org-uid>',
|
|
240
|
+
'',
|
|
241
|
+
'Exporting organization users to csv with organization name provided',
|
|
242
|
+
'csdx cm:export-to-csv --action <users> --org <org-uid> --org-name <org-name>',
|
|
243
|
+
];
|
|
67
244
|
|
|
68
|
-
module.exports = ExportToCsvCommand
|
|
245
|
+
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,413 +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
|
+
});
|
|
107
131
|
}
|
|
108
132
|
|
|
109
|
-
function chooseContentType(
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
+
});
|
|
129
153
|
}
|
|
130
154
|
|
|
131
|
-
function
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
+
});
|
|
141
192
|
}
|
|
142
193
|
|
|
143
|
-
function
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
exitProgram()
|
|
159
|
-
resolve({ name: chosenLanguage, code: languages[chosenLanguage] })
|
|
160
|
-
})
|
|
161
|
-
})
|
|
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
|
+
});
|
|
162
209
|
}
|
|
163
210
|
|
|
164
|
-
function
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
+
});
|
|
174
231
|
}
|
|
175
232
|
|
|
176
|
-
function
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
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
|
+
});
|
|
186
248
|
}
|
|
187
249
|
|
|
188
|
-
function
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
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
|
+
});
|
|
260
|
+
}
|
|
199
261
|
|
|
200
|
-
function
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
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
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
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
|
+
});
|
|
206
299
|
}
|
|
207
300
|
|
|
208
301
|
function exitProgram() {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
302
|
+
debug('Exiting');
|
|
303
|
+
// eslint-disable-next-line no-undef
|
|
304
|
+
process.exit();
|
|
212
305
|
}
|
|
213
306
|
|
|
214
307
|
function cleanEntries(entries, language, environments, contentTypeUid) {
|
|
215
|
-
const filteredEntries = entries.filter(entry => {
|
|
216
|
-
return
|
|
217
|
-
})
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
let workflow = ''
|
|
221
|
-
const envArr = []
|
|
222
|
-
entry.publish_details.forEach(env => {
|
|
223
|
-
envArr.push(JSON.stringify([environments[env['environment']], env['locale']]))
|
|
224
|
-
})
|
|
225
|
-
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;
|
|
226
319
|
if ('_workflow' in entry) {
|
|
227
|
-
workflow = entry['_workflow']['name']
|
|
228
|
-
delete entry['_workflow']
|
|
320
|
+
workflow = entry['_workflow']['name'];
|
|
321
|
+
delete entry['_workflow'];
|
|
229
322
|
}
|
|
230
|
-
entry = flatten(entry)
|
|
231
|
-
entry['publish_details'] = envArr
|
|
232
|
-
entry['_workflow'] = workflow
|
|
233
|
-
entry['ACL'] = JSON.stringify({}) // setting ACL to empty obj
|
|
234
|
-
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
|
|
235
328
|
// entry['url'] might also be wrong
|
|
236
|
-
delete entry.stackHeaders
|
|
237
|
-
delete entry.update
|
|
238
|
-
delete entry.delete
|
|
239
|
-
delete entry.fetch
|
|
240
|
-
delete entry.publish
|
|
241
|
-
delete entry.unpublish
|
|
242
|
-
delete entry.import
|
|
243
|
-
delete entry.publishRequest
|
|
244
|
-
return entry
|
|
245
|
-
})
|
|
246
|
-
|
|
247
|
-
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
|
+
});
|
|
248
339
|
}
|
|
249
340
|
|
|
250
341
|
function getDateTime() {
|
|
251
|
-
let date = new Date()
|
|
252
|
-
let dateTime = date.toLocaleString().split(',')
|
|
253
|
-
dateTime[0] = dateTime[0].split('/').join('-')
|
|
254
|
-
dateTime[1] = dateTime[1].trim() // trim the space before time
|
|
255
|
-
dateTime[1] = dateTime[1].split(' ').join('')
|
|
256
|
-
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('_');
|
|
257
348
|
}
|
|
258
349
|
|
|
259
|
-
function write(command, entries, fileName) {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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
|
+
}
|
|
355
|
+
// eslint-disable-next-line no-undef
|
|
356
|
+
if (process.cwd().split(delimeter).pop() !== 'data') {
|
|
357
|
+
// eslint-disable-next-line no-undef
|
|
358
|
+
process.chdir(directory);
|
|
359
|
+
}
|
|
269
360
|
// eslint-disable-next-line no-undef
|
|
270
|
-
command.log(`Writing
|
|
271
|
-
fastcsv
|
|
272
|
-
.writeToPath(fileName, entries, {headers: true})
|
|
361
|
+
command.log(`Writing ${message} to file: ${process.cwd()}${delimeter}${fileName}`);
|
|
362
|
+
fastcsv.writeToPath(fileName, entries, { headers: true });
|
|
273
363
|
}
|
|
274
364
|
|
|
275
365
|
function startupQuestions() {
|
|
276
|
-
return new Promise(resolve => {
|
|
277
|
-
let actions = [
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
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
|
+
});
|
|
289
380
|
}
|
|
290
381
|
|
|
291
382
|
function getOrgUsers(managementAPIClient, orgUid, ecsv) {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
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
|
+
});
|
|
309
403
|
}
|
|
310
404
|
|
|
311
405
|
function getMappedUsers(users) {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
406
|
+
let mappedUsers = {};
|
|
407
|
+
users.items.forEach((user) => {
|
|
408
|
+
mappedUsers[user.user_uid] = user.email;
|
|
409
|
+
});
|
|
410
|
+
mappedUsers['System'] = 'System';
|
|
411
|
+
return mappedUsers;
|
|
316
412
|
}
|
|
317
413
|
|
|
318
414
|
function getMappedRoles(roles) {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
415
|
+
let mappedRoles = {};
|
|
416
|
+
roles.items.forEach((role) => {
|
|
417
|
+
mappedRoles[role.uid] = role.name;
|
|
418
|
+
});
|
|
419
|
+
return mappedRoles;
|
|
322
420
|
}
|
|
323
421
|
|
|
324
422
|
function getOrgRoles(managementAPIClient, orgUid, ecsv) {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
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
|
+
});
|
|
342
442
|
}
|
|
343
443
|
|
|
344
444
|
function determineUserOrgRole(user, roles) {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
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;
|
|
355
455
|
}
|
|
356
456
|
|
|
357
457
|
function cleanOrgUsers(orgUsers, mappedUsers, mappedRoles) {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
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;
|
|
377
477
|
}
|
|
378
478
|
|
|
379
479
|
function kebabize(str) {
|
|
380
|
-
|
|
480
|
+
return str
|
|
481
|
+
.split(' ')
|
|
482
|
+
.map((word) => word.toLowerCase())
|
|
483
|
+
.join('-');
|
|
381
484
|
}
|
|
382
485
|
|
|
383
486
|
// https://stackoverflow.com/questions/19098797/fastest-way-to-flatten-un-flatten-nested-json-objects
|
|
384
487
|
function flatten(data) {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
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);
|
|
403
515
|
}
|
|
404
|
-
|
|
405
|
-
|
|
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;
|
|
406
529
|
}
|
|
407
530
|
|
|
408
531
|
module.exports = {
|
|
409
|
-
|
|
410
|
-
|
|
532
|
+
chooseOrganization: chooseOrganization,
|
|
533
|
+
chooseStack: chooseStack,
|
|
411
534
|
chooseContentType: chooseContentType,
|
|
412
535
|
chooseLanguage: chooseLanguage,
|
|
413
536
|
getEntries: getEntries,
|
|
@@ -425,5 +548,9 @@ module.exports = {
|
|
|
425
548
|
getOrganizationsWhereUserIsAdmin: getOrganizationsWhereUserIsAdmin,
|
|
426
549
|
kebabize: kebabize,
|
|
427
550
|
flatten: flatten,
|
|
551
|
+
getContentTypeCount: getContentTypeCount,
|
|
552
|
+
getContentTypes: getContentTypes,
|
|
553
|
+
chooseInMemContentTypes: chooseInMemContentTypes,
|
|
428
554
|
getEntriesCount: getEntriesCount,
|
|
429
|
-
|
|
555
|
+
formatError: formatError,
|
|
556
|
+
};
|