Repository: auth0/node-auth0
Pull request #227 (2018-01-03 23:19:52)

Added rules config methods
Added support for the [Rules Configs](https://auth0.com/docs/api/management/v2#!/Rules_Configs/get_rules_configs) endpoints.

```
var auth0 = new ManagementClient({...});

auth0.rulesConfigs.set({ key: 'dbconnectionstring' }, { value: 'secret' }).then(...)

auth0.rulesConfigs.delete({ key: 'dbconnectionstring' }).then(...)

auth0.rulesConfigs.getAll().then(...)
```


Patch:
diff --git a/src/management/RulesConfigsManager.js b/src/management/RulesConfigsManager.js
new file mode 100644
index 000000000..99e81e6e2
--- /dev/null
+++ b/src/management/RulesConfigsManager.js
@@ -0,0 +1,129 @@
+var ArgumentError = require('rest-facade').ArgumentError;
+var utils = require('../utils');
+var Auth0RestClient = require('../Auth0RestClient');
+var RetryRestClient = require('../RetryRestClient');
+
+/**
+ * Simple facade for consuming a REST API endpoint.
+ * @external RestClient
+ * @see https://github.com/ngonzalvez/rest-facade
+ */
+
+
+/**
+ * @class RulesConfigsManager
+ * The rules configs manager class provides a simple abstraction for performing CRUD operations
+ * on Auth0 RulesConfigsManager.
+ * @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 RulesConfigsManager = function (options) {
+  if (options === null || typeof options !== 'object') {
+    throw new ArgumentError('Must provide manager 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 = {
+    headers: options.headers,
+    query: { repeatParams: false }
+  };
+
+  /**
+   * Provides an abstraction layer for performing CRUD operations on
+   * {@link https://auth0.com/docs/api/v2#!/RulesConfigsManager Auth0 RulesConfigsManager}.
+   *
+   * @type {external:RestClient}
+   */
+  var auth0RestClient = new Auth0RestClient(options.baseUrl + '/rules-configs/:key', clientOptions, options.tokenProvider);
+  this.resource = new RetryRestClient(auth0RestClient, options.retry);
+};
+
+
+/**
+ * Set a new rules config.
+ *
+ * @method    set
+ * @memberOf  module:management.RulesConfigsManager.prototype
+ *
+ * @example
+ * var params = { key: RULE_CONFIG_KEY };
+ * var data =   { value: RULES_CONFIG_VALUE };
+ *  
+ * management.rulesConfigs.set(params, data, function (err, rulesConfig) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ *
+ *   // Rules Config set.
+ * });
+ *
+ * @param   {Object}    params        Rule Config parameters.
+ * @param   {String}    params.key    Rule Config key.
+ * @param   {Object}    data          Rule Config Data parameters.
+ * @param   {String}    data.value    Rule Config Data value.
+ * @param   {Function}  [cb]    Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+utils.wrapPropertyMethod(RulesConfigsManager, 'set', 'resource.update');
+
+
+/**
+ * Get all rules configs.
+ *
+ * @method    getAll
+ * @memberOf  module:management.RulesConfigsManager.prototype
+ *
+ * @example
+ * management.rulesConfigs.getAll(function (err, rulesConfig) {
+ *   console.log(rulesConfig.length);
+ * });
+ *
+ * @param   {Function}  [cb]     Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+utils.wrapPropertyMethod(RulesConfigsManager, 'getAll', 'resource.getAll');
+
+
+/**
+ * Delete an existing rules config.
+ *
+ * @method    delete
+ * @memberOf  module:management.RulesConfigsManager.prototype
+ *
+ * @example
+ * management.rulesConfigs.delete({ key: RULE_CONFIG_KEY }, function (err) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ *
+ *   // Rules Config deleted.
+ * });
+ *
+ * @param   {Object}    params        Rule Configs parameters.
+ * @param   {String}    params.key    Rule Configs key.
+ * @param   {Function}  [cb]          Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+utils.wrapPropertyMethod(RulesConfigsManager, 'delete', 'resource.delete');
+
+module.exports = RulesConfigsManager;
\ No newline at end of file
diff --git a/src/management/index.js b/src/management/index.js
index fe5774de6..64d8958bc 100644
--- a/src/management/index.js
+++ b/src/management/index.js
@@ -24,6 +24,7 @@ var TicketsManager = require('./TicketsManager');
 var LogsManager = require('./LogsManager');
 var ResourceServersManager = require('./ResourceServersManager');
 var ManagementTokenProvider = require('./ManagementTokenProvider');
+var RulesConfigsManager = require('./RulesConfigsManager');
 var EmailTemplatesManager = require('./EmailTemplatesManager');
 
 var BASE_URL_FORMAT = 'https://%s/api/v2';
@@ -244,6 +245,13 @@ var ManagementClient = function(options) {
    * @type {EmailTemplatesManager}
    */
   this.emailTemplates = new EmailTemplatesManager(managerOptions);
