From ac08fb2789f428c6b7aa1f5582a5942e541ae7b6 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Mon, 23 Oct 2023 14:48:00 +0530 Subject: [PATCH 1/8] 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 39bb23e76f38e0e9b753bdd871b4913b9ecaf6f2 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Tue, 24 Oct 2023 12:04:13 +0530 Subject: [PATCH 2/8] 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 3/8] 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 4/8] 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 88c98f815bab212202f0229667eb3c4997ec5dca Mon Sep 17 00:00:00 2001 From: raj pandey Date: Wed, 25 Oct 2023 17:41:26 +0530 Subject: [PATCH 5/8] 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 6/8] 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 7/8] 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 8/8] 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