diff --git a/CHANGELOG.md b/CHANGELOG.md index 435bb15c..1bdee9d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [v1.12.0](https://github.com/contentstack/contentstack-management-javascript/tree/v1.12.0) (2023-10-17) + - Feature + - Types support for Taxonomy feature + - Types support for Terms feature +- Fixes + - Correction in refreshToken error message ## [v1.11.0](https://github.com/contentstack/contentstack-management-javascript/tree/v1.11.0) (2023-09-03) - Fixes and Enhancements - Allows contenttype in asset upload diff --git a/lib/core/concurrency-queue.js b/lib/core/concurrency-queue.js index 21e3fef3..321383af 100644 --- a/lib/core/concurrency-queue.js +++ b/lib/core/concurrency-queue.js @@ -147,13 +147,13 @@ export function ConcurrencyQueue ({ axios, config }) { axios.httpClientParams.headers.authtoken = token.authtoken this.config.authtoken = token.authtoken } - }).catch(() => { + }).catch((error) => { this.queue.forEach(queueItem => { queueItem.reject({ errorCode: '401', - errorMessage: 'Unable to refresh token', + errorMessage: (error instanceof Error) ? error.message : error, code: 'Unauthorized', - message: 'Request failed with status code 401', + message: 'Unable to refresh token', name: 'Token Error', config: queueItem.request }) diff --git a/lib/stack/roles/index.js b/lib/stack/roles/index.js index 31ff38eb..483440ad 100644 --- a/lib/stack/roles/index.js +++ b/lib/stack/roles/index.js @@ -1,7 +1,5 @@ import cloneDeep from 'lodash/cloneDeep' import { create, update, deleteEntity, fetch, query, fetchAll } from '../../entity' -import ContentstackCollection from '../../contentstackCollection' -import error from '../../core/contentstackError' /** * A role is a collection of permissions that will be applicable to all the users who are assigned this role. Read more about Roles. * @namespace Role diff --git a/lib/stack/taxonomy/index.js b/lib/stack/taxonomy/index.js index ffd13b79..b9d03df5 100644 --- a/lib/stack/taxonomy/index.js +++ b/lib/stack/taxonomy/index.js @@ -116,7 +116,7 @@ export function Taxonomy (http, data = {}) { } } export function TaxonomyCollection (http, data) { - const obj = cloneDeep(data.taxonomy) || [] + const obj = cloneDeep(data.taxonomies) || [] const taxonomyCollection = obj.map((userdata) => { return new Taxonomy(http, { taxonomy: userdata, stackHeaders: data.stackHeaders }) }) diff --git a/lib/stack/taxonomy/terms/index.js b/lib/stack/taxonomy/terms/index.js index 8a98b5f7..cca55ca9 100644 --- a/lib/stack/taxonomy/terms/index.js +++ b/lib/stack/taxonomy/terms/index.js @@ -192,7 +192,7 @@ export function Terms (http, data) { const headers = { headers: { ...cloneDeep(this.stackHeaders), ...cloneDeep(params) } } - const response = await http.get(`taxonomies/${this.taxonomy_uid}/terms?term=${term}`, headers) + const response = await http.get(`taxonomies/$all/terms?typeahead=${term}`, headers) return parseData(response, this.stackHeaders) } catch (err) { console.error(err) diff --git a/package.json b/package.json index 3ab84b5e..9b6f911e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@contentstack/management", - "version": "1.11.0", + "version": "1.12.0", "description": "The Content Management API is used to manage the content of your Contentstack account", "main": "./dist/node/contentstack-management.js", "browser": "./dist/web/contentstack-management.js", diff --git a/test/typescript/index.test.ts b/test/typescript/index.test.ts index 635c46c7..51e48762 100644 --- a/test/typescript/index.test.ts +++ b/test/typescript/index.test.ts @@ -17,6 +17,8 @@ import { createApp, deleteApp, fetchApp, installation, updateApp, updateAuth } f import { deployment, hosting } from './hosting'; import { orgAppRequest } from './app-request'; import { authorization } from './authorization'; +import { testTaxonomy } from './taxonomy'; +import { testTerm } from './terms'; dotenv.config() jest.setTimeout(10000); @@ -100,6 +102,9 @@ describe('Typescript API test', () => { deleteAsset(stack) queryOnAsset(stack) + testTaxonomy(stack) + testTerm(stack) + deleteEnvironment(stack) logout(client) diff --git a/test/typescript/taxonomy.ts b/test/typescript/taxonomy.ts new file mode 100644 index 00000000..adf200e1 --- /dev/null +++ b/test/typescript/taxonomy.ts @@ -0,0 +1,68 @@ +import { expect } from "chai"; +import { Stack } from "../../types/stack"; + +var taxonomyUID = '' +export function testTaxonomy(stack: Stack) { + describe('Taxonomy API test', () => { + test('Create taxonomy', done => { + const taxonomy = { + uid: 'uid', + name: 'taxonomy', + description: 'Description for Taxonomy' + } + stack.taxonomy().create({taxonomy}) + .then((taxonomyResponse) => { + console.log(taxonomyResponse) + expect(taxonomyResponse.uid).to.be.equal(taxonomy.uid) + expect(taxonomyResponse.name).to.be.equal(taxonomy.name) + done() + }) + .catch(done) + }) + test('Fetch taxonomy from uid', done => { + stack.taxonomy(taxonomyUID).fetch() + .then((taxonomyResponse) => { + console.log(taxonomyResponse) + expect(taxonomyResponse.uid).to.be.equal(taxonomyUID) + expect(taxonomyResponse.name).not.to.be.equal('a') + done() + }) + .catch(done) + }) + test('Update taxonomy from uid', done => { + stack.taxonomy(taxonomyUID) + .fetch() + .then((taxonomyResponse) => { + taxonomyResponse.name = 'updated name' + return taxonomyResponse.update() + }) + .then((taxonomyResponse) => { + console.log(taxonomyResponse) + expect(taxonomyResponse.uid).to.be.equal(taxonomyUID) + expect(taxonomyResponse.name).to.be.equal('updated name') + done() + }) + .catch(done) + }) + test('Delete taxonomy from uid', done => { + stack.taxonomy(taxonomyUID) + .delete() + .then((taxonomyResponse) => { + expect(taxonomyResponse.notice).to.be.equal('Taxonomy deleted successfully.') + done() + }) + .catch(done) + }) + test('Query to get all taxonomies', async () => { + await stack.taxonomy() + .query() + .find() + .then((response) => { + response.items.forEach((taxonomyResponse) => { + expect(taxonomyResponse.uid).to.be.not.equal(null) + expect(taxonomyResponse.name).to.be.not.equal(null) + }) + }) + }) + }) +} diff --git a/test/typescript/terms.ts b/test/typescript/terms.ts new file mode 100644 index 00000000..ecf24dea --- /dev/null +++ b/test/typescript/terms.ts @@ -0,0 +1,118 @@ +import { expect } from "chai"; +import { Stack } from "../../types/stack"; +var taxonomyUID = '' +var termUID = '' +export function testTerm(stack: Stack) { + describe('Term API test', () => { + test('Create Term', done => { + const term = { + uid: 'term_uid', + name: 'term name', + parent_uid: 'parent_uid', + order: 1 + } + stack.taxonomy(taxonomyUID).terms().create({term}) + .then((termResponse) => { + expect(termResponse.uid).to.be.equal(term.uid) + expect(termResponse.name).to.be.equal(term.name) + done() + }) + .catch((err) => { + console.log(err) + }) + }) + test('Fetch term from uid', done => { + stack.taxonomy(taxonomyUID).terms(termUID).fetch() + .then((termResponse) => { + expect(termResponse.uid).to.be.equal(termUID) + expect(termResponse.name).not.to.be.equal(null) + done() + }) + .catch(done) + }) + test('Update term from uid', done => { + stack.taxonomy(taxonomyUID).terms(termUID) + .fetch() + .then((termResponse) => { + termResponse.name = 'Updated Name' + return termResponse.update() + }) + .then((termResponse) => { + expect(termResponse.uid).to.be.equal(termUID) + expect(termResponse.name).to.be.equal('Updated Name') + done() + }) + .catch(done) + }) + test('Delete term from uid', done => { + stack.taxonomy(taxonomyUID).terms(termUID) + .delete() + .then((termResponse) => { + expect(termResponse.notice).to.be.equal('Term deleted successfully.') + done() + }) + .catch(done) + }) + test('Query to get all Terms', done => { + stack.taxonomy(taxonomyUID).terms() + .query() + .find() + .then((response) => { + response.items.forEach((termResponse) => { + expect(termResponse.uid).to.be.not.equal(null) + expect(termResponse.name).to.be.not.equal(null) + }) + done() + }) + .catch(done) + }) + test('Ancestors of the term given', done => { + stack.taxonomy(taxonomyUID).terms(termUID) + .ancestors() + .then((termResponse) => { + expect(termResponse.terms[0].uid).not.to.be.equal(null) + expect(termResponse.terms[0].name).not.to.be.equal(null) + expect(termResponse.terms[0].created_by).not.to.be.equal(null) + expect(termResponse.terms[0].updated_by).not.to.be.equal(null) + done() + }) + .catch(done) + }) + test('Descendants of the term given', done => { + stack.taxonomy(taxonomyUID).terms(termUID) + .descendants() + .then((termResponse) => { + expect(termResponse.terms[0].uid).not.to.be.equal(null) + expect(termResponse.terms[0].name).not.to.be.equal(null) + expect(termResponse.terms[0].created_by).not.to.be.equal(null) + expect(termResponse.terms[0].updated_by).not.to.be.equal(null) + done() + }) + .catch(done) + }) + it('search term', done => { + const typeahead = 'term_string' + stack.taxonomy('$all').terms() + .search(typeahead) + .then((termResponse) => { + expect(termResponse.terms).to.be.an('array') + done() + }) + .catch((err) => {console.log(err)}) + + }) + it('move term', done => { + const term = { + parent_uid: 'parent_uid', + order: 2 + } + stack.taxonomy(taxonomyUID).terms(termUID) + .move({ term }) + .then((termResponse) => { + expect(termResponse.notice).to.be.equal('Term moved successfully.') + done() + }) + .catch(done) + }) + }) +} diff --git a/test/unit/concurrency-Queue-test.js b/test/unit/concurrency-Queue-test.js index 8d52fa7e..04a6fb58 100644 --- a/test/unit/concurrency-Queue-test.js +++ b/test/unit/concurrency-Queue-test.js @@ -163,6 +163,26 @@ describe('Concurrency queue test', () => { .catch(done) }) + it('should give passed error message when refreshToken function fails', done => { + const axios = client({ + baseURL: `${host}:${port}`, + authorization: 'Bearer ', + logHandler: logHandlerStub, + refreshToken: () => { + return new Promise((resolve, reject) => { + reject(new Error('Rejected in Promise')) + }) + } + }) + Promise.all(sequence(3).map(() => axios.axiosInstance.get('/unauthorized'))) + .catch(err => { + expect(err.errorCode).to.equal('401') + expect(err.errorMessage).to.equal('Rejected in Promise') + expect(err.message).to.equal('Unable to refresh token') + done() + }) + }) + it('Initialize with bad axios instance', done => { try { new ConcurrencyQueue({ axios: undefined }) diff --git a/test/unit/taxonomy-test.js b/test/unit/taxonomy-test.js index b9435185..b5f09386 100644 --- a/test/unit/taxonomy-test.js +++ b/test/unit/taxonomy-test.js @@ -44,7 +44,7 @@ describe('Contentstack Taxonomy test', () => { it('Taxonomies query test', done => { var mock = new MockAdapter(Axios) mock.onGet('/taxonomies').reply(200, { - taxonomy: [ + taxonomies: [ taxonomyMock ] }) diff --git a/test/unit/terms-test.js b/test/unit/terms-test.js index 67e93420..39336346 100644 --- a/test/unit/terms-test.js +++ b/test/unit/terms-test.js @@ -169,7 +169,7 @@ describe('Contentstack Term test', () => { }) it('term search test', done => { var mock = new MockAdapter(Axios) - mock.onGet(`/taxonomies/taxonomy_uid/terms?term=UID`).reply(200, { + mock.onGet(`/taxonomies/$all/terms?typeahead=UID`).reply(200, { term: { ...termsMock } diff --git a/types/stack/index.d.ts b/types/stack/index.d.ts index 913585ec..a1363af3 100644 --- a/types/stack/index.d.ts +++ b/types/stack/index.d.ts @@ -18,6 +18,7 @@ import { Release, Releases } from "./release"; import { Role, Roles } from "./role"; import { Webhook, Webhooks } from "./webhook"; import { Workflow, Workflows } from "./workflow"; +import { Taxonomy, Taxonomies } from "./taxonomy"; export interface StackConfig { api_key:string @@ -92,4 +93,7 @@ export interface Stack extends SystemFields { unShare(email: string): Promise role(): Roles role(uid: string): Role + + taxonomy(): Taxonomies + taxonomy(uid: string): Taxonomy } diff --git a/types/stack/taxonomy/index.d.ts b/types/stack/taxonomy/index.d.ts new file mode 100644 index 00000000..c0a23a22 --- /dev/null +++ b/types/stack/taxonomy/index.d.ts @@ -0,0 +1,20 @@ +import { AnyProperty, SystemFields } from "../../utility/fields"; +import { Creatable, Queryable, SystemFunction } from "../../utility/operations"; +import { Term, Terms } from "../taxonomy/terms" + +export interface Taxonomy extends SystemFields, SystemFunction { + terms(): Terms + terms(uid: string): Term +} + +export interface Taxonomies extends Queryable { +} + +export interface Taxonomies extends Creatable { +} + +export interface TaxonomyData extends AnyProperty { + name: string + uid: string + description: string +} diff --git a/types/stack/taxonomy/terms/index.d.ts b/types/stack/taxonomy/terms/index.d.ts new file mode 100644 index 00000000..a95ab7c9 --- /dev/null +++ b/types/stack/taxonomy/terms/index.d.ts @@ -0,0 +1,24 @@ +import { AnyProperty, SystemFields } from "../../../utility/fields"; +import { Creatable, Queryable, Searchable, SystemFunction } from "../../../utility/operations"; + +export interface Term extends SystemFields, SystemFunction { + ancestors(data?: { include_children_count?: boolean, include_referenced_entries_count?: boolean, include_count?: boolean, skip?: number, limit?: number}): Promise + descendants(data?: { include_children_count?: boolean, include_referenced_entries_count?: boolean, include_count?: boolean, skip?: number, limit?: number}): Promise + move(data: { term: { parent_uid?: string, order: number } }, force?: boolean): Promise +} + +export interface Terms extends Creatable { +} + +export interface Terms extends Searchable { +} + +export interface Terms extends Queryable { +} + +export interface TermData extends AnyProperty { + name: string + uid: string + parent_uid?: string + order: number +} diff --git a/types/utility/operations.d.ts b/types/utility/operations.d.ts index 6e43cfed..89840f26 100644 --- a/types/utility/operations.d.ts +++ b/types/utility/operations.d.ts @@ -6,6 +6,10 @@ export interface Creatable { create(data: D, param?: AnyProperty): Promise } +export interface Searchable { + search(string: D, param?: AnyProperty): Promise +} + export interface SystemFunction { update(param?: AnyProperty): Promise fetch(param?: AnyProperty): Promise