@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 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.
@@ -1 +1 @@
1
- {"version":"0.1.0-beta.1","commands":{"cm:export-to-csv":{"id":"cm:export-to-csv","description":"Export entries or organization users to csv using this command\n","pluginName":"@contentstack/cli-cm-export-to-csv","pluginType":"core","aliases":[],"flags":{},"args":[]}}}
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": "0.1.0-beta.1",
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": "^0.1.1-beta.1",
9
- "@contentstack/management": "^1.2.1",
10
- "@oclif/command": "^1.8.0",
11
- "@oclif/config": "^1.17.0",
12
- "axios": "^0.21.1",
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": "^3.2.1",
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": "^5.16.0",
25
- "eslint-config-oclif": "^3.1.0",
25
+ "eslint": "^8.18.0",
26
+ "eslint-config-oclif": "^4.0.0",
26
27
  "globby": "^10.0.2",
27
- "mocha": "^8.3.1",
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 util = require('../../util/index')
3
- const ContentstackManagementSDK = require('@contentstack/management')
4
- const config = require('../../util/config.js')
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
- get managementAPIClient() {
9
- // this._managementAPIClient = ContentstackManagementSDK.client({host:this.cmaHost, authtoken: this.authToken})
10
- this._managementAPIClient = ContentstackManagementSDK.client({host:this.cmaHost, authtoken: this.authToken})
11
- return this._managementAPIClient
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
- const action = await util.startupQuestions()
17
-
18
- switch(action) {
19
- case config.exportEntries: {
20
- const organization = await util.chooseOrganization(this.managementAPIClient) // prompt for organization
21
- const stack = await util.chooseStack(this.managementAPIClient, organization.uid) // prompt for stack
22
- const contentTypes = await util.chooseContentType(this.managementAPIClient, stack.apiKey) // prompt for content Type
23
- const language = await util.chooseLanguage(this.managementAPIClient, stack.apiKey) // prompt for language
24
- const environments = await util.getEnvironments(this.managementAPIClient, stack.apiKey) // fetch environments, because in publish details only env uid are available and we need env names
25
- while(contentTypes.length > 0) {
26
- let contentType = contentTypes.shift()
27
- let entries = await util.getEntries(this.managementAPIClient, stack.apiKey, contentType, language.code) // fetch entries
28
- let flatEntries = util.cleanEntries(entries.items, language.code, environments, contentType); // clean entries to be wderitten to file
29
- // let dateTime = util.getDateTime()
30
- // let fileName = `${contentType}_${language.code}_entries_export_${dateTime}.csv`
31
- let fileName = `${stack.name}_${contentType}_${language.code}_entries_export.csv`
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
- case config.exportUsers: {
38
- try {
39
- const organization = await util.chooseOrganization(this.managementAPIClient, action) // prompt for organization
40
- const orgUsers = await util.getOrgUsers(this.managementAPIClient, organization.uid, this)
41
- const orgRoles = await util.getOrgRoles(this.managementAPIClient, organization.uid, this)
42
- const mappedUsers = util.getMappedUsers(orgUsers)
43
- const mappedRoles = util.getMappedRoles(orgRoles)
44
- const listOfUsers = util.cleanOrgUsers(orgUsers, mappedUsers, mappedRoles)
45
- // const dateTime = util.getDateTime()
46
- // const fileName = `${util.kebabize(organization.name.replace(config.organizationNameRegex, ''))}_users_export_${dateTime}.csv`
47
- const fileName = `${util.kebabize(organization.name.replace(config.organizationNameRegex, ''))}_users_export.csv`
48
-
49
- util.write(this, listOfUsers, fileName)
50
- } catch(error) {
51
- this.error(error)
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
- break;
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;
@@ -1,7 +1,10 @@
1
1
  module.exports = {
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
- }
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 axios = require('axios')
3
- const os = require('os')
4
- const config = require('./config.js')
5
- const fastcsv = require('fast-csv')
6
- const mkdirp = require('mkdirp')
7
- const fs = require('fs')
8
- const debug = require('debug')("export-to-csv")
9
- const directory = './data'
10
- const delimeter = (os.platform() === 'win32') ? '\\' : '/'
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
- return new Promise(async resolve => {
14
- let organizations
15
- if (action === config.exportUsers) {
16
- organizations = await getOrganizationsWhereUserIsAdmin(managementAPIClient)
17
- } else {
18
- organizations = await getOrganizations(managementAPIClient)
19
- }
20
- let orgList = Object.keys(organizations)
21
- orgList.push(config.cancelString)
22
- let chooseOrganization = [{
23
- type: 'list',
24
- name: 'chosenOrg',
25
- message: 'Choose an Organization',
26
- choices: orgList,
27
- loop: false
28
- }]
29
- inquirer.prompt(chooseOrganization).then(({chosenOrg}) => {
30
- if (chosenOrg === config.cancelString)
31
- exitProgram()
32
- resolve({ name: chosenOrg, uid: organizations[chosenOrg] })
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
- return new Promise(resolve => {
39
- let result = {}
40
-
41
- managementAPIClient.organization().fetchAll().then(organizations => {
42
- organizations.items.forEach(org => {
43
- result[org.name] = org.uid
44
- })
45
- resolve(result)
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
- return new Promise(resolve => {
52
- let result = {}
53
- managementAPIClient
54
- .getUser({include_orgs_roles: true})
55
- .then(response => {
56
- let organizations = response.organizations.filter(org => {
57
- if (org.org_roles) {
58
- const org_role = org.org_roles.shift()
59
- return org_role.admin
60
- }
61
- if (org.is_owner === true)
62
- return true
63
- return false
64
- })
65
- organizations.forEach(org => {
66
- result[org.name] = org.uid
67
- })
68
- resolve(result)
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
- return new Promise(async resolve => {
75
- let stacks = await getStacks(managementAPIClient, orgUid)
76
- let stackList = Object.keys(stacks)
77
- stackList.push(config.cancelString)
78
-
79
- let chooseStack = [{
80
- type: 'list',
81
- name: 'chosenStack',
82
- message: 'Choose a Stack',
83
- choices: stackList
84
- }]
85
-
86
- inquirer.prompt(chooseStack).then(({chosenStack}) => {
87
- if (chosenStack === config.cancelString)
88
- exitProgram()
89
- resolve({ name: chosenStack, apiKey: stacks[chosenStack] })
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
- // Adding a query object in query, because it throws an error
96
- // the error is coming from query function lib/entity.js, @contentstack/management pacakge
97
- // where params.query is being set
98
- return new Promise(resolve => {
99
- let result = {}
100
- managementAPIClient.stack({organization_uid: orgUid}).query({query: {}}).find().then(stacks => {
101
- stacks.items.forEach(stack => {
102
- result[stack.name] = stack.api_key
103
- })
104
- resolve(result)
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 chooseContentType(managementAPIClient, stackApiKey) {
110
- return new Promise(async resolve => {
111
- let contentTypes = await getContentTypes(managementAPIClient, stackApiKey)
112
- let contentTypesList = Object.values(contentTypes)
113
- // contentTypesList.push(config.cancelString)
114
-
115
- let chooseContentType = [{
116
- type: 'checkbox',
117
- message: 'Choose Content Type',
118
- choices: contentTypesList,
119
- name: 'chosenContentTypes',
120
- loop: false
121
- }]
122
-
123
- inquirer.prompt(chooseContentType).then(({chosenContentTypes}) => {
124
- // if (chosenContentType === config.cancelString)
125
- // exitProgram()
126
- resolve(chosenContentTypes)
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 getContentTypes(managementAPIClient, stackApiKey) {
132
- return new Promise(resolve => {
133
- let result = {}
134
- managementAPIClient.stack({api_key: stackApiKey}).contentType().query().find().then(contentTypes => {
135
- contentTypes.items.forEach(contentType => {
136
- result[contentType.title] = contentType.uid
137
- })
138
- resolve(result)
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 chooseLanguage(managementAPIClient, stackApiKey) {
144
- return new Promise(async resolve => {
145
- let languages = await getLanguages(managementAPIClient, stackApiKey)
146
- let languagesList = Object.keys(languages)
147
- languagesList.push(config.cancelString)
148
-
149
- let chooseLanguage = [{
150
- type: 'list',
151
- message: 'Choose Language',
152
- choices: languagesList,
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 getLanguages(managementAPIClient, stackApiKey) {
165
- return new Promise(resolve => {
166
- let result = {}
167
- managementAPIClient.stack({api_key: stackApiKey}).locale().query().find().then(languages => {
168
- languages.items.forEach(language => {
169
- result[language.name] = language.code
170
- })
171
- resolve(result)
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 getEntries(managementAPIClient, stackApiKey, contentType, language) {
177
- return new Promise(resolve => {
178
- managementAPIClient
179
- .stack({api_key: stackApiKey})
180
- .contentType(contentType)
181
- .entry()
182
- .query({include_publish_details: true, locale: language})
183
- .find()
184
- .then(entries => resolve(entries))
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 getEnvironments(managementAPIClient, stackApiKey) {
189
- let result = {}
190
- return managementAPIClient.stack({api_key: stackApiKey}).environment().query().find().then(environments => {
191
- environments.items.forEach(env => { result[env['uid']] = env['name']})
192
- return result
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
- debug("Exiting")
198
- // eslint-disable-next-line no-undef
199
- process.exit()
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 (entry['locale'] === language && entry.publish_details.length > 0)
205
- })
206
-
207
- const flatEntries = filteredEntries.map(entry => {
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
- // eslint-disable-next-line no-undef
249
- if (process.cwd().split(delimeter).pop() !== 'data' && !fs.existsSync(directory)) {
250
- mkdirp.sync(directory)
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
- command.log(`Writing entries to file: ${process.cwd()}${delimeter}${fileName}`)
259
- fastcsv
260
- .writeToPath(fileName, entries, {headers: true})
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
- type: 'list',
267
- name: 'action',
268
- message: 'Choose Action',
269
- choices: [config.exportEntries, config.exportUsers, 'Exit'],
270
- }]
271
- inquirer.prompt(actions).then(answers => {
272
- if(answers.action === 'Exit')
273
- exitProgram()
274
- resolve(answers.action)
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
- return new Promise((resolve, reject) => {
281
- managementAPIClient
282
- .getUser({include_orgs_roles: true})
283
- .then(response => {
284
- let organization = response.organizations.filter(org => org.uid === orgUid).pop()
285
- if (organization.is_owner === true) {
286
- let cma = ecsv.region.cma
287
- let authtoken = ecsv.authToken
288
- return axios.get(`${cma}/v3/organizations/${organization.uid}/share`, { headers: { 'authtoken': authtoken }})
289
- .then(response => resolve({ items: response.data.shares }))
290
- }
291
- if (!organization.getInvitations) {
292
- return reject(new Error(config.adminError))
293
- }
294
- organization.getInvitations().then(users => resolve(users))
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
- let mappedUsers = {}
301
- users.items.forEach(user => { mappedUsers[user.user_uid] = user.email })
302
- mappedUsers['System'] = 'System'
303
- return mappedUsers
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
- let mappedRoles = {}
308
- roles.items.forEach(role => { mappedRoles[role.uid] = role.name })
309
- return mappedRoles
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
- return new Promise((resolve, reject) => {
314
- managementAPIClient
315
- .getUser({include_orgs_roles: true})
316
- .then(response => {
317
- let organization = response.organizations.filter(org => org.uid === orgUid).pop()
318
- if (organization.is_owner === true) {
319
- let cma = ecsv.region.cma
320
- let authtoken = ecsv.authToken
321
- return axios.get(`${cma}/v3/organizations/${organization.uid}/roles`, { headers: { 'authtoken': authtoken }})
322
- .then(response => resolve({ items: response.data.roles }))
323
- }
324
- if (!organization.roles) {
325
- return reject(new Error(config.adminError))
326
- }
327
- organization.roles().then(roles => resolve(roles))
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
- let roleName = 'No Role'
334
- let roleUid = user.org_roles || []
335
- if (roleUid.length > 0) {
336
- roleUid = roleUid.shift()
337
- roleName = roles[roleUid]
338
- }
339
- if (user.is_owner) {
340
- roleName = 'Owner'
341
- }
342
- return roleName
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
- const userList = []
347
- orgUsers.items.forEach(user => {
348
- let invitedBy
349
- let formattedUser = {}
350
- try {
351
- invitedBy = mappedUsers[user['invited_by']]
352
- } catch (error) {
353
- invitedBy = 'System'
354
- }
355
- formattedUser['Email'] = user['email']
356
- formattedUser['User UID'] = user['user_uid']
357
- formattedUser['Organization Role'] = determineUserOrgRole(user, mappedRoles)
358
- formattedUser['Status'] = user['status']
359
- formattedUser['Invited By'] = invitedBy
360
- formattedUser['Created Time'] = user['created_at']
361
- formattedUser['Updated Time'] = user['updated_at']
362
- userList.push(formattedUser)
363
- })
364
- return userList
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
- return str.split(' ').map((word) => word.toLowerCase()).join('-')
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
- var result = {};
374
- function recurse (cur, prop) {
375
- if (Object(cur) !== cur) {
376
- result[prop] = cur;
377
- } else if (Array.isArray(cur)) {
378
- for(var i=0, l=cur.length; i<l; i++)
379
- recurse(cur[i], prop + "[" + i + "]");
380
- if (l == 0)
381
- result[prop] = [];
382
- } else {
383
- var isEmpty = true;
384
- for (var p in cur) {
385
- isEmpty = false;
386
- recurse(cur[p], prop ? prop+"."+p : p);
387
- }
388
- if (isEmpty && prop)
389
- result[prop] = {};
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
- recurse(data, "");
393
- return result;
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
- chooseOrganization: chooseOrganization,
398
- chooseStack: chooseStack,
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
+ };