@contentstack/cli-cm-export-to-csv 1.4.0 → 1.4.2

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/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@contentstack/cli-cm-export-to-csv",
3
3
  "description": "Export entities to csv",
4
- "version": "1.4.0",
4
+ "version": "1.4.2",
5
5
  "author": "Abhinav Gupta @abhinav-from-contentstack",
6
6
  "bugs": "https://github.com/contentstack/cli/issues",
7
7
  "dependencies": {
8
- "@contentstack/cli-command": "~1.2.11",
9
- "@contentstack/cli-utilities": "~1.5.1",
8
+ "@contentstack/cli-command": "~1.2.12",
9
+ "@contentstack/cli-utilities": "~1.5.2",
10
10
  "chalk": "^4.1.0",
11
11
  "fast-csv": "^4.3.6",
12
12
  "inquirer": "8.2.4",
13
13
  "inquirer-checkbox-plus-prompt": "1.0.1",
14
- "mkdirp": "^1.0.4"
14
+ "mkdirp": "^3.0.1"
15
15
  },
16
16
  "devDependencies": {
17
17
  "@oclif/test": "^2.2.10",
@@ -207,7 +207,7 @@ class ExportToCsvCommand extends Command {
207
207
  const entriesCount = await util.getEntriesCount(stackAPIClient, contentType, language.code);
208
208
  let flatEntries = [];
209
209
  for (let index = 0; index < entriesCount / 100; index++) {
210
- const entriesResult = await util.getEntries(stackAPIClient, contentType, language.code, index);
210
+ const entriesResult = await util.getEntries(stackAPIClient, contentType, language.code, index, 100);
211
211
  const flatEntriesResult = util.cleanEntries(
212
212
  entriesResult.items,
213
213
  language.code,
package/src/util/index.js CHANGED
@@ -199,7 +199,7 @@ function chooseContentType(stackAPIClient, skip) {
199
199
  let _chooseContentType = [
200
200
  {
201
201
  type: 'checkbox',
202
- message: 'Choose Content Type',
202
+ message: 'Choose Content Type (Press Space to select the content types) ',
203
203
  choices: contentTypesList,
204
204
  name: 'chosenContentTypes',
205
205
  loop: false,
@@ -218,7 +218,7 @@ function chooseInMemContentTypes(contentTypesList) {
218
218
  let _chooseContentType = [
219
219
  {
220
220
  type: 'checkbox-plus',
221
- message: 'Choose Content Type',
221
+ message: 'Choose Content Type (Press Space to select the content types)',
222
222
  choices: contentTypesList,
223
223
  name: 'chosenContentTypes',
224
224
  loop: false,
@@ -316,12 +316,12 @@ function getLanguages(stackAPIClient) {
316
316
  });
317
317
  }
318
318
 
319
- function getEntries(stackAPIClient, contentType, language, skip) {
319
+ function getEntries(stackAPIClient, contentType, language, skip, limit) {
320
320
  return new Promise((resolve, reject) => {
321
321
  stackAPIClient
322
322
  .contentType(contentType)
323
323
  .entry()
324
- .query({ include_publish_details: true, locale: language, skip: skip * 100 })
324
+ .query({ include_publish_details: true, locale: language, skip: skip * 100, limit: limit, include_workflow: true })
325
325
  .find()
326
326
  .then((entries) => resolve(entries))
327
327
  .catch((error) => reject(error));
@@ -371,27 +371,50 @@ function exitProgram() {
371
371
  process.exit();
372
372
  }
373
373
 
374
+ function sanitizeEntries(flatEntry) {
375
+ // sanitize against CSV Injections
376
+ const CSVRegex = /^[\\+\\=@\\-]/
377
+ for (key in flatEntry) {
378
+ if (typeof flatEntry[key] === 'string' && flatEntry[key].match(CSVRegex)) {
379
+ flatEntry[key] = flatEntry[key].replace(/\"/g, "\"\"");
380
+ flatEntry[key] = `"'${flatEntry[key]}"`
381
+ } else if (typeof flatEntry[key] === 'object') {
382
+ // convert any objects or arrays to string
383
+ // to store this data correctly in csv
384
+ flatEntry[key] = JSON.stringify(flatEntry[key]);
385
+ }
386
+ }
387
+ return flatEntry;
388
+ }
389
+
374
390
  function cleanEntries(entries, language, environments, contentTypeUid) {
375
391
  const filteredEntries = entries.filter((entry) => {
376
- return entry['locale'] === language && entry.publish_details.length > 0;
392
+ return entry['locale'] === language;
377
393
  });
378
-
379
394
  return filteredEntries.map((entry) => {
380
395
  let workflow = '';
381
396
  const envArr = [];
382
- entry.publish_details.forEach((env) => {
383
- envArr.push(JSON.stringify([environments[env['environment']], env['locale'], env['time']]));
384
- });
397
+ if(entry.publish_details.length) {
398
+ entry.publish_details.forEach((env) => {
399
+ envArr.push(JSON.stringify([environments[env['environment']], env['locale'], env['time']]));
400
+ });
401
+ }
402
+
385
403
  delete entry.publish_details;
404
+ delete entry.setWorkflowStage;
386
405
  if ('_workflow' in entry) {
387
- workflow = entry['_workflow']['name'];
388
- delete entry['_workflow'];
406
+ if(entry._workflow?.name) {
407
+ workflow = entry['_workflow']['name'];
408
+ delete entry['_workflow'];
409
+ }
389
410
  }
390
411
  entry = flatten(entry);
412
+ entry = sanitizeEntries(entry);
391
413
  entry['publish_details'] = envArr;
392
414
  entry['_workflow'] = workflow;
393
415
  entry['ACL'] = JSON.stringify({}); // setting ACL to empty obj
394
416
  entry['content_type_uid'] = contentTypeUid; // content_type_uid is being returned as 'uid' from the sdk for some reason
417
+
395
418
  // entry['url'] might also be wrong
396
419
  delete entry.stackHeaders;
397
420
  delete entry.update;