diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 5bb82fba..cb626701 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -1,7 +1,10 @@ name: Unit Test & Reports on: pull_request: - push: + branches: + - master + - main + - next jobs: build-test: name: Build & Test @@ -23,6 +26,5 @@ jobs: reporter: mocha-json # Format of test results - name: Coverage report uses: lucassabreu/comment-coverage-clover@main - with: - name: Unit test Coverage report + with: file: coverage/clover.xml \ No newline at end of file diff --git a/.jsdoc.json b/.jsdoc.json index 6da32180..c0363440 100644 --- a/.jsdoc.json +++ b/.jsdoc.json @@ -32,8 +32,10 @@ "lib/stack/roles/index.js", "lib/stack/webhook/index.js", "lib/stack/workflow/index.js", - "lib/stack/workflow/publishRules/index.js" - + "lib/stack/workflow/publishRules/index.js", + "lib/organization/teams/index.js", + "lib/organization/teams/stackRoleMappings/index.js", + "lib/organization/teams/teamUsers/index.js" ], "excludePattern": "(node_modules/|jsdocs)" }, diff --git a/.talismanrc b/.talismanrc index b61827c6..adb09795 100644 --- a/.talismanrc +++ b/.talismanrc @@ -1,5 +1,5 @@ threshold: medium fileignoreconfig: - filename: package-lock.json - checksum: ef5d374553f431b5a952069f46184ec7e49efd7d72143e1a1642994758db4359 + checksum: 9a7bec9513834a0fc7db31b9a312ec35980600415c04f0d404e1370cfce1ef1b version: "" \ No newline at end of file diff --git a/lib/organization/index.js b/lib/organization/index.js index 5d35409f..725bd65a 100644 --- a/lib/organization/index.js +++ b/lib/organization/index.js @@ -7,6 +7,7 @@ import { StackCollection } from '../stack' import { UserCollection } from '../user' import { App } from '../app' import { AppRequest } from '../app/request' +import { Teams } from './teams' /** * Organization is the top-level entity in the hierarchy of Contentstack, consisting of stacks and stack resources, and users. Organization allows easy management of projects as well as users within the Organization. Read more about Organizations.. * @namespace Organization @@ -18,6 +19,26 @@ export function Organization (http, data) { Object.assign(this, cloneDeep(data.organization)) this.urlPath = `/organizations/${this.uid}` + /** + * @description The teams call fetches teams details. + * @memberof Organization + * @func teams + * @returns {Promise} Promise for Organization instance + * @example + * import * as contentstack from '@contentstack/management' + * const client = contentstack.client() + * + * client.organization('organization_uid').teams('teamsUid').fetch() + * .then((organization) => console.log(organization)) + * + */ + this.teams = (teamUid = null) => { + data.organizationUid = this.uid + if (teamUid) { + data.uid = teamUid + } + return new Teams(http, data) + } /** * @description The fetch Organization call fetches Organization details. * @memberof Organization diff --git a/lib/organization/teams/index.js b/lib/organization/teams/index.js new file mode 100644 index 00000000..7585fb9d --- /dev/null +++ b/lib/organization/teams/index.js @@ -0,0 +1,153 @@ +import cloneDeep from 'lodash/cloneDeep' +import { + create, + fetch, + deleteEntity, + fetchAll +} from '../../entity' +import { TeamUsers } from './teamUsers' +import { StackRoleMappings } from './stackRoleMappings' +import error from '../../core/contentstackError' + +export function Teams (http, data) { + this.organizationUid = data.organizationUid + this.urlPath = `/organizations/${this.organizationUid}/teams` + if (data && data.uid) { + Object.assign(this, cloneDeep(data)) + + this.urlPath = `/organizations/${this.organizationUid}/teams/${this.uid}` + + /** + * @description The update call on team will allow to update details of team. + * @memberof Teams + * @func update + * @returns {Promise} Response Object. + * @example + * import * as contentstack from '@contentstack/management' + * const client = contentstack.client() + * const updateData = { + * name: 'updatedname', + * users: [ + * { + * email: 'abc@abc.com' + * } + * ], + * organizationRole: 'blt09e5dfced326aaea', + * stackRoleMapping: [] + * } + * client.organization(s'organizationUid').teams('teamUid').update(updateData) + * .then((response) => console.log(response)) + * + */ + this.update = async (updateData) => { + try { + const response = await http.put(this.urlPath, updateData) + if (response.data) { + return response.data + } + } catch (err) { + throw error(err) + } + } + + /** + * @description The delete call on team will delete the existing team. + * @memberof Teams + * @func delete + * @returns {Promise} Response Object. + * @example + * import * as contentstack from '@contentstack/management' + * const client = contentstack.client() + * client.organization('organizationUid').teams('teamUid').delete() + * .then((response) => console.log(response)) + * + */ + this.delete = deleteEntity(http) + + /** + * @description The fetch call on team will delete the existing team. + * @memberof Teams + * @func fetch + * @returns {Promise} Response Object. + * @example + * import * as contentstack from '@contentstack/management' + * const client = contentstack.client() + * client.organization('organizationUid').teams('teamUid').fetch() + * .then((response) => console.log(response)) + * + */ + this.fetch = fetch(http, 'team') + + /** + * @description The users call on team will get users details. + * @memberof Teams + * @func users + * @returns {Promise} Response Object. + * @example + * import * as contentstack from '@contentstack/management' + * const client = contentstack.client() + * client.organization('organizationUid').teams('teamUid').users().fetchAll() + * .then((response) => console.log(response)) + * + */ + this.users = (userId = null) => { + data.organizationUid = this.organizationUid + data.teamUid = this.uid + if (userId) { + data.userId = userId + } + return new TeamUsers(http, data) + } + + this.stackRoleMappings = (stackApiKey = null) => { + data.organizationUid = this.organizationUid + data.teamUid = this.uid + if (stackApiKey) { + data.stackApiKey = stackApiKey + } + return new StackRoleMappings(http, data) + } + } else { + /** + * @description The fetch call on team will delete the existing team. + * @memberof Teams + * @func create + * @returns {Promise} Response Object. + * @example + * import * as contentstack from '@contentstack/management' + * const client = contentstack.client() + * const team = { + * name: 'name', + * organizationUid: 'organization_uid', + * users: [], + * stackRoleMapping: [], + * organizationRole: 'organizationRole' + * } + * client.organization('organizationUid').teams().create(team) + * .then((response) => console.log(response)) + * + */ + this.create = create({ http }) + + /** + * @description The fetchAll on team will allow to fetch details of all teams. + * @memberof Teams + * @func fetchAll + * @returns {Promise} Response Object. + * @example + * import * as contentstack from '@contentstack/management' + * const client = contentstack.client() + * + * client.organization('organizationUid').teams().fetchAll() + * .then((response) => console.log(response)) + */ + this.fetchAll = fetchAll(http, TeamsCollection) + } +} +export function TeamsCollection (http, teamsData) { + const obj = cloneDeep(teamsData) || [] + const teamsCollection = obj.map((team) => { + return new Teams(http, team) + }) + return teamsCollection +} diff --git a/lib/organization/teams/stackRoleMappings/index.js b/lib/organization/teams/stackRoleMappings/index.js new file mode 100644 index 00000000..2d34d5f4 --- /dev/null +++ b/lib/organization/teams/stackRoleMappings/index.js @@ -0,0 +1,118 @@ +/** + * @namespace StackRoleMappings + */ +import cloneDeep from 'lodash/cloneDeep' +import { + deleteEntity +} from '../../../entity' +import error from '../../../core/contentstackError' + +export function StackRoleMappings (http, data) { + const _urlPath = `/organizations/${data.organizationUid}/teams/${data.teamUid}/stack_role_mappings` + if (data && data.stackApiKey) { + Object.assign(this, cloneDeep(data)) + + if (this.organizationUid) this.urlPath = `${_urlPath}/${this.stackApiKey}` + /** + * @description The update stackRoleMappings call is used to update the roles. + * @memberof StackRoleMappings + * @func update + * @returns {Promise} Response Object. + * @example + * import * as contentstack from '@contentstack/management' + * const client = contentstack.client() + * const updateRoles = { + * roles: [ + * 'roles_uid1', + * 'roles_uid2' + * ] + * } + * client.organization('organizationUid').teams('teamUid').stackRoleMappings('stackApiKey').update(updateRoles) + * .then((response) => console.log(response)) + */ + this.update = async (updateData, params = {}) => { + try { + const response = await http.put(this.urlPath, updateData, { params }) + if (response.data) { + return response.data + } + } catch (err) { + throw error(err) + } + } + + /** + * @description The delete stackRoleMappings call is used to delete the roles. + * @memberof StackRoleMappings + * @func delete + * @returns {Promise} Response Object. + * @example + * import * as contentstack from '@contentstack/management' + * const client = contentstack.client() + * + * client.organization('organizationUid').teams('teamUid').stackRoleMappings('stackApiKey').delete() + * .then((response) => console.log(response)) + */ + this.delete = deleteEntity(http) + } else { + this.urlPath = _urlPath + /** + * @description The add stackRoleMappings call is used to add the roles. + * @memberof StackRoleMappings + * @func add + * @returns {Promise} Response Object. + * @example + * import * as contentstack from '@contentstack/management' + * const client = contentstack.client() + * + * const addRole = { + * 'stackApiKey: 'stackApiKey', + * 'roles': [ + * 'role_uid' + * ] + * } + * client.organization('organizationUid').teams('teamUid').stackRoleMappings().add(addRole) + * .then((response) => console.log(response)) + */ + this.add = async (updateData, params = {}) => { + try { + const response = await http.post(this.urlPath, updateData, { params }) + if (response.data) { + return response.data + } + } catch (err) { + throw error(err) + } + } + + /** + * @description The fetchAll stackRoleMappings call is used to fetchAll the roles. + * @memberof StackRoleMappings + * @func fetchAll + * @returns {Promise} Response Object. + * @example + * import * as contentstack from '@contentstack/management' + * const client = contentstack.client() + * + * client.organization('organizationUid').teams('teamUid').stackRoleMappings().fetchAll + * .then((response) => console.log(response)) + */ + this.fetchAll = async () => { + try { + const response = await http.get(this.urlPath) + if (response.data) { + return response.data + } + } catch (err) { + throw error(err) + } + } + } +} +export function stackRoleMappingsCollection (http, data) { + const obj = cloneDeep(data.stackRoleMappings) || [] + const stackRoleMappingCollection = obj.map((stackRoleMappings) => { + return stackRoleMappings(http, { stackRoleMappings: stackRoleMappings }) + }) + return new StackRoleMappings(http, stackRoleMappingCollection) +} diff --git a/lib/organization/teams/teamUsers/index.js b/lib/organization/teams/teamUsers/index.js new file mode 100644 index 00000000..b56b4c21 --- /dev/null +++ b/lib/organization/teams/teamUsers/index.js @@ -0,0 +1,72 @@ +import cloneDeep from 'lodash/cloneDeep' +import { + create, + deleteEntity, + fetchAll +} from '../../../entity' + +export function TeamUsers (http, data) { + if (data && data.userId) { + Object.assign(this, cloneDeep(data)) + + const _urlPath = `/organizations/${this.organizationUid}/teams/${this.teamUid}/users/${data.userId}` + if (this.organizationUid) this.urlPath = _urlPath + + /** + * @description The Remove teamUser call is used to remove an existing user of that team. + * @memberof TeamUsers + * @func remove + * @returns {Promise} Response Object. + * @example + * import * as contentstack from '@contentstack/management' + * const client = contentstack.client() + * + * client.organization('organizationUid').teams('teamUid').users('userId').remove() + * .then((response) => console.log(response)) + * + */ + this.remove = deleteEntity(http) + } else { + this.urlPath = `/organizations/${data.organizationUid}/teams/${data.teamUid}/users` + + /** + * @description The Add teamUser call is used to add an user the team. + * @memberof TeamUsers + * @func add + * @returns {Promise} Response Object. + * @example + * import * as contentstack from '@contentstack/management' + * const client = contentstack.client() + * const usersMail = { + * emails: ['emailId1','emailId2' ] + * } + * client.organization('organizationUid').teams('teamUid').users('userId').add(usersMail) + * .then((response) => console.log(response)) + * + */ + this.add = create({ http }) + + /** + * @description The Query on teamUser will allow to fetch details of all teamUsers. + * @memberof TeamUsers + * @func query + * @returns {Promise} Response Object. + * @example + * import * as contentstack from '@contentstack/management' + * const client = contentstack.client() + * const usersMail = { + * emails: ['emailId1','emailId2' ]} + * client.organization('organizationUid').teams('teamUid').users('userId').query().find() + * .then((response) => console.log(response)) + * + */ + this.fetchAll = fetchAll(http, UsersCollection) + } +} +export function UsersCollection (http, data) { + const obj = cloneDeep(data.users) || [] + const usersCollection = obj.map((user) => { + return new TeamUsers(http, { userId: user }) + }) + return usersCollection +} diff --git a/package-lock.json b/package-lock.json index eb8d451e..aaa58d6e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "@contentstack/management", - "version": "1.10.2", + "version": "1.11.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@contentstack/management", - "version": "1.10.2", + "version": "1.11.0", "license": "MIT", "dependencies": { - "axios": "^1.5.1", + "axios": "^1.6.0", "form-data": "^3.0.1", "lodash": "^4.17.21", "qs": "^6.11.2" @@ -3617,9 +3617,9 @@ } }, "node_modules/axios": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz", - "integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.0.tgz", + "integrity": "sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==", "dependencies": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", @@ -15160,9 +15160,9 @@ "dev": true }, "axios": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz", - "integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.0.tgz", + "integrity": "sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==", "requires": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", diff --git a/package.json b/package.json index 3ab84b5e..742e27bb 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "author": "Contentstack", "license": "MIT", "dependencies": { - "axios": "^1.5.1", + "axios": "^1.6.0", "form-data": "^3.0.1", "lodash": "^4.17.21", "qs": "^6.11.2" diff --git a/test/api/team-stack-role-mapping-test.js b/test/api/team-stack-role-mapping-test.js new file mode 100644 index 00000000..c94bc318 --- /dev/null +++ b/test/api/team-stack-role-mapping-test.js @@ -0,0 +1,65 @@ +import { describe, it, beforeEach } from 'mocha' +import { expect } from 'chai' +import { jsonReader } from '../utility/fileOperations/readwrite' +import { contentstackClient } from '../utility/ContentstackClient.js' + +let client = {} + +const stackApiKey = 'stackApiKey' +const organizationUid = 'organizationUid' +const teamUid = 'teamUid' + +describe('Teams API Test', () => { + beforeEach(() => { + const user = jsonReader('loggedinuser.json') + client = contentstackClient(user.authtoken) + }) + it('should fetch all stackRoleMappings', done => { + makestackRoleMappings(organizationUid, teamUid).fetchAll().then((response) => { + expect(response.stackRoleMappings).to.be.not.equal(undefined) + done() + }) + .catch(done) + }) + it('should add roles', done => { + const stackRoleMappings = { + stackApiKey: 'stackApiKey', + roles: [ + 'role_uid' + ] + } + makestackRoleMappings(organizationUid, teamUid).add(stackRoleMappings).then((response) => { + expect(response.stackRoleMapping).not.to.be.equal(undefined) + expect(response.stackRoleMapping.roles[0]).to.be.equal(stackRoleMappings.roles[0]) + expect(response.stackRoleMapping.stackApiKey).to.be.equal(stackRoleMappings.stackApiKey) + done() + }) + .catch(done) + }) + it('should update roles', done => { + const stackRoleMappings = { + roles: [ + 'role_uid1', + 'role_uid2' + ] + } + makestackRoleMappings(organizationUid, teamUid, stackApiKey).update(stackRoleMappings).then((response) => { + expect(response.stackRoleMapping).not.to.be.equal(undefined) + expect(response.stackRoleMapping.roles[0]).to.be.equal(stackRoleMappings.roles[0]) + expect(response.stackRoleMapping.stackApiKey).to.be.equal(stackApiKey) + done() + }) + .catch(done) + }) + it('should delete roles', done => { + makestackRoleMappings(organizationUid, teamUid, stackApiKey).delete().then((response) => { + expect(response.status).to.be.equal(204) + done() + }) + .catch(done) + }) +}) + +function makestackRoleMappings (organizationUid, teamUid, stackApiKey = null) { + return client.organization(organizationUid).teams(teamUid).stackRoleMappings(stackApiKey) +} diff --git a/test/api/team-test.js b/test/api/team-test.js new file mode 100644 index 00000000..4cbb6408 --- /dev/null +++ b/test/api/team-test.js @@ -0,0 +1,69 @@ +import { describe, it, beforeEach } from 'mocha' +import { expect } from 'chai' +import { jsonReader } from '../utility/fileOperations/readwrite' +import { contentstackClient } from '../utility/ContentstackClient.js' + +let client = {} + +const organizationUid = 'organizationUid' +const teamUid = 'teamUid' +const deleteUid = 'deleteUid' + +describe('Teams API Test', () => { + beforeEach(() => { + const user = jsonReader('loggedinuser.json') + client = contentstackClient(user.authtoken) + }) + it('should get all the teams when correct organization uid is passed', async () => { + const response = await makeTeams(organizationUid).fetchAll() + expect(response.items[0].organizationUid).to.be.equal(organizationUid) + expect(response.items[0].name).not.to.be.equal(null) + expect(response.items[0].created_by).not.to.be.equal(null) + expect(response.items[0].updated_by).not.to.be.equal(null) + }) + it('should fetch the team when correct organization uid and team uid is passed', async () => { + const response = await makeTeams(organizationUid, teamUid).fetch() + expect(response.uid).to.be.equal(teamUid) + expect(response.organizationUid).to.be.equal(organizationUid) + expect(response.name).not.to.be.equal(null) + expect(response.created_by).not.to.be.equal(null) + expect(response.updated_by).not.to.be.equal(null) + }) + it('should create new team when required object is passed', async () => { + const response = await makeTeams(organizationUid).create({ + name: 'test_team', + users: [], + stackRoleMapping: [], + organizationRole: 'organizationRole' }) + expect(response.uid).not.to.be.equal(null) + expect(response.name).not.to.be.equal(null) + expect(response.stackRoleMapping).not.to.be.equal(null) + expect(response.organizationRole).not.to.be.equal(null) + }) + it('should delete team when correct organization uid and team uid is passed', async () => { + const response = await makeTeams(organizationUid, deleteUid).delete() + expect(response.status).to.be.equal(204) + }) + it('should update team when updating data is passed', async () => { + const updateData = { + name: 'name', + users: [ + { + email: 'abc@abc.com' + } + ], + organizationRole: '', + stackRoleMapping: [] + } + await makeTeams(organizationUid, teamUid).update(updateData) + .then((team) => { + expect(team.name).to.be.equal(updateData.name) + expect(team.createdByUserName).not.to.be.equal(undefined) + expect(team.updatedByUserName).not.to.be.equal(undefined) + }) + }) +}) + +function makeTeams (organizationUid, teamUid = null) { + return client.organization(organizationUid).teams(teamUid) +} diff --git a/test/api/team-users-test.js b/test/api/team-users-test.js new file mode 100644 index 00000000..674cfb57 --- /dev/null +++ b/test/api/team-users-test.js @@ -0,0 +1,46 @@ +import { describe, it, beforeEach } from 'mocha' +import { expect } from 'chai' +import { jsonReader } from '../utility/fileOperations/readwrite' +import { contentstackClient } from '../utility/ContentstackClient.js' + +let client = {} + +const organizationUid = 'organizationUid' +const teamUid = 'teamUid' +const userId = 'userId' + +describe('Teams Users API Test', () => { + beforeEach(() => { + const user = jsonReader('loggedinuser.json') + client = contentstackClient(user.authtoken) + }) + it('should add the user when user\'s mail is passed', done => { + const usersMail = { + emails: ['email@email.com'] + } + makeUsers(organizationUid, teamUid).add(usersMail).then((response) => { + expect(response).to.be.equal(null) + }) + .catch(done) + }) + it('should remove the user when uid is passed', done => { + makeUsers(organizationUid, teamUid, userId).remove().then((response) => { + expect(response.status).to.be.equal(204) + done() + }) + .catch(done) + }) + it('should fetch all users', async () => { + makeUsers(organizationUid, teamUid) + .fetchAll() + .then((response) => { + response.items.forEach((user) => { + expect(user.uidId).to.be.not.equal(null) + }) + }) + }) +}) + +function makeUsers (organizationUid, teamUid, userId = null) { + return client.organization(organizationUid).teams(teamUid).users(userId) +} diff --git a/test/test.js b/test/test.js index d7e30522..8b4ec6b2 100644 --- a/test/test.js +++ b/test/test.js @@ -27,3 +27,6 @@ require('./api/contentType-delete-test') require('./api/delete-test') require('./api/taxonomy-test') require('./api/terms-test') +require('./api/team-test') +require('./api/team-users-test') +require('./api/team-stack-role-mapping-test') diff --git a/test/typescript/index.test.ts b/test/typescript/index.test.ts index 51e48762..e7546da4 100644 --- a/test/typescript/index.test.ts +++ b/test/typescript/index.test.ts @@ -19,6 +19,9 @@ import { orgAppRequest } from './app-request'; import { authorization } from './authorization'; import { testTaxonomy } from './taxonomy'; import { testTerm } from './terms'; +import { testTeams } from './teams'; +import { testTeamUsers } from './teamUsers'; +import { testTeamStackRoleMapping } from './teamsStackRoleMappings'; dotenv.config() jest.setTimeout(10000); @@ -49,7 +52,10 @@ describe('Typescript API test', () => { authorization(org.app(process.env.APP_UID as string).authorization()) orgAppRequest(org.appRequest()) deleteApp(org) - + testTeams(org) + testTeamUsers(org) + testTeamStackRoleMapping(org) + const stack = client.stack({api_key: process.env.APIKEY as string}) createBranch(stack) diff --git a/test/typescript/teamUsers.ts b/test/typescript/teamUsers.ts new file mode 100644 index 00000000..45245a3f --- /dev/null +++ b/test/typescript/teamUsers.ts @@ -0,0 +1,36 @@ +import { expect } from "chai"; +import { Organization } from "../../types/organization"; + +let teamUid = 'teamUid' +export function testTeamUsers (organization: Organization) { + describe('Contentstack Team Users test', () => { + test('should add the user when user\'s mail is passed', done => { + const usersMail = { + emails: ['email@email.com'] + } + organization.teams(teamUid).users().add(usersMail).then((response) => { + expect(response).not.to.be.equal(null) + done() + }) + .catch(done) + }) + test('should remove the user when uid is passed', done => { + const user_id = 'user_id' + organization.teams(teamUid).users(user_id).remove().then((response) => { + expect(response.status).to.be.equal(204) + done() + }) + .catch(done) + }) + test('should fetch all users', done => { + organization.teams(teamUid).users() + .fetchAll() + .then((response) => { + expect(response.items[0]).not.to.be.equal(undefined) + done() + }) + .catch(done) + }) + }) +} + diff --git a/test/typescript/teams.ts b/test/typescript/teams.ts new file mode 100644 index 00000000..158fe4a1 --- /dev/null +++ b/test/typescript/teams.ts @@ -0,0 +1,78 @@ +import { expect } from "chai"; +import { Organization } from "../../types/organization"; + +let teamUid = '' +export function testTeams (organization: Organization) { + describe('Contentstack Teams test', () => { + test('should fetch all the teams', done => { + organization.teams().fetchAll() + .then((teams) => { + expect(teams[0].organizationUid).not.to.be.equal(undefined) + expect(teams[0].name).not.to.be.equal(null) + expect(teams[0].created_by).not.to.be.equal(null) + expect(teams[0].updated_by).not.to.be.equal(null) + done() + }) + .catch(done) + }) + test('should fetch the team when correct organization uid and team uid is passed', done => { + organization.teams(teamUid).fetch() + .then((teams) => { + expect(teams.uid).to.be.equal(teamUid) + expect(teams.organizationUid).not.to.be.equal(undefined) + expect(teams.name).not.to.be.equal(null) + expect(teams.created_by).not.to.be.equal(null) + expect(teams.updated_by).not.to.be.equal(null) + done() + }) + .catch(done) + }) + test('should create new team when required object is passed', done => { + const createData = { + name: 'test_team', + users: [], + stackRoleMapping: [], + organizationRole: '' + } + organization.teams().create(createData) + .then((teams) => { + expect(teams.uid).not.to.be.equal(null) + expect(teams.name).not.to.be.equal(null) + expect(teams.stackRoleMapping).not.to.be.equal(null) + expect(teams.organizationRole).not.to.be.equal(null) + done() + }) + .catch(done) + }) + test('should delete team when correct organization uid and team uid is passed', done => { + organization.teams(teamUid).delete() + .then((teams) => { + expect(teams.status).to.be.equal(204) + done() + }) + .catch(done) + }) + test('should update team when update data is passed', done => { + const updateData = { + name: 'name', + users: [ + { + email: 'abc@abc.com' + } + ], + organizationRole: '', + stackRoleMapping: [] + } + organization.teams(teamUid).update(updateData) + .then((team) => { + expect(team.name).to.be.equal(updateData.name) + expect(team.organizationRole).to.be.equal(updateData.organizationRole) + expect(team.createdByUserName).not.to.be.equal(undefined) + expect(team.updatedByUserName).not.to.be.equal(undefined) + done() + }) + .catch(done) + }) + }) +} + diff --git a/test/typescript/teamsStackRoleMappings.ts b/test/typescript/teamsStackRoleMappings.ts new file mode 100644 index 00000000..60cf5257 --- /dev/null +++ b/test/typescript/teamsStackRoleMappings.ts @@ -0,0 +1,54 @@ +import { expect } from "chai"; +import { Organization } from "../../types/organization"; + +let teamUid = 'teamUid' +let stackApiKey = 'stackApiKey' +export function testTeamStackRoleMapping (organization: Organization) { + describe('Contentstack Teams Stack Role Mapping test', () => { + it('should fetch all stackRoleMappings', done => { + organization.teams(teamUid).stackRoleMappings().fetchAll().then((response) => { + expect(response).to.be.not.equal(undefined) + done() + }) + .catch(done) + }) + it('should add roles', done => { + const stackRoleMappings = { + stackApiKey: 'stackApiKey', + roles: [ + 'role_uid' + ] + } + organization.teams(teamUid).stackRoleMappings().add(stackRoleMappings).then((response) => { + expect(response.stackRoleMapping).not.to.be.equal(undefined) + expect(response.stackRoleMapping.roles[0]).to.be.equal(stackRoleMappings.roles[0]) + expect(response.stackRoleMapping.stackApiKey).to.be.equal(stackRoleMappings.stackApiKey) + done() + }) + .catch(done) + }) + it('should update roles', (done) => { + const stackRoleMappings = { + roles: [ + 'role_uid1', + 'role_uid2' + ] + } + organization.teams(teamUid).stackRoleMappings(stackApiKey).update(stackRoleMappings).then((response) => { + expect(response).not.to.be.equal(undefined) + expect(response.stackRoleMapping.roles).to.be.eql(stackRoleMappings.roles) + expect(response.stackRoleMapping.stackApiKey).to.be.equal(stackApiKey) + done() + }) + .catch(done) + }) + it('should delete roles', done => { + organization.teams(teamUid).stackRoleMappings(stackApiKey).delete().then((response) => { + expect(response.status).to.be.equal(204) + done() + }) + .catch(done) + }) + }) +} + diff --git a/test/unit/index.js b/test/unit/index.js index 2877b750..1eccb05e 100644 --- a/test/unit/index.js +++ b/test/unit/index.js @@ -35,3 +35,6 @@ require('./authorization-test') require('./auditLog-test') require('./taxonomy-test') require('./terms-test') +require('./team-test') +require('./team-users-test') +require('./team-stack-role-mapping-test') diff --git a/test/unit/mock/objects.js b/test/unit/mock/objects.js index 1c82cc1a..a8dbf9a9 100644 --- a/test/unit/mock/objects.js +++ b/test/unit/mock/objects.js @@ -774,7 +774,30 @@ const termsMock = { referenced_entries_count: 4 }] } - +const teamsMock = { + uid: 'UID', + name: 'name', + organizationUid: 'organization_uid', + users: [], + stackRoleMapping: [], + organizationRole: 'organizationRole' +} +const teamUsersMock = { + users: ['user1', 'user2', 'UID'], + addUser: { + userId: 'UID' + } +} +const stackRoleMappingMock = { + stackRoleMappings: [ + { + stackApiKey: 'stackApiKey', + roles: [ + 'roles_uid' + ] + } + ] +} function mockCollection (mockData, type) { const mock = { ...cloneDeep(noticeMock), @@ -845,6 +868,9 @@ export { auditLogItemMock, taxonomyMock, termsMock, + teamsMock, + teamUsersMock, + stackRoleMappingMock, mockCollection, entryMockCollection, checkSystemFields diff --git a/test/unit/taxonomy-test.js b/test/unit/taxonomy-test.js index b5f09386..c5f67190 100644 --- a/test/unit/taxonomy-test.js +++ b/test/unit/taxonomy-test.js @@ -3,7 +3,7 @@ import { expect } from 'chai' import { describe, it } from 'mocha' import MockAdapter from 'axios-mock-adapter' import { Taxonomy } from '../../lib/stack/taxonomy' -import { systemUidMock, stackHeadersMock, taxonomyMock, noticeMock } from './mock/objects' +import { systemUidMock, stackHeadersMock, taxonomyMock, noticeMock, termsMock } from './mock/objects' describe('Contentstack Taxonomy test', () => { it('taxonomy create test', done => { @@ -121,6 +121,29 @@ describe('Contentstack Taxonomy test', () => { expect(taxonomy.query).to.be.equal(undefined) done() }) + + it('term create test', done => { + var mock = new MockAdapter(Axios) + mock.onPost(`/taxonomies/taxonomy_uid/terms`).reply(200, { + term: { + ...termsMock + } + }) + makeTaxonomy({ + taxonomy: { + uid: 'taxonomy_uid' + }, + stackHeaders: stackHeadersMock + }).terms() + .create() + .then((term) => { + expect(term.taxonomy_uid).to.be.not.equal(undefined) + expect(term.uid).to.be.equal('UID') + expect(term.name).to.be.equal('name') + done() + }) + .catch(done) + }) }) function makeTaxonomy (data = {}) { diff --git a/test/unit/team-stack-role-mapping-test.js b/test/unit/team-stack-role-mapping-test.js new file mode 100644 index 00000000..96fe642d --- /dev/null +++ b/test/unit/team-stack-role-mapping-test.js @@ -0,0 +1,88 @@ +import Axios from 'axios' +import { expect } from 'chai' +import { describe, it } from 'mocha' +import MockAdapter from 'axios-mock-adapter' +import { StackRoleMappings } from '../../lib/organization/teams/stackRoleMappings' +import { stackRoleMappingMock } from './mock/objects' + +describe('Contentstack Team Stack Role Mapping test', () => { + it('should fetch all the roles', done => { + var mock = new MockAdapter(Axios) + mock.onGet(`/organizations/organization_uid/teams/team_uid/stack_role_mappings`).reply(200, stackRoleMappingMock) + makeStackRoleMapping().fetchAll() + .then((response) => { + expect(response.stackRoleMappings).to.be.not.equal(undefined) + done() + }) + .catch(done) + }) + it('should add roles when correct data is passed', done => { + const addStackRoleMappingMock = { + stackRoleMapping: { + stackApiKey: 'stackApiKey', + roles: [ + 'role_uid' + ] + } + } + var mock = new MockAdapter(Axios) + mock.onPost(`/organizations/organization_uid/teams/team_uid/stack_role_mappings`).reply(200, addStackRoleMappingMock) + const addRole = { + stackApiKey: 'stackApiKey', + roles: [ + 'role_uid' + + ] + } + makeStackRoleMapping() + .add(addRole) + .then((response) => { + expect(response.stackRoleMapping).not.to.be.equal(undefined) + expect(response.stackRoleMapping.roles[0]).to.be.equal(addRole.roles[0]) + expect(response.stackRoleMapping.stackApiKey).to.be.equal(addRole.stackApiKey) + done() + }) + .catch(done) + }) + it('should update stack role mapping when stack api key and updateData are passed', done => { + const updateStackRoleMappingMock = { + stackRoleMapping: { + stackApiKey: 'STACKAPIKEY', + roles: [ + 'role_uid1', + 'role_uid2' + ] + } + } + var mock = new MockAdapter(Axios) + mock.onPut(`/organizations/organization_uid/teams/team_uid/stack_role_mappings/STACKAPIKEY`).reply(200, updateStackRoleMappingMock) + const stackRoleMappings = { + roles: [ + 'role_uid1', + 'role_uid2' + ] + } + makeStackRoleMapping({ stackApiKey: 'STACKAPIKEY' }).update(stackRoleMappings) + .then((response) => { + expect(response.stackRoleMapping).not.to.be.equal(undefined) + expect(response.stackRoleMapping.roles[0]).to.be.equal(stackRoleMappings.roles[0]) + expect(response.stackRoleMapping.stackApiKey).to.be.equal('STACKAPIKEY') + done() + }) + .catch(done) + }) + it('should delete stack role mapping when stack api key is passed', done => { + var mock = new MockAdapter(Axios) + mock.onDelete(`/organizations/organization_uid/teams/team_uid/stack_role_mappings/STACKAPIKEY`).reply(200, { status: 204 }) + makeStackRoleMapping({ stackApiKey: 'STACKAPIKEY' }).delete() + .then((response) => { + expect(response.status).to.be.equal(204) + done() + }) + .catch(done) + }) +}) + +function makeStackRoleMapping (data = {}) { + return new StackRoleMappings(Axios, { organizationUid: 'organization_uid', teamUid: 'team_uid', ...data }) +} diff --git a/test/unit/team-test.js b/test/unit/team-test.js new file mode 100644 index 00000000..9c2ee28c --- /dev/null +++ b/test/unit/team-test.js @@ -0,0 +1,81 @@ +import Axios from 'axios' +import { expect } from 'chai' +import { describe, it } from 'mocha' +import MockAdapter from 'axios-mock-adapter' +import { Teams } from '../../lib/organization/teams' +import { systemUidMock, teamsMock, noticeMock } from './mock/objects' + +describe('Contentstack Team test', () => { + it('should get all the teams when correct organization uid is passed', done => { + var mock = new MockAdapter(Axios) + mock.onGet(`/organizations/organization_uid/teams`).reply(200, [teamsMock]) + makeTeams().fetchAll() + .then((teams) => { + expect(teams.items[0].uid).to.be.equal('UID') + checkTeams(teams.items[0]) + done() + }) + .catch(done) + }) + it('should fetch the team when correct organization uid and team uid is passed', done => { + var mock = new MockAdapter(Axios) + mock.onGet(`/organizations/organization_uid/teams/UID`).reply(200, { ...teamsMock }) + makeTeams({ ...systemUidMock }) + .fetch() + .then((team) => { + checkTeams(team) + done() + }) + .catch(done) + }) + it('should create new team when required object is passedt', done => { + var mock = new MockAdapter(Axios) + mock.onPost(`/organizations/organization_uid/teams`).reply(200, { ...teamsMock }) + makeTeams() + .create({ + name: 'name', + organizationUid: 'organization_uid', + users: [], + stackRoleMapping: [], + organizationRole: 'organizationRole' + }) + .then((team) => { + checkTeams(team) + done() + }) + .catch(done) + }) + it('should update team when updating data is passed', done => { + var mock = new MockAdapter(Axios) + mock.onPut(`/organizations/organization_uid/teams/UID`).reply(200, { ...teamsMock + }) + makeTeams({ ...systemUidMock }) + .update() + .then((team) => { + checkTeams(team) + done() + }) + .catch(done) + }) + it('should delete team when correct organization uid and team uid is passed', done => { + var mock = new MockAdapter(Axios) + mock.onDelete(`/organizations/organization_uid/teams/UID`).reply(200, { + ...noticeMock + }) + makeTeams({ ...systemUidMock }) + .delete() + .then((team) => { + expect(team.notice).to.be.equal(noticeMock.notice) + done() + }) + .catch(done) + }) +}) + +function makeTeams (data = {}) { + return new Teams(Axios, { organizationUid: 'organization_uid', ...data }) +} + +function checkTeams (teams) { + expect(teams.name).to.be.equal('name') +} diff --git a/test/unit/team-users-test.js b/test/unit/team-users-test.js new file mode 100644 index 00000000..5bb9a4f1 --- /dev/null +++ b/test/unit/team-users-test.js @@ -0,0 +1,50 @@ +import Axios from 'axios' +import { expect } from 'chai' +import { describe, it } from 'mocha' +import MockAdapter from 'axios-mock-adapter' +import { TeamUsers } from '../../lib/organization/teams/teamUsers' +import { teamUsersMock, noticeMock } from './mock/objects' + +describe('Contentstack Team Users test', () => { + it('should query and find all users', done => { + var mock = new MockAdapter(Axios) + mock.onGet(`/organizations/organization_uid/teams/team_uid/users`).reply(200, teamUsersMock) + makeTeamUsers().fetchAll() + .then((users) => { + users.items.forEach((user) => { + expect(user.uidId).to.be.not.equal(null) + }) + done() + }) + .catch(done) + }) + it('should add the user when user\'s mail is passed', done => { + var mock = new MockAdapter(Axios) + mock.onPost(`/organizations/organization_uid/teams/team_uid/users`).reply(200, teamUsersMock.addUser) + const usersMail = { + emails: ['email@email.com'] + } + makeTeamUsers() + .add(usersMail) + .then((team) => { + expect(team.userId).to.be.equal('UID') + done() + }) + .catch(done) + }) + it('should remove the user when uid is passed', done => { + var mock = new MockAdapter(Axios) + mock.onDelete(`/organizations/organization_uid/teams/team_uid/users/UID`).reply(200, { ...noticeMock }) + makeTeamUsers({ userId: 'UID' }, noticeMock) + .remove() + .then((user) => { + expect(user.notice).to.be.equal(noticeMock.notice) + done() + }) + .catch(done) + }) +}) + +function makeTeamUsers (data = {}) { + return new TeamUsers(Axios, { organizationUid: 'organization_uid', teamUid: 'team_uid', ...data }) +} diff --git a/types/organization.d.ts b/types/organization.d.ts index 0612b25f..3dc040c3 100644 --- a/types/organization.d.ts +++ b/types/organization.d.ts @@ -7,6 +7,7 @@ import { AnyProperty, SystemFields } from './utility/fields' import { ContentstackCollection, Response } from './contentstackCollection' import { App, Apps } from './app' import { AppRequest } from './app/request' +import { Team, Teams } from './teams' export interface Organizations { fetchAll(params?: AnyProperty): Promise> @@ -25,6 +26,8 @@ export interface Organization extends SystemFields { app(): Apps app(uid: string): App appRequest(): AppRequest + teams(): Teams + teams(uid: string): Team } export interface OrganizationInvite { diff --git a/types/teams/index.d.ts b/types/teams/index.d.ts new file mode 100644 index 00000000..4d980ea0 --- /dev/null +++ b/types/teams/index.d.ts @@ -0,0 +1,28 @@ +import { AnyProperty } from "../utility/fields"; +import { ContentstackCollection } from '../contentstackCollection' +import { Creatable } from "../utility/operations"; +import { TeamUser, TeamUsers, TeamUserData } from "./teamUsers"; +import { StackRoleMapping, StackRoleMappings, StackRoleMappingData } from "./stackRoleMappings"; + +export interface Team extends TeamData { + update(data: TeamData, param?: { includeUserDetails?: boolean}): Promise + users(): TeamUsers + users(uid: string): TeamUser + stackRoleMappings(): StackRoleMappings + stackRoleMappings(stackApiKey: string): StackRoleMapping + fetch(): Promise + delete(): Promise +} + +export interface Teams extends Creatable { + fetchAll(params?: AnyProperty): Promise> +} + +export interface TeamData extends AnyProperty { + uid?: string, + name?: string, + users?: TeamUserData | string[] | [], + stackRoleMapping?: StackRoleMappingData[] | [], + organizationRole?: string +} + diff --git a/types/teams/stackRoleMappings/index.d.ts b/types/teams/stackRoleMappings/index.d.ts new file mode 100644 index 00000000..f85c7447 --- /dev/null +++ b/types/teams/stackRoleMappings/index.d.ts @@ -0,0 +1,18 @@ +import { AnyProperty, SystemFields } from "../../utility/fields"; +import { ContentstackCollection } from '../../contentstackCollection' +import { SystemFunction } from "../../utility/operations"; + +export interface StackRoleMapping extends StackRoleMappingData { + update(data:StackRoleMappingData): Promise +} + +export interface StackRoleMappings extends StackRoleMappingData { + fetchAll(params?: AnyProperty): Promise> + add(data: StackRoleMappingData): Promise +} + +export interface StackRoleMappingData extends AnyProperty { + stackApiKey?: string, + roles: string[] +} + diff --git a/types/teams/teamUsers/index.d.ts b/types/teams/teamUsers/index.d.ts new file mode 100644 index 00000000..a992eef0 --- /dev/null +++ b/types/teams/teamUsers/index.d.ts @@ -0,0 +1,15 @@ +import { AnyProperty } from "../../utility/fields"; + +export interface TeamUsers extends TeamUserData { + add(data:TeamUserData): Promise + fetchAll(params?: { includeUserDetails: boolean, include_count: boolean}): Promise +} + +export interface TeamUser { + remove(): Promise +} + +export interface TeamUserData extends AnyProperty { + emails?: string[] + users?: string[] +}