Skip to content

Commit

Permalink
Merge pull request #28 from contentstack/export-csv
Browse files Browse the repository at this point in the history
Export csv
  • Loading branch information
abhinav-from-contentstack authored Mar 15, 2021
2 parents 0f4f930 + 47bc353 commit f831b86
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 32 deletions.
5 changes: 3 additions & 2 deletions packages/export-to-csv/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"@oclif/config": "^1.17.0",
"chalk": "^4.1.0",
"fast-csv": "^4.3.6",
"inquirer": "^7.3.3"
"inquirer": "^7.3.3",
"mkdirp": "^1.0.4"
},
"devDependencies": {
"@oclif/dev-cli": "^1.26.0",
Expand All @@ -22,7 +23,7 @@
"eslint": "^5.16.0",
"eslint-config-oclif": "^3.1.0",
"globby": "^10.0.2",
"mocha": "^5.2.0",
"mocha": "^8.3.1",
"nyc": "^14.1.1"
},
"engines": {
Expand Down
26 changes: 17 additions & 9 deletions packages/export-to-csv/src/commands/cm/export-to-csv.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const {Command} = require('@contentstack/cli-command')
const util = require('../../util/index')
const ContentstackManagementSDK = require('@contentstack/management')
const config = require('../../util/config.js')

class ExportToCsvCommand extends Command {

Expand All @@ -15,20 +16,25 @@ class ExportToCsvCommand extends Command {
const action = await util.startupQuestions()

switch(action) {
case 'Export Entries to CSV': {
case config.exportEntries: {
const organization = await util.chooseOrganization(this.managementAPIClient) // prompt for organization
const stack = await util.chooseStack(this.managementAPIClient, organization.uid) // prompt for stack
const contentType = await util.chooseContentType(this.managementAPIClient, stack.apiKey) // prompt for content Type
const contentTypes = await util.chooseContentType(this.managementAPIClient, stack.apiKey) // prompt for content Type
const language = await util.chooseLanguage(this.managementAPIClient, stack.apiKey) // prompt for language
const entries = await util.getEntries(this.managementAPIClient, stack.apiKey, contentType.uid, language.code) // fetch entries
const environments = await util.getEnvironments(this.managementAPIClient, stack.apiKey) // fetch environments, because in publish details only env uid are available and we need env names
const flatEntries = util.cleanEntries(entries.items, language.code, environments, contentType.uid); // clean entries to be wderitten to file
const dateTime = util.getDateTime()
const fileName = `${contentType.uid}_${language.code}_entries_export_${dateTime}.csv`
util.write(this, flatEntries, fileName) // write to file
while(contentTypes.length > 0) {
let contentType = contentTypes.shift()
let entries = await util.getEntries(this.managementAPIClient, stack.apiKey, contentType, language.code) // fetch entries
let flatEntries = util.cleanEntries(entries.items, language.code, environments, contentType); // clean entries to be wderitten to file
let dateTime = util.getDateTime()
// let fileName = `${contentType}_${language.code}_entries_export_${dateTime}.csv`
let fileName = `${stack.name}_${contentType}_${language.code}_entries_export.csv`

util.write(this, flatEntries, fileName) // write to file
}
break;
}
case 'Export Organization Users to CSV': {
case config.exportUsers: {
try {
const organization = await util.chooseOrganization(this.managementAPIClient, action) // prompt for organization
const orgUsers = await util.getOrgUsers(this.managementAPIClient, organization.uid)
Expand All @@ -37,7 +43,9 @@ class ExportToCsvCommand extends Command {
const mappedRoles = util.getMappedRoles(orgRoles)
const listOfUsers = util.cleanOrgUsers(orgUsers, mappedUsers, mappedRoles)
const dateTime = util.getDateTime()
const fileName = `${organization.name}_users_export_${dateTime}.csv`
// const fileName = `${util.kebabize(organization.name.replace(config.organizationNameRegex, ''))}_users_export_${dateTime}.csv`
const fileName = `${util.kebabize(organization.name.replace(config.organizationNameRegex, ''))}_users_export.csv`

util.write(this, listOfUsers, fileName)
} catch(error) {
this.error(error)
Expand Down
6 changes: 5 additions & 1 deletion packages/export-to-csv/src/util/config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
module.exports = {
cancelString: 'Cancel and Exit'
cancelString: 'Cancel and Exit',
exportEntries: 'Export entries to a .CSV file',
exportUsers: 'Export organization users\' data to a .CSV file',
adminError: 'Unable to export data. Make sure you\'re an admin or owner of this organization',
organizationNameRegex: /\'/
}
51 changes: 31 additions & 20 deletions packages/export-to-csv/src/util/index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
const inquirer = require('inquirer')
const os = require('os')
const config = require('./config.js')
const fastcsv = require('fast-csv')
const mkdirp = require('mkdirp')
const fs = require('fs')
const debug = require('debug')("export-to-csv")
const directory = './data'
const delimeter = (os.platform() === 'win32') ? '\\' : '/'

function chooseOrganization(managementAPIClient, action) {
return new Promise(async resolve => {
let organizations
if (action === 'Export Organization Users to CSV') {
if (action === config.exportUsers) {
organizations = await getOrganizationsWhereUserIsAdmin(managementAPIClient)
} else {
organizations = await getOrganizations(managementAPIClient)
Expand Down Expand Up @@ -99,21 +102,21 @@ function getStacks(managementAPIClient, orgUid) {
function chooseContentType(managementAPIClient, stackApiKey) {
return new Promise(async resolve => {
let contentTypes = await getContentTypes(managementAPIClient, stackApiKey)
let contentTypesList = Object.keys(contentTypes)
contentTypesList.push(config.cancelString)
let contentTypesList = Object.values(contentTypes)
// contentTypesList.push(config.cancelString)

let chooseContentType = [{
type: 'list',
type: 'checkbox',
message: 'Choose Content Type',
choices: contentTypesList,
name: 'chosenContentType',
name: 'chosenContentTypes',
loop: false
}]

inquirer.prompt(chooseContentType).then(({chosenContentType}) => {
if (chosenContentType === config.cancelString)
exitProgram()
resolve({ name: chosenContentType, uid: contentTypes[chosenContentType] })
inquirer.prompt(chooseContentType).then(({chosenContentTypes}) => {
// if (chosenContentType === config.cancelString)
// exitProgram()
resolve(chosenContentTypes)
})
})
}
Expand Down Expand Up @@ -177,6 +180,7 @@ function getEntries(managementAPIClient, stackApiKey, contentType, language) {

function getEnvironments(managementAPIClient, stackApiKey) {
let result = {}
debugger
return managementAPIClient.stack({api_key: stackApiKey}).environment().query().find().then(environments => {
environments.items.forEach(env => { result[env['uid']] = env['name']})
return result
Expand Down Expand Up @@ -233,17 +237,19 @@ function getDateTime() {
}

function write(command, entries, fileName) {
if (!fs.existsSync(directory)) {
fs.mkdirSync(directory)
// eslint-disable-next-line no-undef
if (process.cwd().split(delimeter).pop() !== 'data' && !fs.existsSync(directory)) {
mkdirp.sync(directory)
}
// eslint-disable-next-line no-undef
process.chdir(directory)
const ws = fs.createWriteStream(fileName)
if (process.cwd().split(delimeter).pop() !== 'data') {
// eslint-disable-next-line no-undef
process.chdir(directory)
}
// eslint-disable-next-line no-undef
command.log(`Writing entries to file: ${process.cwd()}/${fileName}`)
command.log(`Writing entries to file: ${process.cwd()}${delimeter}${fileName}`)
fastcsv
.write(entries, {headers: true})
.pipe(ws)
.writeToPath(fileName, entries, {headers: true})
}

function startupQuestions() {
Expand All @@ -252,7 +258,7 @@ function startupQuestions() {
type: 'list',
name: 'action',
message: 'Choose Action',
choices: ['Export Entries to CSV', 'Export Organization Users to CSV', 'Exit'],
choices: [config.exportEntries, config.exportUsers, 'Exit'],
}]
inquirer.prompt(actions).then(answers => {
if(answers.action === 'Exit')
Expand All @@ -269,7 +275,7 @@ function getOrgUsers(managementAPIClient, orgUid) {
.then(response => {
let organization = response.organizations.filter(org => org.uid === orgUid).pop()
if (!organization.getInvitations) {
return reject(new Error('You need to be an admin for exporting this organization\'s users'))
return reject(new Error(config.adminError))
}
organization.getInvitations().then(users => resolve(users))
})
Expand All @@ -296,7 +302,7 @@ function getOrgRoles(managementAPIClient, orgUid) {
.then(response => {
let organization = response.organizations.filter(org => org.uid === orgUid).pop()
if (!organization.roles) {
return reject(new Error('You need to be an admin for exporting this organization\'s users'))
return reject(new Error(config.adminError))
}
organization.roles().then(roles => resolve(roles))
})
Expand Down Expand Up @@ -336,7 +342,11 @@ function cleanOrgUsers(orgUsers, mappedUsers, mappedRoles) {
userList.push(formattedUser)
})
return userList
}
}

function kebabize(str) {
return str.split(' ').map((word) => word.toLowerCase()).join('-')
}

module.exports = {
chooseOrganization: chooseOrganization,
Expand All @@ -356,4 +366,5 @@ module.exports = {
cleanOrgUsers: cleanOrgUsers,
determineUserOrgRole: determineUserOrgRole,
getOrganizationsWhereUserIsAdmin: getOrganizationsWhereUserIsAdmin,
kebabize: kebabize,
}

0 comments on commit f831b86

Please sign in to comment.