Repository: auth0/node-auth0
Pull request #260 (2018-04-17 18:56:08)

Adding email templates
```js
var auth = require('auth0');

var mgmt = new auth.ManagementClient({
  domain: 'domain',
  token: 'token'
});

(async () => {
  try {
    const name = 'reset_email';

    const newTemplate = await mgmt.emailTemplates.create({
      template: name,
      body: '',
      from: 'sender@auth0.com',
      resultUrl: '',
      subject: '',
      syntax: 'liquid',
      urlLifetimeInSeconds: 0,
      enabled: false
    });
    console.log(newTemplate);

    const template = await mgmt.emailTemplates.get({ name });
    console.log(template);

    const updatedTemplate = await mgmt.emailTemplates.update(
      { name },
      {
        template: name,
        body: '',
        from: 'sender2@auth0.com',
        resultUrl: '',
        subject: '',
        syntax: 'liquid',
        urlLifetimeInSeconds: 0,
        enabled: false
      }
    );
    console.log(updatedTemplate);
  } catch (error) {
    console.log(error);
  }
})();

```


Patch:
diff --git a/src/management/EmailTemplatesManager.js b/src/management/EmailTemplatesManager.js
new file mode 100644
index 000000000..c92ea85c8
--- /dev/null
+++ b/src/management/EmailTemplatesManager.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 EmailTemplatesManager
+ * This class provides a simple abstraction for performing CRUD operations
+ * on Auth0's Email Templates. {@see https://auth0.com/docs/api/management/v2#!/Email_Templates/get_email_templates_by_templateName}
+ * @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 EmailTemplatesManager = function(options) {
+  if (!options || 'object' !== typeof options) {
+    throw new ArgumentError('Must provide manager options');
+  }
+
+  if (!options.baseUrl || 'string' !== typeof options.baseUrl) {
+    throw new ArgumentError('Must provide a valid string as base URL for the API');
+  }
+
+  /**
+   * 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/management/v2#!/Email_Templates/get_email_templates_by_templateName Auth0's Email Templates}.
+   *
+   * @type {external:RestClient}
+   */
+  var auth0RestClient = new Auth0RestClient(
+    options.baseUrl + '/email-templates/:name',
+    clientOptions,
+    options.tokenProvider
+  );
+  this.resource = new RetryRestClient(auth0RestClient, options.retry);
+};
+
+/**
+ * Create a new Email Template.
+ *
+ * @method    create
+ * @memberOf  module:management.EmailTemplatesManager.prototype
+ *
+ * @example
+ * management.emailTemplates.create(data, function (err) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ *
+ *   // Email Template created.
+ * });
+ *
+ * @param   {Object}    data     Email Template data object.
+ * @param   {Function}  [cb]     Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+utils.wrapPropertyMethod(EmailTemplatesManager, 'create', 'resource.create');
+
+/**
+ * Get an Auth0 Email Template.
+ *
+ * @method    get
+ * @memberOf  module:management.EmailTemplatesManager.prototype
+ *
+ * @example
+ * management.emailTemplates.get({ name: EMAIL_TEMPLATE_NAME }, function (err, emailTemplate) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ *
+ *   console.log(emailTemplate);
+ * });
+ *
+ * @param   {Object}    params          Email Template parameters.
+ * @param   {String}    params.name     Template Name
+ * @param   {Function}  [cb]            Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+utils.wrapPropertyMethod(EmailTemplatesManager, 'get', 'resource.get');
+
+/**
+ * Update an existing Email Template.
+ *
+ * @method    update
+ * @memberOf  module:management.EmailTemplatesManager.prototype
+ *
+ * @example
+ * var data = { from: 'new@email.com' };
+ * var params = { name: EMAIL_TEMPLATE_NAME };
+ *
+ * management.emailTemplates.update(params, data, function (err, emailTemplate) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ *
+ *   console.log(emailTemplate.from);  // 'new@email.com'
+ * });
+ *
+ * @param   {Object}    params          Email Template parameters.
+ * @param   {String}    params.name     Template Name
+ * @param   {Object}    data            Updated Email Template data.
+ * @param   {Function}  [cb]            Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+utils.wrapPropertyMethod(EmailTemplatesManager, 'update', 'resource.patch');
+
+module.exports = EmailTemplatesManager;
diff --git a/src/management/index.js b/src/management/index.js
index ca706be96..96754028c 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 EmailTemplatesManager = require('./EmailTemplatesManager');
 
 var BASE_URL_FORMAT = 'https://%s/api/v2';
 var MANAGEMENT_API_AUD_FORMAT = 'https://%s/api/v2/';
@@ -235,6 +236,14 @@ var ManagementClient = function(options) {
    * @type {ResourceServersManager}
    */
   this.resourceServers = new ResourceServersManager(managerOptions);
+
+  /**
+   * Simple abstraction for performing CRUD operations on
+   * Auth0's Email Templates
+   *
+   * @type {EmailTemplatesManager}
+   */
+  this.emailTemplates = new EmailTemplatesManager(managerOptions);
 };
 
 /**


Test patch:
diff --git a/test/management/email-templates.tests.js b/test/management/email-templates.tests.js
new file mode 100644
index 000000000..24139e5f9
--- /dev/null
+++ b/test/management/email-templates.tests.js
@@ -0,0 +1,247 @@
+var expect = require('chai').expect;
+var nock = require('nock');
+var EmailTemplatesManager = require('../../src/management/EmailTemplatesManager');
+var ArgumentError = require('rest-facade').ArgumentError;
+
+var API_URL = 'https://tenant.auth0.com';
+const TEMPLATE_NAME = 'foobar';
+const DEFAULT_PARAMS = { name: TEMPLATE_NAME };
+const DEFAULT_DATA = {
+  template: 'verify_email',
+  body: '',
+  from: 'sender@auth0.com',
+  resultUrl: '',
+  subject: '',
+  syntax: 'liquid',
+  urlLifetimeInSeconds: 0,
+  enabled: false
+};
+
+describe('EmailTemplatesManager', function() {
+  before(function() {
+    this.token = 'TOKEN';
+    this.emailTemplates = new EmailTemplatesManager({
+      headers: { authorization: 'Bearer ' + this.token },
+      baseUrl: API_URL
+    });
+  });
+  describe('instance', function() {
+    var methods = ['get', 'create', 'update'];
+
+    methods.forEach(function(method) {
+      it('should have a ' + method + ' method', function() {
+        expect(this.emailTemplates[method]).to.exist.to.be.an.instanceOf(Function);
+      });
+    });
+  });
+
+  describe('#constructor', function() {
+    it('should error when no options are provided', function() {
+      expect(EmailTemplatesManager).to.throw(ArgumentError, 'Must provide manager options');
+    });
+
+    it('should throw an error when no base URL is provided', function() {
+      var client = EmailTemplatesManager.bind(null, {});
+
+      expect(client).to.throw(ArgumentError, 'Must provide a valid string as base URL for the API');
+    });
+
+    it('should throw an error when the base URL is invalid', function() {
+      var client = EmailTemplatesManager.bind(null, { baseUrl: '' });
+
+      expect(client).to.throw(ArgumentError, 'Must provide a valid string as base URL for the API');
+    });
+  });
+
+  describe('#get', function() {
+    beforeEach(function() {
+      this.request = nock(API_URL)
+        .get('/email-templates/' + TEMPLATE_NAME)
+        .reply(200, DEFAULT_DATA);
+    });
+
+    it('should accept a callback', function(done) {
+      this.emailTemplates.get(DEFAULT_PARAMS, done.bind(null, null));
+    });
+
+    it('should return a promise if no callback is given', function(done) {
+      this.emailTemplates
+        .get(DEFAULT_PARAMS)
+        .then(done.bind(null, null))
+        .catch(done.bind(null, null));
+    });
+
+    it('should perform a GET request to /api/v2/email-templates/' + TEMPLATE_NAME, function(done) {
+      var request = this.request;
+      this.emailTemplates.get(DEFAULT_PARAMS).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)
+        .get('/email-templates/' + TEMPLATE_NAME)
+        .reply(500);
+
+      this.emailTemplates.get(DEFAULT_PARAMS).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)
+        .get('/email-templates/' + TEMPLATE_NAME)
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.emailTemplates.get(DEFAULT_PARAMS).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+
+  describe('#create', function() {
+    beforeEach(function() {
+      this.request = nock(API_URL)
+        .post('/email-templates')
+        .reply(200);
+    });
+
+    it('should accept a callback', function(done) {
+      this.emailTemplates.create(DEFAULT_DATA, function() {
+        done();
+      });
+    });
+
+    it('should return a promise if no callback is given', function(done) {
+      this.emailTemplates
+        .create(DEFAULT_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)
+        .post('/email-templates')
+        .reply(500);
+
+      this.emailTemplates.create(DEFAULT_DATA).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should perform a POST request to /api/v2/email-templates', function(done) {
+      var request = this.request;
+
+      this.emailTemplates.create(DEFAULT_DATA).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should pass the data in the body of the request', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .post('/email-templates', DEFAULT_DATA)
+        .reply(200);
+
+      this.emailTemplates.create(DEFAULT_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)
+        .post('/email-templates')
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.emailTemplates.create(DEFAULT_DATA).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+
+  describe('#update', function() {
+    beforeEach(function() {
+      this.patchData = { from: 'new@email.com' };
+
+      this.request = nock(API_URL)
+        .patch('/email-templates/' + TEMPLATE_NAME)
+        .reply(200, DEFAULT_DATA);
+    });
+
+    it('should accept a callback', function(done) {
+      this.emailTemplates.update(DEFAULT_PARAMS, {}, done.bind(null, null));
+    });
+
+    it('should return a promise if no callback is given', function(done) {
+      this.emailTemplates
+        .update(DEFAULT_PARAMS, {})
+        .then(done.bind(null, null))
+        .catch(done.bind(null, null));
+    });
+
+    it('should perform a PATCH request to /api/v2/email-templates/' + TEMPLATE_NAME, function(
+      done
+    ) {
+      var request = this.request;
+
+      this.emailTemplates.update(DEFAULT_PARAMS, {}).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+
+    it('should include the new data in the body of the request', function(done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .patch('/email-templates/' + TEMPLATE_NAME, this.patchData)
+        .reply(200);
+
+      this.emailTemplates.update(DEFAULT_PARAMS, this.patchData).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)
+        .patch('/email-templates/' + TEMPLATE_NAME)
+        .reply(500);
+
+      this.emailTemplates.update(DEFAULT_PARAMS, this.patchData).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+  });
+});