+
+  /**
+   * RulesConfigs manager.
+   *
+   * @type {RulesConfigsManager}
+   */
+  this.rulesConfigs = new RulesConfigsManager(managerOptions);
 };
 
 /**
@@ -1693,4 +1701,78 @@ utils.wrapPropertyMethod(ManagementClient, 'deleteResourceServer', 'resourceServ
  * @return    {Promise|undefined}
  */
 utils.wrapPropertyMethod(ManagementClient, 'updateResourceServer', 'resourceServers.update');
+
+/**
+ * Set a new rules config.
+ *
+ * @method    setRulesConfig
+ * @memberOf  module:management.ManagementClient.prototype
+ *
+ * @example
+ * var params = { key: RULE_CONFIG_KEY };
+ * var data =   { value: RULES_CONFIG_VALUE };
+ *
+ * management.setRulesConfig(params, data, function (err, rulesConfig) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ *
+ *   // Rules Config set.
+ * });
+ *
+ * @param   {Object}    params        Rule Config parameters.
+ * @param   {String}    params.key    Rule Config key.
+ * @param   {Object}    data          Rule Config Data parameters.
+ * @param   {String}    data.value    Rule Config Data value.
+ * @param   {Function}  [cb]    Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+utils.wrapPropertyMethod(ManagementClient, 'setRulesConfig', 'rulesConfigs.set');
+
+/**
+ * Get rules config.
+ *
+ * @method    getRulesConfigs
+ * @memberOf  module:management.ManagementClient.prototype
+ *
+ * @example
+ *
+ * management.getRulesConfigs(function (err, rulesConfigs) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ *
+ *   // Get Rules Configs.
+ * });
+ *
+ * @return  {Promise|undefined}
+ */
+utils.wrapPropertyMethod(ManagementClient, 'getRulesConfigs', 'rulesConfigs.getAll');
+
+/**
+ * Delete rules config.
+ *
+ * @method    deleteRulesConfig
+ * @memberOf  module:management.ManagementClient.prototype
+ *
+ * @example
+ *
+ * management.deleteRulesConfig({ key: RULE_CONFIG_KEY }, function (err) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ *
+ *   // Rules Config deleted.
+ * });
+ *
+ * @param   {Object}    params        Rule Configs parameters.
+ * @param   {String}    params.key    Rule Configs key.
+ * @param   {Function}  [cb]          Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+utils.wrapPropertyMethod(ManagementClient, 'deleteRulesConfig', 'rulesConfigs.delete');
+
+
 module.exports = ManagementClient;


Test patch:
diff --git a/test/management/management-client.tests.js b/test/management/management-client.tests.js
index 4ae834299..86ef52613 100644
--- a/test/management/management-client.tests.js
+++ b/test/management/management-client.tests.js
@@ -14,6 +14,7 @@ var EmailProviderManager = require('../../src/management/EmailProviderManager');
 var JobsManager = require('../../src/management/JobsManager');
 var RulesManager = require('../../src/management/RulesManager');
 var StatsManager = require('../../src/management/StatsManager');
+var RulesConfigsManager = require('../../src/management/RulesConfigsManager');
 
 var TenantManager = require('../../src/management/TenantManager');
 
@@ -137,7 +138,11 @@ describe('ManagementClient', function() {
       TenantManager: {
         property: 'tenant',
         cls: TenantManager
-      }
+      },
+      'RulesConfigsManager': {
+        property: 'rulesConfigs',
+        cls: RulesConfigsManager
+      },
     };
 
     before(function() {
@@ -197,7 +202,10 @@ describe('ManagementClient', function() {
       'getTenantSettings',
       'updateTenantSettings',
       'deleteUserMultifactor',
-      'deleteUserMultifcator'
+      'deleteUserMultifcator',
+      'setRulesConfig',
+      'getRulesConfigs',
+      'deleteRulesConfig'
     ];
 
     before(function() {
diff --git a/test/management/rules-configs.tests.js b/test/management/rules-configs.tests.js
new file mode 100644
index 000000000..691e0e0a3
--- /dev/null
+++ b/test/management/rules-configs.tests.js
@@ -0,0 +1,357 @@
+var expect = require('chai').expect;
+var nock = require('nock');
+
+var SRC_DIR = '../../src';
+var API_URL = 'https://tenant.auth0.com';
+
+var RulesConfigsManager = require(SRC_DIR + '/management/RulesConfigsManager');
+var ArgumentError = require('rest-facade').ArgumentError;
+
+
+describe('RulesConfigsManager', function () {
+  before(function () {
+    this.token = 'TOKEN';
+    this.rulesConfigs = new RulesConfigsManager({
+      headers: { authorization: 'Bearer ' + this.token },
+      baseUrl: API_URL
+    });
+  });
+
+  describe('instance', function () {
+    var methods = ['set', 'getAll', 'delete'];
+
+    methods.forEach(function (method) {
+      it('should have a ' + method + ' method', function () {
+        expect(this.rulesConfigs[method])
+          .to.exist
+          .to.be.an.instanceOf(Function);
+      })
+    });
+  });
+
+  describe('#constructor', function () {
+    it('should error when no options are provided', function () {
+      expect(RulesConfigsManager)
+        .to.throw(ArgumentError, 'Must provide manager options');
+    });
+
+
+    it('should throw an error when no base URL is provided', function () {
+      var client = RulesConfigsManager.bind(null, {});
+
+      expect(client)
+        .to.throw(ArgumentError, 'Must provide a base URL for the API');
+    });
+
+
+    it('should throw an error when the base URL is invalid', function () {
+      var client = RulesConfigsManager.bind(null, { baseUrl: '' });
+
+      expect(client)
+        .to.throw(ArgumentError, 'The provided base URL is invalid');
+    });
+  });
+
+  describe('#getAll', function () {
+
+    it('should accept a callback', function (done) {
+      this
+        .rulesConfigs
+        .getAll(function () {
+          done();
+        });
+    });
+
+
+    it('should return a promise if no callback is given', function (done) {
+      this
+        .rulesConfigs
+        .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('/rules-configs')
+        .reply(500);
+
+      this
+        .rulesConfigs
+        .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 = [{ key: 'dbconnectionstring' }];
+      var request = nock(API_URL)
+        .get('/rules-configs')
+        .reply(200, data);
+
+      this
+        .rulesConfigs
+        .getAll()
+        .then(function (rulesConfigs) {
+          expect(rulesConfigs)
+            .to.be.an.instanceOf(Array);
+
+          expect(rulesConfigs.length)
+            .to.equal(data.length);
+
+          expect(rulesConfigs[0].key)
+            .to.equal(data[0].key);
+
+          done();
+        });
+    });
+
+
+    it('should perform a GET request to rules-configs', function (done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/rules-configs')
+        .reply(200);
+
+      this
+        .rulesConfigs
+        .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('/rules-configs')
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200)
+
+      this
+        .rulesConfigs
+        .getAll()
+        .then(function () {
+          expect(request.isDone()).to.be.true;
+          done();
+        });
+    });
+
+
+    it('should pass the parameters in the query-string', function (done) {
+      nock.cleanAll();
+
+      var params = {
+        include_fields: true,
+        fields: 'test'
+      };
+      var request = nock(API_URL)
+        .get('/rules-configs')
+        .query(params)
+        .reply(200)
+
+      this
+        .rulesConfigs
+        .getAll(params)
+        .then(function () {
+          expect(request.isDone())
+            .to.be.true;
+
+          done();
+        });
+    });
+  });
+
+  describe('#set', function () {
+
+    beforeEach(function () {
+      this.data = { value: 'foobar' };
+      this.params = { key: 'KEY' };
+    });
+
+    it('should accept a callback', function (done) {
+      this
+        .rulesConfigs
+        .set(this.params, this.data, function () {
+          done();
+        });
+    });
+
+    it('should return a promise if no callback is given', function (done) {
+      this
+        .rulesConfigs
+        .set(this.params, this.data)
+        .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)
+        .put('/rules-configs/' + this.params.key)
+        .reply(500);
+
+      this
+        .rulesConfigs
+        .set(this.params, this.data)
+        .catch(function (err) {
+          expect(err)
+            .to.exist;
+
+          done();
+        });
+    });
+
+    it('should perform a PUT request to /rules-configs/{KEY}', function (done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .put('/rules-configs/' + this.params.key, this.data)
+        .reply(200);
+
+      this
+        .rulesConfigs
+        .set(this.params, this.data)
+        .then(function () {
+          expect(request.isDone())
+            .to.be.true;
+
+          done();
+        })
+        .catch(function (err) {
+          console.error(err);
+          expect.fail();
+          done();
+        });
+    });
+
+    it('should pass the data in the body of the request', function (done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .put('/rules-configs/' + this.params.key, this.data)
+        .reply(200);
+
+      this
+        .rulesConfigs
+        .set(this.params, this.data)
+        .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)
+        .put('/rules-configs/' + this.params.key, this.data)
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200)
+
+      this
+        .rulesConfigs
+        .set(this.params, this.data)
+        .then(function () {
+          expect(request.isDone())
+            .to.be.true;
+
+          done();
+        });
+    });
+  });
+
+  describe('#delete', function () {
+    var key = 'KEY';
+
+    beforeEach(function () {
+      this.request = nock(API_URL)
+        .delete('/rules-configs/' + key)
+        .reply(200);
+    });
+
+
+    it('should accept a callback', function (done) {
+      this
+        .rulesConfigs
+        .delete({ key: key }, done.bind(null, null));
+    });
+
+
+    it('should return a promise when no callback is given', function (done) {
+      this
+        .rulesConfigs
+        .delete({ key: key })
+        .then(done.bind(null, null));
+    });
+
+
+    it('should perform a delete request to /rules-configs/' + key, function (done) {
+      var request = this.request;
+ 
+      this
+        .rulesConfigs
+        .delete({ key: key })
+        .then(function () {
+          expect(request.isDone())
+            .to.be.true;
+
+          done();
+        });
+    });
+
+
+    it('should pass any errors to the promise catch handler', function (done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .delete('/rules-configs/' + key)
+        .reply(500);
+
+      this
+        .rulesConfigs
+        .delete({ key: key })
+        .catch(function (err) {
+          expect(err)
+            .to.exist;
+
+          done();
+        });
+    });
+
+
+    it('should include the token in the authorization header', function (done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .delete('/rules-configs/' + key)
+        .matchHeader('authorization', 'Bearer ' + this.token)
+        .reply(200)
+
+      this
+        .rulesConfigs
+        .delete({ key: key })
+        .then(function () {
+          expect(request.isDone())
+            .to.be.true;
+
+          done();
+        });
+    });
+  });
+});
\ No newline at end of file