From cd0b5043a0cc9efab7756d166359225a2daa15f2 Mon Sep 17 00:00:00 2001 From: Tim Beyer Date: Fri, 11 Jun 2021 09:49:16 +0200 Subject: [PATCH] feat: add tags support --- lib/create-contentful-api.js | 82 +++++++++++++++++++++---- lib/entities/index.js | 4 +- lib/entities/tag.js | 38 ++++++++++++ test/integration/tests.js | 20 ++++++ test/unit/create-contentful-api-test.js | 4 ++ test/unit/entities/tag-test.js | 23 +++++++ test/unit/mocks.js | 43 ++++++++++++- 7 files changed, 201 insertions(+), 13 deletions(-) create mode 100644 lib/entities/tag.js create mode 100644 test/unit/entities/tag-test.js diff --git a/lib/create-contentful-api.js b/lib/create-contentful-api.js index 480ff97f2..b1ebcb071 100644 --- a/lib/create-contentful-api.js +++ b/lib/create-contentful-api.js @@ -36,6 +36,8 @@ * @typedef {Object} ClientAPI * @prop {function} getSpace * @prop {function} getContentType + * @prop {function} getTag + * @prop {function} getTags * @prop {function} getContentTypes * @prop {function} getEntry * @prop {function} getEntries @@ -69,6 +71,7 @@ export default function createContentfulApi ({ http, getGlobalOptions }) { const { wrapContentType, wrapContentTypeCollection } = entities.contentType const { wrapEntry, wrapEntryCollection } = entities.entry const { wrapAsset, wrapAssetCollection } = entities.asset + const { wrapTag, wrapTagCollection } = entities.tag const { wrapAssetKey } = entities.assetKey const { wrapLocaleCollection } = entities.locale const notFoundError = (id) => { @@ -295,6 +298,61 @@ export default function createContentfulApi ({ http, getGlobalOptions }) { } } + /** + * Gets a Tag + * @memberof ContentfulClientAPI + * @param {string} id + * @return {Promise} Promise for a Tag + * @example + * const contentful = require('contentful') + * + * const client = contentful.createClient({ + * space: '', + * accessToken: '' + * }) + * + * const tag = await client.getTag('') + * console.log(tag) + */ + async function getTag (id) { + switchToEnvironment(http) + + try { + const response = await http.get(`tags/${id}`) + return wrapTag(response.data) + } catch (error) { + errorHandler(error) + } + } + + /** + * Gets a collection of Tags + * @memberof ContentfulClientAPI + * @param {Object=} query - Object with search parameters. + * @return {Promise} Promise for a collection of Tags + * @example + * const contentful = require('contentful') + * + * const client = contentful.createClient({ + * space: '', + * accessToken: '' + * }) + * + * const response = await client.getTags() + * console.log(response.items) + */ + async function getTags (query = {}) { + switchToEnvironment(http) + query = normalizeSelect(query) + + try { + const response = await http.get('tags', createRequestConfig({ query: query })) + return wrapTagCollection(response.data) + } catch (error) { + errorHandler(error) + } + } + /** * Creates an asset key for signing asset URLs (Embargoed Assets) * @memberof ContentfulClientAPI @@ -443,16 +501,18 @@ export default function createContentfulApi ({ http, getGlobalOptions }) { } return { - getSpace: getSpace, - getContentType: getContentType, - getContentTypes: getContentTypes, - getEntry: getEntry, - getEntries: getEntries, - getAsset: getAsset, - getAssets: getAssets, - createAssetKey: createAssetKey, - getLocales: getLocales, - parseEntries: parseEntries, - sync: sync + getSpace, + getContentType, + getContentTypes, + getEntry, + getEntries, + getAsset, + getAssets, + getTag, + getTags, + createAssetKey, + getLocales, + parseEntries, + sync } } diff --git a/lib/entities/index.js b/lib/entities/index.js index c2a25ef3e..e2ef50824 100644 --- a/lib/entities/index.js +++ b/lib/entities/index.js @@ -4,6 +4,7 @@ import * as asset from './asset' import * as assetKey from './asset-key' import * as contentType from './content-type' import * as locale from './locale' +import * as tag from './tag' export default { space, @@ -11,5 +12,6 @@ export default { asset, assetKey, contentType, - locale + locale, + tag } diff --git a/lib/entities/tag.js b/lib/entities/tag.js new file mode 100644 index 000000000..1f13aba57 --- /dev/null +++ b/lib/entities/tag.js @@ -0,0 +1,38 @@ +import copy from 'fast-copy' +import { toPlainObject, freezeSys } from 'contentful-sdk-core' + +/** + * @memberof Entities + * @typedef Tag + * @prop {Entities.Sys} sys - Standard system metadata with additional entry specific properties + * @prop {string} name - Tag name + * @prop {function(): Object} toPlainObject() - Returns this tag as a plain JS object + */ + +/** + * @private + * @param {Object} data - Raw tag data + * @return {Tag} Wrapped tag data + */ +export function wrapTag (data) { + return freezeSys(toPlainObject(copy(data))) +} + +/** + * @memberof Entities + * @typedef TagCollection + * @prop {number} total + * @prop {number} skip + * @prop {number} limit + * @prop {Array} items + * @prop {function(): Object} toPlainObject() - Returns this Tag collection as a plain JS object + */ + +/** + * @private + * @param {Object} data - Raw tag collection data + * @return {TagCollection} Wrapped tag collection data + */ +export function wrapTagCollection (data) { + return freezeSys(toPlainObject(copy(data))) +} diff --git a/test/integration/tests.js b/test/integration/tests.js index c91b086ba..805c80319 100644 --- a/test/integration/tests.js +++ b/test/integration/tests.js @@ -404,12 +404,32 @@ test('Gets assets', async (t) => { const response = await client.getAssets() t.ok(response.items, 'items') }) + test('Gets Locales', async (t) => { t.plan(2) const response = await client.getLocales() t.ok(response.items, 'items') t.equals(response.items[0].code, 'en-US', 'first locale is en-US') }) + +test('Gets tag', async (t) => { + t.plan(3) + const response = await client.getTag('publicTag1') + t.ok(response.sys, 'sys') + t.ok(response.name, 'name') + t.equal(response.name, 'public tag 1') +}) + +test('Gets tags', async (t) => { + t.plan(3) + const response = await client.getTags() + t.ok(response.items, 'items') + + const publicTag = response.items.find((tag) => tag.sys.id === 'publicTag1') + t.ok(publicTag) + t.equal(publicTag.name, 'public tag 1') +}) + test('Sync space', async (t) => { t.plan(6) const response = await client.sync({ initial: true }) diff --git a/test/unit/create-contentful-api-test.js b/test/unit/create-contentful-api-test.js index 1f824dc74..b007ddc1d 100644 --- a/test/unit/create-contentful-api-test.js +++ b/test/unit/create-contentful-api-test.js @@ -41,6 +41,10 @@ function setupWithData ({ locale: { wrapLocale: sinon.stub(), wrapLocaleCollection: sinon.stub() + }, + tag: { + wrapTag: sinon.stub(), + wrapTagCollection: sinon.stub() } } createContentfulApiRewireApi.__Rewire__('entities', entitiesMock) diff --git a/test/unit/entities/tag-test.js b/test/unit/entities/tag-test.js new file mode 100644 index 000000000..d3f80495d --- /dev/null +++ b/test/unit/entities/tag-test.js @@ -0,0 +1,23 @@ +import test from 'blue-tape' +import { tagMock } from '../mocks' +import { wrapTag, wrapTagCollection } from '../../../lib/entities/tag' + +test('Tag is wrapped', (t) => { + const wrappedTag = wrapTag(tagMock) + t.looseEqual(wrappedTag.toPlainObject(), tagMock) + t.end() +}) + +test('Tag collection is wrapped', (t) => { + const tagCollection = { + total: 1, + skip: 0, + limit: 100, + items: [ + tagMock + ] + } + const wrappedTag = wrapTagCollection(tagCollection) + t.looseEqual(wrappedTag.toPlainObject(), tagCollection) + t.end() +}) diff --git a/test/unit/mocks.js b/test/unit/mocks.js index 1bb7a94cb..3067e0a54 100644 --- a/test/unit/mocks.js +++ b/test/unit/mocks.js @@ -74,6 +74,46 @@ const localeMock = { code: 'en-US' } +const tagMock = { + sys: { + space: { + sys: { + type: 'Link', + linkType: 'Space', + id: 'ezs1swce23xe' + } + }, + id: 'publicTag1', + type: 'Tag', + createdAt: '2021-02-11T14:44:48.594Z', + updatedAt: '2021-02-11T14:44:48.594Z', + environment: { + sys: { + id: 'master', + type: 'Link', + linkType: 'Environment' + } + }, + createdBy: { + sys: { + type: 'Link', + linkType: 'User', + id: '1a9rUrb3AjDqTxUGOYxBDe' + } + }, + updatedBy: { + sys: { + type: 'Link', + linkType: 'User', + id: '1a9rUrb3AjDqTxUGOYxBDe' + } + }, + version: 1, + visibility: 'public' + }, + name: 'mock tag' +} + export { linkMock, sysMock, @@ -81,5 +121,6 @@ export { entryMock, assetMock, assetKeyMock, - localeMock + localeMock, + tagMock }