Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

contentful-management

Package Overview
Dependencies
Maintainers
5
Versions
584
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

contentful-management - npm Package Compare versions

Comparing version 0.1.1 to 0.2.0

CHANGELOG.md

21

example/clone-space.js

@@ -73,3 +73,6 @@ #!/usr/bin/env node

.then(getDestinationSpace)
.tap(logSummary)
.then(function (summary) {
logSummary(summary);
return summary;
})
.spread(clone)

@@ -110,3 +113,3 @@ .done();

}).then(function(sourceContentTypes) {
return Promise.reduce(sourceContentTypes, function(result, sourceContentType) {
return reduce$(sourceContentTypes, function(result, sourceContentType) {
console.log('Creating Content Type %s', sourceContentType.name);

@@ -183,3 +186,3 @@ return destinationSpace.createContentType(sourceContentType).then(function(destinationContentType) {

}).delay(5e3).then(function() {
return Promise.map(sourceEntries, function(sourceEntry) {
return Promise.all(sourceEntries.map(function(sourceEntry) {
if (!('publishedVersion' in sourceEntry.sys)) {

@@ -194,3 +197,3 @@ return;

});
}, {concurrency: 1});
}));
});

@@ -213,3 +216,3 @@ });

console.log('Cloning %d items at %d/%d', items.length, items.skip, items.total);
return Promise.reduce(items, function(memo, item) {
return reduce$(items, function(memo, item) {
return map(item);

@@ -226,3 +229,11 @@ }, null).then(function() {

function reduce$ (array, fn, acc) {
return array.reduce(function (prev, value) {
return prev.then(function (acc) {
return fn(acc, value);
});
}, Promise.resolve(acc));
}
var forEachEntry = _.partial(forEach, 'getEntries');
var forEachAsset = _.partial(forEach, 'getAssets');
'use strict';
var Promise = require('es6-promise').Promise;
var _ = require('underscore-contrib');

@@ -7,4 +9,7 @@ var questor = require('questor');

var querystring = require('querystring');
var rateLimit = require('./rate-limit');
var APIError = require('./lib/api-error');
var createBackoff = require('./lib/backoff');
var rateLimit = require('./lib/rate-limit');
// Identifiable

@@ -64,3 +69,5 @@ // Object{sys: {id: Id}} -> Id

secure: true,
rateLimit: 6
rateLimit: 6,
retryOnTooManyRequests: true,
maxRetries: 5
});

@@ -72,3 +79,3 @@

request: function(path, options) {
request: function(path, options, backoff) {
if (!options) options = {};

@@ -80,2 +87,6 @@ if (!options.method) options.method = 'GET';

options.query.access_token = this.options.accessToken;
if (!backoff && this.options.retryOnTooManyRequests) {
backoff = createBackoff(this.options.maxRetries)
}

@@ -94,22 +105,20 @@ var uri = [

var self = this;
return questor(uri, options)
.then(parseJSONBody)
.catch(function(error) {
return 'body' in error;
}, function(response) {
// Rate-limited by the server, retry the request
if (response.status === 429) {
return self.request(path, options);
var response = questor(uri, options).then(parseJSONBody)
if (backoff) {
response = response.catch(function(error) {
// Rate-limited by the server, maybe backoff and retry
if (error.status === 429) {
return backoff(error, function () {
return self.request(path, options, backoff);
});
}
// Otherwise parse, wrap, and rethrow the error
var error = parseJSONBody(response);
throw new exports.APIError(error, {
method: options.method,
uri: uri,
body: options.body
});
throw error
})
.catch(SyntaxError, function (err) {
// Attach request info if JSON.parse throws
err.request = {
}
return response.catch(function (error) {
if (!('body' in error)) {
// Attach request info to errors that don't have a response body
error.request = {
method: options.method,

@@ -119,4 +128,13 @@ uri: uri,

};
throw err;
throw error;
}
// Otherwise parse, wrap, and rethrow the error
error = parseJSONBody(error);
throw new APIError(error, {
method: options.method,
uri: uri,
body: options.body
});
});
},

@@ -175,2 +193,38 @@

// Space functions
/**
* Gets all locales enabled in space.
* @returns JSON of locale data for space
*/
getLocales: function() {
return this.client.request('/spaces/' + this.sys.id + '/locales');
},
/**
* Creates a locale
* @param name The readable name of the locale, e.g. U.S English
* @param code the i18n abbreviation, e.g. en-US
*/
createLocale: function(name, code) {
var localeInfo = {"name":name,"code":code};
var localePath = '/spaces/' + this.sys.id + '/locales';
return this.client.request(localePath, {
method: 'POST',
body: localeInfo
});
},
/**
*
* @param localeID
* @returns {*|{method: string, uri: string, body: *}}
*/
deleteLocale: function(localeID) {
var localePath = '/spaces/' + this.sys.id + '/locales/' + localeID;
return this.client.request(localePath, {
method: 'DELETE'
});
},
//

@@ -550,3 +604,3 @@ // Content Type functions

exports.APIError = require('./api-error');
exports.APIError = APIError

@@ -553,0 +607,0 @@ function compacto(object) {

{
"name": "contentful-management",
"description": "Client for Contentful's Content Management API",
"version": "0.1.1",
"version": "0.2.0",
"homepage": "https://www.contentful.com/developers/documentation/content-management-api/",

@@ -14,6 +14,6 @@ "main": "index.js",

"dependencies": {
"bluebird": "^2.1.2",
"es6-promise": "^2.3.0",
"inherits": "^2.0.1",
"questor": "1.0.0",
"redefine": "^0.2.0",
"questor": "1.0.0",
"inherits": "^2.0.1",
"underscore-contrib": "0.2.2"

@@ -34,4 +34,4 @@ },

"prepare-browser-test": "browserify -d -t envify -x buster test/helper.js > test/bundle-helper.js",
"test": "testem ci"
"test": "buster-test -r tap"
}
}

@@ -5,3 +5,4 @@ # contentful-management.js

- [Documentation](https://www.contentful.com/developers/documentation/content-management-api)
- [API Documentation](#api)
- [REST API Documentation](https://www.contentful.com/developers/documentation/content-management-api)
- [Examples](#examples)

@@ -30,32 +31,2 @@ - [Create an access token for the Content Management API (need account)](https://www.contentful.com/developers/documentation/content-management-api/#getting-started)

## Usage
[Create an access token](https://www.contentful.com/developers/documentation/content-management-api/#getting-started) for the Content Management API first. Use it as the `accessToken` parameter when creating the client.
``` js
var contentful = require('contentful-management');
var client = contentful.createClient({
// A valid access token for your user (see above on how to create a valid access token)
accessToken: 'b4c0n73n7fu1',
// Enable or disable SSL. Enabled by default.
secure: true
});
var log = console.log.bind(console); // wat
// Get Space
client.getSpace('foobar').then(log, log);
// Get all Entries
client.getSpace('foobar').then(function(space) {
return space.getEntries();
}).then(log, log);
```
For now, please check out the
[Content Management API documentation](https://www.contentful.com/developers/documentation/content-management-api)
to learn how the API and the JavaScript client work.
## Examples

@@ -92,3 +63,3 @@

--source-space-id $SOURCE_SPACE_ID \
--destination-space-id $DESTINATION_SPACE_ID
--destination-space-id $DESTINATION_SPACE_ID \
--only-content-types

@@ -110,3 +81,3 @@ ```

[View Source](example/migrate-fields.js)
[View Source](example/migrate-field.js)

@@ -122,2 +93,513 @@ ``` sh

## API
### createClient(opts) -> Client
To use the Content Management API you will need an access token. The easiest
way to get a token for local scripts/experimentation is by using the OAuth app
embedded in our [Developer center documentation][get-token].
``` js
var contentful = require('contentful-management');
var client = contentful.createClient({
// A valid access token for your user (see above on how to create a valid access token)
accessToken: 'b4c0n73n7fu1',
// Enable or disable SSL. Enabled by default.
secure: true
});
```
### Client#getSpace(id) -> SpacePromise
```js
client.getSpace('foobar')
```
Returns a promise for a [Space][] object.
### Client#createSpace(opts) -> SpacePromise
Create a space with the name 'CMA Example Space'.
```js
client.createSpace({name: 'CMA Example Space'})
```
Returns a promise for a [Space][] object.
### Client#deleteSpace -> Promise
Delete a space and all of it's content. **Warning:** there is no undo!
```js
client.deleteSpace(space);
```
Returns a promise for nothing, which should still be checked for errors.
### Space API
A space is a top level container for all other resources. In addition to the
methods documented below, a space has the following data properties:
```js
{
"name": "Example Space",
"sys": {
"type": "Space",
"id": "1vlwe1hnkhmk",
"version": 0,
"createdBy": {
"sys": {
"type": "Link",
"linkType": "User",
"id": "0lEP0wVJL8WSQSbRuVUdcJ"
}
},
"createdAt": "2013-09-22T17:34:53Z",
"updatedBy": {
"sys": {
"type": "Link",
"linkType": "User",
"id": "0lEP0wVJL8WSQSbRuVUdcJ"
}
},
"updatedAt": "2013-09-22T17:34:53Z"
}
}
```
#### Space#createContentType(contentTypeId, entry) -> ContentTypePromise
Create a new content type by providing a name, fields, optional description,
and an optional ID. If you do not provide the `sys.id` property, an ID will be
generated for you.
```js
space.createContentType({
sys: {id: 'blog-post'},
name: 'Blog Post',
description: 'For like, blogging',
fields: [
{id: 'title', name: 'Title', type: 'Text'},
{id: 'body', name: 'Body', type: 'Text'}
]
})
```
The easiest way to find out what field types are available and how to represent
them in JSON is to use the content type editor built into the [Contentful
app][cf-app]. (Note that you will need administrative privileges for a space to
edit content types).
Returns a promise for a [ContentType][].
#### Space#getContentType(id) -> ContentTypePromise
Retrieve a content type by it's ID (**not** it's name). Returns a promise for a
[ContentType][].
#### Space#publishContentType(contentType) -> ContentTypePromise
Publish a [content type][], making it available for use by [create-entry], as
well as visible to the [Content Delivery API][].
```js
space.publishContentType(contentType)
```
Returns a promise for an updated version of the content type.
#### Space#unpublishContentType(contentType) -> ContentTypePromise
Unpublish a [content type][]. This operation is not allowed if there
are any entries of this content type (because entries may only be created for
published content types). If you wish to delete a content type and all of it's
entries, you will need to iterate over the entries and delete them before
unpublishing and deleting the content type.
```js
space.unpublishContentType(contentType)
```
Returns a promise for an updated version of the content type.
#### Space#deleteContentType(contentType) -> Promise
Delete a content type, note that the content type must be unpublished (and
therefore have no entries) before it can be deleted.
```js
space.deleteContentType(contentType)
```
#### Space#getContentTypes() -> ContentTypeCollectionPromise
Retrieve all content types for the space. Returns a promise for a [collection][]
of [ContentType][] objects.
#### Space#createEntry(contentType, entry) -> EntryPromise
Create a new entry by providing field values and and an optional ID. If you do
not provide the `sys.id` property, an ID will be generated for you.
```js
space.createEntry(contentType, {
sys: {id: 'hello-world'},
fields: {
title: {'en-US': 'Hello, World!'},
body: {'en-US': 'Bacon is healthy!'}
}
})
```
For more information on what is allowed in the `fields` property, see [Entry
fields][].
Returns a promise for an [Entry][].
#### Space#getEntry(id) -> EntryPromise
Retrieve an entry by it's ID. Returns a promise for an [Entry][].
```js
space.getEntry('hello-world')
```
#### Space#publishEntry(entry) -> EntryPromise
Publish an [Entry][], making it visible to the [Content Delivery API][].
```js
space.publishEntry(entry)
```
Returns a promise for an updated version of the entry.
#### Space#unpublishEntry(entry) -> EntryPromise
Unpublish an [Entry][], this appears to the [Content Delivery API][] as though
the entry was deleted.
```js
space.unpublishEntry(entry)
```
Returns a promise for an updated version of the entry.
#### Space#deleteEntry(entry) -> Promise
Delete an entry. Note that entries must be unpublished before deleting them.
```js
space.deleteEntry(entry)
```
Returns a promise for nothing, which should still be checked for errors.
#### Space#getEntries(query) -> EntryCollectionPromise
Search & filter all of the entries in a space. The `query` parameter should be
an object of querystring key-value pairs. The [query examples](#query-examples)
section containts more examples of the kinds of queries you can perform.
```js
space.getEntries({content_type: 'blog-post'})
```
Returns a promise for a [collection][] of [Entry][] objects.
#### Space#createAsset(contentTypeId, entry) -> AssetPromise
Create a new asset by providing field values and and an optional ID. If you do
not provide the `sys.id` property, an ID will be generated for you.
```js
space.createAsset({
sys: {id: 'dinosaurs'},
fields: {
title: {'en-US': 'Dinosaur'},
file: {
'en-US': {
upload: 'http://www.qwantz.com/comics/comic2-2870.png'
}
}
}
})
```
Returns a promise for an [Asset][], which must be [processed][process-asset]
before it can be published.
#### Space#processAssetFile(asset, locale) -> Promise
Process the file for a particular asset & locale. Note that this operation is
asynchronous on the Contentful backend; you will receive a successful response
before the asset is fully processed.
```js
space.processAssetFile(asset, 'en-US');
```
Returns a promise for nothing, which should still be checked for errors. In
order to detect when an asset has finished processing, retrieve the asset using
`space.getAsset` and test for the presence of `asset.fields.file[locale].url`.
#### Space#getAsset(id) -> AssetPromise
Retrieve an asset by it's ID. Returns a promise for an [Asset][].
```js
space.getAsset('dinosaurs')
```
#### Space#publishAsset(asset) -> AssetPromise
Publish an [Asset][], making it visible to the [Content Delivery API][].
```js
space.publishAsset(asset)
```
Returns a promise for an updated version of the asset.
#### Space#unpublishAsset(asset) -> AssetPromise
Unpublish an [Asset][], this appears to the [Content Delivery API][] as though
the asset was deleted.
```js
space.unpublishAsset(asset)
```
Returns a promise for an updated version of the asset.
#### Space#getAssets(query) -> AssetCollectionPromise
Search & filter all of the assets in a space. The `query` parameter should be
an object of querystring key-value pairs. The [query examples](#query-examples)
section containts more examples of the kinds of queries you can perform.
```js
space.getAssets({'fields.file.url[exists]': false})
```
Returns a promise for a [collection][] of [Asset][] objects.
### ContentType properties
Each content type defines a schema for entries in it's `fields` array. Every
entry has a corresponding content type, and it's _own_ `fields` property, which
is an object. The allowed keys and values in an entries `fields` object
correspond to the field ids defined in that entries content type.
A complete content type (the one created in [create-content-type][]) looks like:
```js
{
"name": "Blog Post",
"fields": [
{ "id": "title", "name": "Title", "type": "Text" },
{ "id": "body", "name": "Body", "type": "Text" }
],
"sys": {
"id": "blog-post",
"type": "ContentType",
"space": {
"sys": { "type": "Link", "linkType": "Space", "id": "7daovfk1olns" }
},
"createdAt": "2013-09-22T21:42:00.184Z",
"createdBy": {
"sys": { "type": "Link", "linkType": "User", "id": "0lEP0wVJL8WSQSbRuVUdcJ" }
},
"version": 1,
"updatedAt": "2013-09-22T21:42:00.187Z",
"updatedBy": {
"sys": { "type": "Link", "linkType": "User", "id": "0lEP0wVJL8WSQSbRuVUdcJ" }
}
}
}
```
### Entry properties
An entry is a piece of content containing fields and values. Every entry has a
corresponding content type (denoted by it's `sys.contentType` property) that
defines what keys are allowed in it's `fields` property, and what types those
keys can contain. Note that field values are always nested in an object whose
keys correspond to the locales available in a space.
```js
{
"fields": {
"title": { "en-US": "Hello, World!" },
"body": { "en-US": "Bacon is healthy!" }
},
"sys": {
"id": "hello-world",
"type": "Entry",
"space": {
"sys": { "type": "Link", "linkType": "Space", "id": "7daovfk1olns" }
},
"createdAt": "2013-09-22T23:05:03.271Z",
"createdBy": {
"sys": { "type": "Link", "linkType": "User", "id": "0lEP0wVJL8WSQSbRuVUdcJ" }
},
"contentType": {
"sys": { "type": "Link", "linkType": "ContentType", "id": "blog-post" }
},
"version": 1,
"updatedAt": "2013-09-22T23:05:03.271Z",
"updatedBy": {
"sys": { "type": "Link", "linkType": "User", "id": "0lEP0wVJL8WSQSbRuVUdcJ" }
}
}
}
```
### Asset properties
An asset is special kind of entry containing metadata for a binary file (e.g. an
image or video). Note that asset files have multiple states.
```js
{
"fields": {
"title": { "en-US": "Dinosaurs" },
"file": { "en-US": { /* See comments regarding asset file states below */ } }
},
"sys": {
"id": "dinosaurs",
"type": "Asset",
"space": {
"sys": { "type": "Link", "linkType": "Space", "id": "7daovfk1olns" }
},
"createdAt": "2013-09-22T23:05:03.271Z",
"createdBy": {
"sys": { "type": "Link", "linkType": "User", "id": "0lEP0wVJL8WSQSbRuVUdcJ" }
},
"version": 1,
"updatedAt": "2013-09-22T23:05:03.271Z",
"updatedBy": {
"sys": { "type": "Link", "linkType": "User", "id": "0lEP0wVJL8WSQSbRuVUdcJ" }
}
}
}
```
#### Asset file states
Assets may contain references to multiple files (one for each locale of their
space) and each one of those files may be in one of three states: "new",
"ready to process", or "processed".
To determine the state of an asset file, you can test for the presence of
`fields.file[locale].upload` and `fields.file[locale].url`. If the `url`
property is set, then the file has already been processed. If the `url` property
is not set, but the `upload` property is, you can attempt processing of the
file.
If neither property is present, the `upload` property must be set to a valid
publically accessible URL before calling [Space#processAssetFile][process-asset].
Note that an asset with unprocessed files can not be published.
### Query Examples
You can filter & search the entries and assets in your space by passing query
params to [`Space#getEntries`](#spacegetentriesquery---entrycollectionpromise)
and [`Space#getAssets`](#spacegetassetsquery---assetcollectionpromise). There are
a few predefined query parameter names (such as `content_type` and `order`), and
you can also query against document properties by using a dot-separated property
path (followed by an optional operator in square brackets) as a query parameter
name.
For example: `fields.name[ne]` means "entries where `fields.name` is not-equal
to ...". Full documentation of the allowed query parameters & field operators
can be found in [our API Documentation][search-parameters], but below are some
examples of common queries to get you started:
Search entries that have been updated since the 1st of January, 2013:
```js
space.getEntries({ 'sys.updatedAt[gte]': '2013-01-01T00:00:00Z' })
```
Retrieve a specific set of entries by their `sys.id`:
```js
space.getEntries({ 'sys.id[in]': [ 'finn', 'jake' ] })
```
Search for `cat` entries that have less than three lives left:
```js
space.getEntries({
'content_type': 'cat',
'fields.lives[lt]': 3
})
```
> Specifying the `content_type` query parameter is _required_ when querying on
> fields (such as `fields.lives` above). Note that `'cat'` is the content type
> **ID** and not it's name.
Full-text search for entries with "bacon" anywhere in their textual content:
```js
space.getEntries({ query: 'bacon' })
```
Full-text search for dogs with "bacon" specifically in the `description` field:
```js
space.getEntries({
'content_type': 'dog',
'fields.description[match]': 'bacon'
})
```
Get the 50 most recently created entries, and the next 50:
```js
space.getEntries({
order: '-sys.createdAt',
limit: 50
})
space.getEntries({
order: '-sys.createdAt',
skip: 50,
limit: 50
})
```
See also: [Collections and pagination][collection].
### Collections and pagination
Many methods return collections of resources. These collections are represented
as a JSON object containing items and pagination details:
```
{
"sys": {
"type": "Array"
},
"total": 1, // Total number of items matching the query
"skip": 0, // Offset into the result set represented by this response
"limit": 100, // Effective limit on # of items returned in this response
"items": [
// Full representations of each item
]
}
```
The `getEntries` and `getAssets` methods both accept `limit`, `skip`, and
`order` as query parameters, allowing you to paginate through larger result
sets. Note that specifying a stable property (such as `'sys.createdAt'`) for
ordering results is recommended.
## Unit Tests

@@ -138,1 +620,11 @@

MIT
[get-token]: https://www.contentful.com/developers/docs/references/authentication/#the-management-api
[search-parameters]: http://docs.contentfulcda.apiary.io/#reference/search-parameters
[collection]: #collections-and-pagination
[Space]: #space-api
[ContentType]: #contenttype-properties
[Entry]: #entry-properties
[Asset]: #asset-properties
[process-asset]: #spaceprocessassetfileasset-locale---promise
[create-content-type]: #spacecreatecontenttype---contenttypepromise

@@ -14,3 +14,3 @@ 'use strict';

name: 'Asset Integration Test'
}, 'contentful').then(function(space) {
}, process.env.CONTENTFUL_ORGANIZATION_ID).then(function(space) {
that.space = space;

@@ -17,0 +17,0 @@ });

@@ -12,3 +12,3 @@ 'use strict';

name: 'Content Type Integration Test'
}, 'contentful').then(function(space) {
}, process.env.CONTENTFUL_ORGANIZATION_ID).then(function(space) {
that.space = space;

@@ -15,0 +15,0 @@ });

@@ -12,3 +12,3 @@ 'use strict';

name: 'Entry Integration Test'
}, 'contentful').then(function(space) {
}, process.env.CONTENTFUL_ORGANIZATION_ID).then(function(space) {
that.space = space;

@@ -15,0 +15,0 @@ return space.createContentType({

@@ -10,3 +10,3 @@ 'use strict';

name: 'Space Integration Test'
}, 'contentful').then(function(space) {
}, process.env.CONTENTFUL_ORGANIZATION_ID).then(function(space) {
that.space = space;

@@ -53,3 +53,3 @@ });

name: 'Space Integration Test'
}, 'contentful').then(function(space) {
}, process.env.CONTENTFUL_ORGANIZATION_ID).then(function(space) {
assert(true);

@@ -56,0 +56,0 @@ return client.deleteSpace(space);

'use strict';
var contentful = require('..');
var Promise = require('bluebird');

@@ -12,2 +11,5 @@ if (process.env.CONTENTFUL_ACCESS_TOKEN === undefined) {

}
exports.wait = require('../lib/wait');
exports.client = contentful.createClient({

@@ -19,6 +21,1 @@ accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,

exports.wait = wait;
function wait(ms) {
if (!ms) { ms = 5000; }
return Promise.delay(ms);
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc