Skip to content
This repository was archived by the owner on May 19, 2025. It is now read-only.

Add support for EU Contentstack API URLs #39

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
8aa7223
management_token support
rohitmishra209 Apr 9, 2020
e909709
management_token support
rohitmishra209 Apr 9, 2020
75e27e4
Added validation
rohitmishra209 Apr 17, 2020
98f2b20
made changes in validation
rohitmishra209 Apr 20, 2020
2d7b207
made changes in validation
rohitmishra209 Apr 20, 2020
aa53933
Added validation
rohitmishra209 Apr 20, 2020
bf64f28
updated the validation
rohitmishra209 Apr 22, 2020
49c09ce
updated the validation
rohitmishra209 Apr 22, 2020
fef44e5
merge the master branch
rohitmishra209 Apr 23, 2020
fb957a7
solved the bug
rohitmishra209 Apr 24, 2020
54a4640
updated in initial file
rohitmishra209 Apr 26, 2020
a84e4cb
updated the README file
rohitmishra209 Apr 27, 2020
6a68499
Merge pull request #25 from contentstack/management_token_support
rohitmishra209 Apr 28, 2020
44a48c4
updated the package file
rohitmishra209 Apr 28, 2020
3eeacd0
Merge pull request #27 from contentstack/management_token_support
rohitmishra209 Apr 28, 2020
e26db35
Update README.md
rohitmishra209 Apr 28, 2020
3597356
Merge branch 'master' into publish-details-support
rohitmishra209 May 15, 2020
9429cdd
Merge pull request #28 from contentstack/publish-details-support
rohitmishra209 May 15, 2020
de2b55f
hotfix in request call for query
rohitmishra209 Oct 21, 2020
e939d81
Merge pull request #35 from contentstack/hot-fix-1.6.1
rohitmishra209 Oct 22, 2020
f2b720a
Made changes in validation
rohitmishra209 Jan 26, 2021
6d01da3
Merge pull request #36 from contentstack/Hotfix-1.6.2
rohitmishra209 Jan 27, 2021
b541907
Made changes in validation
rohitmishra209 Jan 27, 2021
37327f1
Merge pull request #37 from contentstack/Hotfix-1.6.2
rohitmishra209 Jan 27, 2021
cbea269
Add support for EU Contentstack API URLs
luke88jones Jul 19, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ package-lock.json
contents
logs
_contents_new
SYNcontents
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@ Update configuration details at config/index.js
password: '', // Account password
source_stack: '' // Stack api_key
access_token: '' // Stack access_token
management_token: '' //Stack management_token
data: '' // Relative path to the directory, where exported data is to be stored. ex: './contents'
useEUApi: false // Set to true if your stacks are hosted in the Europe
...
}
```

## Usage
After setting the configuration, you'll can run the below given commands!

Expand All @@ -39,7 +41,7 @@ After setting the configuration, you'll can run the below given commands!
```bash
$ npm run export
```

2. Export a specific module
```bash
$ npm run export-assets
Expand All @@ -55,9 +57,11 @@ $ npm run export-labels
```
> Note: Before exporting entries, you must export locales, assets and content types.

### Known issues
> Note: If you keep the value of preserveStackVersion to true, then you will have to provide the email and password mandatorily in the config file, the management token will not work in that case.

### Known Limitations and Issues
* If 2 assets share same uid and filename, only the first version of the asset would be available
* The following contents are not supported
* Does not support the following
* Roles
* Users
* Releases
Expand Down
108 changes: 65 additions & 43 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,56 +1,78 @@
/* eslint-disable no-redeclare */
var Bluebird = require('bluebird');
var util = require('./lib/util');
var login = require('./lib/util/login');
var config = require('./config');
var log = require('./lib/util/log');

config = util.buildAppConfig(config)
util.validateConfig(config)

let validate = util.validateConfig(config)
validate.then(() => {
intialProcess().then(() => {
return
}).catch((error) => {
log.error(error);
return
})
}).catch((error) => {
log.error(error)
return
})
exports.getConfig = function () {
return config;
};

async function intialProcess() {
return new Promise(function (resolve, reject) {
login(config).then(function () {
var types = config.modules.types;
if (process.argv.length === 3) {
var val = process.argv[2];

login(config).then(function () {
var types = config.modules.types;
if (val && types.indexOf(val) > -1) {
var exportedModule = require('./lib/export/' + val);
return exportedModule.start().then(function () {
log.success(val + ' was exported successfully!');
return resolve()
}).catch(function (error) {
log.error('Failed to migrate ' + val);
log.error(error);
return reject()
})
} else {
log.error('Please provide valid module name.');
return 0;
}
} else if (process.argv.length === 2) {
var counter = 0;
return Bluebird.map(types, function (type) {
if (config.preserveStackVersion) {
log.success('Exporting: ' + types[counter])
var exportedModule = require('./lib/export/' + types[counter]);
counter++
return exportedModule.start()
} else if (!config.preserveStackVersion && type !== 'stack') {
log.success('Exporting: ' + types[counter])
var exportedModule = require('./lib/export/' + types[counter]);
counter++
return exportedModule.start()
} else {
counter++
}
}, {
concurrency: 1
}).then(function () {
log.success('Stack: ' + config.source_stack + ' has been exported succesfully!');
return resolve()
}).catch(function (error) {
log.error('Failed to migrate stack: ' + config.source_stack + '. Please check error logs for more info');
return reject(error)
});

if (process.argv.length === 3) {
var val = process.argv[2];

if (val && types.indexOf(val) > -1) {
var exportedModule = require('./lib/export/' + val);

return exportedModule.start().then(function () {
log.success(val + ' was exported successfully!');
return;
}).catch(function (error) {
log.error('Failed to migrate ' + val);
log.error(error);
return;
})
} else {
log.error('Please provide valid module name.');
return 0;
}
} else if (process.argv.length === 2) {
var counter = 0;
return Bluebird.map(types, function (type) {
log.success('Exporting: ' + types[counter])
var exportedModule = require('./lib/export/' + types[counter]);
counter++
return exportedModule.start()
}, {
concurrency: 1
}).then(function () {
log.success('Stack: ' + config.source_stack + ' has been exported succesfully!');
}).catch(function (error) {
console.error(error)
log.error('Failed to migrate stack: ' + config.source_stack + '. Please check error logs for more info');
log.error(error);
});
} else {
log.error('Only one module can be exported at a time.');
return 0;
}
});
} else {
log.error('Only one module can be exported at a time.');
return 0;
}
});
})
}
18 changes: 16 additions & 2 deletions config/default.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
module.exports = {
var _ = require('lodash')

const defaultConfig = {
versioning: false,
host: 'https://api.contentstack.io/v3',
cdn: 'https://cdn.contentstack.io/v3',
Expand Down Expand Up @@ -110,7 +112,7 @@ module.exports = {
userSession: '/user-session/',
globalfields: '/global_fields/',
locales: '/locales/',
labels: '/labels/',
labels: '/labels/',
environments: '/environments/',
assets: '/assets/',
content_types: '/content_types/',
Expand All @@ -119,5 +121,17 @@ module.exports = {
extension: '/extensions',
webhooks: '/webhooks/',
stacks: '/stacks/'
},
preserveStackVersion: false
}

module.exports = function (useEUApi) {
if (!useEUApi) return defaultConfig;

const euHosts = {
host: 'https://eu-api.contentstack.com/v3',
cdn: 'https://eu-cdn.contentstack.com/v3',
}

return _.merge(defaultConfig, euHosts);
}
12 changes: 6 additions & 6 deletions config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ module.exports = {
code: 'en-us'
},
// Credentials
email: '',
password: '',

email: '', // (optional)
password: '', // (optional)
// Stack API KEY
source_stack: '',
// Stack ACCESS TOKEN
source_stack: '', // mandatory
access_token: '',
management_token: '',
// Path where the exported data will be stored (relative path)
data: './contents'
data: './contents',
useEUApi: false
};
37 changes: 21 additions & 16 deletions lib/export/assets.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ var path = require('path');
var fs = require('fs');
var Promise = require('bluebird');
var _ = require('lodash');
var chalk = require('chalk');

var request = require('../util/request');
var app = require('../../app')
Expand Down Expand Up @@ -61,7 +62,7 @@ ExportAssets.prototype = {
return new Promise(function (resolve, reject) {
return self.getAssetCount().then(function (count) {
if (typeof count !== 'number' || count === 0) {
log.success('There were no assets to be download');
log.success(chalk.yellow('There were no assets to be download'));
return resolve();
} else {
var assetBatches = [];
Expand All @@ -74,13 +75,12 @@ ExportAssets.prototype = {
return self.getVersionedAssetJSON(assetJSON.uid, assetJSON._version).then(
function () {
self.assetContents[assetJSON.uid] = assetJSON;
log.success(
'The following asset has been downloaded successfully: ' +
assetJSON.uid);
log.success(chalk.green('The following asset has been downloaded successfully: ' +
assetJSON.uid));
return;
}).catch(function (error) {
log.error('The following asset failed to download\n' + JSON.stringify(
assetJSON));
log.error(chalk.red('The following asset failed to download\n' + JSON.stringify(
assetJSON)));
log.error(error);
return;
});
Expand All @@ -103,20 +103,20 @@ ExportAssets.prototype = {
concurrency: 1
}).then(function () {
return self.exportFolders().then(function () {
log.success('Asset export completed successfully');
log.success(chalk.green('Asset export completed successfully'));
return resolve();
}).catch(function (error) {
return reject(error)
});
}).catch(function (error) {
log.error('Asset export failed due to the following errrors ' + JSON.stringify(
error));
log.error(chalk.red('Asset export failed due to the following errrors ' + JSON.stringify(
error)));
return reject(error);
});
}
}).catch(function (error) {
log.error('Failed to download assets due to the following error: ' + JSON.stringify(
error));
// log.error(chalk.red('Failed to download assets due to the following error: ' + JSON.stringify(
// error)));
return reject(error);
});
});
Expand All @@ -131,10 +131,10 @@ ExportAssets.prototype = {
}
return self.getFolderJSON(0, fCount).then(function () {
// asset folders have been successfully exported
log.success('Asset-folders have been successfully exported!');
log.success(chalk.green('Asset-folders have been successfully exported!'));
return resolve();
}).catch(function (error) {
log.error('Error while exporting asset-folders!');
log.error(chalk.red('Error while exporting asset-folders!'));
return reject(error)
});
}).catch(function (error) {
Expand Down Expand Up @@ -186,7 +186,12 @@ ExportAssets.prototype = {

return request(_requestOptions).then(function (response) {
return resolve(response.body.assets);
}).catch(reject);
}).catch(function (error) {
if(error.body.errors.authorization || error.body.errors.api_key) {
log.error(chalk.red('Api_key or management_token is not valid'))
}
return reject(error);
});
});
},
getAssetJSON: function (skip) {
Expand Down Expand Up @@ -265,7 +270,7 @@ ExportAssets.prototype = {
var assetFileStream = fs.createWriteStream(assetFilePath);
assetStreamRequest.pipe(assetFileStream);
assetFileStream.on('close', function () {
log.success('Downloaded ' + asset.filename + ': ' + asset.uid + ' successfully!');
log.success(chalk.green('Downloaded ' + asset.filename + ': ' + asset.uid + ' successfully!'));
return resolve();
});
}).on('error', reject)
Expand All @@ -280,7 +285,7 @@ ExportAssets.prototype = {
return resolve();
} else {
return self.getFolderDetails(0, count).then(function () {
log.success('Exported asset-folders successfully!');
log.success(chalk.green('Exported asset-folders successfully!'));
return resolve();
}).catch(function (error) {
return reject(error);
Expand Down
1 change: 1 addition & 0 deletions lib/export/entries.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ exportEntries.prototype.getEntries = function (apiDetails) {
}
};

requestObject.qs['query'] = JSON.stringify(requestObject.qs.query)
return request(requestObject).then(function (response) {
// /entries/content_type_uid/locale.json
if (!fs.existsSync(path.join(entryFolderPath, apiDetails.content_type))) {
Expand Down
10 changes: 9 additions & 1 deletion lib/export/labels.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,15 @@ ExportLabels.prototype.start = function () {
helper.writeFile(path.join(labelsFolderPath, labelConfig.fileName), self.labels);
log.success(chalk.blue('All the labels have been exported successfully'));
return resolve();
}).catch(reject);
}).catch(function (error) {
if(error.statusCode == 401) {
log.error(chalk.red('You are not allowed to export label, Unless you provide email and password in config'));
return resolve();
} else {
log.error(error);
}
return reject();
})
});
};

Expand Down
1 change: 1 addition & 0 deletions lib/export/locales.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ function ExportLocales () {
ExportLocales.prototype.start = function () {
log.success(chalk.blue('Starting locale export'));
var self = this;
self.requestOptions.qs['query'] = JSON.stringify(self.requestOptions.qs.query)
return new Promise(function (resolve, reject) {
return request(self.requestOptions).then(function (response) {
if (response.body.locales.length !== 0) {
Expand Down
2 changes: 1 addition & 1 deletion lib/export/webhooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ ExportWebhooks.prototype.start = function () {
}
}).catch(function (error) {
if(error.statusCode == 401) {
log.error(chalk.red('You are not allowed to export webhooks unless you provide email and password in config'));
log.error(chalk.red('You are not allowed to export webhooks, Unless you provide email and password in config'));
return resolve();
} else {
log.error(error);
Expand Down
Loading