@contentstack/cli-cm-export-to-csv 1.6.1 → 1.7.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2023 Contentstack
3
+ Copyright (c) 2024 Contentstack
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@contentstack/cli-cm-export-to-csv",
3
3
  "description": "Export entities to csv",
4
- "version": "1.6.1",
4
+ "version": "1.7.0",
5
5
  "author": "Abhinav Gupta @abhinav-from-contentstack",
6
6
  "bugs": "https://github.com/contentstack/cli/issues",
7
7
  "dependencies": {
8
8
  "@contentstack/cli-command": "~1.2.16",
9
- "@contentstack/cli-utilities": "~1.5.7",
9
+ "@contentstack/cli-utilities": "~1.5.12",
10
10
  "chalk": "^4.1.0",
11
11
  "fast-csv": "^4.3.6",
12
12
  "inquirer": "8.2.4",
@@ -14,7 +14,7 @@
14
14
  "mkdirp": "^3.0.1"
15
15
  },
16
16
  "devDependencies": {
17
- "@oclif/test": "^2.2.10",
17
+ "@oclif/test": "^2.5.6",
18
18
  "@types/chai": "^4.3.6",
19
19
  "@types/mocha": "^10.0.1",
20
20
  "chai": "^4.3.8",
@@ -334,8 +334,8 @@ class ExportToCsvCommand extends Command {
334
334
  const listOfTokens = configHandler.get('tokens');
335
335
  if (managementTokenAlias && listOfTokens[managementTokenAlias]) {
336
336
  const checkManagementTokenValidity = await isManagementTokenValid((listOfTokens[managementTokenAlias].apiKey) ,listOfTokens[managementTokenAlias].token);
337
- if(!checkManagementTokenValidity?.valid) {
338
- throw checkManagementTokenValidity.hasOwnProperty('valid')?(`error: Management token or stack API key is invalid. ${checkManagementTokenValidity?.message||""}`):checkManagementTokenValidity?.message||"";
337
+ if(checkManagementTokenValidity.hasOwnProperty('message')) {
338
+ throw checkManagementTokenValidity.valid==='failedToCheck'?checkManagementTokenValidity.message:(`error: Management token or stack API key is invalid. ${checkManagementTokenValidity.message}`);
339
339
  }
340
340
  apiClient = await managementSDKClient({
341
341
  host: this.cmaHost,
@@ -449,31 +449,31 @@ ExportToCsvCommand.description = `Export entries, taxonomies, terms or organizat
449
449
  ExportToCsvCommand.examples = [
450
450
  'csdx cm:export-to-csv',
451
451
  '',
452
- 'Exporting entries to csv',
452
+ 'Exporting entries to CSV',
453
453
  'csdx cm:export-to-csv --action <entries> --locale <locale> --alias <management-token-alias> --content-type <content-type>',
454
454
  '',
455
- 'Exporting entries to csv with stack name provided and branch name provided',
455
+ 'Exporting entries to CSV with stack name provided and branch name provided',
456
456
  'csdx cm:export-to-csv --action <entries> --locale <locale> --alias <management-token-alias> --content-type <content-type> --stack-name <stack-name> --branch <branch-name>',
457
457
  '',
458
- 'Exporting organization users to csv',
458
+ 'Exporting organization users to CSV',
459
459
  'csdx cm:export-to-csv --action <users> --org <org-uid>',
460
460
  '',
461
- 'Exporting organization users to csv with organization name provided',
461
+ 'Exporting organization users to CSV with organization name provided',
462
462
  'csdx cm:export-to-csv --action <users> --org <org-uid> --org-name <org-name>',
463
463
  '',
464
- 'Exporting Organizations Teams to CSV',
464
+ 'Exporting organization teams to CSV',
465
465
  'csdx cm:export-to-csv --action <teams>',
466
466
  '',
467
- 'Exporting Organizations Teams to CSV with org-uid',
467
+ 'Exporting organization teams to CSV with org UID',
468
468
  'csdx cm:export-to-csv --action <teams> --org <org-uid>',
469
469
  '',
470
- 'Exporting Organizations Teams to CSV with team uid',
470
+ 'Exporting organization teams to CSV with team UID',
471
471
  'csdx cm:export-to-csv --action <teams> --team-uid <team-uid>',
472
472
  '',
473
- 'Exporting Organizations Teams to CSV with org-uid and team uid',
473
+ 'Exporting organization teams to CSV with org UID and team UID',
474
474
  'csdx cm:export-to-csv --action <teams> --org <org-uid> --team-uid <team-uid>',
475
475
  '',
476
- 'Exporting Organizations Teams to CSV with org-uid and team uid',
476
+ 'Exporting organization teams to CSV with org UID and team UID',
477
477
  'csdx cm:export-to-csv --action <teams> --org <org-uid> --team-uid <team-uid> --org-name <org-name>',
478
478
  '',
479
479
  'Exporting taxonomies and related terms to a .CSV file with the provided taxonomy UID',
@@ -2,8 +2,8 @@ module.exports = {
2
2
  limit:100,
3
3
  cancelString: 'Cancel and Exit',
4
4
  exportEntries: 'Export entries to a .CSV file',
5
- exportUsers: "Export organization user's data to a .CSV file",
6
- exportTeams: "Export organization team's data to a .csv file",
5
+ exportUsers: "Export organization users' data to a .CSV file",
6
+ exportTeams: "Export organization teams' data to a .CSV file",
7
7
  exportTaxonomies: 'Export taxonomies to a .CSV file',
8
8
  adminError: "Unable to export data. Make sure you're an admin or owner of this organization",
9
9
  organizationNameRegex: /\'/,
package/src/util/index.js CHANGED
@@ -62,7 +62,6 @@ async function getOrganizations(managementAPIClient) {
62
62
  try {
63
63
  return await getOrganizationList(managementAPIClient, { skip: 0, page: 1, limit: 100 }, []);
64
64
  } catch (error) {
65
- console.log(error);
66
65
  throw error;
67
66
  }
68
67
  }
@@ -461,7 +460,7 @@ function write(command, entries, fileName, message, delimiter, headers) {
461
460
  process.chdir(directory);
462
461
  }
463
462
  // eslint-disable-next-line no-undef
464
- cliux.print(`Writing ${message} to file: ${process.cwd()}${delimeter}${fileName}`);
463
+ cliux.print(`Writing ${message} to file: "${process.cwd()}${delimeter}${fileName}"`);
465
464
  if (headers?.length) fastcsv.writeToPath(fileName, entries, { headers, delimiter });
466
465
  else fastcsv.writeToPath(fileName, entries, { headers: true, delimiter });
467
466
  }
@@ -693,54 +692,59 @@ function wait(time) {
693
692
  }
694
693
 
695
694
  function handleErrorMsg(err) {
696
- cliux.print(`Error: ${(err?.errorMessage || err?.message) ? err?.errorMessage || err?.message : messageHandler.parse('CLI_EXPORT_CSV_API_FAILED')}`, { color: 'red' })
695
+ cliux.print(`Error: ${(err?.errorMessage || err?.message) ?? messageHandler.parse('CLI_EXPORT_CSV_API_FAILED')}`, {
696
+ color: 'red',
697
+ });
697
698
  process.exit(1);
698
699
  }
699
700
 
700
- async function apiRequestHandler(org, queryParam = {}) {
701
- const headers = {
702
- authtoken: configHandler.get('authtoken'),
703
- organization_uid: org.uid,
704
- 'Content-Type': 'application/json',
705
- api_version: 1.1,
706
- };
707
-
708
- return await new HttpClient()
709
- .headers(headers)
710
- .queryParams(queryParam)
711
- .get(`${configHandler.get('region')?.cma}/organizations/${org?.uid}/teams`)
712
- .then((res) => {
713
- const { status, data } = res;
714
- if (status === 200) {
715
- return data;
716
- } else {
717
- cliux.print(`${data?.error_message || data?.message || data?.errorMessage}`, { color: 'red' });
718
- process.exit(1);
719
- }
720
- })
721
- .catch((error) => {
722
- handleErrorMsg(error);
723
- });
701
+ /**
702
+ * This function does the sdk calls to get all the teams in org
703
+ * @param {object} managementAPIClient
704
+ * @param {object} org
705
+ * @param {object} queryParam
706
+ * @returns
707
+ */
708
+ async function getAllTeams(managementAPIClient, org, queryParam = {}) {
709
+ try {
710
+ return await managementAPIClient.organization(org.uid).teams().fetchAll(queryParam);
711
+ } catch (error) {
712
+ handleErrorMsg(error);
713
+ }
724
714
  }
725
715
 
716
+ /**
717
+ * This function is used to handle the pagination and call the sdk
718
+ * @param {object} managementAPIClient
719
+ * @param {object} org
720
+ */
726
721
  async function exportOrgTeams(managementAPIClient, org) {
727
- let teamsObjectArray = [];
722
+ let allTeamsInOrg = [];
728
723
  let skip = 0;
729
724
  let limit = config?.limit || 100;
730
725
  do {
731
- const data = await apiRequestHandler(org, { skip: skip, limit: limit, includeUserDetails: true });
726
+ const data = await getAllTeams(managementAPIClient, org, {
727
+ skip: skip,
728
+ limit: limit,
729
+ includeUserDetails: true,
730
+ });
732
731
  skip += limit;
733
- teamsObjectArray.push(...data?.teams);
732
+ allTeamsInOrg.push(...data.items);
734
733
  if (skip >= data?.count) break;
735
734
  } while (1);
736
- teamsObjectArray = await cleanTeamsData(teamsObjectArray, managementAPIClient, org);
737
- return teamsObjectArray;
735
+ allTeamsInOrg = await cleanTeamsData(allTeamsInOrg, managementAPIClient, org);
736
+ return allTeamsInOrg;
738
737
  }
739
738
 
739
+ /**
740
+ * This function will get all the org level roles
741
+ * @param {object} managementAPIClient
742
+ * @param {object} org
743
+ */
740
744
  async function getOrgRolesForTeams(managementAPIClient, org) {
741
745
  let roleMap = {}; // for org level there are two roles only admin and member
742
746
 
743
- // SDK call to get the role uids
747
+ // SDK call to get the role UIDs
744
748
  await managementAPIClient
745
749
  .organization(org.uid)
746
750
  .roles()
@@ -757,6 +761,12 @@ async function getOrgRolesForTeams(managementAPIClient, org) {
757
761
  return roleMap;
758
762
  }
759
763
 
764
+ /**
765
+ * Removes the unnecessary fields from the objects in the data and assign org level roles to the team based on role uid
766
+ * @param {array} data
767
+ * @param {object} managementAPIClient
768
+ * @param {object} org
769
+ */
760
770
  async function cleanTeamsData(data, managementAPIClient, org) {
761
771
  const roleMap = await getOrgRolesForTeams(managementAPIClient, org);
762
772
  const fieldToBeDeleted = [
@@ -769,18 +779,24 @@ async function cleanTeamsData(data, managementAPIClient, org) {
769
779
  'createdByUserName',
770
780
  'updatedByUserName',
771
781
  'organizationUid',
782
+ 'urlPath',
783
+ 'update',
784
+ 'delete',
785
+ 'fetch',
786
+ 'stackRoleMappings',
787
+ 'teamUsers',
772
788
  ];
773
789
  if (data?.length) {
774
790
  return data.map((team) => {
775
791
  team = omit(team, fieldToBeDeleted);
776
-
777
- team.organizationRole = (team.organizationRole === roleMap["member"]) ? "member" : "admin";
778
-
779
- if (!team.hasOwnProperty("description")) {
780
- team.description = "";
792
+
793
+ team.organizationRole = team.organizationRole === roleMap['member'] ? 'member' : 'admin';
794
+
795
+ if (!team.hasOwnProperty('description')) {
796
+ team.description = '';
781
797
  }
782
798
  team.Total_Members = team?.users?.length || 0;
783
-
799
+
784
800
  return team;
785
801
  });
786
802
  } else {
@@ -788,6 +804,13 @@ async function cleanTeamsData(data, managementAPIClient, org) {
788
804
  }
789
805
  }
790
806
 
807
+ /**
808
+ * This function is used to call all the other teams function to export the required files
809
+ * @param {object} managementAPIClient
810
+ * @param {object} organization
811
+ * @param {string} teamUid
812
+ * @param {character} delimiter
813
+ */
791
814
  async function exportTeams(managementAPIClient, organization, teamUid, delimiter) {
792
815
  cliux.print(
793
816
  `info: Exporting the ${
@@ -799,7 +822,9 @@ async function exportTeams(managementAPIClient, organization, teamUid, delimiter
799
822
  );
800
823
  const allTeamsData = await exportOrgTeams(managementAPIClient, organization);
801
824
  if (!allTeamsData?.length) {
802
- cliux.print(`info: The organization ${organization?.name} does not have any teams associated with it. Please verify and provide the correct organization name.`);
825
+ cliux.print(
826
+ `info: The organization ${organization?.name} does not have any teams associated with it. Please verify and provide the correct organization name.`,
827
+ );
803
828
  } else {
804
829
  const modifiedTeam = cloneDeep(allTeamsData);
805
830
  modifiedTeam.forEach((team) => {
@@ -825,6 +850,13 @@ async function exportTeams(managementAPIClient, organization, teamUid, delimiter
825
850
  }
826
851
  }
827
852
 
853
+ /**
854
+ * This function is used to get individual team user details and write to file
855
+ * @param {array} allTeamsData
856
+ * @param {object} organization
857
+ * @param {string} teamUid optional
858
+ * @param {character} delimiter
859
+ */
828
860
  async function getTeamsDetail(allTeamsData, organization, teamUid, delimiter) {
829
861
  if (!teamUid) {
830
862
  const userData = await getTeamsUserDetails(allTeamsData);
@@ -835,14 +867,12 @@ async function getTeamsDetail(allTeamsData, organization, teamUid, delimiter) {
835
867
  write(this, userData, fileName, 'Team User details', delimiter);
836
868
  } else {
837
869
  const team = allTeamsData.filter((team) => team.uid === teamUid)[0];
838
-
839
870
  team.users.forEach((user) => {
840
871
  user['team-name'] = team.name;
841
872
  user['team-uid'] = team.uid;
842
873
  delete user['active'];
843
874
  delete user['orgInvitationStatus'];
844
875
  });
845
-
846
876
  const fileName = `${kebabize(
847
877
  organization.name.replace(config.organizationNameRegex, ''),
848
878
  )}_team_${teamUid}_User_Details_export.csv`;
@@ -851,16 +881,25 @@ async function getTeamsDetail(allTeamsData, organization, teamUid, delimiter) {
851
881
  }
852
882
  }
853
883
 
884
+ /**
885
+ * This will export the role mappings of the team, for which stack the team has which role
886
+ * @param {object} managementAPIClient
887
+ * @param {array} allTeamsData Data for all the teams in the stack
888
+ * @param {string} teamUid for a particular team who's data we want
889
+ * @param {character} delimiter
890
+ */
854
891
  async function exportRoleMappings(managementAPIClient, allTeamsData, teamUid, delimiter) {
855
892
  let stackRoleWithTeamData = [];
856
893
  let flag = false;
857
894
  const stackNotAdmin = [];
858
895
  if (teamUid) {
859
- const team = find(allTeamsData,function(teamObject) { return teamObject?.uid===teamUid });
896
+ const team = find(allTeamsData, function (teamObject) {
897
+ return teamObject?.uid === teamUid;
898
+ });
860
899
  for (const stack of team?.stackRoleMapping) {
861
900
  const roleData = await mapRoleWithTeams(managementAPIClient, stack, team?.name, team?.uid);
862
901
  stackRoleWithTeamData.push(...roleData);
863
- if(roleData[0]['Stack Name']==='') {
902
+ if (roleData[0]['Stack Name'] === '') {
864
903
  flag = true;
865
904
  stackNotAdmin.push(stack.stackApiKey);
866
905
  }
@@ -870,18 +909,21 @@ async function exportRoleMappings(managementAPIClient, allTeamsData, teamUid, de
870
909
  for (const stack of team?.stackRoleMapping ?? []) {
871
910
  const roleData = await mapRoleWithTeams(managementAPIClient, stack, team?.name, team?.uid);
872
911
  stackRoleWithTeamData.push(...roleData);
873
- if(roleData[0]['Stack Name']==='') {
912
+ if (roleData[0]['Stack Name'] === '') {
874
913
  flag = true;
875
914
  stackNotAdmin.push(stack.stackApiKey);
876
915
  }
877
916
  }
878
917
  }
879
918
  }
880
- if(stackNotAdmin?.length) {
881
- cliux.print(`warning: Admin access denied to the following stacks using the provided API keys. Please get in touch with the stack owner to request access.`,{color:"yellow"});
882
- cliux.print(`${stackNotAdmin.join(' , ')}`,{color:"yellow"});
919
+ if (stackNotAdmin?.length) {
920
+ cliux.print(
921
+ `warning: Admin access denied to the following stacks using the provided API keys. Please get in touch with the stack owner to request access.`,
922
+ { color: 'yellow' },
923
+ );
924
+ cliux.print(`${stackNotAdmin.join(' , ')}`, { color: 'yellow' });
883
925
  }
884
- if(flag) {
926
+ if (flag) {
885
927
  let export_stack_role = [
886
928
  {
887
929
  type: 'list',
@@ -889,19 +931,17 @@ async function exportRoleMappings(managementAPIClient, allTeamsData, teamUid, de
889
931
  message: `Access denied: Please confirm if you still want to continue exporting the data without the { Stack Name, Stack Uid, Role Name } fields.`,
890
932
  choices: ['yes', 'no'],
891
933
  loop: false,
892
- }]
893
- const exportStackRole = await inquirer
894
- .prompt(export_stack_role)
895
- .then(( chosenOrg ) => {
896
- return chosenOrg
897
- })
898
- .catch((error) => {
899
- cliux.print(error, {color:'red'});
900
- process.exit(1);
901
- });
902
- if(exportStackRole.chooseExport === 'no') {
934
+ },
935
+ ];
936
+ try {
937
+ const exportStackRole = await inquirer.prompt(export_stack_role);
938
+ if (exportStackRole.chooseExport === 'no') {
903
939
  process.exit(1);
904
- }
940
+ }
941
+ } catch (error) {
942
+ cliux.print(error, { color: 'red' });
943
+ process.exit(1);
944
+ }
905
945
  }
906
946
 
907
947
  const fileName = `${kebabize('Stack_Role_Mapping'.replace(config.organizationNameRegex, ''))}${
@@ -911,13 +951,20 @@ async function exportRoleMappings(managementAPIClient, allTeamsData, teamUid, de
911
951
  write(this, stackRoleWithTeamData, fileName, 'Team Stack Role details', delimiter);
912
952
  }
913
953
 
954
+ /**
955
+ * Mapping the team stacks with the stack role and returning and array of object
956
+ * @param {object} managementAPIClient
957
+ * @param {array} stackRoleMapping
958
+ * @param {string} teamName
959
+ * @param {string} teamUid
960
+ */
914
961
  async function mapRoleWithTeams(managementAPIClient, stackRoleMapping, teamName, teamUid) {
915
962
  const roles = await getRoleData(managementAPIClient, stackRoleMapping.stackApiKey);
916
963
  const stackRole = {};
917
964
  roles?.items?.forEach((role) => {
918
965
  if (!stackRole.hasOwnProperty(role?.uid)) {
919
966
  stackRole[role?.uid] = role?.name;
920
- stackRole[role?.stack?.api_key] = {name: role?.stack?.name, uid: role?.stack?.uid }
967
+ stackRole[role?.stack?.api_key] = { name: role?.stack?.name, uid: role?.stack?.uid };
921
968
  }
922
969
  });
923
970
  const stackRoleMapOfTeam = stackRoleMapping?.roles.map((role) => {
@@ -933,17 +980,26 @@ async function mapRoleWithTeams(managementAPIClient, stackRoleMapping, teamName,
933
980
  return stackRoleMapOfTeam;
934
981
  }
935
982
 
983
+ /**
984
+ * Making sdk call to get all the roles in the given stack
985
+ * @param {object} managementAPIClient
986
+ * @param {string} stackApiKey
987
+ */
936
988
  async function getRoleData(managementAPIClient, stackApiKey) {
937
989
  try {
938
990
  return await managementAPIClient.stack({ api_key: stackApiKey }).role().fetchAll();
939
991
  } catch (error) {
940
- return {}
992
+ return {};
941
993
  }
942
994
  }
943
995
 
944
- async function getTeamsUserDetails(teamsObject) {
996
+ /**
997
+ * Here in the users array we are adding the team-name and team-uid to individual users and returning an array of object of user details only
998
+ * @param {array} teams
999
+ */
1000
+ async function getTeamsUserDetails(teams) {
945
1001
  const allTeamUsers = [];
946
- teamsObject.forEach((team) => {
1002
+ teams.forEach((team) => {
947
1003
  if (team?.users?.length) {
948
1004
  team.users.forEach((user) => {
949
1005
  user['team-name'] = team.name;
@@ -1024,7 +1080,7 @@ async function getTaxonomy(payload) {
1024
1080
  * @returns {*} Promise<any>
1025
1081
  */
1026
1082
  async function taxonomySDKHandler(payload, skip) {
1027
- const { stackAPIClient, taxonomyUID, type } = payload;
1083
+ const { stackAPIClient, taxonomyUID, type, format } = payload;
1028
1084
 
1029
1085
  const queryParams = { include_count: true, limit: payload.limit };
1030
1086
  if (skip >= 0) queryParams['skip'] = skip || 0;
@@ -1036,13 +1092,13 @@ async function taxonomySDKHandler(payload, skip) {
1036
1092
  .query(queryParams)
1037
1093
  .find()
1038
1094
  .then((data) => data)
1039
- .catch((err) => handleErrorMsg(err));
1095
+ .catch((err) => handleTaxonomyErrorMsg(err));
1040
1096
  case 'taxonomy':
1041
1097
  return await stackAPIClient
1042
1098
  .taxonomy(taxonomyUID)
1043
1099
  .fetch()
1044
1100
  .then((data) => data)
1045
- .catch((err) => handleErrorMsg(err));
1101
+ .catch((err) => handleTaxonomyErrorMsg(err));
1046
1102
  case 'terms':
1047
1103
  queryParams['depth'] = 0;
1048
1104
  return await stackAPIClient
@@ -1051,9 +1107,15 @@ async function taxonomySDKHandler(payload, skip) {
1051
1107
  .query(queryParams)
1052
1108
  .find()
1053
1109
  .then((data) => data)
1054
- .catch((err) => handleErrorMsg(err));
1110
+ .catch((err) => handleTaxonomyErrorMsg(err));
1111
+ case 'export-taxonomies':
1112
+ return await stackAPIClient
1113
+ .taxonomy(taxonomyUID)
1114
+ .export({ format })
1115
+ .then((data) => data)
1116
+ .catch((err) => handleTaxonomyErrorMsg(err));
1055
1117
  default:
1056
- handleErrorMsg({ errorMessage: 'Invalid module!' });
1118
+ handleTaxonomyErrorMsg({ errorMessage: 'Invalid module!' });
1057
1119
  }
1058
1120
  }
1059
1121
 
@@ -1096,11 +1158,9 @@ function formatTermsOfTaxonomyData(terms, taxonomyUID) {
1096
1158
  }
1097
1159
  }
1098
1160
 
1099
- function handleErrorMsg(err) {
1100
- if (err?.errorMessage) {
1101
- cliux.print(`Error: ${err.errorMessage}`, { color: 'red' });
1102
- } else if (err?.message) {
1103
- const errorMsg = err?.errors?.taxonomy || err?.errors?.term || err?.message;
1161
+ function handleTaxonomyErrorMsg(err) {
1162
+ if (err?.errorMessage || err?.message) {
1163
+ const errorMsg = err?.errorMessage || err?.errors?.taxonomy || err?.errors?.term || err?.message;
1104
1164
  cliux.print(`Error: ${errorMsg}`, { color: 'red' });
1105
1165
  } else {
1106
1166
  console.log(err);
@@ -1110,60 +1170,53 @@ function handleErrorMsg(err) {
1110
1170
  }
1111
1171
 
1112
1172
  /**
1113
- * create an importable CSV file, to utilize with the migration script.
1173
+ * Generate a CSV file that can be imported for use with the migration script.
1114
1174
  * @param {*} payload api request payload
1115
1175
  * @param {*} taxonomies taxonomies data
1116
1176
  * @returns
1117
1177
  */
1118
1178
  async function createImportableCSV(payload, taxonomies) {
1119
- let taxonomiesData = [];
1120
- let headers = ['Taxonomy Name','Taxonomy UID','Taxonomy Description'];
1121
- for (let index = 0; index < taxonomies?.length; index++) {
1122
- const taxonomy = taxonomies[index];
1123
- const taxonomyUID = taxonomy?.uid;
1124
- if (taxonomyUID) {
1125
- const sanitizedTaxonomy = sanitizeData({
1126
- 'Taxonomy Name': taxonomy?.name,
1127
- 'Taxonomy UID': taxonomyUID,
1128
- 'Taxonomy Description': taxonomy?.description,
1129
- });
1130
- taxonomiesData.push(sanitizedTaxonomy);
1131
- payload['taxonomyUID'] = taxonomyUID;
1132
- const terms = await getAllTermsOfTaxonomy(payload);
1133
- //fetch all parent terms
1134
- const parentTerms = terms.filter((term) => term?.parent_uid === null);
1135
- const termsData = getParentAndChildTerms(parentTerms, terms, headers);
1136
- taxonomiesData.push(...termsData)
1179
+ let taxonomiesData = [];
1180
+ let headers = [];
1181
+ payload['type'] = 'export-taxonomies';
1182
+ payload['format'] = 'csv';
1183
+ for (const taxonomy of taxonomies) {
1184
+ if (taxonomy?.uid) {
1185
+ payload['taxonomyUID'] = taxonomy?.uid;
1186
+ const data = await taxonomySDKHandler(payload);
1187
+ const taxonomies = await csvParse(data, headers);
1188
+ taxonomiesData.push(...taxonomies);
1189
+ }
1137
1190
  }
1138
- }
1139
1191
 
1140
- return {taxonomiesData, headers};
1192
+ return { taxonomiesData, headers };
1141
1193
  }
1142
1194
 
1143
1195
  /**
1144
- * Get the parent and child terms, then arrange them hierarchically in a CSV file.
1145
- * @param {*} parentTerms list of parent terms
1146
- * @param {*} terms respective terms of taxonomies
1147
- * @param {*} headers list of csv headers include taxonomy and terms column
1148
- * @param {*} termsData parent and child terms
1196
+ * Parse the CSV data and segregate the headers from the actual data.
1197
+ * @param {*} data taxonomy csv data with headers
1198
+ * @param {*} headers list of csv headers
1199
+ * @returns taxonomy data without headers
1149
1200
  */
1150
- function getParentAndChildTerms(parentTerms, terms, headers, termsData=[]) {
1151
- for (let i = 0; i < parentTerms?.length; i++) {
1152
- const parentTerm = parentTerms[i];
1153
- const levelUID = `Term Level${parentTerm.depth} UID`;
1154
- const levelName = `Term Level${parentTerm.depth} Name`;
1155
- if (headers.indexOf(levelName) === -1) headers.push(levelName);
1156
- if (headers.indexOf(levelUID) === -1) headers.push(levelUID);
1157
- const sanitizedTermData = sanitizeData({ [levelName]: parentTerm.name, [levelUID]: parentTerm.uid });
1158
- termsData.push(sanitizedTermData);
1159
- //fetch all sibling terms
1160
- const newParents = terms.filter((term) => term.parent_uid === parentTerm.uid);
1161
- if (newParents?.length) {
1162
- getParentAndChildTerms(newParents, terms, headers, termsData);
1163
- }
1164
- }
1165
- return termsData;
1166
- }
1201
+ const csvParse = (data, headers) => {
1202
+ return new Promise((resolve, reject) => {
1203
+ const taxonomies = [];
1204
+ const stream = fastcsv.parseStream(fastcsv.parse());
1205
+ stream.write(data);
1206
+ stream.end();
1207
+ stream
1208
+ .on('data', (data) => {
1209
+ taxonomies.push(data);
1210
+ })
1211
+ .on('error', (err) => reject(err))
1212
+ .on('end', () => {
1213
+ taxonomies[0]?.forEach((header) => {
1214
+ if (!headers.includes(header)) headers.push(header);
1215
+ });
1216
+ resolve(taxonomies.splice(1));
1217
+ });
1218
+ });
1219
+ };
1167
1220
 
1168
1221
  module.exports = {
1169
1222
  chooseOrganization: chooseOrganization,