From 791a1e8e51d7db8bda8c3a8382229c558a2d65ca Mon Sep 17 00:00:00 2001 From: raj pandey Date: Tue, 17 Oct 2023 15:49:22 +0530 Subject: [PATCH 01/32] Added function to get all the teams --- .../src/commands/cm/export-to-csv.js | 35 +++++++++++++++++-- .../src/util/config.js | 2 +- .../src/util/index.js | 34 ++++++++++++++++-- 3 files changed, 66 insertions(+), 5 deletions(-) diff --git a/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js b/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js index 8fa579906c..c1aec60fe4 100644 --- a/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js +++ b/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js @@ -15,8 +15,8 @@ class ExportToCsvCommand extends Command { action: flags.string({ required: false, multiple: false, - options: ['entries', 'users'], - description: `Option to export data (entries, users)`, + options: ['entries', 'users', 'teams'], + description: `Option to export data (entries, users, teams)`, }), alias: flags.string({ char: 'a', @@ -258,6 +258,34 @@ class ExportToCsvCommand extends Command { } break; } + case config.exportTeams: + case 'teams': { + try{ + if (!isAuthenticated()) { + this.error(config.CLI_EXPORT_CSV_LOGIN_FAILED, { + exit: 2, + suggestions: ['https://www.contentstack.com/docs/developers/cli/authentication/'], + }); + } + let organization; + + if (org) { + organization = { uid: org, name: orgName || org }; + } else { + organization = await util.chooseOrganization(managementAPIClient, action); // prompt for organization + } + + // getTeams + // getTeam + // geStackRoleMapping + await util.exportOrgTeams(managementAPIClient, organization); + } catch (error) { + if (error.message || error.errorMessage) { + cliux.error(util.formatError(error)); + } + } + } + break; } } catch (error) { if (error.message || error.errorMessage) { @@ -310,6 +338,9 @@ ExportToCsvCommand.examples = [ '', 'Exporting organization users to csv with organization name provided', 'csdx cm:export-to-csv --action --org --org-name ', + '', + 'Exporting Organizations Teams to CSV', + 'csdx cm:export-to-csv --action --org ', ]; module.exports = ExportToCsvCommand; diff --git a/packages/contentstack-export-to-csv/src/util/config.js b/packages/contentstack-export-to-csv/src/util/config.js index 6a424cc3a5..e0965f2b4b 100644 --- a/packages/contentstack-export-to-csv/src/util/config.js +++ b/packages/contentstack-export-to-csv/src/util/config.js @@ -2,9 +2,9 @@ module.exports = { cancelString: 'Cancel and Exit', exportEntries: 'Export entries to a .CSV file', exportUsers: "Export organization users' data to a .CSV file", + exportTeams: "Export organization teams data to a .csv file", adminError: "Unable to export data. Make sure you're an admin or owner of this organization", organizationNameRegex: /\'/, CLI_EXPORT_CSV_LOGIN_FAILED: "You need to login to execute this command. See: auth:login --help", CLI_EXPORT_CSV_ENTRIES_ERROR: "You need to either login or provide a management token to execute this command" - }; diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index daeee46058..97b6208c19 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -8,7 +8,7 @@ const debug = require('debug')('export-to-csv'); const checkboxPlus = require('inquirer-checkbox-plus-prompt'); const config = require('./config.js'); -const { cliux, configHandler } = require('@contentstack/cli-utilities'); +const { cliux, configHandler, HttpClient } = require('@contentstack/cli-utilities'); const directory = './data'; const delimeter = os.platform() === 'win32' ? '\\' : '/'; @@ -20,7 +20,7 @@ function chooseOrganization(managementAPIClient, action) { return new Promise(async (resolve, reject) => { try { let organizations; - if (action === config.exportUsers) { + if (action === config.exportUsers || action === 'teams') { organizations = await getOrganizationsWhereUserIsAdmin(managementAPIClient); } else { organizations = await getOrganizations(managementAPIClient); @@ -678,6 +678,35 @@ function wait(time) { }); } +async function apiRequestHandler(payload, queryParam={}) { + const headers = payload.headers; + console.log(headers); + return await new HttpClient().headers(headers).queryParams(queryParam).get(`${payload.url}/organizations/${payload.orgUid}/teams`).then((data)=>{ + return data.data + }).catch((error)=>{ + console.log(error); + console.log(error.error_message); + }) +} + +async function exportOrgTeams(managementAPIClient,org) { + payload = {} + console.log(configHandler.get('region')); + payload.url = configHandler.get('region').cma; + payload.orgUid = org.uid; + payload.headers = { + authtoken: configHandler.get('authtoken'), + organization_uid: org.uid, + 'Content-Type': 'application/json', + } + let teamsObject = [] + const data = await apiRequestHandler(payload,{}); + console.log(data); +} + +function getTeamDetails(){ + +} module.exports = { chooseOrganization: chooseOrganization, chooseStack: chooseStack, @@ -704,4 +733,5 @@ module.exports = { chooseInMemContentTypes: chooseInMemContentTypes, getEntriesCount: getEntriesCount, formatError: formatError, + exportOrgTeams: exportOrgTeams }; From 2be572bbd87acae05f45d06a5e08d322b278bdc6 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Tue, 17 Oct 2023 15:59:42 +0530 Subject: [PATCH 02/32] added pagination to get only 100 teams as the limit on get API call will change --- .../src/util/index.js | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index 97b6208c19..a193e7a7ff 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -682,7 +682,7 @@ async function apiRequestHandler(payload, queryParam={}) { const headers = payload.headers; console.log(headers); return await new HttpClient().headers(headers).queryParams(queryParam).get(`${payload.url}/organizations/${payload.orgUid}/teams`).then((data)=>{ - return data.data + return data?.data }).catch((error)=>{ console.log(error); console.log(error.error_message); @@ -700,8 +700,23 @@ async function exportOrgTeams(managementAPIClient,org) { 'Content-Type': 'application/json', } let teamsObject = [] - const data = await apiRequestHandler(payload,{}); - console.log(data); + const maxLimit = 500 // Max teams per org + let skip = 0; + let limit = 100; + while(limit!==500) { + const data = await apiRequestHandler(payload,{skip:500,limit:limit}); + skip = limit; + limit += 100; + if(data.length!==0){ + data.forEach((t)=>{ + teamsObject.push(t); + }) + } else { + break; + } + } + console.log(teamsObject); + } function getTeamDetails(){ From 3c8f04952890f65f890f74ca2b24554b497f0c6c Mon Sep 17 00:00:00 2001 From: raj pandey Date: Tue, 17 Oct 2023 17:39:22 +0530 Subject: [PATCH 03/32] Getting the teams from api calls to --- .../src/util/index.js | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index a193e7a7ff..8e199876ce 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -680,7 +680,7 @@ function wait(time) { async function apiRequestHandler(payload, queryParam={}) { const headers = payload.headers; - console.log(headers); + // console.log(headers); return await new HttpClient().headers(headers).queryParams(queryParam).get(`${payload.url}/organizations/${payload.orgUid}/teams`).then((data)=>{ return data?.data }).catch((error)=>{ @@ -691,7 +691,7 @@ async function apiRequestHandler(payload, queryParam={}) { async function exportOrgTeams(managementAPIClient,org) { payload = {} - console.log(configHandler.get('region')); + // console.log(configHandler.get('region')); payload.url = configHandler.get('region').cma; payload.orgUid = org.uid; payload.headers = { @@ -703,20 +703,45 @@ async function exportOrgTeams(managementAPIClient,org) { const maxLimit = 500 // Max teams per org let skip = 0; let limit = 100; + const fieldToBeDeleted = ["_id","createdAt", "createdBy","updatedAt","updatedBy","__v","createdByUserName", "updatedByUserName"] + let roleMap = {} // for org level there are two roles only admin and member + + // SDK call to get the role uids + managementAPIClient.organization(org.uid).roles() + .then((roles) => { + roles.items.forEach((item)=>{ + if(item.name==='member' || item.name==='admin'){ + roleMap.name = item.uid + } + }) + }) + + // Limit of 500 was hard coded while(limit!==500) { - const data = await apiRequestHandler(payload,{skip:500,limit:limit}); + const data = await apiRequestHandler(payload,{skip:skip,limit:limit}); skip = limit; limit += 100; if(data.length!==0){ data.forEach((t)=>{ + fieldToBeDeleted.forEach((fields)=>{ + delete t[fields] + }); + if(!t.hasOwnProperty('description')){ + t.description = '' + } + if(t.organizationRole===roleMap['member']){ + t.organizationRole = 'member'; + } else { + t.organizationRole = 'admin'; + } + t.users = t.users.length; teamsObject.push(t); }) } else { break; } } - console.log(teamsObject); - + return teamsObject; } function getTeamDetails(){ From 0993759dd19fd4579d003d6885c7743c23792eba Mon Sep 17 00:00:00 2001 From: raj pandey Date: Wed, 18 Oct 2023 09:40:18 +0530 Subject: [PATCH 04/32] added api-version to header and includeUserDetails so that a single api get call gets all the required data --- .../contentstack-export-to-csv/src/util/index.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index 8e199876ce..c67c412768 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -698,6 +698,7 @@ async function exportOrgTeams(managementAPIClient,org) { authtoken: configHandler.get('authtoken'), organization_uid: org.uid, 'Content-Type': 'application/json', + api_version: 1.1 } let teamsObject = [] const maxLimit = 500 // Max teams per org @@ -711,18 +712,18 @@ async function exportOrgTeams(managementAPIClient,org) { .then((roles) => { roles.items.forEach((item)=>{ if(item.name==='member' || item.name==='admin'){ - roleMap.name = item.uid + roleMap.name = item.uid; } }) }) // Limit of 500 was hard coded while(limit!==500) { - const data = await apiRequestHandler(payload,{skip:skip,limit:limit}); + const data = await apiRequestHandler(payload,{skip:skip,limit:limit,includeUserDetails:true}); skip = limit; limit += 100; - if(data.length!==0){ - data.forEach((t)=>{ + if(data.teams.length!==0){ + data.teams.forEach((t)=>{ fieldToBeDeleted.forEach((fields)=>{ delete t[fields] }); @@ -734,13 +735,14 @@ async function exportOrgTeams(managementAPIClient,org) { } else { t.organizationRole = 'admin'; } - t.users = t.users.length; + t.Number_of_Members = t.users.length; teamsObject.push(t); }) } else { break; } } + console.log(teamsObject) return teamsObject; } From e1a79cce08649fb602dac3375b842d6f00aa1fef Mon Sep 17 00:00:00 2001 From: raj pandey Date: Wed, 18 Oct 2023 10:28:05 +0530 Subject: [PATCH 05/32] Exporting all the teams into csv --- .../src/commands/cm/export-to-csv.js | 11 +++++++++- .../src/util/index.js | 21 +++++++++++++------ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js b/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js index c1aec60fe4..5441e7cdd9 100644 --- a/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js +++ b/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js @@ -278,7 +278,16 @@ class ExportToCsvCommand extends Command { // getTeams // getTeam // geStackRoleMapping - await util.exportOrgTeams(managementAPIClient, organization); + const allTeamsData = await util.exportOrgTeams(managementAPIClient, organization); + if(allTeamsData.teams.length===0){ + this.log(`There are not teams in the organization named ${organization.name}`); + } else { + const fileName = `${util.kebabize( + (orgName ? orgName : organization.name).replace(config.organizationNameRegex, ''), + )}_teams_export.csv`; + util.write(this, allTeamsData.teams, fileName, 'organization Team details'); + } + } catch (error) { if (error.message || error.errorMessage) { cliux.error(util.formatError(error)); diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index c67c412768..9737c88852 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -691,7 +691,6 @@ async function apiRequestHandler(payload, queryParam={}) { async function exportOrgTeams(managementAPIClient,org) { payload = {} - // console.log(configHandler.get('region')); payload.url = configHandler.get('region').cma; payload.orgUid = org.uid; payload.headers = { @@ -700,11 +699,13 @@ async function exportOrgTeams(managementAPIClient,org) { 'Content-Type': 'application/json', api_version: 1.1 } - let teamsObject = [] + let teamsObject = []; + let userObject = []; + let stackRoleMapObject = []; const maxLimit = 500 // Max teams per org let skip = 0; let limit = 100; - const fieldToBeDeleted = ["_id","createdAt", "createdBy","updatedAt","updatedBy","__v","createdByUserName", "updatedByUserName"] + const fieldToBeDeleted = ["_id","createdAt", "createdBy","updatedAt","updatedBy","__v","createdByUserName", "updatedByUserName","organizationUid"] let roleMap = {} // for org level there are two roles only admin and member // SDK call to get the role uids @@ -735,20 +736,28 @@ async function exportOrgTeams(managementAPIClient,org) { } else { t.organizationRole = 'admin'; } - t.Number_of_Members = t.users.length; + t.Total_Members = t.users.length; + userObject.push(t.users); + stackRoleMapObject.push(t.stackRoleMapping); + delete t['stackRoleMapping']; + delete t['users'] teamsObject.push(t); }) } else { break; } } - console.log(teamsObject) - return teamsObject; + let teamsData ={}; + teamsData['teams'] = teamsObject; + teamsData['users'] = userObject; + teamsData['stackRoleMapping'] = stackRoleMapObject; + return teamsData; } function getTeamDetails(){ } + module.exports = { chooseOrganization: chooseOrganization, chooseStack: chooseStack, From b212d65c36c8f68b64ba7f134edf735c5ec3e09b Mon Sep 17 00:00:00 2001 From: raj pandey Date: Wed, 18 Oct 2023 16:03:02 +0530 Subject: [PATCH 06/32] Refactoring --- .../src/commands/cm/export-to-csv.js | 15 +- .../src/util/config.js | 7 +- .../src/util/index.js | 204 +++++++++++------- 3 files changed, 133 insertions(+), 93 deletions(-) diff --git a/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js b/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js index 5441e7cdd9..f3e054c20f 100644 --- a/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js +++ b/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js @@ -275,19 +275,8 @@ class ExportToCsvCommand extends Command { organization = await util.chooseOrganization(managementAPIClient, action); // prompt for organization } - // getTeams - // getTeam - // geStackRoleMapping - const allTeamsData = await util.exportOrgTeams(managementAPIClient, organization); - if(allTeamsData.teams.length===0){ - this.log(`There are not teams in the organization named ${organization.name}`); - } else { - const fileName = `${util.kebabize( - (orgName ? orgName : organization.name).replace(config.organizationNameRegex, ''), - )}_teams_export.csv`; - util.write(this, allTeamsData.teams, fileName, 'organization Team details'); - } - + await util.exportTeams(managementAPIClient,organization); + } catch (error) { if (error.message || error.errorMessage) { cliux.error(util.formatError(error)); diff --git a/packages/contentstack-export-to-csv/src/util/config.js b/packages/contentstack-export-to-csv/src/util/config.js index e0965f2b4b..c17d953447 100644 --- a/packages/contentstack-export-to-csv/src/util/config.js +++ b/packages/contentstack-export-to-csv/src/util/config.js @@ -1,10 +1,11 @@ module.exports = { cancelString: 'Cancel and Exit', exportEntries: 'Export entries to a .CSV file', - exportUsers: "Export organization users' data to a .CSV file", - exportTeams: "Export organization teams data to a .csv file", + exportUsers: "Export organization user's data to a .CSV file", + exportTeams: "Export organization team's data to a .csv file", adminError: "Unable to export data. Make sure you're an admin or owner of this organization", organizationNameRegex: /\'/, CLI_EXPORT_CSV_LOGIN_FAILED: "You need to login to execute this command. See: auth:login --help", - CLI_EXPORT_CSV_ENTRIES_ERROR: "You need to either login or provide a management token to execute this command" + CLI_EXPORT_CSV_ENTRIES_ERROR: "You need to either login or provide a management token to execute this command", + CLI_EXPORT_CSV_API_FAILED: 'Something went wrong. Please try again' }; diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index 9737c88852..22e328dcc8 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -6,7 +6,6 @@ const fastcsv = require('fast-csv'); const inquirer = require('inquirer'); const debug = require('debug')('export-to-csv'); const checkboxPlus = require('inquirer-checkbox-plus-prompt'); - const config = require('./config.js'); const { cliux, configHandler, HttpClient } = require('@contentstack/cli-utilities'); @@ -105,7 +104,7 @@ async function getOrganizationsWhereUserIsAdmin(managementAPIClient) { organizations.forEach((org) => { result[org.name] = org.uid; }); - } + } return result; } catch (error) { @@ -321,7 +320,13 @@ function getEntries(stackAPIClient, contentType, language, skip, limit) { stackAPIClient .contentType(contentType) .entry() - .query({ include_publish_details: true, locale: language, skip: skip * 100, limit: limit, include_workflow: true }) + .query({ + include_publish_details: true, + locale: language, + skip: skip * 100, + limit: limit, + include_workflow: true, + }) .find() .then((entries) => resolve(entries)) .catch((error) => reject(error)); @@ -373,11 +378,11 @@ function exitProgram() { function sanitizeEntries(flatEntry) { // sanitize against CSV Injections - const CSVRegex = /^[\\+\\=@\\-]/ + const CSVRegex = /^[\\+\\=@\\-]/; for (key in flatEntry) { if (typeof flatEntry[key] === 'string' && flatEntry[key].match(CSVRegex)) { flatEntry[key] = flatEntry[key].replace(/\"/g, "\"\""); - flatEntry[key] = `"'${flatEntry[key]}"` + flatEntry[key] = `"'${flatEntry[key]}"`; } else if (typeof flatEntry[key] === 'object') { // convert any objects or arrays to string // to store this data correctly in csv @@ -394,7 +399,7 @@ function cleanEntries(entries, language, environments, contentTypeUid) { return filteredEntries.map((entry) => { let workflow = ''; const envArr = []; - if(entry.publish_details.length) { + if (entry.publish_details.length) { entry.publish_details.forEach((env) => { envArr.push(JSON.stringify([environments[env['environment']], env['locale'], env['time']])); }); @@ -403,10 +408,10 @@ function cleanEntries(entries, language, environments, contentTypeUid) { delete entry.publish_details; delete entry.setWorkflowStage; if ('_workflow' in entry) { - if(entry._workflow?.name) { - workflow = entry['_workflow']['name']; - delete entry['_workflow']; - } + if (entry._workflow?.name) { + workflow = entry['_workflow']['name']; + delete entry['_workflow']; + } } entry = flatten(entry); entry = sanitizeEntries(entry); @@ -678,86 +683,130 @@ function wait(time) { }); } -async function apiRequestHandler(payload, queryParam={}) { - const headers = payload.headers; - // console.log(headers); - return await new HttpClient().headers(headers).queryParams(queryParam).get(`${payload.url}/organizations/${payload.orgUid}/teams`).then((data)=>{ - return data?.data - }).catch((error)=>{ - console.log(error); - console.log(error.error_message); - }) +function handleErrorMsg(err) { + if (err?.errorMessage) { + cliux.print(`Error: ${err.errorMessage}`, { color: 'red' }); + } else if (err?.message) { + cliux.print(`Error: ${err.message}`, { color: 'red' }); + } else { + console.log(err); + cliux.print(`Error: ${messageHandler.parse('CLI_EXPORT_CSV_API_FAILED')}`, { color: 'red' }); + } + process.exit(1); } - -async function exportOrgTeams(managementAPIClient,org) { - payload = {} - payload.url = configHandler.get('region').cma; - payload.orgUid = org.uid; - payload.headers = { +async function apiRequestHandler(org, queryParam = {}) { + const headers = { authtoken: configHandler.get('authtoken'), organization_uid: org.uid, 'Content-Type': 'application/json', - api_version: 1.1 - } - let teamsObject = []; - let userObject = []; - let stackRoleMapObject = []; - const maxLimit = 500 // Max teams per org + api_version: 1.1, + }; + + return await new HttpClient() + .headers(headers) + .queryParams(queryParam) + .get(`${configHandler.get('region')?.cma}/organizations/${org.uid}/teams`) + .then((res) => { + const {status, data} = res; + if(data.hasOwnProperty('error_code')) { + cliux.print(`${data.error_message}`,{color:'red'}); + process.exit(1); + } + return data; + }) + .catch((error) => { + handleErrorMsg(error); + }); +} + +async function exportOrgTeams(managementAPIClient, org) { + let teamsObjectArray = []; let skip = 0; let limit = 100; - const fieldToBeDeleted = ["_id","createdAt", "createdBy","updatedAt","updatedBy","__v","createdByUserName", "updatedByUserName","organizationUid"] - let roleMap = {} // for org level there are two roles only admin and member + do { + const data = await apiRequestHandler(org,{ skip: skip, limit: limit, includeUserDetails: true }); + skip += limit; + teamsObjectArray = [...teamsObjectArray,...data?.teams] + if(skip>data?.count) break; + } while (1); + teamsObjectArray = await cleanTeamsData(teamsObjectArray,managementAPIClient,org); + return teamsObjectArray; +} + +async function getOrgRoles(managementAPIClient, org) { + let roleMap = {}; // for org level there are two roles only admin and member // SDK call to get the role uids - managementAPIClient.organization(org.uid).roles() - .then((roles) => { - roles.items.forEach((item)=>{ - if(item.name==='member' || item.name==='admin'){ - roleMap.name = item.uid; + managementAPIClient + .organization(org.uid) + .roles() + .then((roles) => { + roles.items.forEach((item) => { + if (item.name === 'member' || item.name === 'admin') { + roleMap.name = item.uid; + } + }); + }); + + return roleMap; +} + +async function cleanTeamsData(data,managementAPIClient,org) { + const roleMap = await getOrgRoles(managementAPIClient,org) + const fieldToBeDeleted = [ + '_id', + 'createdAt', + 'createdBy', + 'updatedAt', + 'updatedBy', + '__v', + 'createdByUserName', + 'updatedByUserName', + 'organizationUid', + ]; + if (data.length !== 0) { + data.forEach((team) => { + fieldToBeDeleted.forEach((fields) => { + delete team[fields]; + }); + if (!team.hasOwnProperty('description')) { + team.description = ''; } + if (team.organizationRole === roleMap['member']) { + team.organizationRole = 'member'; + } else { + team.organizationRole = 'admin'; + } + team.Total_Members = team.users.length; + }); + } else { + cliux.print(`There are no teams in the given org`); + } + return data +} + +async function exportTeams(managementAPIClient, organization) { + const allTeamsData = await exportOrgTeams(managementAPIClient, organization); + if (allTeamsData.length === 0) { + this.log(`There are not teams in the organization named ${organization?.name}`); + } else { + const modifiedTeam = []; + allTeamsData.forEach((team)=>{ + modifiedTeam.push(Object.assign({}, team)); }) - }) - - // Limit of 500 was hard coded - while(limit!==500) { - const data = await apiRequestHandler(payload,{skip:skip,limit:limit,includeUserDetails:true}); - skip = limit; - limit += 100; - if(data.teams.length!==0){ - data.teams.forEach((t)=>{ - fieldToBeDeleted.forEach((fields)=>{ - delete t[fields] - }); - if(!t.hasOwnProperty('description')){ - t.description = '' - } - if(t.organizationRole===roleMap['member']){ - t.organizationRole = 'member'; - } else { - t.organizationRole = 'admin'; - } - t.Total_Members = t.users.length; - userObject.push(t.users); - stackRoleMapObject.push(t.stackRoleMapping); - delete t['stackRoleMapping']; - delete t['users'] - teamsObject.push(t); - }) - } else { - break; - } + modifiedTeam.forEach((team)=>{ + delete team['users'] + delete team['stackRoleMapping'] + }) + const fileName = `${kebabize( + (organization.name).replace(config.organizationNameRegex, ''), + )}_teams_export.csv`; + write(this, modifiedTeam, fileName, 'organization Team details'); } - let teamsData ={}; - teamsData['teams'] = teamsObject; - teamsData['users'] = userObject; - teamsData['stackRoleMapping'] = stackRoleMapObject; - return teamsData; } -function getTeamDetails(){ +function getTeamDetails() {} -} - module.exports = { chooseOrganization: chooseOrganization, chooseStack: chooseStack, @@ -784,5 +833,6 @@ module.exports = { chooseInMemContentTypes: chooseInMemContentTypes, getEntriesCount: getEntriesCount, formatError: formatError, - exportOrgTeams: exportOrgTeams + exportOrgTeams: exportOrgTeams, + exportTeams: exportTeams, }; From b53f88f7bff9962e2ca17622a2318cc0a797144f Mon Sep 17 00:00:00 2001 From: raj pandey Date: Thu, 19 Oct 2023 14:14:21 +0530 Subject: [PATCH 07/32] Used loadash deep clone, added catch block in sdk call added team-uid flag --- .../src/commands/cm/export-to-csv.js | 8 ++- .../src/util/index.js | 58 ++++++++++++++----- 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js b/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js index f3e054c20f..3c3ddbd8ea 100644 --- a/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js +++ b/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js @@ -59,6 +59,11 @@ class ExportToCsvCommand extends Command { multiple: false, required: false, }), + "team-uid": flags.string({ + description: 'Uid of the team whose user data and stack roles are required', + multiple: false, + required: false, + }) }; async run() { @@ -75,6 +80,7 @@ class ExportToCsvCommand extends Command { 'content-type': contentTypesFlag, alias: managementTokenAlias, branch: branchUid, + "team-uid": teamUid }, } = await this.parse(ExportToCsvCommand); @@ -275,7 +281,7 @@ class ExportToCsvCommand extends Command { organization = await util.chooseOrganization(managementAPIClient, action); // prompt for organization } - await util.exportTeams(managementAPIClient,organization); + await util.exportTeams(managementAPIClient,organization,teamUid); } catch (error) { if (error.message || error.errorMessage) { diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index 22e328dcc8..74aac44820 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -8,7 +8,7 @@ const debug = require('debug')('export-to-csv'); const checkboxPlus = require('inquirer-checkbox-plus-prompt'); const config = require('./config.js'); const { cliux, configHandler, HttpClient } = require('@contentstack/cli-utilities'); - +const _ = require('lodash'); const directory = './data'; const delimeter = os.platform() === 'win32' ? '\\' : '/'; @@ -722,7 +722,7 @@ async function apiRequestHandler(org, queryParam = {}) { async function exportOrgTeams(managementAPIClient, org) { let teamsObjectArray = []; let skip = 0; - let limit = 100; + let limit = config.limit || 100; do { const data = await apiRequestHandler(org,{ skip: skip, limit: limit, includeUserDetails: true }); skip += limit; @@ -746,8 +746,10 @@ async function getOrgRoles(managementAPIClient, org) { roleMap.name = item.uid; } }); - }); - + }) + .catch((err)=>{ + handleErrorMsg(err); + }) return roleMap; } @@ -764,7 +766,7 @@ async function cleanTeamsData(data,managementAPIClient,org) { 'updatedByUserName', 'organizationUid', ]; - if (data.length !== 0) { + if (data?.length !== 0) { data.forEach((team) => { fieldToBeDeleted.forEach((fields) => { delete team[fields]; @@ -777,23 +779,20 @@ async function cleanTeamsData(data,managementAPIClient,org) { } else { team.organizationRole = 'admin'; } - team.Total_Members = team.users.length; + team.Total_Members = team?.users?.length || 0; }); } else { - cliux.print(`There are no teams in the given org`); + cliux.print(`info: There are no teams in the given org`); } return data } -async function exportTeams(managementAPIClient, organization) { +async function exportTeams(managementAPIClient, organization,teamUid) { const allTeamsData = await exportOrgTeams(managementAPIClient, organization); if (allTeamsData.length === 0) { this.log(`There are not teams in the organization named ${organization?.name}`); } else { - const modifiedTeam = []; - allTeamsData.forEach((team)=>{ - modifiedTeam.push(Object.assign({}, team)); - }) + const modifiedTeam = _.cloneDeep(allTeamsData); modifiedTeam.forEach((team)=>{ delete team['users'] delete team['stackRoleMapping'] @@ -802,10 +801,43 @@ async function exportTeams(managementAPIClient, organization) { (organization.name).replace(config.organizationNameRegex, ''), )}_teams_export.csv`; write(this, modifiedTeam, fileName, 'organization Team details'); + if(!teamUid) { + const userData = await getTeamDetails(allTeamsData); + const fileName = `${kebabize( + (organization.name).replace(config.organizationNameRegex, ''), + )}_team_User_Details_export.csv`; + write(this, userData, fileName, 'Team User details'); + } else { + const team = allTeamsData.filter((team)=>team.uid===teamUid)[0] + team.users.forEach((user)=>{ + user['team-name'] = team.name; + user['team-uid'] = team.uid; + delete user['active']; + delete user['orgInvitationStatus']; + }) + const fileName = `${kebabize( + (organization.name).replace(config.organizationNameRegex, ''), + )}_team_${teamUid}_User_Details_export.csv`; + write(this, team.users, fileName, 'Team User details'); + } } } -function getTeamDetails() {} +async function getTeamDetails(teamsObject) { + const allTeamUsers = []; + teamsObject.forEach((team)=>{ + if(team.users.length){ + team.users.forEach((user)=>{ + user['team-name'] = team.name; + user['team-uid'] = team.uid; + delete user['active']; + delete user['orgInvitationStatus'] + allTeamUsers.push(user); + }) + } + }) + return allTeamUsers; +} module.exports = { chooseOrganization: chooseOrganization, From cb76049750879463ad9fad0b0d54cf1fa82d4ad0 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Thu, 19 Oct 2023 14:39:31 +0530 Subject: [PATCH 08/32] refactoring --- .../src/util/index.js | 101 +++++++++--------- 1 file changed, 52 insertions(+), 49 deletions(-) diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index 74aac44820..8844be17bd 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -701,17 +701,17 @@ async function apiRequestHandler(org, queryParam = {}) { 'Content-Type': 'application/json', api_version: 1.1, }; - + return await new HttpClient() .headers(headers) .queryParams(queryParam) .get(`${configHandler.get('region')?.cma}/organizations/${org.uid}/teams`) .then((res) => { - const {status, data} = res; - if(data.hasOwnProperty('error_code')) { - cliux.print(`${data.error_message}`,{color:'red'}); + const { status, data } = res; + if (data.hasOwnProperty('error_code')) { + cliux.print(`${data.error_message}`, { color: 'red' }); process.exit(1); - } + } return data; }) .catch((error) => { @@ -724,12 +724,12 @@ async function exportOrgTeams(managementAPIClient, org) { let skip = 0; let limit = config.limit || 100; do { - const data = await apiRequestHandler(org,{ skip: skip, limit: limit, includeUserDetails: true }); + const data = await apiRequestHandler(org, { skip: skip, limit: limit, includeUserDetails: true }); skip += limit; - teamsObjectArray = [...teamsObjectArray,...data?.teams] - if(skip>data?.count) break; + teamsObjectArray = [...teamsObjectArray, ...data?.teams]; + if (skip > data?.count) break; } while (1); - teamsObjectArray = await cleanTeamsData(teamsObjectArray,managementAPIClient,org); + teamsObjectArray = await cleanTeamsData(teamsObjectArray, managementAPIClient, org); return teamsObjectArray; } @@ -747,14 +747,14 @@ async function getOrgRoles(managementAPIClient, org) { } }); }) - .catch((err)=>{ + .catch((err) => { handleErrorMsg(err); - }) - return roleMap; + }); + return roleMap; } -async function cleanTeamsData(data,managementAPIClient,org) { - const roleMap = await getOrgRoles(managementAPIClient,org) +async function cleanTeamsData(data, managementAPIClient, org) { + const roleMap = await getOrgRoles(managementAPIClient, org); const fieldToBeDeleted = [ '_id', 'createdAt', @@ -784,58 +784,61 @@ async function cleanTeamsData(data,managementAPIClient,org) { } else { cliux.print(`info: There are no teams in the given org`); } - return data + return data; } -async function exportTeams(managementAPIClient, organization,teamUid) { +async function exportTeams(managementAPIClient, organization, teamUid) { const allTeamsData = await exportOrgTeams(managementAPIClient, organization); if (allTeamsData.length === 0) { this.log(`There are not teams in the organization named ${organization?.name}`); } else { const modifiedTeam = _.cloneDeep(allTeamsData); - modifiedTeam.forEach((team)=>{ - delete team['users'] - delete team['stackRoleMapping'] - }) - const fileName = `${kebabize( - (organization.name).replace(config.organizationNameRegex, ''), - )}_teams_export.csv`; + modifiedTeam.forEach((team) => { + delete team['users']; + delete team['stackRoleMapping']; + }); + const fileName = `${kebabize(organization.name.replace(config.organizationNameRegex, ''))}_teams_export.csv`; write(this, modifiedTeam, fileName, 'organization Team details'); - if(!teamUid) { - const userData = await getTeamDetails(allTeamsData); - const fileName = `${kebabize( - (organization.name).replace(config.organizationNameRegex, ''), - )}_team_User_Details_export.csv`; - write(this, userData, fileName, 'Team User details'); - } else { - const team = allTeamsData.filter((team)=>team.uid===teamUid)[0] - team.users.forEach((user)=>{ - user['team-name'] = team.name; - user['team-uid'] = team.uid; - delete user['active']; - delete user['orgInvitationStatus']; - }) - const fileName = `${kebabize( - (organization.name).replace(config.organizationNameRegex, ''), - )}_team_${teamUid}_User_Details_export.csv`; - write(this, team.users, fileName, 'Team User details'); - } + // exporting teams user data or a single team user data + await getTeamsDetail(allTeamsData,organization,teamUid); + } +} + +async function getTeamsDetail(allTeamsData, organization ,teamUid) { + if (!teamUid) { + const userData = await getTeamsUserDetails(allTeamsData); + const fileName = `${kebabize( + organization.name.replace(config.organizationNameRegex, ''), + )}_team_User_Details_export.csv`; + write(this, userData, fileName, 'Team User details'); + } else { + const team = allTeamsData.filter((team) => team.uid === teamUid)[0]; + team.users.forEach((user) => { + user['team-name'] = team.name; + user['team-uid'] = team.uid; + delete user['active']; + delete user['orgInvitationStatus']; + }); + const fileName = `${kebabize( + organization.name.replace(config.organizationNameRegex, ''), + )}_team_${teamUid}_User_Details_export.csv`; + write(this, team.users, fileName, 'Team User details'); } } -async function getTeamDetails(teamsObject) { +async function getTeamsUserDetails(teamsObject) { const allTeamUsers = []; - teamsObject.forEach((team)=>{ - if(team.users.length){ - team.users.forEach((user)=>{ + teamsObject.forEach((team) => { + if (team.users.length) { + team.users.forEach((user) => { user['team-name'] = team.name; user['team-uid'] = team.uid; delete user['active']; - delete user['orgInvitationStatus'] + delete user['orgInvitationStatus']; allTeamUsers.push(user); - }) + }); } - }) + }); return allTeamUsers; } From 0d9d04bfe2fab034395d15746e60739d4231614d Mon Sep 17 00:00:00 2001 From: raj pandey Date: Thu, 19 Oct 2023 14:54:47 +0530 Subject: [PATCH 09/32] change api response handler --- .../contentstack-export-to-csv/src/util/config.js | 2 +- .../contentstack-export-to-csv/src/util/index.js | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/contentstack-export-to-csv/src/util/config.js b/packages/contentstack-export-to-csv/src/util/config.js index c17d953447..92c83aa1d7 100644 --- a/packages/contentstack-export-to-csv/src/util/config.js +++ b/packages/contentstack-export-to-csv/src/util/config.js @@ -7,5 +7,5 @@ module.exports = { organizationNameRegex: /\'/, CLI_EXPORT_CSV_LOGIN_FAILED: "You need to login to execute this command. See: auth:login --help", CLI_EXPORT_CSV_ENTRIES_ERROR: "You need to either login or provide a management token to execute this command", - CLI_EXPORT_CSV_API_FAILED: 'Something went wrong. Please try again' + CLI_EXPORT_CSV_API_FAILED: 'Something went wrong. Please try again!' }; diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index 8844be17bd..6d51e5fba3 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -708,11 +708,12 @@ async function apiRequestHandler(org, queryParam = {}) { .get(`${configHandler.get('region')?.cma}/organizations/${org.uid}/teams`) .then((res) => { const { status, data } = res; - if (data.hasOwnProperty('error_code')) { - cliux.print(`${data.error_message}`, { color: 'red' }); + if(status===200) { + return data; + } else { + cliux.print(`${data.error_message || data.message || data.errorMessage}`, { color: 'red' }); process.exit(1); } - return data; }) .catch((error) => { handleErrorMsg(error); @@ -806,23 +807,31 @@ async function exportTeams(managementAPIClient, organization, teamUid) { async function getTeamsDetail(allTeamsData, organization ,teamUid) { if (!teamUid) { + const userData = await getTeamsUserDetails(allTeamsData); const fileName = `${kebabize( organization.name.replace(config.organizationNameRegex, ''), )}_team_User_Details_export.csv`; + write(this, userData, fileName, 'Team User details'); + } else { + const team = allTeamsData.filter((team) => team.uid === teamUid)[0]; + team.users.forEach((user) => { user['team-name'] = team.name; user['team-uid'] = team.uid; delete user['active']; delete user['orgInvitationStatus']; }); + const fileName = `${kebabize( organization.name.replace(config.organizationNameRegex, ''), )}_team_${teamUid}_User_Details_export.csv`; + write(this, team.users, fileName, 'Team User details'); + } } From ac08fb2789f428c6b7aa1f5582a5942e541ae7b6 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Mon, 23 Oct 2023 14:48:00 +0530 Subject: [PATCH 10/32] Exporting Teams stack role --- .../src/util/index.js | 64 ++++++++++++++++--- 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index 6d51e5fba3..f1352c8e24 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -708,7 +708,7 @@ async function apiRequestHandler(org, queryParam = {}) { .get(`${configHandler.get('region')?.cma}/organizations/${org.uid}/teams`) .then((res) => { const { status, data } = res; - if(status===200) { + if (status === 200) { return data; } else { cliux.print(`${data.error_message || data.message || data.errorMessage}`, { color: 'red' }); @@ -802,23 +802,21 @@ async function exportTeams(managementAPIClient, organization, teamUid) { write(this, modifiedTeam, fileName, 'organization Team details'); // exporting teams user data or a single team user data await getTeamsDetail(allTeamsData,organization,teamUid); + await exportRoleMappings(managementAPIClient, allTeamsData, teamUid); } } -async function getTeamsDetail(allTeamsData, organization ,teamUid) { +async function getTeamsDetail(allTeamsData, organization, teamUid) { if (!teamUid) { - const userData = await getTeamsUserDetails(allTeamsData); const fileName = `${kebabize( organization.name.replace(config.organizationNameRegex, ''), )}_team_User_Details_export.csv`; write(this, userData, fileName, 'Team User details'); - } else { - const team = allTeamsData.filter((team) => team.uid === teamUid)[0]; - + team.users.forEach((user) => { user['team-name'] = team.name; user['team-uid'] = team.uid; @@ -829,12 +827,62 @@ async function getTeamsDetail(allTeamsData, organization ,teamUid) { const fileName = `${kebabize( organization.name.replace(config.organizationNameRegex, ''), )}_team_${teamUid}_User_Details_export.csv`; - + write(this, team.users, fileName, 'Team User details'); - } } +async function exportRoleMappings(managementAPIClient, allTeamsData, teamUid) { + let stackRoleWithTeamData = []; + if(teamUid) { + const team = allTeamsData.filter((team) => team?.uid === teamUid)[0]; + for (const stack of team?.stackRoleMapping) { + const roleData = await mapRoleWithTeams(managementAPIClient, stack, team?.name, team?.uid); + stackRoleWithTeamData.push(...roleData); + } + } else { + for (const team of allTeamsData) { + for (const stack of team?.stackRoleMapping) { + const roleData = await mapRoleWithTeams(managementAPIClient, stack, team?.name, team?.uid); + stackRoleWithTeamData.push(...roleData); + } + } + } + const fileName = `${kebabize( + "All_Teams_Role_Mapping".replace(config.organizationNameRegex, ''), + )}.csv`; + + write(this, stackRoleWithTeamData, fileName, 'Team Stack Role details'); +} + +async function mapRoleWithTeams(managementAPIClient, stackRoleMapping, teamName, teamUid) { + const Stack = await getStackData(managementAPIClient, stackRoleMapping.stackApiKey); + const stackRole = {}; + const roles = await Stack.role().fetchAll() + roles?.items?.forEach((role) => { + if(!stackRole.hasOwnProperty(role?.uid)){ + stackRole[role?.uid] = role?.name; + } + }); + let stackRoleMapOfTeam = []; + stackRoleMapping?.roles.forEach((role)=>{ + let stackRoleMap = {}; + stackRoleMap['Team Name'] = teamName; + stackRoleMap['Team Uid'] = teamUid; + stackRoleMap['Stack Name'] = Stack?.name; + stackRoleMap['Stack Uid'] = Stack?.uid; + stackRoleMap['Role Name'] = stackRole[role] + stackRoleMap['Role Uid'] = role; + stackRoleMapOfTeam.push(stackRoleMap); + }) + + // console.log(stackRole); + return stackRoleMapOfTeam; +} + +async function getStackData(managementAPIClient, stackApiKey) { + return await managementAPIClient.stack({ api_key: stackApiKey }).fetch(); +} async function getTeamsUserDetails(teamsObject) { const allTeamUsers = []; teamsObject.forEach((team) => { From 411bb4a82441bd95491c614395809b4ec204e61a Mon Sep 17 00:00:00 2001 From: raj pandey Date: Mon, 23 Oct 2023 15:39:33 +0530 Subject: [PATCH 11/32] PR changes --- package-lock.json | 315 +++++++++++++----- .../src/commands/cm/export-to-csv.js | 4 +- .../src/util/index.js | 21 +- 3 files changed, 235 insertions(+), 105 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3d69b66d7f..bd47d043cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -82,17 +82,89 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", - "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "dependencies": { - "@babel/highlight": "^7.22.5" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/compat-data": { "version": "7.22.9", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", @@ -178,12 +250,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz", - "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -221,22 +293,22 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "dependencies": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" @@ -328,9 +400,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, "engines": { "node": ">=6.9.0" @@ -360,13 +432,13 @@ } }, "node_modules/@babel/highlight": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", - "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -445,9 +517,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", - "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -646,33 +718,33 @@ } }, "node_modules/@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.22.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz", - "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.7", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.7", - "@babel/types": "^7.22.5", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -690,13 +762,13 @@ } }, "node_modules/@babel/types": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", - "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -26363,12 +26435,71 @@ } }, "@babel/code-frame": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", - "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "requires": { - "@babel/highlight": "^7.22.5" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "@babel/compat-data": { @@ -26434,12 +26565,12 @@ } }, "@babel/generator": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz", - "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dev": true, "requires": { - "@babel/types": "^7.22.5", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -26467,19 +26598,19 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true }, "@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "requires": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" } }, "@babel/helper-hoist-variables": { @@ -26544,9 +26675,9 @@ "dev": true }, "@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true }, "@babel/helper-validator-option": { @@ -26567,13 +26698,13 @@ } }, "@babel/highlight": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", - "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "dependencies": { @@ -26636,9 +26767,9 @@ } }, "@babel/parser": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", - "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -26777,30 +26908,30 @@ } }, "@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "requires": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" } }, "@babel/traverse": { - "version": "7.22.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz", - "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", "dev": true, "requires": { - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.7", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.7", - "@babel/types": "^7.22.5", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -26814,13 +26945,13 @@ } }, "@babel/types": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", - "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dev": true, "requires": { "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" } }, diff --git a/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js b/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js index 3c3ddbd8ea..28523798a1 100644 --- a/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js +++ b/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js @@ -60,9 +60,7 @@ class ExportToCsvCommand extends Command { required: false, }), "team-uid": flags.string({ - description: 'Uid of the team whose user data and stack roles are required', - multiple: false, - required: false, + description: 'Uid of the team whose user data and stack roles are required' }) }; diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index 6d51e5fba3..cda5113610 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -8,7 +8,7 @@ const debug = require('debug')('export-to-csv'); const checkboxPlus = require('inquirer-checkbox-plus-prompt'); const config = require('./config.js'); const { cliux, configHandler, HttpClient } = require('@contentstack/cli-utilities'); -const _ = require('lodash'); +const {cloneDeep} = require('lodash'); const directory = './data'; const delimeter = os.platform() === 'win32' ? '\\' : '/'; @@ -727,7 +727,7 @@ async function exportOrgTeams(managementAPIClient, org) { do { const data = await apiRequestHandler(org, { skip: skip, limit: limit, includeUserDetails: true }); skip += limit; - teamsObjectArray = [...teamsObjectArray, ...data?.teams]; + teamsObjectArray.push(...data?.teams); if (skip > data?.count) break; } while (1); teamsObjectArray = await cleanTeamsData(teamsObjectArray, managementAPIClient, org); @@ -767,7 +767,7 @@ async function cleanTeamsData(data, managementAPIClient, org) { 'updatedByUserName', 'organizationUid', ]; - if (data?.length !== 0) { + if (data?.length) { data.forEach((team) => { fieldToBeDeleted.forEach((fields) => { delete team[fields]; @@ -783,23 +783,24 @@ async function cleanTeamsData(data, managementAPIClient, org) { team.Total_Members = team?.users?.length || 0; }); } else { - cliux.print(`info: There are no teams in the given org`); + cliux.print(`info: There are no teams in the given Organisation`); + return []; } return data; } async function exportTeams(managementAPIClient, organization, teamUid) { const allTeamsData = await exportOrgTeams(managementAPIClient, organization); - if (allTeamsData.length === 0) { - this.log(`There are not teams in the organization named ${organization?.name}`); + if (!allTeamsData?.length) { + console.log(`There are not teams in the organization named ${organization?.name}`); } else { - const modifiedTeam = _.cloneDeep(allTeamsData); + const modifiedTeam = cloneDeep(allTeamsData); modifiedTeam.forEach((team) => { delete team['users']; delete team['stackRoleMapping']; }); const fileName = `${kebabize(organization.name.replace(config.organizationNameRegex, ''))}_teams_export.csv`; - write(this, modifiedTeam, fileName, 'organization Team details'); + write(this, modifiedTeam, fileName, ' organization Team details'); // exporting teams user data or a single team user data await getTeamsDetail(allTeamsData,organization,teamUid); } @@ -838,8 +839,8 @@ async function getTeamsDetail(allTeamsData, organization ,teamUid) { async function getTeamsUserDetails(teamsObject) { const allTeamUsers = []; teamsObject.forEach((team) => { - if (team.users.length) { - team.users.forEach((user) => { + if (team?.users?.length) { + team?.users?.forEach((user) => { user['team-name'] = team.name; user['team-uid'] = team.uid; delete user['active']; From 9a01f3920652b2b2919e8a8bbeb5710b244f7dfb Mon Sep 17 00:00:00 2001 From: raj pandey Date: Mon, 23 Oct 2023 16:56:49 +0530 Subject: [PATCH 12/32] PR changes --- packages/contentstack-export-to-csv/src/util/index.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index cda5113610..e1138a3b43 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -782,17 +782,16 @@ async function cleanTeamsData(data, managementAPIClient, org) { } team.Total_Members = team?.users?.length || 0; }); + return data; } else { - cliux.print(`info: There are no teams in the given Organisation`); return []; } - return data; } async function exportTeams(managementAPIClient, organization, teamUid) { const allTeamsData = await exportOrgTeams(managementAPIClient, organization); if (!allTeamsData?.length) { - console.log(`There are not teams in the organization named ${organization?.name}`); + cliux.print(`info: There are not teams in the organization named ${organization?.name}`); } else { const modifiedTeam = cloneDeep(allTeamsData); modifiedTeam.forEach((team) => { @@ -840,7 +839,7 @@ async function getTeamsUserDetails(teamsObject) { const allTeamUsers = []; teamsObject.forEach((team) => { if (team?.users?.length) { - team?.users?.forEach((user) => { + team.users.forEach((user) => { user['team-name'] = team.name; user['team-uid'] = team.uid; delete user['active']; From 28ce26378b619d6912c89c77bc899feeb7d14dc6 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Mon, 23 Oct 2023 17:12:16 +0530 Subject: [PATCH 13/32] PR changes --- packages/contentstack-export-to-csv/src/util/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index e1138a3b43..d52b97d763 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -2,13 +2,13 @@ const os = require('os'); const fs = require('fs'); const mkdirp = require('mkdirp'); const find = require('lodash/find'); +const cloneDeep = require('lodash/cloneDeep'); const fastcsv = require('fast-csv'); const inquirer = require('inquirer'); const debug = require('debug')('export-to-csv'); const checkboxPlus = require('inquirer-checkbox-plus-prompt'); const config = require('./config.js'); const { cliux, configHandler, HttpClient } = require('@contentstack/cli-utilities'); -const {cloneDeep} = require('lodash'); const directory = './data'; const delimeter = os.platform() === 'win32' ? '\\' : '/'; @@ -728,7 +728,7 @@ async function exportOrgTeams(managementAPIClient, org) { const data = await apiRequestHandler(org, { skip: skip, limit: limit, includeUserDetails: true }); skip += limit; teamsObjectArray.push(...data?.teams); - if (skip > data?.count) break; + if (skip >= data?.count) break; } while (1); teamsObjectArray = await cleanTeamsData(teamsObjectArray, managementAPIClient, org); return teamsObjectArray; From 79b97f4c78edbce5026b58cf06c2094a1601d98b Mon Sep 17 00:00:00 2001 From: raj pandey Date: Mon, 23 Oct 2023 17:19:20 +0530 Subject: [PATCH 14/32] added examples --- .../src/commands/cm/export-to-csv.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js b/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js index 28523798a1..4b6eaf0fef 100644 --- a/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js +++ b/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js @@ -342,7 +342,16 @@ ExportToCsvCommand.examples = [ 'csdx cm:export-to-csv --action --org --org-name ', '', 'Exporting Organizations Teams to CSV', + 'csdx cm:export-to-csv --action ', + '', + 'Exporting Organizations Teams to CSV with org-uid', 'csdx cm:export-to-csv --action --org ', + '', + 'Exporting Organizations Teams to CSV with team uid', + 'csdx cm:export-to-csv --action --team-uid ', + '', + 'Exporting Organizations Teams to CSV with org-uid and team uid', + 'csdx cm:export-to-csv --action --org --team-uid ', ]; module.exports = ExportToCsvCommand; From c5a3f9ea8a8d07c776805c61392a22ba6728739c Mon Sep 17 00:00:00 2001 From: raj pandey Date: Mon, 23 Oct 2023 17:51:37 +0530 Subject: [PATCH 15/32] Modified the handle error message. Added common auth check and removed from switch statements --- .../src/commands/cm/export-to-csv.js | 27 +++++-------------- .../src/util/index.js | 10 ++----- 2 files changed, 9 insertions(+), 28 deletions(-) diff --git a/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js b/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js index 4b6eaf0fef..0f4f0aafd3 100644 --- a/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js +++ b/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js @@ -84,6 +84,12 @@ class ExportToCsvCommand extends Command { if (!managementTokenAlias) { managementAPIClient = await managementSDKClient({ host: this.cmaHost }); + if (!isAuthenticated()) { + this.error(config.CLI_EXPORT_CSV_ENTRIES_ERROR, { + exit: 2, + suggestions: ['https://www.contentstack.com/docs/developers/cli/authentication/'], + }); + } } if (actionFlag) { @@ -117,14 +123,6 @@ class ExportToCsvCommand extends Command { this.error('Provided management token alias not found in your config.!'); } else { let organization; - - if (!isAuthenticated()) { - this.error(config.CLI_EXPORT_CSV_ENTRIES_ERROR, { - exit: 2, - suggestions: ['https://www.contentstack.com/docs/developers/cli/authentication/'], - }); - } - if (org) { organization = { uid: org }; } else { @@ -231,12 +229,6 @@ class ExportToCsvCommand extends Command { case config.exportUsers: case 'users': { try { - if (!isAuthenticated()) { - this.error(config.CLI_EXPORT_CSV_LOGIN_FAILED, { - exit: 2, - suggestions: ['https://www.contentstack.com/docs/developers/cli/authentication/'], - }); - } let organization; if (org) { @@ -265,12 +257,7 @@ class ExportToCsvCommand extends Command { case config.exportTeams: case 'teams': { try{ - if (!isAuthenticated()) { - this.error(config.CLI_EXPORT_CSV_LOGIN_FAILED, { - exit: 2, - suggestions: ['https://www.contentstack.com/docs/developers/cli/authentication/'], - }); - } + let organization; if (org) { diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index d52b97d763..740a923e2e 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -684,16 +684,10 @@ function wait(time) { } function handleErrorMsg(err) { - if (err?.errorMessage) { - cliux.print(`Error: ${err.errorMessage}`, { color: 'red' }); - } else if (err?.message) { - cliux.print(`Error: ${err.message}`, { color: 'red' }); - } else { - console.log(err); - cliux.print(`Error: ${messageHandler.parse('CLI_EXPORT_CSV_API_FAILED')}`, { color: 'red' }); - } + cliux.print(`Error: ${err?.errorMessage ? err?.message: messageHandler.parse('CLI_EXPORT_CSV_API_FAILED')}`, { color: 'red' }); process.exit(1); } + async function apiRequestHandler(org, queryParam = {}) { const headers = { authtoken: configHandler.get('authtoken'), From 39bb23e76f38e0e9b753bdd871b4913b9ecaf6f2 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Tue, 24 Oct 2023 12:04:13 +0530 Subject: [PATCH 16/32] added optional chaining and comments --- .../src/util/index.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index e45700b888..c1aa71cff6 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -699,13 +699,13 @@ async function apiRequestHandler(org, queryParam = {}) { return await new HttpClient() .headers(headers) .queryParams(queryParam) - .get(`${configHandler.get('region')?.cma}/organizations/${org.uid}/teams`) + .get(`${configHandler.get('region')?.cma}/organizations/${org?.uid}/teams`) .then((res) => { const { status, data } = res; if (status === 200) { return data; } else { - cliux.print(`${data.error_message || data.message || data.errorMessage}`, { color: 'red' }); + cliux.print(`${data?.error_message || data?.message || data?.errorMessage}`, { color: 'red' }); process.exit(1); } }) @@ -717,7 +717,7 @@ async function apiRequestHandler(org, queryParam = {}) { async function exportOrgTeams(managementAPIClient, org) { let teamsObjectArray = []; let skip = 0; - let limit = config.limit || 100; + let limit = config?.limit || 100; do { const data = await apiRequestHandler(org, { skip: skip, limit: limit, includeUserDetails: true }); skip += limit; @@ -796,6 +796,7 @@ async function exportTeams(managementAPIClient, organization, teamUid) { write(this, modifiedTeam, fileName, ' organization Team details'); // exporting teams user data or a single team user data await getTeamsDetail(allTeamsData,organization,teamUid); + // Exporting the stack Role data for all the teams or exporting stack role data for a single team await exportRoleMappings(managementAPIClient, allTeamsData, teamUid); } } @@ -843,8 +844,8 @@ async function exportRoleMappings(managementAPIClient, allTeamsData, teamUid) { } } const fileName = `${kebabize( - "All_Teams_Role_Mapping".replace(config.organizationNameRegex, ''), - )}.csv`; + "Stack_Role_Mapping".replace(config.organizationNameRegex, ''), + )}${teamUid?teamUid:""}.csv`; write(this, stackRoleWithTeamData, fileName, 'Team Stack Role details'); } @@ -853,7 +854,7 @@ async function mapRoleWithTeams(managementAPIClient, stackRoleMapping, teamName, const Stack = await getStackData(managementAPIClient, stackRoleMapping.stackApiKey); const stackRole = {}; const roles = await Stack.role().fetchAll() - roles?.items?.forEach((role) => { + roles?.items.forEach((role) => { if(!stackRole.hasOwnProperty(role?.uid)){ stackRole[role?.uid] = role?.name; } @@ -868,15 +869,15 @@ async function mapRoleWithTeams(managementAPIClient, stackRoleMapping, teamName, stackRoleMap['Role Name'] = stackRole[role] stackRoleMap['Role Uid'] = role; stackRoleMapOfTeam.push(stackRoleMap); - }) + }); - // console.log(stackRole); return stackRoleMapOfTeam; } async function getStackData(managementAPIClient, stackApiKey) { return await managementAPIClient.stack({ api_key: stackApiKey }).fetch(); } + async function getTeamsUserDetails(teamsObject) { const allTeamUsers = []; teamsObject.forEach((team) => { From bc06695c18d5ef3a321ca547bf74a242192e4332 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Wed, 25 Oct 2023 10:35:21 +0530 Subject: [PATCH 17/32] added text message before exporting the teams --- packages/contentstack-export-to-csv/src/util/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index c1aa71cff6..07a004b7cb 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -783,6 +783,7 @@ async function cleanTeamsData(data, managementAPIClient, org) { } async function exportTeams(managementAPIClient, organization, teamUid) { + cliux.print(`info: Exporting the ${teamUid && organization?.name? `team with uid ${teamUid} in Organisation ${organization?.name} `:`teams of Organisation `+organization?.name}`, {color: "green"}); const allTeamsData = await exportOrgTeams(managementAPIClient, organization); if (!allTeamsData?.length) { cliux.print(`info: There are not teams in the organization named ${organization?.name}`); @@ -795,7 +796,9 @@ async function exportTeams(managementAPIClient, organization, teamUid) { const fileName = `${kebabize(organization.name.replace(config.organizationNameRegex, ''))}_teams_export.csv`; write(this, modifiedTeam, fileName, ' organization Team details'); // exporting teams user data or a single team user data + cliux.print(`info: Exporting the teams user data for ${teamUid?`Team `+teamUid:`Organisation `+organization?.name}`, {color: "green"}); await getTeamsDetail(allTeamsData,organization,teamUid); + cliux.print(`info: Exporting the Stack Role Details for ${teamUid?`Team `+teamUid:`Organisation `+organization?.name}`,{color: "green"}); // Exporting the stack Role data for all the teams or exporting stack role data for a single team await exportRoleMappings(managementAPIClient, allTeamsData, teamUid); } From ab58e7308e192ab70a9d15cb81ee41c082408ecd Mon Sep 17 00:00:00 2001 From: raj pandey Date: Wed, 25 Oct 2023 12:27:10 +0530 Subject: [PATCH 18/32] used map in exporting the role mapping, changed the color of message displayed, and corrected the handle error message function --- .../src/util/index.js | 56 ++++++++++++------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index 07a004b7cb..cfbe8fdf45 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -684,7 +684,7 @@ function wait(time) { } function handleErrorMsg(err) { - cliux.print(`Error: ${err?.errorMessage ? err?.message: messageHandler.parse('CLI_EXPORT_CSV_API_FAILED')}`, { color: 'red' }); + cliux.print(`Error: ${(err?.errorMessage || err?.message) ? err?.errorMessage || err?.message : messageHandler.parse('CLI_EXPORT_CSV_API_FAILED')}`, { color: 'red' }) process.exit(1); } @@ -783,7 +783,14 @@ async function cleanTeamsData(data, managementAPIClient, org) { } async function exportTeams(managementAPIClient, organization, teamUid) { - cliux.print(`info: Exporting the ${teamUid && organization?.name? `team with uid ${teamUid} in Organisation ${organization?.name} `:`teams of Organisation `+organization?.name}`, {color: "green"}); + cliux.print( + `info: Exporting the ${ + teamUid && organization?.name + ? `team with uid ${teamUid} in Organisation ${organization?.name} ` + : `teams of Organisation ` + organization?.name + }`, + { color: 'blue' }, + ); const allTeamsData = await exportOrgTeams(managementAPIClient, organization); if (!allTeamsData?.length) { cliux.print(`info: There are not teams in the organization named ${organization?.name}`); @@ -796,9 +803,17 @@ async function exportTeams(managementAPIClient, organization, teamUid) { const fileName = `${kebabize(organization.name.replace(config.organizationNameRegex, ''))}_teams_export.csv`; write(this, modifiedTeam, fileName, ' organization Team details'); // exporting teams user data or a single team user data - cliux.print(`info: Exporting the teams user data for ${teamUid?`Team `+teamUid:`Organisation `+organization?.name}`, {color: "green"}); - await getTeamsDetail(allTeamsData,organization,teamUid); - cliux.print(`info: Exporting the Stack Role Details for ${teamUid?`Team `+teamUid:`Organisation `+organization?.name}`,{color: "green"}); + cliux.print( + `info: Exporting the teams user data for ${teamUid ? `Team ` + teamUid : `Organisation ` + organization?.name}`, + { color: 'blue' }, + ); + await getTeamsDetail(allTeamsData, organization, teamUid); + cliux.print( + `info: Exporting the Stack Role Details for ${ + teamUid ? `Team ` + teamUid : `Organisation ` + organization?.name + }`, + { color: 'blue' }, + ); // Exporting the stack Role data for all the teams or exporting stack role data for a single team await exportRoleMappings(managementAPIClient, allTeamsData, teamUid); } @@ -832,7 +847,7 @@ async function getTeamsDetail(allTeamsData, organization, teamUid) { async function exportRoleMappings(managementAPIClient, allTeamsData, teamUid) { let stackRoleWithTeamData = []; - if(teamUid) { + if (teamUid) { const team = allTeamsData.filter((team) => team?.uid === teamUid)[0]; for (const stack of team?.stackRoleMapping) { const roleData = await mapRoleWithTeams(managementAPIClient, stack, team?.name, team?.uid); @@ -846,9 +861,9 @@ async function exportRoleMappings(managementAPIClient, allTeamsData, teamUid) { } } } - const fileName = `${kebabize( - "Stack_Role_Mapping".replace(config.organizationNameRegex, ''), - )}${teamUid?teamUid:""}.csv`; + const fileName = `${kebabize('Stack_Role_Mapping'.replace(config.organizationNameRegex, ''))}${ + teamUid ? teamUid : '' + }.csv`; write(this, stackRoleWithTeamData, fileName, 'Team Stack Role details'); } @@ -856,22 +871,21 @@ async function exportRoleMappings(managementAPIClient, allTeamsData, teamUid) { async function mapRoleWithTeams(managementAPIClient, stackRoleMapping, teamName, teamUid) { const Stack = await getStackData(managementAPIClient, stackRoleMapping.stackApiKey); const stackRole = {}; - const roles = await Stack.role().fetchAll() + const roles = await Stack.role().fetchAll(); roles?.items.forEach((role) => { - if(!stackRole.hasOwnProperty(role?.uid)){ + if (!stackRole.hasOwnProperty(role?.uid)) { stackRole[role?.uid] = role?.name; } }); - let stackRoleMapOfTeam = []; - stackRoleMapping?.roles.forEach((role)=>{ - let stackRoleMap = {}; - stackRoleMap['Team Name'] = teamName; - stackRoleMap['Team Uid'] = teamUid; - stackRoleMap['Stack Name'] = Stack?.name; - stackRoleMap['Stack Uid'] = Stack?.uid; - stackRoleMap['Role Name'] = stackRole[role] - stackRoleMap['Role Uid'] = role; - stackRoleMapOfTeam.push(stackRoleMap); + const stackRoleMapOfTeam = stackRoleMapping?.roles.map((role) => { + return { + 'Team Name': teamName, + 'Team Uid': teamUid, + 'Stack Name': Stack?.name, + 'Stack Uid': Stack?.uid, + 'Role Name': stackRole[role], + 'Role Uid': role, + }; }); return stackRoleMapOfTeam; From 0b23fad803e6751fb4a8ae31f5d93bc567a41e94 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Wed, 25 Oct 2023 12:31:32 +0530 Subject: [PATCH 19/32] corrected the error message --- packages/contentstack-export-to-csv/src/util/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index 740a923e2e..40bbd9d9e1 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -684,7 +684,7 @@ function wait(time) { } function handleErrorMsg(err) { - cliux.print(`Error: ${err?.errorMessage ? err?.message: messageHandler.parse('CLI_EXPORT_CSV_API_FAILED')}`, { color: 'red' }); + cliux.print(`Error: ${(err?.errorMessage || err?.message) ? err?.errorMessage || err?.message : messageHandler.parse('CLI_EXPORT_CSV_API_FAILED')}`, { color: 'red' }) process.exit(1); } From 88c98f815bab212202f0229667eb3c4997ec5dca Mon Sep 17 00:00:00 2001 From: raj pandey Date: Wed, 25 Oct 2023 17:41:26 +0530 Subject: [PATCH 20/32] used loadash find method and handled iteration over empty array --- packages/contentstack-export-to-csv/src/util/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index cfbe8fdf45..67e2b4a5f4 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -848,14 +848,14 @@ async function getTeamsDetail(allTeamsData, organization, teamUid) { async function exportRoleMappings(managementAPIClient, allTeamsData, teamUid) { let stackRoleWithTeamData = []; if (teamUid) { - const team = allTeamsData.filter((team) => team?.uid === teamUid)[0]; + const team = find(allTeamsData,function(teamObject) { return teamObject?.uid===teamUid }); for (const stack of team?.stackRoleMapping) { const roleData = await mapRoleWithTeams(managementAPIClient, stack, team?.name, team?.uid); stackRoleWithTeamData.push(...roleData); } } else { - for (const team of allTeamsData) { - for (const stack of team?.stackRoleMapping) { + for (const team of allTeamsData || []) { + for (const stack of team?.stackRoleMapping || []) { const roleData = await mapRoleWithTeams(managementAPIClient, stack, team?.name, team?.uid); stackRoleWithTeamData.push(...roleData); } From d4d64d35de82072376d7ae5883c784d9b45a3b9e Mon Sep 17 00:00:00 2001 From: raj pandey Date: Wed, 25 Oct 2023 17:50:48 +0530 Subject: [PATCH 21/32] used Nullish coalescing operator --- packages/contentstack-export-to-csv/src/util/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index 67e2b4a5f4..91f99d2988 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -854,8 +854,8 @@ async function exportRoleMappings(managementAPIClient, allTeamsData, teamUid) { stackRoleWithTeamData.push(...roleData); } } else { - for (const team of allTeamsData || []) { - for (const stack of team?.stackRoleMapping || []) { + for (const team of allTeamsData ?? []) { + for (const stack of team?.stackRoleMapping ?? []) { const roleData = await mapRoleWithTeams(managementAPIClient, stack, team?.name, team?.uid); stackRoleWithTeamData.push(...roleData); } From b295e85968b0c207ab2a12f05131f3f57b30b8f1 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Thu, 26 Oct 2023 10:03:47 +0530 Subject: [PATCH 22/32] Replaced getStack SDK call with getRole SDK call --- .../src/commands/cm/export-to-csv.js | 5 +---- .../contentstack-export-to-csv/src/util/index.js | 12 ++++++------ 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js b/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js index 0f4f0aafd3..34669b3adb 100644 --- a/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js +++ b/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js @@ -257,17 +257,14 @@ class ExportToCsvCommand extends Command { case config.exportTeams: case 'teams': { try{ - let organization; - if (org) { organization = { uid: org, name: orgName || org }; } else { organization = await util.chooseOrganization(managementAPIClient, action); // prompt for organization } - + await util.exportTeams(managementAPIClient,organization,teamUid); - } catch (error) { if (error.message || error.errorMessage) { cliux.error(util.formatError(error)); diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index 91f99d2988..e2625d324b 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -869,20 +869,20 @@ async function exportRoleMappings(managementAPIClient, allTeamsData, teamUid) { } async function mapRoleWithTeams(managementAPIClient, stackRoleMapping, teamName, teamUid) { - const Stack = await getStackData(managementAPIClient, stackRoleMapping.stackApiKey); + const roles = await getRoleData(managementAPIClient, stackRoleMapping.stackApiKey); const stackRole = {}; - const roles = await Stack.role().fetchAll(); roles?.items.forEach((role) => { if (!stackRole.hasOwnProperty(role?.uid)) { stackRole[role?.uid] = role?.name; + stackRole[role?.stack?.api_key] = {name: role?.stack?.name, uid: role?.stack?.uid } } }); const stackRoleMapOfTeam = stackRoleMapping?.roles.map((role) => { return { 'Team Name': teamName, 'Team Uid': teamUid, - 'Stack Name': Stack?.name, - 'Stack Uid': Stack?.uid, + 'Stack Name': stackRole[stackRoleMapping?.stackApiKey]?.name, + 'Stack Uid': stackRole[stackRoleMapping?.stackApiKey]?.uid, 'Role Name': stackRole[role], 'Role Uid': role, }; @@ -891,8 +891,8 @@ async function mapRoleWithTeams(managementAPIClient, stackRoleMapping, teamName, return stackRoleMapOfTeam; } -async function getStackData(managementAPIClient, stackApiKey) { - return await managementAPIClient.stack({ api_key: stackApiKey }).fetch(); +async function getRoleData(managementAPIClient, stackApiKey) { + return await managementAPIClient.stack({ api_key: stackApiKey }).role().fetchAll(); } async function getTeamsUserDetails(teamsObject) { From 33fc0a4d0f83d1d9762d3c0ed1e44b87fa370b79 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Thu, 26 Oct 2023 14:10:23 +0530 Subject: [PATCH 23/32] added prompt --- packages/contentstack-export-to-csv/src/util/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index e2625d324b..cec5a1b49e 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -464,7 +464,7 @@ function startupQuestions() { type: 'list', name: 'action', message: 'Choose Action', - choices: [config.exportEntries, config.exportUsers, 'Exit'], + choices: [config.exportEntries, config.exportUsers, config.exportTeams, 'Exit'], }, ]; inquirer From 16440ae24ef4f8a0e0d64fb18280832f0347404c Mon Sep 17 00:00:00 2001 From: raj pandey Date: Thu, 26 Oct 2023 14:14:01 +0530 Subject: [PATCH 24/32] pr changes --- .../src/util/index.js | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index 40bbd9d9e1..b96277b591 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -3,6 +3,7 @@ const fs = require('fs'); const mkdirp = require('mkdirp'); const find = require('lodash/find'); const cloneDeep = require('lodash/cloneDeep'); +const omit = require('lodash/omit'); const fastcsv = require('fast-csv'); const inquirer = require('inquirer'); const debug = require('debug')('export-to-csv'); @@ -762,21 +763,18 @@ async function cleanTeamsData(data, managementAPIClient, org) { 'organizationUid', ]; if (data?.length) { - data.forEach((team) => { - fieldToBeDeleted.forEach((fields) => { - delete team[fields]; - }); - if (!team.hasOwnProperty('description')) { - team.description = ''; - } - if (team.organizationRole === roleMap['member']) { - team.organizationRole = 'member'; - } else { - team.organizationRole = 'admin'; + return data.map((team) => { + team = omit(team, fieldToBeDeleted); + + team.organizationRole = team.organizationRole === roleMap["member"] ? "member" : "admin"; + + if (!team.hasOwnProperty("description")) { + team.description = ""; } team.Total_Members = team?.users?.length || 0; + + return team; }); - return data; } else { return []; } From d1719b4a4988c71e3452ebc82cf7a349a1f8449b Mon Sep 17 00:00:00 2001 From: raj pandey Date: Mon, 30 Oct 2023 17:22:39 +0530 Subject: [PATCH 25/32] added unit test case for teams in export-to-csv --- .../src/util/index.js | 2 +- .../test/mock-data/common.mock.json | 422 ++++++++++++++++++ .../test/unit/commands/export-to-csv.test.js | 351 ++++++--------- 3 files changed, 562 insertions(+), 213 deletions(-) create mode 100644 packages/contentstack-export-to-csv/test/mock-data/common.mock.json diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index 16ab4eb32b..44633bbd8c 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -869,7 +869,7 @@ async function exportRoleMappings(managementAPIClient, allTeamsData, teamUid) { async function mapRoleWithTeams(managementAPIClient, stackRoleMapping, teamName, teamUid) { const roles = await getRoleData(managementAPIClient, stackRoleMapping.stackApiKey); const stackRole = {}; - roles?.items.forEach((role) => { + roles?.items?.forEach((role) => { if (!stackRole.hasOwnProperty(role?.uid)) { stackRole[role?.uid] = role?.name; stackRole[role?.stack?.api_key] = {name: role?.stack?.name, uid: role?.stack?.uid } diff --git a/packages/contentstack-export-to-csv/test/mock-data/common.mock.json b/packages/contentstack-export-to-csv/test/mock-data/common.mock.json new file mode 100644 index 0000000000..48d9f7630a --- /dev/null +++ b/packages/contentstack-export-to-csv/test/mock-data/common.mock.json @@ -0,0 +1,422 @@ +{ + "taxonomiesResp": { + "taxonomies": [ + { + "uid": "taxonomy_uid_1", + "name": "taxonomy uid 1", + "description": "", + "created_at": "2023-09-01T06:09:44.934Z", + "created_by": "user1", + "updated_at": "2023-09-01T06:44:16.604Z", + "updated_by": "user1" + }, + { + "uid": "taxonomy_uid_2", + "name": "taxonomy uid 2", + "description": "", + "created_at": "2023-09-01T06:09:44.934Z", + "created_by": "user1", + "updated_at": "2023-09-01T06:44:16.604Z", + "updated_by": "user1" + } + ], + "count": 2 + }, + "termsResp": { + "terms": [ + { + "uid": "wsq", + "name": "wsq", + "created_at": "2023-08-30T09:51:12.043Z", + "created_by": "user1", + "updated_at": "2023-08-30T09:51:12.043Z", + "updated_by": "user1", + "parent_uid": null, + "depth": 1 + }, + { + "uid": "term2", + "name": "term2", + "created_at": "2023-08-30T09:45:11.963Z", + "created_by": "user2", + "updated_at": "2023-08-30T09:45:11.963Z", + "updated_by": "user2", + "parent_uid": null, + "depth": 1 + } + ], + "count": 2 + }, + "organizations": [ + { + "uid": "test-uid-1", + "name": "test org 1" + }, + { + "uid": "test-uid-2", + "name": "test org 2" + }, + { + "uid": "org_uid_1_teams", + "name": "Teams Org" + } + ], + "stacks": [ + { + "name": "Stack 1", + "uid": "stack-uid-1", + "api_key": "stack_api_key_1" + }, + { + "name": "Stack 2", + "uid": "stack-uid-2", + "api_key": "stack_api_key_2" + } + ], + "users": [ + { + "uid": "uid1", + "email": "test@gmail.abc", + "user_uid": "user1", + "org_uid": "test-uid-1", + "invited_by": "user2", + "invited_at": "2023-08-21T11:08:41.038Z", + "status": "accepted", + "acceptance_token": "dfghdfgd", + "created_at": "2023-08-21T11:08:41.036Z", + "updated_at": "2023-08-21T11:09:11.342Z", + "urlPath": "/user", + "organizations": [ + { + "uid": "test-uid-1", + "name": "test org 1", + "org_roles": [ + { + "uid": "role1", + "name": "Admin", + "description": "Admin Role", + "org_uid": "test-uid-1", + "admin": true, + "default": true + } + ] + } + ] + }, + { + "uid": "test-uid-2", + "name": "test org 2" + }, + { + "uid": "uid2", + "email": "test@gmail.abc", + "user_uid": "user2", + "org_uid": "test-uid-2", + "invited_by": "user3", + "invited_at": "2023-08-21T11:08:41.038Z", + "status": "accepted", + "acceptance_token": "thor", + "created_at": "2023-08-21T11:08:41.036Z", + "updated_at": "2023-08-21T11:09:11.342Z", + "urlPath": "/user", + "organizations": [ + { + "uid": "org_uid_1_teams", + "name": "Teams Org", + "org_roles": [ + { + "uid": "role1", + "name": "Admin", + "description": "Admin Role", + "org_uid": "test-uid-1", + "admin": true, + "default": true + } + ] + } + ] + } + ], + "roles": [ + { + "urlPath": "/roles/role1", + "uid": "role1", + "name": "admin", + "description": "The Admin role has rights to add/remove users from an organization, and has access to stacks created by self or shared by others.", + "org_uid": "test-uid-1", + "owner_uid": "user1", + "admin": true, + "default": true, + "users": ["user2", "user3"], + "created_at": "2023-08-08T10:09:43.445Z", + "updated_at": "2023-08-21T11:08:41.042Z" + } + ], + "contentTypes": [ + { + "stackHeaders": { + "api_key": "stack_api_key_1" + }, + "urlPath": "/content_types/ct1", + "created_at": "2023-08-08T13:52:31.980Z", + "updated_at": "2023-08-08T13:52:34.265Z", + "title": "CT 1", + "uid": "ct_1", + "_version": 2, + "inbuilt_class": false, + "schema": [ + { + "data_type": "text", + "display_name": "Title", + "field_metadata": { + "_default": true, + "version": 3 + }, + "mandatory": true, + "uid": "title", + "unique": true, + "multiple": false, + "non_localizable": false + } + ] + }, + { + "stackHeaders": { + "api_key": "stack_api_key_1" + }, + "urlPath": "/content_types/ct2", + "created_at": "2023-08-08T13:52:31.980Z", + "updated_at": "2023-08-08T13:52:34.265Z", + "title": "CT 2", + "uid": "ct_2", + "_version": 2, + "inbuilt_class": false, + "schema": [ + { + "data_type": "text", + "display_name": "Title", + "field_metadata": { + "_default": true, + "version": 3 + }, + "mandatory": true, + "uid": "title", + "unique": true, + "multiple": false, + "non_localizable": false + } + ] + } + ], + "branch": { + "stackHeaders": { + "api_key": "stack_api_key_1" + }, + "urlPath": "/stacks/branches/test_branch1", + "uid": "test_branch1", + "source": "", + "created_by": "user1", + "updated_by": "user1", + "created_at": "2023-08-08T13:51:43.217Z", + "updated_at": "2023-08-08T13:51:43.217Z", + "deleted_at": false + }, + "entry": [ + { + "stackHeaders": { + "api_key": "stack_api_key_1" + }, + "content_type_uid": "home", + "urlPath": "/content_types/ct1/entries/test_entry1", + "title": "Test Entry1", + "url": "/", + "tags": [], + "locale": "en1", + "uid": "test_entry1", + "created_by": "user1", + "updated_by": "user1", + "created_at": "2023-08-08T13:52:46.592Z", + "updated_at": "2023-08-08T13:52:46.592Z", + "_version": 1 + } + ], + "environments": [ + { + "stackHeaders": { + "api_key": "stack_api_key_1" + }, + "urlPath": "/environments/development", + "urls": [ + { + "url": "http://localhost:3000/", + "locale": "en1" + } + ], + "name": "development", + "_version": 3, + "uid": "env1", + "created_by": "user1", + "updated_by": "user1", + "created_at": "2023-06-12T18:59:56.853Z", + "updated_at": "2023-06-12T18:59:56.853Z" + } + ], + "locales": [ + { + "code": "en1", + "name": "English - En", + "fallback_locale": "en-us", + "uid": "gsfdasgdf", + "created_at": "2023-09-11T10:44:40.213Z", + "updated_at": "2023-09-11T10:44:40.213Z", + "ACL": [], + "_version": 1 + } + ], + "Teams": { + "emptyTeam": [], + "allTeams": { + "count": 1, + "teams": [ + { + "_id": "team_1_uid", + "name": "Test_Team_1", + + + + + "organizationUid": "org_uid_1_teams", + "users": [], + "stackRoleMapping": [ + { + "stackApiKey": "stack_api_key", + "roles": ["role_uid_1"] + } + ], + "organizationRole": "org_role_uid_1", + + "uid": "team_1_uid", + "createdByUserName": "team_creator", + "updatedByUserName": "team_creator" + } + ] + } + }, + "roless": { + "roles": [{ + "name": "Developer", + "description": "Developer can perform all Content Manager's actions, view audit logs, create roles, invite users, manage content types, languages, and environments.", + "uid": "stack_role_uid_3", + "users": [], + "owner": "ownerEmail@domain.com", + "stack": { + + + "uid": "stack_uid", + "name": "CLI Test", + "org_uid": "org_uid_1_teams", + "api_key": "stack_api_key", + "master_locale": "en-us", + + "owner_uid": "team_owner_uid", + "user_uids": ["team_owner_uid"] + }, + "SYS_ACL": {} + }, + { + "name": "Content Manager", + "description": "Content Managers can view all content types, manage entries and assets. They cannot edit content types or access stack settings.", + "uid": "stack_role_uid_1", + + "updated_by": "team_owner_uid", + + + "owner": "ownerEmail@domain.com", + "stack": { + + + "uid": "stack_uid", + "name": "CLI Test", + "org_uid": "org_uid_1_teams", + "api_key": "stack_api_key", + "master_locale": "en-us", + + "owner_uid": "team_owner_uid", + "user_uids": ["team_owner_uid"] + }, + "SYS_ACL": {} + }, + { + "name": "Admin", + "description": "Admin can perform all actions and manage all settings of the stack, except the ability to delete or transfer ownership of the stack.", + "uid": "role_uid_1", + + + + "updated_at": "2023-10-26T04:44:51.529Z", + "users": [], + "owner": "ownerEmail@domain.com", + "stack": { + + + "uid": "stack_uid", + "name": "CLI Test", + "org_uid": "org_uid_1_teams", + "api_key": "stack_api_key", + "master_locale": "en-us", + + "owner_uid": "team_owner_uid", + "user_uids": ["team_owner_uid"] + }, + "SYS_ACL": {} + }, + { + "name": "Custom_Role_1", + "description": "", + "users": [], + "uid": "stack_role_uid_2", + + "updated_by": "team_owner_uid", + + + "owner": "ownerEmail@domain.com", + "stack": { + + + "uid": "stack_uid", + "name": "CLI Test", + "org_uid": "org_uid_1_teams", + "api_key": "stack_api_key", + "master_locale": "en-us", + + "owner_uid": "team_owner_uid", + "user_uids": ["team_owner_uid"] + }, + "SYS_ACL": {} + } +]}, + "org_roles": { + "roles": [ + { + "uid": "org_role_uid_1", + "name": "admin", + "description": "The Admin role has rights to add/remove users from an organization, and has access to stacks created by self or shared by others.", + "org_uid": "org_uid_1_teams", + "owner_uid": "org_owner_uid", + "admin": true, + "default": true, + "users": ["user_1_uid", "org_owner_uid", "user_2_uid"] + }, + { + "uid": "org_role_uid_2", + "name": "member", + "description": "The Member role has access only to the stacks created by or shared with him/her, and does not have access to organization settings.", + "org_uid": "org_uid_1_teams", + "owner_uid": "org_owner_uid", + "admin": false, + "default": true, + "users": ["user_1_uid_member", "user_2_uid_member", "user_3_uid_member", "user_4_uid_member"] + } + ] + } +} diff --git a/packages/contentstack-export-to-csv/test/unit/commands/export-to-csv.test.js b/packages/contentstack-export-to-csv/test/unit/commands/export-to-csv.test.js index d2415f7179..d03877b643 100644 --- a/packages/contentstack-export-to-csv/test/unit/commands/export-to-csv.test.js +++ b/packages/contentstack-export-to-csv/test/unit/commands/export-to-csv.test.js @@ -5,215 +5,142 @@ const { stub, assert } = require('sinon'); const { config } = require('dotenv'); const inquirer = require('inquirer'); const { cliux } = require('@contentstack/cli-utilities'); - -config(); - -describe('Export to csv command with action = entries', () => { - let inquireStub; - let errorStub; - let consoleLogStub; - - beforeEach(() => { - inquireStub = stub(inquirer, 'prompt'); - errorStub = stub(cliux, 'error'); - consoleLogStub = stub(cliux, 'print'); - }); - - afterEach(() => { - inquireStub.restore(); - errorStub.restore(); - consoleLogStub.restore(); - }); - - it('Should ask for action when action is not passed (entries or users)', async () => { - await ExportToCsvCommand.run([]); - assert.calledOnce(inquireStub); - }); - - it('Should ask for org when org is not passed', async () => { - const args = ['--action', 'entries']; - await ExportToCsvCommand.run(args); - assert.calledOnce(inquireStub); - }); - - it('Should ask for stack when stack api key flag is not passed', async (done) => { - const args = ['--action', 'entries', '--org', process.env.ORG]; - done(); - await ExportToCsvCommand.run(args); - assert.calledOnce(inquireStub); - }); - - it('Should ask for branch when branch flag is not passed', async () => { - const args = ['--action', 'entries', '--org', process.env.ORG, '--stack-api-key', process.env.STACK]; - await ExportToCsvCommand.run(args); - assert.calledTwice(inquireStub); - }); - - it('Should throw an error if stack does not have branches enabled', async () => { - const args = [ - '--action', - 'entries', - '--org', - process.env.ORG_WITH_NO_BRANCHES, - '--stack-api-key', - process.env.STACK_WITH_ORG_WITH_NO_BRANCHES, - '--branch', - 'invalid', - ]; - await ExportToCsvCommand.run(args); - assert.calledWith( - errorStub, - 'Branches are not part of your plan. Please contact support@contentstack.com to upgrade your plan.', - ); - }); - - it('Should ask for content type when content type flag is not passed', async () => { - const args = [ - '--action', - 'entries', - '--org', - process.env.ORG, - '--stack-api-key', - process.env.STACK, - '--branch', - process.env.BRANCH, - ]; - await ExportToCsvCommand.run(args); - assert.calledOnce(inquireStub); - }); - - it('Should create a file starting with the name passed as stack-name flag', async () => { - const args = [ - '--action', - 'entries', - '--org', - process.env.ORG, - '--stack-api-key', - process.env.STACK, - '--branch', - process.env.BRANCH, - '--content-type', - 'page', - '--locale', - 'en-us', - '--stack-name', - 'okok', - ]; - await ExportToCsvCommand.run(args); - assert.calledWith(consoleLogStub, `Writing entries to file: ${process.cwd()}/okok_page_en-us_entries_export.csv`); - }); - - it('Should throw an error when invalid org is passed', async () => { - const args = ['--action', 'entries', '--org', 'invalid']; - await ExportToCsvCommand.run(args); - assert.calledWith(errorStub, `Couldn't find the organization. Please check input parameters.`); - }); - - it('Should throw an error when invalid stack is passed', async () => { - const args = ['--action', 'entries', '--org', process.env.ORG, '--stack-api-key', 'invalid']; - await ExportToCsvCommand.run(args); - assert.calledWith(errorStub, 'Could not find stack'); - }); - - it('Should throw an error when invalid branch is passed', async () => { - const args = [ - '--action', - 'entries', - '--org', - process.env.ORG, - '--stack-api-key', - process.env.STACK, - '--branch', - process.env.INVALID_BRANCH, - ]; - await ExportToCsvCommand.run(args); - assert.calledWith(errorStub, 'Failed to fetch Branch. Please try again with valid parameters.'); - }); - - it('Should throw an error when invalid contenttype is passed', async () => { - const args = [ - '--action', - 'entries', - '--org', - process.env.ORG, - '--stack-api-key', - process.env.STACK, - '--branch', - process.env.BRANCH, - '--content-type', - 'invalid', - '--locale', - 'en-us', - ]; - await ExportToCsvCommand.run(args); - assert.calledWith( - errorStub, - `The Content Type invalid was not found. Please try again. Content Type is not valid.`, - ); - }); - - it('Should throw an error when invalid locale is passed', async () => { - const args = [ - '--action', - 'entries', - '--org', - process.env.ORG, - '--stack-api-key', - process.env.STACK, - '--branch', - process.env.BRANCH, - '--content-type', - 'header', - '--locale', - 'invalid', - ]; - await ExportToCsvCommand.run(args); - assert.calledWith(errorStub, 'Language was not found. Please try again.'); - }); -}); - -describe('Export to csv command with action = users', () => { - let inquireStub; - let errorStub; - let consoleLogStub; - - beforeEach(() => { - inquireStub = stub(inquirer, 'prompt'); - errorStub = stub(cliux, 'error'); - consoleLogStub = stub(cliux, 'print'); - }); - - afterEach(() => { - inquireStub.restore(); - errorStub.restore(); - consoleLogStub.restore(); - }); - - it('Should ask for org when org is not passed', async () => { - const args = ['--action', 'entries']; - await ExportToCsvCommand.run(args); - assert.calledOnce(inquireStub); - }); - - it('Should write users data to file if the user has permissions', async () => { - const args = ['--action', 'users', '--org', process.env.ORG]; - - await ExportToCsvCommand.run(args); - assert.calledWith( - consoleLogStub, - `Writing organization details to file: ${process.cwd()}/${process.env.ORG}_users_export.csv`, - ); - }); - - it('Should show an error that user does not have org permissions to perform the operation if user enters such org', async () => { - const args = ['--action', 'users', '--org', process.env.ORG_WITH_NO_PERMISSION]; - await ExportToCsvCommand.run(args); - assert.calledWith(errorStub, `You don't have the permission to do this operation.`); - }); - - it('Should create a file starting with the name passed as org-name flag', async () => { - const args = ['--action', 'users', '--org', process.env.ORG, '--org-name', 'okok']; - await ExportToCsvCommand.run(args); - assert.calledWith(consoleLogStub, `Writing organization details to file: ${process.cwd()}/okok_users_export.csv`); - }); -}); +const mockData = require('../../mock-data/common.mock.json'); +const { test, expect } = require('@oclif/test'); +const fs = require('fs'); +const mkdirp = require('mkdirp'); +const { configHandler } = require('@contentstack/cli-utilities'); +const { kebabize } = require('../../../src/util/index'); +const { cma } = configHandler.get('region'); +const { PassThrough } = require('stream'); + +describe('Testing the teams support in cli export-to-csv',()=>{ + + describe('Testing Teams Command with using org flag and team flag', () => { + test + .stdout({ print: process.env.PRINT === 'true' || true }) + .stub(fs, 'createWriteStream', () => new PassThrough()) + .stub(mkdirp, 'sync', () => {}) + .stub(process, 'chdir', () => {}) + .nock(cma, (api) => { + api + .get(`/organizations/org_uid_1_teams/teams?skip=0&limit=100&includeUserDetails=true`) + .reply(200, mockData.Teams.allTeams); + }) + .nock(cma, (api) => { + api + .get(`/v3/organizations/org_uid_1_teams/roles`) + .reply(200, mockData.org_roles); + }) + .nock(cma, (api) => { + api + .get(`/v3/roles`) + .reply(200, {roles: mockData.roless.roles}); + }) + .command([ + 'cm:export-to-csv', + '--action', + 'teams', + '--org', + 'org_uid_1_teams', + '--team-uid', + 'team_1_uid' + ]) + .it('CSV file should be created'); + }); + describe('Testing Teams Command with using org flag and team flag and there are no teams', () => { + test + .stdout({ print: process.env.PRINT === 'true' || true }) + .stub(fs, 'createWriteStream', () => new PassThrough()) + .stub(mkdirp, 'sync', () => {}) + .stub(process, 'chdir', () => {}) + .nock(cma, (api) => { + api + .get(`/organizations/org_uid_1_teams/teams?skip=0&limit=100&includeUserDetails=true`) + .reply(200, mockData.Teams.allTeams); + }) + .nock(cma, (api) => { + api + .get(`/v3/organizations/org_uid_1_teams/roles`) + .reply(200, mockData.org_roles); + }) + .nock(cma, (api) => { + api + .get(`/v3/roles`) + .reply(200, {roles: mockData.roless.roles}); + }) + .command([ + 'cm:export-to-csv', + '--action', + 'teams', + '--org', + 'org_uid_1_teams', + '--team-uid', + 'team_1_uid' + ]) + .it('CSV file should be created'); + }); + describe('Testing Teams Command with using org flag', () => { + test + .stdout({ print: process.env.PRINT === 'true' || true }) + .stub(fs, 'createWriteStream', () => new PassThrough()) + .stub(mkdirp, 'sync', () => {}) + .stub(process, 'chdir', () => {}) + .nock(cma, (api) => { + api + .get(`/organizations/org_uid_1_teams/teams?skip=0&limit=100&includeUserDetails=true`) + .reply(200, mockData.Teams.allTeams); + }) + .nock(cma, (api) => { + api + .get(`/v3/organizations/org_uid_1_teams/roles`) + .reply(200, mockData.org_roles); + }) + .nock(cma, (api) => { + api + .get(`/v3/roles`) + .reply(200, {roles: mockData.roless.roles}); + }) + .command([ + 'cm:export-to-csv', + '--action', + 'teams', + '--org', + 'org_uid_1_teams' + ]) + .it('CSV file should be created'); + }); + describe('Testing Teams Command with prompt', () => { + test + .stdout({ print: process.env.PRINT === 'true' || true }) + .stub(fs, 'createWriteStream', () => new PassThrough()) + .stub(mkdirp, 'sync', () => {}) + .stub(process, 'chdir', () => {}) + .stub(inquirer, 'registerPrompt', () => {}) + .stub(inquirer, 'prompt', () => { + return Promise.resolve({ action: 'teams', chosenOrg: mockData.organizations[2].name}); + }) + .nock(cma, (api) => { + api.get('/v3/user?include_orgs_roles=true').reply(200, { user: mockData.users[2] }); + }) + .nock(cma, (api) => { + api + .get(`/organizations/org_uid_1_teams/teams?skip=0&limit=100&includeUserDetails=true`) + .reply(200, mockData.Teams.allTeams); + }) + .nock(cma, (api) => { + api + .get(`/v3/organizations/org_uid_1_teams/roles`) + .reply(200, mockData.org_roles); + }) + .nock(cma, (api) => { + api + .get(`/v3/roles`) + .reply(200, {roles: mockData.roless.roles}); + }) + .command([ + 'cm:export-to-csv' + ]) + .it('CSV file should be created'); + }); +}); \ No newline at end of file From 605312b44a3782fad41b03e1f544679a80f2509b Mon Sep 17 00:00:00 2001 From: raj pandey Date: Wed, 1 Nov 2023 14:06:22 +0530 Subject: [PATCH 26/32] fixed case when the teams is selected through the prompt --- packages/contentstack-export-to-csv/src/util/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index 16ab4eb32b..cb4b655288 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -20,7 +20,7 @@ function chooseOrganization(managementAPIClient, action) { return new Promise(async (resolve, reject) => { try { let organizations; - if (action === config.exportUsers || action === 'teams') { + if (action === config.exportUsers || action === config.exportTeams || action === 'teams') { organizations = await getOrganizationsWhereUserIsAdmin(managementAPIClient); } else { organizations = await getOrganizations(managementAPIClient); @@ -860,7 +860,7 @@ async function exportRoleMappings(managementAPIClient, allTeamsData, teamUid) { } } const fileName = `${kebabize('Stack_Role_Mapping'.replace(config.organizationNameRegex, ''))}${ - teamUid ? teamUid : '' + teamUid ? `_${teamUid}` : '' }.csv`; write(this, stackRoleWithTeamData, fileName, 'Team Stack Role details'); From 902e9c8678a0119fbc04722fe787ac3923737282 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Wed, 1 Nov 2023 17:21:40 +0530 Subject: [PATCH 27/32] handling case where the user is not admin in the stack and exporting the roels --- .../src/util/index.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index cb4b655288..a758b67178 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -869,7 +869,10 @@ async function exportRoleMappings(managementAPIClient, allTeamsData, teamUid) { async function mapRoleWithTeams(managementAPIClient, stackRoleMapping, teamName, teamUid) { const roles = await getRoleData(managementAPIClient, stackRoleMapping.stackApiKey); const stackRole = {}; - roles?.items.forEach((role) => { + if(!roles.hasOwnProperty('items')) { + cliux.print(`warning: You don't have admin access to stack with API Key ${stackRoleMapping.stackApiKey} to access the stack role data`,{color:"yellow"}); + } + roles?.items?.forEach((role) => { if (!stackRole.hasOwnProperty(role?.uid)) { stackRole[role?.uid] = role?.name; stackRole[role?.stack?.api_key] = {name: role?.stack?.name, uid: role?.stack?.uid } @@ -879,10 +882,10 @@ async function mapRoleWithTeams(managementAPIClient, stackRoleMapping, teamName, return { 'Team Name': teamName, 'Team Uid': teamUid, - 'Stack Name': stackRole[stackRoleMapping?.stackApiKey]?.name, - 'Stack Uid': stackRole[stackRoleMapping?.stackApiKey]?.uid, - 'Role Name': stackRole[role], - 'Role Uid': role, + 'Stack Name': stackRole[stackRoleMapping?.stackApiKey]?.name || '', + 'Stack Uid': stackRole[stackRoleMapping?.stackApiKey]?.uid || '', + 'Role Name': stackRole[role] || '', + 'Role Uid': role || '', }; }); @@ -890,7 +893,11 @@ async function mapRoleWithTeams(managementAPIClient, stackRoleMapping, teamName, } async function getRoleData(managementAPIClient, stackApiKey) { - return await managementAPIClient.stack({ api_key: stackApiKey }).role().fetchAll(); + try { + return await managementAPIClient.stack({ api_key: stackApiKey }).role().fetchAll(); + } catch (error) { + return {} + } } async function getTeamsUserDetails(teamsObject) { From cf938b86a650116a0fc3c4b3f9955295c2e0ca0f Mon Sep 17 00:00:00 2001 From: raj pandey Date: Wed, 1 Nov 2023 18:13:26 +0530 Subject: [PATCH 28/32] added prompt to ask user about whether to export the stack role mappings or not if there is warnings --- .../src/util/index.js | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index a758b67178..dfb88ec842 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -10,6 +10,7 @@ const debug = require('debug')('export-to-csv'); const checkboxPlus = require('inquirer-checkbox-plus-prompt'); const config = require('./config.js'); const { cliux, configHandler, HttpClient } = require('@contentstack/cli-utilities'); +const { error } = require('console'); const directory = './data'; const delimeter = os.platform() === 'win32' ? '\\' : '/'; @@ -845,6 +846,7 @@ async function getTeamsDetail(allTeamsData, organization, teamUid) { async function exportRoleMappings(managementAPIClient, allTeamsData, teamUid) { let stackRoleWithTeamData = []; + let flag = false; if (teamUid) { const team = find(allTeamsData,function(teamObject) { return teamObject?.uid===teamUid }); for (const stack of team?.stackRoleMapping) { @@ -859,6 +861,36 @@ async function exportRoleMappings(managementAPIClient, allTeamsData, teamUid) { } } } + + stackRoleWithTeamData?.forEach((team)=>{ + if(team['Stack Name']==='') { + flag = true; + } + }) + + if(flag) { + let export_stack_role = [ + { + type: 'list', + name: 'chooseExport', + message: `You don't have access to view the roles in the above stacks. Would you still like to export { Stack Name, Stack Uid, Role Name } field will be empty`, + choices: ['yes', 'no'], + loop: false, + }] + const exportStackRole = await inquirer + .prompt(export_stack_role) + .then(( chosenOrg ) => { + return chosenOrg + }) + .catch((error) => { + cliux.print(error, {color:'red'}); + process.exit(1); + }); + if(exportStackRole.chooseExport === 'no') { + process.exit(1); + } + } + const fileName = `${kebabize('Stack_Role_Mapping'.replace(config.organizationNameRegex, ''))}${ teamUid ? `_${teamUid}` : '' }.csv`; @@ -888,7 +920,6 @@ async function mapRoleWithTeams(managementAPIClient, stackRoleMapping, teamName, 'Role Uid': role || '', }; }); - return stackRoleMapOfTeam; } From 947ad50a00ae6b0504d73e0991f3df8966165a32 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Wed, 1 Nov 2023 19:30:19 +0530 Subject: [PATCH 29/32] modified the test cases --- .../test/unit/commands/export-to-csv.test.js | 68 ++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/packages/contentstack-export-to-csv/test/unit/commands/export-to-csv.test.js b/packages/contentstack-export-to-csv/test/unit/commands/export-to-csv.test.js index d03877b643..26f421b4d6 100644 --- a/packages/contentstack-export-to-csv/test/unit/commands/export-to-csv.test.js +++ b/packages/contentstack-export-to-csv/test/unit/commands/export-to-csv.test.js @@ -118,7 +118,7 @@ describe('Testing the teams support in cli export-to-csv',()=>{ .stub(process, 'chdir', () => {}) .stub(inquirer, 'registerPrompt', () => {}) .stub(inquirer, 'prompt', () => { - return Promise.resolve({ action: 'teams', chosenOrg: mockData.organizations[2].name}); + return Promise.resolve({ action: 'teams', chosenOrg: mockData.organizations[2].name }); }) .nock(cma, (api) => { api.get('/v3/user?include_orgs_roles=true').reply(200, { user: mockData.users[2] }); @@ -143,4 +143,70 @@ describe('Testing the teams support in cli export-to-csv',()=>{ ]) .it('CSV file should be created'); }); + describe('Testing Teams Command with prompt and no stack role data', () => { + test + .stdout({ print: process.env.PRINT === 'true' || true }) + .stub(fs, 'createWriteStream', () => new PassThrough()) + .stub(mkdirp, 'sync', () => {}) + .stub(process, 'chdir', () => {}) + .stub(inquirer, 'registerPrompt', () => {}) + .stub(inquirer, 'prompt', () => { + return Promise.resolve({ action: 'teams', chosenOrg: mockData.organizations[2].name, chooseExport: 'yes'}); + }) + .nock(cma, (api) => { + api.get('/v3/user?include_orgs_roles=true').reply(200, { user: mockData.users[2] }); + }) + .nock(cma, (api) => { + api + .get(`/organizations/org_uid_1_teams/teams?skip=0&limit=100&includeUserDetails=true`) + .reply(200, mockData.Teams.allTeams); + }) + .nock(cma, (api) => { + api + .get(`/v3/organizations/org_uid_1_teams/roles`) + .reply(200, mockData.org_roles); + }) + .nock(cma, (api) => { + api + .get(`/v3/roles`) + .reply(200, {roles: {}}); + }) + .command([ + 'cm:export-to-csv' + ]) + .it('CSV file should be created'); +}); +describe('Testing Teams Command with prompt and no stack role data', () => { + test + .stdout({ print: process.env.PRINT === 'true' || true }) + .stub(fs, 'createWriteStream', () => new PassThrough()) + .stub(mkdirp, 'sync', () => {}) + .stub(process, 'chdir', () => {}) + .stub(inquirer, 'registerPrompt', () => {}) + .stub(inquirer, 'prompt', () => { + return Promise.resolve({ action: 'teams', chosenOrg: mockData.organizations[2].name, chooseExport: 'no'}); + }) + .nock(cma, (api) => { + api.get('/v3/user?include_orgs_roles=true').reply(200, { user: mockData.users[2] }); + }) + .nock(cma, (api) => { + api + .get(`/organizations/org_uid_1_teams/teams?skip=0&limit=100&includeUserDetails=true`) + .reply(200, mockData.Teams.allTeams); + }) + .nock(cma, (api) => { + api + .get(`/v3/organizations/org_uid_1_teams/roles`) + .reply(200, mockData.org_roles); + }) + .nock(cma, (api) => { + api + .get(`/v3/roles`) + .reply(200, {roles: {}}); + }) + .command([ + 'cm:export-to-csv' + ]) + .it('No CSV file should be created'); +}); }); \ No newline at end of file From 549ef475d5df662706ed787a9f9dd40df9525b71 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Thu, 2 Nov 2023 14:49:59 +0530 Subject: [PATCH 30/32] modified the warning message, and handled condition when org role is empty and version bump --- package-lock.json | 6 ++-- .../contentstack-export-to-csv/package.json | 2 +- .../src/commands/cm/export-to-csv.js | 3 ++ .../src/util/index.js | 29 ++++++++++--------- packages/contentstack/package.json | 2 +- pnpm-lock.yaml | 2 +- 6 files changed, 25 insertions(+), 19 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9cbe4c49b4..43e87b9865 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22845,7 +22845,7 @@ "@contentstack/cli-cm-bulk-publish": "~1.3.13", "@contentstack/cli-cm-clone": "~1.6.0", "@contentstack/cli-cm-export": "~1.9.2", - "@contentstack/cli-cm-export-to-csv": "~1.4.4", + "@contentstack/cli-cm-export-to-csv": "~1.5.0", "@contentstack/cli-cm-import": "~1.10.0", "@contentstack/cli-cm-migrate-rte": "~1.4.13", "@contentstack/cli-cm-seed": "~1.6.0", @@ -24256,7 +24256,7 @@ }, "packages/contentstack-export-to-csv": { "name": "@contentstack/cli-cm-export-to-csv", - "version": "1.4.4", + "version": "1.5.0", "license": "MIT", "dependencies": { "@contentstack/cli-command": "~1.2.14", @@ -26967,7 +26967,7 @@ "@contentstack/cli-cm-bulk-publish": "~1.3.13", "@contentstack/cli-cm-clone": "~1.6.0", "@contentstack/cli-cm-export": "~1.9.2", - "@contentstack/cli-cm-export-to-csv": "~1.4.4", + "@contentstack/cli-cm-export-to-csv": "~1.5.0", "@contentstack/cli-cm-import": "~1.10.0", "@contentstack/cli-cm-migrate-rte": "~1.4.13", "@contentstack/cli-cm-seed": "~1.6.0", diff --git a/packages/contentstack-export-to-csv/package.json b/packages/contentstack-export-to-csv/package.json index 0f5c36b25b..4de33b158a 100644 --- a/packages/contentstack-export-to-csv/package.json +++ b/packages/contentstack-export-to-csv/package.json @@ -1,7 +1,7 @@ { "name": "@contentstack/cli-cm-export-to-csv", "description": "Export entities to csv", - "version": "1.4.4", + "version": "1.5.0", "author": "Abhinav Gupta @abhinav-from-contentstack", "bugs": "https://github.com/contentstack/cli/issues", "dependencies": { diff --git a/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js b/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js index 34669b3adb..7dfe314abc 100644 --- a/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js +++ b/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js @@ -336,6 +336,9 @@ ExportToCsvCommand.examples = [ '', 'Exporting Organizations Teams to CSV with org-uid and team uid', 'csdx cm:export-to-csv --action --org --team-uid ', + '', + 'Exporting Organizations Teams to CSV with org-uid and team uid', + 'csdx cm:export-to-csv --action --org --team-uid --org-name ', ]; module.exports = ExportToCsvCommand; diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index dfb88ec842..f928123d82 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -734,13 +734,13 @@ async function getOrgRoles(managementAPIClient, org) { let roleMap = {}; // for org level there are two roles only admin and member // SDK call to get the role uids - managementAPIClient + await managementAPIClient .organization(org.uid) .roles() .then((roles) => { roles.items.forEach((item) => { if (item.name === 'member' || item.name === 'admin') { - roleMap.name = item.uid; + roleMap[item.name] = item.uid; } }); }) @@ -767,7 +767,7 @@ async function cleanTeamsData(data, managementAPIClient, org) { return data.map((team) => { team = omit(team, fieldToBeDeleted); - team.organizationRole = team.organizationRole === roleMap["member"] ? "member" : "admin"; + team.organizationRole = (team.organizationRole === roleMap["member"]) ? "member" : "admin"; if (!team.hasOwnProperty("description")) { team.description = ""; @@ -847,27 +847,33 @@ async function getTeamsDetail(allTeamsData, organization, teamUid) { async function exportRoleMappings(managementAPIClient, allTeamsData, teamUid) { let stackRoleWithTeamData = []; let flag = false; + const stackNotAdmin = []; if (teamUid) { const team = find(allTeamsData,function(teamObject) { return teamObject?.uid===teamUid }); for (const stack of team?.stackRoleMapping) { const roleData = await mapRoleWithTeams(managementAPIClient, stack, team?.name, team?.uid); stackRoleWithTeamData.push(...roleData); + if(roleData[0]['Stack Name']==='') { + flag = true; + stackNotAdmin.push(stack.stackApiKey); + } } } else { for (const team of allTeamsData ?? []) { for (const stack of team?.stackRoleMapping ?? []) { const roleData = await mapRoleWithTeams(managementAPIClient, stack, team?.name, team?.uid); stackRoleWithTeamData.push(...roleData); + if(roleData[0]['Stack Name']==='') { + flag = true; + stackNotAdmin.push(stack.stackApiKey); + } } } } - - stackRoleWithTeamData?.forEach((team)=>{ - if(team['Stack Name']==='') { - flag = true; - } - }) - + if(stackNotAdmin?.length) { + cliux.print(`warning: You don't have admin access to the following stack with API Keys to access stack role data `,{color:"yellow"}); + cliux.print(`${stackNotAdmin.join(' , ')}`,{color:"yellow"}); + } if(flag) { let export_stack_role = [ { @@ -901,9 +907,6 @@ async function exportRoleMappings(managementAPIClient, allTeamsData, teamUid) { async function mapRoleWithTeams(managementAPIClient, stackRoleMapping, teamName, teamUid) { const roles = await getRoleData(managementAPIClient, stackRoleMapping.stackApiKey); const stackRole = {}; - if(!roles.hasOwnProperty('items')) { - cliux.print(`warning: You don't have admin access to stack with API Key ${stackRoleMapping.stackApiKey} to access the stack role data`,{color:"yellow"}); - } roles?.items?.forEach((role) => { if (!stackRole.hasOwnProperty(role?.uid)) { stackRole[role?.uid] = role?.name; diff --git a/packages/contentstack/package.json b/packages/contentstack/package.json index aa73bc4db4..4616d57613 100755 --- a/packages/contentstack/package.json +++ b/packages/contentstack/package.json @@ -29,7 +29,7 @@ "@contentstack/cli-cm-bulk-publish": "~1.3.13", "@contentstack/cli-cm-clone": "~1.6.0", "@contentstack/cli-cm-export": "~1.9.2", - "@contentstack/cli-cm-export-to-csv": "~1.4.4", + "@contentstack/cli-cm-export-to-csv": "~1.5.0", "@contentstack/cli-cm-import": "~1.10.0", "@contentstack/cli-cm-migrate-rte": "~1.4.13", "@contentstack/cli-cm-seed": "~1.6.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 99e6a0743e..2e4a7e81de 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,7 +17,7 @@ importers: '@contentstack/cli-cm-bulk-publish': ~1.3.13 '@contentstack/cli-cm-clone': ~1.6.0 '@contentstack/cli-cm-export': ~1.9.2 - '@contentstack/cli-cm-export-to-csv': ~1.4.4 + '@contentstack/cli-cm-export-to-csv': ~1.5.0 '@contentstack/cli-cm-import': ~1.10.0 '@contentstack/cli-cm-migrate-rte': ~1.4.13 '@contentstack/cli-cm-seed': ~1.6.0 From 2a48b941bda2fd0d17b18a64eec93761b0268798 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Thu, 2 Nov 2023 18:41:52 +0530 Subject: [PATCH 31/32] Ui text changes --- .../contentstack-export-to-csv/src/util/index.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index f928123d82..da4c1356f1 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -792,7 +792,7 @@ async function exportTeams(managementAPIClient, organization, teamUid) { ); const allTeamsData = await exportOrgTeams(managementAPIClient, organization); if (!allTeamsData?.length) { - cliux.print(`info: There are not teams in the organization named ${organization?.name}`); + cliux.print(`info: The organization ${organization?.name} does not have any teams associated with it. Please verify and provide the correct organization name.`); } else { const modifiedTeam = cloneDeep(allTeamsData); modifiedTeam.forEach((team) => { @@ -803,13 +803,13 @@ async function exportTeams(managementAPIClient, organization, teamUid) { write(this, modifiedTeam, fileName, ' organization Team details'); // exporting teams user data or a single team user data cliux.print( - `info: Exporting the teams user data for ${teamUid ? `Team ` + teamUid : `Organisation ` + organization?.name}`, + `info: Exporting the teams user data for ${teamUid ? `team ` + teamUid : `organisation ` + organization?.name}`, { color: 'blue' }, ); await getTeamsDetail(allTeamsData, organization, teamUid); cliux.print( - `info: Exporting the Stack Role Details for ${ - teamUid ? `Team ` + teamUid : `Organisation ` + organization?.name + `info: Exporting the stack role details for ${ + teamUid ? `team ` + teamUid : `organisation ` + organization?.name }`, { color: 'blue' }, ); @@ -871,7 +871,7 @@ async function exportRoleMappings(managementAPIClient, allTeamsData, teamUid) { } } if(stackNotAdmin?.length) { - cliux.print(`warning: You don't have admin access to the following stack with API Keys to access stack role data `,{color:"yellow"}); + 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"}); cliux.print(`${stackNotAdmin.join(' , ')}`,{color:"yellow"}); } if(flag) { @@ -879,7 +879,7 @@ async function exportRoleMappings(managementAPIClient, allTeamsData, teamUid) { { type: 'list', name: 'chooseExport', - message: `You don't have access to view the roles in the above stacks. Would you still like to export { Stack Name, Stack Uid, Role Name } field will be empty`, + message: `Access denied: Please confirm if you still want to continue exporting the data without the { Stack Name, Stack Uid, Role Name } fields.`, choices: ['yes', 'no'], loop: false, }] From faaf1afdd5820eed64f38add758ab7273d1e031a Mon Sep 17 00:00:00 2001 From: raj pandey Date: Thu, 2 Nov 2023 18:50:13 +0530 Subject: [PATCH 32/32] error --- packages/contentstack-export-to-csv/src/util/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index da4c1356f1..1d28cf06c5 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -10,7 +10,6 @@ const debug = require('debug')('export-to-csv'); const checkboxPlus = require('inquirer-checkbox-plus-prompt'); const config = require('./config.js'); const { cliux, configHandler, HttpClient } = require('@contentstack/cli-utilities'); -const { error } = require('console'); const directory = './data'; const delimeter = os.platform() === 'win32' ? '\\' : '/';