Repository: auth0/node-auth0
Pull request #574 (2021-01-18 20:10:00)

ULP-2609/ULP-2914: add page templates support to /branding
### Changes
This PR adds support for `PUT/GET/DELETE /branding/templates/universal-login`:
- `BrandingManager#setUniversalLoginTemplate` / `ManagementClient#setBrandingUniversalLoginTemplate`
- `BrandingManager#getUniversalLoginTemplate` / `ManagementClient#getBrandingUniversalLoginTemplate`
- `BrandingManager#deleteUniversalLoginTemplate` / `ManagementClient#deleteBrandingUniversalLoginTemplate`

Must be merged after: https://github.com/auth0/api2/pull/4613

### References
- Jira: https://auth0team.atlassian.net/browse/ULP-2914
- Jira parent: https://auth0team.atlassian.net/browse/ULP-2609
- Required: https://github.com/auth0/api2/pull/4613

### Testing

To test this, wait until the changes are available in the Management API and then make calls to `PUT/GET/DELETE /branding/templates/universal-login` through the `BrandingManager` / `ManagementClient`.

- [x] This change adds unit test coverage
- [ ] This change adds integration test coverage

### Checklist

- [x] I have read the [Auth0 general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md)
- [x] I have read the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md)
- [x] All existing and new tests complete without errors



Patch:
diff --git a/src/management/BrandingManager.js b/src/management/BrandingManager.js
index a537d6cae..42609bdfb 100644
--- a/src/management/BrandingManager.js
+++ b/src/management/BrandingManager.js
@@ -51,6 +51,19 @@ var BrandingManager = function(options) {
     options.tokenProvider
   );
   this.resource = new RetryRestClient(auth0RestClient, options.retry);
+
+  /**
+   * Provides an abstraction layer for consuming the
+   * {@link https://auth0.com/docs/api/management/v2#!/Branding/get_universal_login Branding new universal login template endpoint}.
+   *
+   * @type {external:RestClient}
+   */
+  var brandingTemplateAuth0RestClient = new Auth0RestClient(
+    options.baseUrl + '/branding/templates/universal-login',
+    clientOptions,
+    options.tokenProvider
+  );
+  this.brandingTemplates = new RetryRestClient(brandingTemplateAuth0RestClient, options.retry);
 };
 
 /**
@@ -101,4 +114,70 @@ utils.wrapPropertyMethod(BrandingManager, 'updateSettings', 'resource.patch');
  */
 utils.wrapPropertyMethod(BrandingManager, 'getSettings', 'resource.get');
 
+/**
+ * Get the new universal login template.
+ *
+ * @method    getUniversalLoginTemplate
+ * @memberOf  module:management.BrandingManager.prototype
+ *
+ * @example
+ * management.branding.getUniversalLoginTemplate(data, function (err, template) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ *
+ * // Branding
+ *    console.log(template);
+ * });
+ *
+ * @param   {Object}    params            Branding parameters (leave empty).
+ * @param   {Object}    data              Branding data (leave empty).
+ * @param   {Function}  [cb]              Callback function.
+ *
+ * @return    {Promise|undefined}
+ */
+utils.wrapPropertyMethod(BrandingManager, 'getUniversalLoginTemplate', 'brandingTemplates.get');
+
+/**
+ * Set the new universal login template.
+ *
+ * @method    setUniversalLoginTemplate
+ * @memberOf  module:management.BrandingManager.prototype
+ *
+ * @example
+ * management.branding.setUniversalLoginTemplate({ template: "a template" }, function (err) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ * });
+ *
+ * @param   {Object}    params            Branding parameters (leavy empty).
+ * @param   {Object}    data              Branding data (object with template field).
+ * @param   {Function}  [cb]              Callback function.
+ *
+ * @return    {Promise|undefined}
+ */
+utils.wrapPropertyMethod(BrandingManager, 'setUniversalLoginTemplate', 'brandingTemplates.update');
+
+/**
+ * Delete the new universal login template (revert to default).
+ *
+ * @method    deleteUniversalLoginTemplate
+ * @memberOf  module:management.BrandingManager.prototype
+ *
+ * @example
+ * management.branding.deleteUniversalLoginTemplate(data, function (err) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ * });
+ *
+ * @param   {Object}    params            Branding parameters (leavy empty).
+ * @param   {Object}    data              Branding data (leave empty).
+ * @param   {Function}  [cb]              Callback function.
+ *
+ * @return    {Promise|undefined}
+ */
+utils.wrapPropertyMethod(BrandingManager, 'deleteUniversalLoginTemplate', 'brandingTemplates.delete');
+
 module.exports = BrandingManager;
diff --git a/src/management/index.js b/src/management/index.js
index 1dfac641d..95cfd4522 100644
--- a/src/management/index.js
+++ b/src/management/index.js
@@ -3651,6 +3651,72 @@ utils.wrapPropertyMethod(ManagementClient, 'updateBrandingSettings', 'branding.u
  */
 utils.wrapPropertyMethod(ManagementClient, 'getBrandingSettings', 'branding.getSettings');
 
+/**
+ * Get the new universal login template.
+ *
+ * @method    getBrandingUniversalLoginTemplate
+ * @memberOf  module:management.ManagementClient.prototype
+ *
+ * @example
+ * management.getBrandingUniversalLoginTemplate(data, function (err, template) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ *
+ * // Branding
+ *    console.log(template);
+ * });
+ *
+ * @param   {Object}    params            Branding parameters (leave empty).
+ * @param   {Object}    data              Branding data (leave empty).
+ * @param   {Function}  [cb]              Callback function.
+ *
+ * @return    {Promise|undefined}
+ */
+utils.wrapPropertyMethod(ManagementClient, 'getBrandingUniversalLoginTemplate', 'branding.getUniversalLoginTemplate');
+
+/**
+ * Get the new universal login template.
+ *
+ * @method    setBrandingUniversalLoginTemplate
+ * @memberOf  module:management.ManagementClient.prototype
+ *
+ * @example
+ * management.setBrandingUniversalLoginTemplate({ template: "a template" }, function (err, template) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ * });
+ *
+ * @param   {Object}    params            Branding parameters (leave empty).
+ * @param   {Object}    template          Branding data (object with template field).
+ * @param   {Function}  [cb]              Callback function.
+ *
+ * @return    {Promise|undefined}
+ */
+utils.wrapPropertyMethod(ManagementClient, 'setBrandingUniversalLoginTemplate', 'branding.setUniversalLoginTemplate');
+
+/**
+ * Delete the new universal login template.
+ *
+ * @method    deleteBrandingUniversalLoginTemplate
+ * @memberOf  module:management.ManagementClient.prototype
+ *
+ * @example
+ * management.deleteBrandingUniversalLoginTemplate(template, function (err) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ * });
+ *
+ * @param   {Object}    params            Branding parameters (leave empty).
+ * @param   {Object}    data              Branding data (leave empty).
+ * @param   {Function}  [cb]              Callback function.
+ *
+ * @return    {Promise|undefined}
+ */
+utils.wrapPropertyMethod(ManagementClient, 'deleteBrandingUniversalLoginTemplate', 'branding.deleteUniversalLoginTemplate');
+
 /**
  * Update the tenant migrations.
  *


Test patch:
diff --git a/test/management/branding.tests.js b/test/management/branding.tests.js
index 103559ce7..e8c69c59c 100644
--- a/test/management/branding.tests.js
+++ b/test/management/branding.tests.js
@@ -233,4 +233,244 @@ describe('BrandingManager', function() {
       });
     });
   });
+
+  describe('#getUniversalLoginTemplate', function() {
+    beforeEach(function() {
+      this.request = nock(API_URL)
+        .get('/branding/templates/universal-login')
+        .reply(200);
+    });
+
+    afterEach(function() {
+      nock.cleanAll();
+    });
+
+    it('should accept a callback', function(done) {
+      this.branding.getUniversalLoginTemplate(function() {
+        done();
+      });
+    });
+
+    it('should return a promise if no callback is given', function(done) {
+      this.branding
+        .getUniversalLoginTemplate()
+        .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('/branding/templates/universal-login')
+        .reply(500);
+
+      this.branding.getUniversalLoginTemplate().catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should pass the body of the response to the "then" handler', function(done) {
+      var data = { body: 'test' };
+
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/branding/templates/universal-login')
+        .reply(200, data);
+
+      this.branding.getUniversalLoginTemplate().then(function(response) {
+        expect(response.body).to.equal(data.body);
+
+        done();
+      });
+    });
+
+    it('should perform a GET request to /api/v2/branding', function(done) {
+      var request = this.request;
+
+      this.branding.getUniversalLoginTemplate().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('/branding/templates/universal-login')
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.branding.getUniversalLoginTemplate().then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+
+  describe('#setUniversalLoginTemplate', function() {
+    beforeEach(function() {
+      this.request = nock(API_URL)
+        .put('/branding/templates/universal-login')
+        .reply(200);
+    });
+
+    afterEach(function() {
+      nock.cleanAll();
+    });
+
+    it('should accept a callback', function(done) {
+      this.branding.setUniversalLoginTemplate({}, {}, function() {
+        done();
+      });
+    });
+
+    it('should return a promise if no callback is given', function(done) {
+      this.branding
+        .setUniversalLoginTemplate({}, {})
+        .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('/branding/templates/universal-login')
+        .reply(500);
+
+      this.branding.setUniversalLoginTemplate({}, {}).catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should pass the body of the response to the "then" handler', function(done) {
+      var data = { body: 'test' };
+
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .put('/branding/templates/universal-login')
+        .reply(200, data);
+
+      this.branding.setUniversalLoginTemplate({}, data).then(function(response) {
+        expect(response.body).to.equal(data.body);
+
+        done();
+      });
+    });
+
+    it('should perform a PUT request to /api/v2/branding/templates/universal-login', function(done) {
+      var request = this.request;
+
+      this.branding.setUniversalLoginTemplate({}, {}).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('/branding/templates/universal-login')
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.branding.setUniversalLoginTemplate({}, {}).then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
+
+  describe('#deleteUniversalLoginTemplate', function() {
+    beforeEach(function() {
+      this.request = nock(API_URL)
+        .delete('/branding/templates/universal-login')
+        .reply(200);
+    });
+
+    afterEach(function() {
+      nock.cleanAll();
+    });
+
+    it('should accept a callback', function(done) {
+      this.branding.deleteUniversalLoginTemplate(function() {
+        done();
+      });
+    });
+
+    it('should return a promise if no callback is given', function(done) {
+      this.branding
+        .deleteUniversalLoginTemplate()
+        .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)
+        .delete('/branding/templates/universal-login')
+        .reply(500);
+
+      this.branding.deleteUniversalLoginTemplate().catch(function(err) {
+        expect(err).to.exist;
+
+        done();
+      });
+    });
+
+    it('should pass the body of the response to the "then" handler', function(done) {
+      var data = { body: 'test' };
+
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .delete('/branding/templates/universal-login')
+        .reply(200, data);
+
+      this.branding.deleteUniversalLoginTemplate().then(function(response) {
+        expect(response.body).to.equal(data.body);
+
+        done();
+      });
+    });
+
+    it('should perform a DELETE request to /api/v2/branding/templates/universal-login', function(done) {
+      var request = this.request;
+
+      this.branding.deleteUniversalLoginTemplate().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)
+        .delete('/branding/templates/universal-login')
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200);
+
+      this.branding.deleteUniversalLoginTemplate().then(function() {
+        expect(request.isDone()).to.be.true;
+
+        done();
+      });
+    });
+  });
 });