diff --git a/src/management/GrantsManager.js b/src/management/GrantsManager.js new file mode 100644 index 000000000..9ccaf09a7 --- /dev/null +++ b/src/management/GrantsManager.js @@ -0,0 +1,119 @@ +var ArgumentError = require('rest-facade').ArgumentError; +var utils = require('../utils'); +var Auth0RestClient = require('../Auth0RestClient'); +var RetryRestClient = require('../RetryRestClient'); +/** + * @class GrantsManager + * Auth0 Grants Manager. + * + * See {@link https://auth0.com/docs/api/v2#!/Grants Grants} + * + * @constructor + * @memberOf module:management + * + * @param {Object} options The client options. + * @param {String} options.baseUrl The URL of the API. + * @param {Object} [options.headers] Headers to be included in all requests. + * @param {Object} [options.retry] Retry Policy Config + */ +var GrantsManager = function(options) { + if (options === null || typeof options !== 'object') { + throw new ArgumentError('Must provide client options'); + } + + if (options.baseUrl === null || options.baseUrl === undefined) { + throw new ArgumentError('Must provide a base URL for the API'); + } + + if ('string' !== typeof options.baseUrl || options.baseUrl.length === 0) { + throw new ArgumentError('The provided base URL is invalid'); + } + + /** + * Options object for the Rest Client instance. + * + * @type {Object} + */ + var clientOptions = { + errorFormatter: { message: 'message', name: 'error' }, + headers: options.headers, + query: { repeatParams: false } + }; + + /** + * Provides an abstraction layer for consuming the + * {@link https://auth0.com/docs/api/v2#!/Grants Auth0 Grants endpoint}. + * + * @type {external:RestClient} + */ + var auth0RestClient = new Auth0RestClient( + options.baseUrl + '/grants/:id', + clientOptions, + options.tokenProvider + ); + this.resource = new RetryRestClient(auth0RestClient, options.retry); +}; + +/** + * Get all Auth0 Grants. + * + * @method getAll + * @memberOf module:management.GrantsManager.prototype + * + * @example + * var params = { + * per_page: 10, + * page: 0, + * include_totals: true, + * user_id: 'USER_ID', + * client_id: 'CLIENT_ID', + * audience: 'AUDIENCE' + * }; + * + * management.getGrants(params, function (err, grants) { + * console.log(grants.length); + * }); + * + * @param {Object} params Grants parameters. + * @param {Number} params.per_page Number of results per page. + * @param {Number} params.page Page number, zero indexed. + * @param {Boolean} params.include_totals true if a query summary must be included in the result, false otherwise. Default false; + * @param {String} params.user_id The user_id of the grants to retrieve. + * @param {String} params.client_id The client_id of the grants to retrieve. + * @param {String} params.audience The audience of the grants to retrieve. + * @param {Function} [cb] Callback function. + * + * @return {Promise|undefined} + */ +utils.wrapPropertyMethod(GrantsManager, 'getAll', 'resource.getAll'); + +/** + * Delete an Auth0 grant. + * + * @method delete + * @memberOf module:management.GrantsManager.prototype + * + * @example + * var params = { + * id: 'GRANT_ID', + * user_id: 'USER_ID' + * }; + * + * management.deleteGrant(params, function (err) { + * if (err) { + * // Handle error. + * } + * + * // Grant deleted. + * }); + * + * @param {Object} params Grant parameters. + * @param {String} params.id Grant ID. + * @param {String} params.user_id The user_id of the grants to delete. + * @param {Function} [cb] Callback function. + * + * @return {Promise|undefined} + */ +utils.wrapPropertyMethod(GrantsManager, 'delete', 'resource.delete'); + +module.exports = GrantsManager; diff --git a/src/management/index.js b/src/management/index.js index ee75f5964..106128d6a 100644 --- a/src/management/index.js +++ b/src/management/index.js @@ -11,6 +11,7 @@ var assign = Object.assign || require('object.assign'); // Managers. var ClientsManager = require('./ClientsManager'); var ClientGrantsManager = require('./ClientGrantsManager'); +var GrantsManager = require('./GrantsManager'); var UsersManager = require('./UsersManager'); var ConnectionsManager = require('./ConnectionsManager'); var BlacklistedTokensManager = require('./BlacklistedTokensManager'); @@ -149,6 +150,14 @@ var ManagementClient = function(options) { */ this.clientGrants = new ClientGrantsManager(managerOptions); + /** + * Simple abstraction for performing CRUD operations on the grants + * endpoint. + * + * @type {GrantsManager} + */ + this.grants = new GrantsManager(managerOptions); + /** * Simple abstraction for performing CRUD operations on the * users endpoint. @@ -662,6 +671,68 @@ utils.wrapPropertyMethod(ManagementClient, 'updateClientGrant', 'clientGrants.up */ utils.wrapPropertyMethod(ManagementClient, 'deleteClientGrant', 'clientGrants.delete'); +/** + * Get all Auth0 Grants. + * + * @method getGrants + * @memberOf module:management.ManagementClient.prototype + * + * @example + * var params = { + * per_page: 10, + * page: 0, + * include_totals: true, + * user_id: USER_ID, + * client_id: CLIENT_ID, + * audience: AUDIENCE + * }; + * + * management.getGrants(params, function (err, grants) { + * console.log(grants.length); + * }); + * + * @param {Object} params Grants parameters. + * @param {Number} params.per_page Number of results per page. + * @param {Number} params.page Page number, zero indexed. + * @param {Boolean} params.include_totals true if a query summary must be included in the result, false otherwise. Default false; + * @param {String} params.user_id The user_id of the grants to retrieve. + * @param {String} params.client_id The client_id of the grants to retrieve. + * @param {String} params.audience The audience of the grants to retrieve. + * @param {Function} [cb] Callback function. + * + * @return {Promise|undefined} + */ +utils.wrapPropertyMethod(ManagementClient, 'getGrants', 'grants.getAll'); + +/** + * Delete an Auth0 grant. + * + * @method deleteGrant + * @memberOf module:management.GrantsManager.prototype + * + * @example + * var params = { + * id: GRANT_ID, + * user_id: USER_ID + * }; + * + * management.deleteGrant(params, function (err) { + * if (err) { + * // Handle error. + * } + * + * // Grant deleted. + * }); + * + * @param {Object} params Grant parameters. + * @param {String} params.id Grant ID. + * @param {String} params.user_id The user_id of the grants to delete. + * @param {Function} [cb] Callback function. + * + * @return {Promise|undefined} + */ +utils.wrapPropertyMethod(ManagementClient, 'deleteGrant', 'grants.delete'); + /** * Create an Auth0 credential. * diff --git a/test/management/grants.tests.js b/test/management/grants.tests.js new file mode 100644 index 000000000..665a34a7f --- /dev/null +++ b/test/management/grants.tests.js @@ -0,0 +1,174 @@ +var expect = require('chai').expect; +var nock = require('nock'); +var Promise = require('bluebird'); + +var SRC_DIR = '../../src'; +var API_URL = 'https://tenant.auth0.com'; + +var GrantsManager = require(SRC_DIR + '/management/GrantsManager'); +var ArgumentError = require('rest-facade').ArgumentError; + +describe('GrantsManager', function() { + before(function() { + this.token = 'TOKEN'; + this.grants = new GrantsManager({ + headers: { + authorization: 'Bearer ' + this.token + }, + baseUrl: API_URL + }); + }); + + afterEach(function() { + nock.cleanAll(); + }); + + describe('instance', function() { + var methods = ['getAll', 'delete']; + + methods.forEach(function(method) { + it('should have a ' + method + ' method', function() { + expect(this.grants[method]).to.exist.to.be.an.instanceOf(Function); + }); + }); + }); + + describe('#constructor', function() { + it('should error when no options are provided', function() { + expect(GrantsManager).to.throw(ArgumentError, 'Must provide client options'); + }); + + it('should throw an error when no base URL is provided', function() { + var grants = GrantsManager.bind(null, {}); + + expect(grants).to.throw(ArgumentError, 'Must provide a base URL for the API'); + }); + + it('should throw an error when the base URL is invalid', function() { + var grants = GrantsManager.bind(null, { baseUrl: '' }); + + expect(grants).to.throw(ArgumentError, 'The provided base URL is invalid'); + }); + }); + + describe('#getAll', function() { + beforeEach(function() { + this.request = nock(API_URL) + .get('/grants') + .reply(200); + }); + + it('should accept a callback', function(done) { + this.grants.getAll(function() { + done(); + }); + }); + + it('should return a promise if no callback is given', function(done) { + this.grants + .getAll() + .then(done.bind(null, null)) + .catch(done.bind(null, null)); + }); + + it('should pass any errors to the promise catch handler', function(done) { + nock.cleanAll(); + + var request = nock(API_URL) + .get('/grants') + .reply(500); + + this.grants.getAll().catch(function(err) { + expect(err).to.exist; + done(); + }); + }); + + it('should pass the body of the response to the "then" handler', function(done) { + nock.cleanAll(); + + var data = [{ test: true }]; + var request = nock(API_URL) + .get('/grants') + .reply(200, data); + + this.grants.getAll().then(function(grants) { + expect(grants).to.be.an.instanceOf(Array); + + expect(grants.length).to.equal(data.length); + + expect(grants[0].test).to.equal(data[0].test); + + done(); + }); + }); + + it('should perform a GET request to /api/v2/grants', function(done) { + var request = this.request; + + this.grants.getAll().then(function() { + expect(request.isDone()).to.be.true; + done(); + }); + }); + + it('should include the token in the Authorization header', function(done) { + nock.cleanAll(); + + var request = nock(API_URL) + .get('/grants') + .matchHeader('Authorization', 'Bearer ' + this.token) + .reply(200); + + this.grants.getAll().then(function() { + expect(request.isDone()).to.be.true; + done(); + }); + }); + + it('should pass the parameters in the query-string', function(done) { + nock.cleanAll(); + + var request = nock(API_URL) + .get('/grants') + .query({ + include_fields: true, + fields: 'test' + }) + .reply(200); + + this.grants.getAll({ include_fields: true, fields: 'test' }).then(function() { + expect(request.isDone()).to.be.true; + done(); + }); + }); + }); + + describe('#delete', function() { + var id = 5; + + beforeEach(function() { + this.request = nock(API_URL) + .delete('/grants/' + id) + .reply(200); + }); + + it('should accept a callback', function(done) { + this.grants.delete({ id: id }, done.bind(null, null)); + }); + + it('should return a promise when no callback is given', function(done) { + this.grants.delete({ id: id }).then(done.bind(null, null)); + }); + + it('should perform a DELETE request to /grants/' + id, function(done) { + var request = this.request; + + this.grants.delete({ id: id }).then(function() { + expect(request.isDone()).to.be.true; + + done(); + }); + }); + }); +}); diff --git a/test/management/management-client.tests.js b/test/management/management-client.tests.js index 86ef52613..955fb6c2c 100644 --- a/test/management/management-client.tests.js +++ b/test/management/management-client.tests.js @@ -8,6 +8,7 @@ var UsersManager = require('../../src/management/UsersManager'); var BlacklistedTokensManager = require('../../src/management/BlacklistedTokensManager'); var ClientsManager = require('../../src/management/ClientsManager'); var ClientGrantsManager = require('../../src/management/ClientGrantsManager'); +var GrantsManager = require('../../src/management/GrantsManager'); var ConnectionsManager = require('../../src/management/ConnectionsManager'); var DeviceCredentialsManager = require('../../src/management/DeviceCredentialsManager'); var EmailProviderManager = require('../../src/management/EmailProviderManager'); @@ -111,6 +112,10 @@ describe('ManagementClient', function() { property: 'clientGrants', cls: ClientGrantsManager }, + GrantsManager: { + property: 'grants', + cls: GrantsManager + }, ConnectionsManager: { property: 'connections', cls: ConnectionsManager @@ -177,6 +182,8 @@ describe('ManagementClient', function() { 'createClientGrant', 'updateClientGrant', 'deleteClientGrant', + 'getGrants', + 'deleteGrant', 'createDevicePublicKey', 'getDeviceCredentials', 'deleteDeviceCredential',